add firmware source code (#4)

* add firmware source code
This commit is contained in:
Forairaaaaa
2026-01-08 09:18:20 +08:00
committed by GitHub
parent 4f1373e449
commit 5001b7081b
164 changed files with 81663 additions and 1 deletions
+164
View File
@@ -0,0 +1,164 @@
BasedOnStyle: Google
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: true
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: true
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
SortPriority: 0
- Regex: '^<.*\.h>'
Priority: 1
SortPriority: 0
- Regex: '^<.*'
Priority: 2
SortPriority: 0
- Regex: '.*'
Priority: 3
SortPriority: 0
IncludeIsMainRegex: '([-_](test|unittest))?$'
IncludeIsMainSourceRegex: ''
IndentCaseLabels: true
IndentGotoLabels: true
IndentPPDirectives: None
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- 'c++'
- 'C++'
CanonicalDelimiter: ''
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
CanonicalDelimiter: ''
BasedOnStyle: google
ReflowComments: true
SortIncludes: false
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
Standard: Auto
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 4
UseCRLF: false
UseTab: Never
+67
View File
@@ -0,0 +1,67 @@
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# MacOS desktop metadata files
.DS_Store
# Build files
build/
cmake-build-*/
/components/
managed_components/
# PlatformIO
.pio/
# VSCode
.vscode/
.cache/
# Python virtual environment
.venv/
# Debug / Release files
Debug/
debug/
Release/
release/
out/
bin/
obj/
*.code-workspace
sdkconfig
sdkconfig.old
xiaozhi-esp32/
+11
View File
@@ -0,0 +1,11 @@
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
set(PROJECT_VER "2.0.4")
# Add this line to disable the specific warning
add_compile_options(-Wno-missing-field-initializers)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(StackChan)
+25 -1
View File
@@ -1 +1,25 @@
# StackChan Firmware
# StackChan Firmware
## Build
### Fetch Dependencies
```bash
python3 ./fetch_repos.py
```
### Tool Chains
[ESP-IDF v5.5.1](https://docs.espressif.com/projects/esp-idf/en/v5.5.1/esp32s3/index.html)
### Build
```bash
idf.py build
```
### Flash
```bash
idf.py flash
```
+770
View File
@@ -0,0 +1,770 @@
dependencies:
78/esp-ml307:
component_hash: 57c8cc3309fb3da9195ec861cba3726b5cf24c362def803e7174c0b1d72e60e3
dependencies:
- name: idf
require: private
version: '>=5.3'
source:
registry_url: https://components.espressif.com/
type: service
version: 3.3.7
78/esp-opus:
component_hash: 8182b733f071d7bfe1e837f4c9f8649a63e4c937177f089e65772880c02f2e17
dependencies:
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com
type: service
version: 1.0.5
78/esp-opus-encoder:
component_hash: b80e5b6d6dc4bf6b0bf1a3729f52b80500e9e6b1003b3e827b78ba738283a296
dependencies:
- name: 78/esp-opus
registry_url: https://components.espressif.com
require: private
version: ^1.0.5
- name: idf
require: private
version: '>=5.3'
source:
registry_url: https://components.espressif.com/
type: service
version: 2.4.1
78/esp-wifi-connect:
component_hash: 2613d9970df9f2203c2c549991e3bad74847b0a7facffe6698f4341e0bf73589
dependencies:
- name: idf
require: private
version: '>=5.3'
source:
registry_url: https://components.espressif.com/
type: service
version: 2.6.1
78/esp_lcd_nv3023:
component_hash: fa88abfc19a312eb5e6f2ffa187e0a9faf67e01e758bfb979d3f9d92561a494f
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: idf
require: private
version: '>=4.4'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.0
78/xiaozhi-fonts:
component_hash: 51f67bcf9dec623de90d9deb72de50dfbc3634fb948b7abf27df65b386258b94
dependencies:
- name: idf
require: private
version: '>=5.3'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.5.4
espressif/adc_battery_estimation:
component_hash: b915167c87ed5a84b13d680bd011c2ed9a15121f1e247c6903141b9f138f3606
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: '*'
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 0.2.1
espressif/adc_mic:
component_hash: ca6ef69bba4dc0d3e0ce53937635ed2734d38ac947881da81b8526e6851a71a4
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: '*'
- name: espressif/esp_codec_dev
registry_url: https://components.espressif.com
require: private
version: ^1.3.*
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 0.2.1
espressif/button:
component_hash: 4ed25fcf354b48aa5e5680b9e7549e38d7738f9b613c94a2e39119c100db9c95
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: '*'
- name: idf
require: private
version: '>=4.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 4.1.4
espressif/cmake_utilities:
component_hash: 351350613ceafba240b761b4ea991e0f231ac7a9f59a9ee901f751bddc0bb18f
dependencies:
- name: idf
require: private
version: '>=4.1'
source:
registry_url: https://components.espressif.com/
type: service
version: 0.5.3
espressif/dl_fft:
component_hash: 7dadbd644c0d7ba4733cc3726ec4cff6edf27b043725e1115861dec1609a3d28
dependencies:
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 0.3.1
espressif/esp-dsp:
component_hash: 42dce32d46ac93dc11f60d368e29a830e9661c7345d794b8a45c343479cae636
dependencies:
- name: idf
require: private
version: '>=4.2'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.7.0
espressif/esp_cam_sensor:
component_hash: 35c1648ea87aac81da7a085d35f61b6d5ad88574bd0c5fdc4ab75efdef4ee6c1
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: espressif/esp_sccb_intf
registry_url: https://components.espressif.com
require: private
version: '>=0.0.5'
- name: idf
require: private
version: '>=5.3'
source:
registry_url: https://components.espressif.com
type: service
targets:
- esp32p4
- esp32s3
- esp32c3
- esp32c5
- esp32c6
- esp32c61
version: 1.5.2
espressif/esp_codec_dev:
component_hash: 0d9e9bc288156eb55f79338d312e1ebf8c9dfbd5e7d13ef0f20ccb031b4e15cf
dependencies:
- name: idf
require: private
version: '>=4.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.5.4
espressif/esp_image_effects:
component_hash: a35037db02862d3cef6f72c25f422ae62da6e6c88219ce03c9ea24e0315ceaaa
dependencies:
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.1
espressif/esp_io_expander:
component_hash: abf3ea0d71407d79d15500550aa3ba433848459b0fa94717cf9478822593ee5d
dependencies:
- name: idf
require: private
version: '>=4.4.2'
source:
registry_url: https://components.espressif.com
type: service
version: 1.1.0
espressif/esp_io_expander_tca9554:
component_hash: 8a9e3a7dbef589a54f814ff22e9121da86bce19d0e1ccffa53f5df6bb346a140
dependencies:
- name: espressif/esp_io_expander
registry_url: https://components.espressif.com
require: public
version: ^1.0.1
- name: idf
require: private
version: '>=5.2'
source:
registry_url: https://components.espressif.com/
type: service
version: 2.0.0
espressif/esp_io_expander_tca95xx_16bit:
component_hash: c384d55e429775d6a1eef26512fbc33bc41823745a8c2ad6d5927729f33a2c21
dependencies:
- name: espressif/esp_io_expander
registry_url: https://components.espressif.com
require: public
version: ^1.0.1
- name: idf
require: private
version: '>=5.2'
source:
registry_url: https://components.espressif.com/
type: service
version: 2.0.1
espressif/esp_lcd_axs15231b:
component_hash: e614bd75827e95800e39df1ba9474166060ab26c3807d06df9cc312a27021cda
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: espressif/esp_lcd_touch
registry_url: https://components.espressif.com
require: public
version: ^1
- name: idf
require: private
version: '>5.0.4,!=5.1.1'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.1~1
espressif/esp_lcd_gc9a01:
component_hash: 09ddc8f5c9d718a659ffa30a4040e1ae75077e68492c38aec8c2beaaa7b3a9bc
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: idf
require: private
version: '>=4.4'
source:
registry_url: https://components.espressif.com/
type: service
version: 2.0.1
espressif/esp_lcd_ili9341:
component_hash: 31f1b793aa2110dd2ae071c21ccbff0a4eb20d9a4ee40b6294c0dc0ad9552c4e
dependencies:
- name: idf
require: private
version: '>=4.4'
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
source:
registry_url: https://components.espressif.com/
type: service
version: 1.2.0
espressif/esp_lcd_panel_io_additions:
component_hash: 213d5c4a3c322a48c9f993d6bc2372206d34af95db34e87a3e02601bdcad7ce8
dependencies:
- name: idf
require: private
version: '>=4.4.2'
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: espressif/esp_io_expander
registry_url: https://components.espressif.com
require: public
version: ^1
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.1
espressif/esp_lcd_spd2010:
component_hash: 8637c97feeb8d83ba637599f6bf4ef30e83595486930e7df17ffa24f3fef1242
dependencies:
- name: idf
require: private
version: '>5.0.4,!=5.1.1'
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.2
espressif/esp_lcd_st7701:
component_hash: 0b11e8733e51e12da83003b9d475777eaf47bfbdce01379879bd2504d14f4f83
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: idf
require: private
version: '>5.0.4,!=5.1.1'
source:
registry_url: https://components.espressif.com/
type: service
targets:
- esp32s3
- esp32p4
version: 1.1.5
espressif/esp_lcd_st77916:
component_hash: 5fa0f8b1274576d4484e2b8d9358e2a5d09c721511bef0dce6a55b4206b5f0e9
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: idf
require: private
version: '>5.0.4,!=5.1.1'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.1
espressif/esp_lcd_st7796:
component_hash: c37b10363125eb3b4757d509392ffca963c27262b61939fdb49a7b18eeef975c
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: idf
require: private
version: '>=4.4'
source:
registry_url: https://components.espressif.com/
type: service
targets:
- esp32
- esp32s2
- esp32s3
- esp32p4
version: 1.3.5
espressif/esp_lcd_touch:
component_hash: 3f85a7d95af876f1a6ecca8eb90a81614890d0f03a038390804e5a77e2caf862
dependencies:
- name: idf
require: private
version: '>=4.4.2'
source:
registry_url: https://components.espressif.com
type: service
version: 1.2.1
espressif/esp_lcd_touch_cst816s:
component_hash: 51dfa9cee38d8a20f4b625d7f89120dff08c8557e613e09dfb31f53d48648235
dependencies:
- name: espressif/esp_lcd_touch
registry_url: https://components.espressif.com
require: public
version: ^1.0.4
- name: idf
require: private
version: '>=4.4.2'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.1.0
espressif/esp_lcd_touch_ft5x06:
component_hash: abaec05f46a793549b60afdda9eff86e3c8e87782c8c169007911232388d2858
dependencies:
- name: espressif/esp_lcd_touch
registry_url: https://components.espressif.com
require: public
version: ^1.0.4
- name: idf
require: private
version: '>=4.4.2'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.7
espressif/esp_lcd_touch_gt1151:
component_hash: 69dd86cd5fad2442e3bf15c8c4ddddbe9e8739bdb26cd5f2c5249601b4c3cc38
dependencies:
- name: idf
require: private
version: '>=4.4.2'
- name: espressif/esp_lcd_touch
registry_url: https://components.espressif.com
require: public
version: ^1.0.4
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.5~2
espressif/esp_lcd_touch_gt911:
component_hash: acc1c184358aa29ef72506f618c9c76a8cc2bf12af38a2bff3d44d84f3a08857
dependencies:
- name: espressif/esp_lcd_touch
registry_url: https://components.espressif.com
require: public
version: ^1.1.0
- name: idf
require: private
version: '>=4.4.2'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.1.3
espressif/esp_lcd_touch_st7123:
component_hash: 3592f0dac4b3baf34c40679922026c1e22e9b925b9446e981cd1c23306ecfe65
dependencies:
- name: idf
require: private
version: '>=4.4.2'
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: espressif/esp_lcd_touch
registry_url: https://components.espressif.com
require: public
version: ^1
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.0
espressif/esp_lvgl_port:
component_hash: bfb2778c063b05a6c47c1a8de6d166ee4d911bc86fe0b3ff9e6bab06d2812033
dependencies:
- name: idf
require: private
version: '>=5.1'
- name: lvgl/lvgl
registry_url: https://components.espressif.com
require: public
version: '>=8,<10'
source:
registry_url: https://components.espressif.com/
type: service
version: 2.6.2
espressif/esp_mmap_assets:
component_hash: 91d785326b03db15e2f7f1314d8c976d38f21aa5759b570dcbbc89bcf247fd27
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.4.0
espressif/esp_new_jpeg:
component_hash: e6af208a875abd0ecfc0213d3751a11b504b463ebde6930f24096047925fa5c1
dependencies: []
source:
registry_url: https://components.espressif.com/
type: service
targets:
- esp32
- esp32s2
- esp32s3
- esp32p4
- esp32c2
- esp32c3
- esp32c5
- esp32c6
version: 0.6.1
espressif/esp_sccb_intf:
component_hash: 44dfa738680ccbc3705ae6940f59be603165f4f7e4d05c3eb5f433705fdc92be
dependencies:
- name: idf
require: private
version: '>=5.3'
source:
registry_url: https://components.espressif.com
type: service
version: 0.0.7
espressif/esp_video:
component_hash: fbad1178f39cb5a81ed808c460c851b911a9858db833e2e667ada988022c0660
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: espressif/esp_cam_sensor
registry_url: https://components.espressif.com
require: private
version: 1.5.*
- name: espressif/esp_h264
registry_url: https://components.espressif.com
require: private
rules:
- if: target in [esp32p4]
version: 1.0.4
- name: espressif/esp_ipa
registry_url: https://components.espressif.com
require: private
rules:
- if: target in [esp32p4]
version: ~1.2.0
- name: idf
require: private
version: '>=5.4'
- name: espressif/usb
registry_url: https://components.espressif.com
require: private
rules:
- if: target in [esp32p4, esp32s3]
- if: idf_version >=6.0
version: '*'
- name: espressif/usb_host_uvc
registry_url: https://components.espressif.com
require: private
rules:
- if: target in [esp32p4, esp32s3]
version: 2.3.*
source:
registry_url: https://components.espressif.com/
type: service
targets:
- esp32p4
- esp32s3
- esp32c3
- esp32c5
- esp32c6
- esp32c61
version: 1.3.1
espressif/freetype:
component_hash: cd5e2d8458e6e8d73f1120ac474467cabb669d8ea4b25050bf6a348c1e89225e
dependencies:
- name: idf
require: private
version: '>=4.4'
source:
registry_url: https://components.espressif.com
type: service
version: 2.13.3~1
espressif/i2c_bus:
component_hash: 4e990dc11734316186b489b362c61d41f23f79d58bc169795cec215e528cba14
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: '*'
- name: idf
require: private
version: '>=4.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.5.0
espressif/knob:
component_hash: 23bb6b0f62d4a2bbfe8b65e182397541339b8e48d54cef15909f5d4f5bd43d29
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: idf
require: private
version: '>=4.4.1'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.1
espressif/led_strip:
component_hash: 223998f10cae6d81f2ad2dd3c1103c2221be298c708e37917482b0153f3ec64e
dependencies:
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 3.0.1~1
espressif/usb_host_uvc:
component_hash: b0cb9a3a2eaa09dc6e5cc3e47e04d0a73e47c2d3dcfb3afce959224a1fe5fb5e
dependencies:
- name: idf
require: private
version: '>=5.0'
- name: espressif/usb
registry_url: https://components.espressif.com
require: public
rules:
- if: idf_version >=6.0
- if: target not in ["linux"]
version: ^1.0.0
source:
registry_url: https://components.espressif.com
type: service
targets:
- esp32s2
- esp32s3
- esp32p4
- esp32h4
- linux
version: 2.3.1
espressif2022/esp_emote_gfx:
component_hash: 7478561e4e8bd0efd4307647ec7221da2519de4ff1cd0cb08dccfbd0161cadaa
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: espressif/esp_new_jpeg
registry_url: https://components.espressif.com
require: private
version: 0.6.*
- name: espressif/freetype
registry_url: https://components.espressif.com
require: private
version: 2.*
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.2.0~1
espressif2022/image_player:
component_hash: 0e42ed1c9665debd15f2f3e7e56519100e75e446410962226cb5e5402da3fa43
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.1.1
idf:
source:
type: idf
version: 5.5.1
lvgl/lvgl:
component_hash: b702d642e03e95928046d5c6726558e6444e112420c77efa5fdb6650b0a13c5d
dependencies: []
source:
registry_url: https://components.espressif.com/
type: service
version: 9.3.0
tny-robotics/sh1106-esp-idf:
component_hash: 7be190d7c58cd635adf8b74b3a841f8245f2f82f36d135a64d8e53cfab39124d
dependencies: []
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.0
txp666/otto-emoji-gif-component:
component_hash: 5a722dd0a40014b31d5998ea5b21f0b53a99d1025626d765d08710b47636ee97
dependencies:
- name: lvgl/lvgl
registry_url: https://components.espressif.com
require: private
version: '>=9.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.4
waveshare/esp_lcd_sh8601:
component_hash: 1a2829e9db4e0515bad6ce83368f199dec60519fbba40251d6c8249f5d070ae1
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: idf
require: private
version: '>=5.3'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.2
waveshare/esp_lcd_touch_cst9217:
component_hash: c5da844e73ab7b7e02938901e71f38deed94b26976045fb4517e7fc1e8dc4db5
dependencies:
- name: espressif/esp_lcd_touch
registry_url: https://components.espressif.com
require: public
version: ^1.1.0
- name: idf
require: private
version: '>=4.4.2'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.3
wvirgil123/sscma_client:
component_hash: bf7d4a1f157303f4850d0b9b465c733ce38e8689ff40ac4743a44520524c41d5
dependencies:
- name: espressif/esp_io_expander
registry_url: https://components.espressif.com
require: private
version: ^1.0.1
- name: idf
require: private
version: '>=4.4.2'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.0.2
direct_dependencies:
- 78/esp-ml307
- 78/esp-opus-encoder
- 78/esp-wifi-connect
- 78/esp_lcd_nv3023
- 78/xiaozhi-fonts
- espressif/adc_battery_estimation
- espressif/adc_mic
- espressif/button
- espressif/cmake_utilities
- espressif/dl_fft
- espressif/esp-dsp
- espressif/esp_codec_dev
- espressif/esp_image_effects
- espressif/esp_io_expander_tca9554
- espressif/esp_io_expander_tca95xx_16bit
- espressif/esp_lcd_axs15231b
- espressif/esp_lcd_gc9a01
- espressif/esp_lcd_ili9341
- espressif/esp_lcd_panel_io_additions
- espressif/esp_lcd_spd2010
- espressif/esp_lcd_st7701
- espressif/esp_lcd_st77916
- espressif/esp_lcd_st7796
- espressif/esp_lcd_touch_cst816s
- espressif/esp_lcd_touch_ft5x06
- espressif/esp_lcd_touch_gt1151
- espressif/esp_lcd_touch_gt911
- espressif/esp_lcd_touch_st7123
- espressif/esp_lvgl_port
- espressif/esp_mmap_assets
- espressif/esp_new_jpeg
- espressif/esp_video
- espressif/i2c_bus
- espressif/knob
- espressif/led_strip
- espressif2022/esp_emote_gfx
- espressif2022/image_player
- idf
- lvgl/lvgl
- tny-robotics/sh1106-esp-idf
- txp666/otto-emoji-gif-component
- waveshare/esp_lcd_sh8601
- waveshare/esp_lcd_touch_cst9217
- wvirgil123/sscma_client
manifest_hash: 8b8d8d3a405eda302202a654ce1dfdbc17f486994ac285a18867b38f07a065c0
target: esp32s3
version: 2.0.0
+61
View File
@@ -0,0 +1,61 @@
import os
import subprocess
import json
def clone_or_update_repo(
repo_url, path, ref=None, with_submodules=False, patch_path=None
):
import os
if not os.path.exists(path):
subprocess.run(["git", "clone", repo_url, path], check=True)
else:
subprocess.run(["git", "-C", path, "fetch"], check=True)
if ref:
subprocess.run(["git", "-C", path, "checkout", ref], check=True)
if with_submodules:
subprocess.run(
["git", "-C", path, "submodule", "update", "--init", "--recursive"],
check=True,
)
# 应用 patch
if patch_path:
patch_full_path = (
patch_path
if os.path.isabs(patch_path)
else os.path.join(os.getcwd(), patch_path)
)
# 使用 git apply --check 先检测补丁是否能应用,避免报错
check_result = subprocess.run(
["git", "-C", path, "apply", "--check", patch_full_path]
)
if check_result.returncode == 0:
subprocess.run(["git", "-C", path, "apply", patch_full_path], check=True)
print(f"Applied patch {patch_path} to {path}")
else:
print(f"Patch {patch_path} cannot be applied cleanly to {path}, skipped.")
def fetch_dependencies():
script_dir = os.path.dirname(os.path.abspath(__file__))
config_path = os.path.join(script_dir, "repos.json")
with open(config_path) as f:
repos = json.load(f)
for repo in repos:
repo_path = os.path.join(script_dir, repo["path"])
branch = repo.get("branch")
with_submodules = repo.get("with_submodules", False)
patch = repo.get("patch")
if patch and not os.path.isabs(patch):
patch = os.path.join(script_dir, patch)
clone_or_update_repo(repo["url"], repo_path, branch, with_submodules, patch)
if __name__ == "__main__":
fetch_dependencies()
+458
View File
@@ -0,0 +1,458 @@
# Define xiaozhi source directory
set(XIAOZHI_MAIN_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../xiaozhi-esp32/main")
file(GLOB_RECURSE STACK_CHAN_SOURCES
"apps/*.c"
"apps/*.cc"
"apps/*.cpp"
"assets/*.c"
"assets/*.cc"
"assets/*.cpp"
"hal/*.c"
"hal/*.cc"
"hal/*.cpp"
"stackchan/*.c"
"stackchan/*.cc"
"stackchan/*.cpp"
)
set(STACK_CHAN_INCLUDE_DIRS
"."
)
list(APPEND STACK_CHAN_SOURCES main.cpp)
# Define source files
set(SOURCES "audio/audio_codec.cc"
"audio/audio_service.cc"
"audio/codecs/no_audio_codec.cc"
"audio/codecs/box_audio_codec.cc"
"audio/codecs/es8311_audio_codec.cc"
"audio/codecs/es8374_audio_codec.cc"
"audio/codecs/es8388_audio_codec.cc"
"audio/codecs/es8389_audio_codec.cc"
"audio/codecs/dummy_audio_codec.cc"
"audio/processors/audio_debugger.cc"
"led/single_led.cc"
"led/circular_strip.cc"
"led/gpio_led.cc"
"display/display.cc"
"display/lcd_display.cc"
"display/oled_display.cc"
"display/lvgl_display/lvgl_display.cc"
"display/emote_display.cc"
"display/lvgl_display/emoji_collection.cc"
"display/lvgl_display/lvgl_theme.cc"
"display/lvgl_display/lvgl_font.cc"
"display/lvgl_display/lvgl_image.cc"
"display/lvgl_display/gif/lvgl_gif.cc"
"display/lvgl_display/gif/gifdec.c"
"display/lvgl_display/jpg/image_to_jpeg.cpp"
"protocols/protocol.cc"
"protocols/mqtt_protocol.cc"
"protocols/websocket_protocol.cc"
"mcp_server.cc"
"system_info.cc"
"application.cc"
"ota.cc"
"settings.cc"
"device_state_event.cc"
"assets.cc"
)
# Transform relative paths to absolute paths from xiaozhi-esp32/main
list(TRANSFORM SOURCES PREPEND "${XIAOZHI_MAIN_DIR}/")
set(INCLUDE_DIRS "." "display" "display/lvgl_display" "display/lvgl_display/jpg" "audio" "protocols")
# Transform include dirs to absolute paths from xiaozhi-esp32/main
list(TRANSFORM INCLUDE_DIRS PREPEND "${XIAOZHI_MAIN_DIR}/")
list(APPEND INCLUDE_DIRS)
# Add board common files
file(GLOB BOARD_COMMON_SOURCES ${XIAOZHI_MAIN_DIR}/boards/common/*.cc)
list(APPEND SOURCES ${BOARD_COMMON_SOURCES} ${STACK_CHAN_SOURCES})
list(APPEND INCLUDE_DIRS ${XIAOZHI_MAIN_DIR}/boards/common ${STACK_CHAN_INCLUDE_DIRS})
idf_build_get_property(build_components BUILD_COMPONENTS)
# Function to find component dynamically by pattern
function(find_component_by_pattern PATTERN COMPONENT_VAR PATH_VAR)
foreach(COMPONENT ${build_components})
if(COMPONENT MATCHES "${PATTERN}")
set(${COMPONENT_VAR} ${COMPONENT} PARENT_SCOPE)
idf_component_get_property(COMPONENT_PATH ${COMPONENT} COMPONENT_DIR)
set(${PATH_VAR} "${COMPONENT_PATH}" PARENT_SCOPE)
break()
endif()
endforeach()
endfunction()
# Set default BUILTIN_TEXT_FONT and BUILTIN_ICON_FONT
set(BUILTIN_TEXT_FONT font_puhui_14_1)
set(BUILTIN_ICON_FONT font_awesome_14_1)
# Add board files according to BOARD_TYPE
# Set default assets if the board uses partition table V2
if(CONFIG_BOARD_TYPE_M5STACK_STACK_CHAN)
set(BOARD_TYPE "m5stack-stack-chan")
set(BUILTIN_TEXT_FONT font_puhui_basic_20_4)
set(BUILTIN_ICON_FONT font_awesome_20_4)
set(DEFAULT_EMOJI_COLLECTION twemoji_64)
endif()
file(GLOB BOARD_SOURCES
)
list(APPEND SOURCES ${BOARD_SOURCES})
# Select audio processor according to Kconfig
if(CONFIG_USE_AUDIO_PROCESSOR)
set(AUDIO_PROCESSOR_SRC "audio/processors/afe_audio_processor.cc")
else()
set(AUDIO_PROCESSOR_SRC "audio/processors/no_audio_processor.cc")
endif()
list(APPEND SOURCES "${XIAOZHI_MAIN_DIR}/${AUDIO_PROCESSOR_SRC}")
if(CONFIG_IDF_TARGET_ESP32S3 OR CONFIG_IDF_TARGET_ESP32P4)
set(WAKE_WORD_SRCS "audio/wake_words/afe_wake_word.cc" "audio/wake_words/custom_wake_word.cc")
else()
set(WAKE_WORD_SRCS "audio/wake_words/esp_wake_word.cc")
endif()
list(TRANSFORM WAKE_WORD_SRCS PREPEND "${XIAOZHI_MAIN_DIR}/")
list(APPEND SOURCES ${WAKE_WORD_SRCS})
# Select language directory according to Kconfig
if(CONFIG_LANGUAGE_ZH_CN)
set(LANG_DIR "zh-CN")
elseif(CONFIG_LANGUAGE_ZH_TW)
set(LANG_DIR "zh-TW")
elseif(CONFIG_LANGUAGE_EN_US)
set(LANG_DIR "en-US")
elseif(CONFIG_LANGUAGE_JA_JP)
set(LANG_DIR "ja-JP")
elseif(CONFIG_LANGUAGE_KO_KR)
set(LANG_DIR "ko-KR")
elseif(CONFIG_LANGUAGE_VI_VN)
set(LANG_DIR "vi-VN")
elseif(CONFIG_LANGUAGE_TH_TH)
set(LANG_DIR "th-TH")
elseif(CONFIG_LANGUAGE_DE_DE)
set(LANG_DIR "de-DE")
elseif(CONFIG_LANGUAGE_FR_FR)
set(LANG_DIR "fr-FR")
elseif(CONFIG_LANGUAGE_ES_ES)
set(LANG_DIR "es-ES")
elseif(CONFIG_LANGUAGE_IT_IT)
set(LANG_DIR "it-IT")
elseif(CONFIG_LANGUAGE_RU_RU)
set(LANG_DIR "ru-RU")
elseif(CONFIG_LANGUAGE_AR_SA)
set(LANG_DIR "ar-SA")
elseif(CONFIG_LANGUAGE_HI_IN)
set(LANG_DIR "hi-IN")
elseif(CONFIG_LANGUAGE_PT_PT)
set(LANG_DIR "pt-PT")
elseif(CONFIG_LANGUAGE_PL_PL)
set(LANG_DIR "pl-PL")
elseif(CONFIG_LANGUAGE_CS_CZ)
set(LANG_DIR "cs-CZ")
elseif(CONFIG_LANGUAGE_FI_FI)
set(LANG_DIR "fi-FI")
elseif(CONFIG_LANGUAGE_TR_TR)
set(LANG_DIR "tr-TR")
elseif(CONFIG_LANGUAGE_ID_ID)
set(LANG_DIR "id-ID")
elseif(CONFIG_LANGUAGE_UK_UA)
set(LANG_DIR "uk-UA")
elseif(CONFIG_LANGUAGE_RO_RO)
set(LANG_DIR "ro-RO")
elseif(CONFIG_LANGUAGE_BG_BG)
set(LANG_DIR "bg-BG")
elseif(CONFIG_LANGUAGE_CA_ES)
set(LANG_DIR "ca-ES")
elseif(CONFIG_LANGUAGE_DA_DK)
set(LANG_DIR "da-DK")
elseif(CONFIG_LANGUAGE_EL_GR)
set(LANG_DIR "el-GR")
elseif(CONFIG_LANGUAGE_FA_IR)
set(LANG_DIR "fa-IR")
elseif(CONFIG_LANGUAGE_FIL_PH)
set(LANG_DIR "fil-PH")
elseif(CONFIG_LANGUAGE_HE_IL)
set(LANG_DIR "he-IL")
elseif(CONFIG_LANGUAGE_HR_HR)
set(LANG_DIR "hr-HR")
elseif(CONFIG_LANGUAGE_HU_HU)
set(LANG_DIR "hu-HU")
elseif(CONFIG_LANGUAGE_MS_MY)
set(LANG_DIR "ms-MY")
elseif(CONFIG_LANGUAGE_NB_NO)
set(LANG_DIR "nb-NO")
elseif(CONFIG_LANGUAGE_NL_NL)
set(LANG_DIR "nl-NL")
elseif(CONFIG_LANGUAGE_SK_SK)
set(LANG_DIR "sk-SK")
elseif(CONFIG_LANGUAGE_SL_SI)
set(LANG_DIR "sl-SI")
elseif(CONFIG_LANGUAGE_SV_SE)
set(LANG_DIR "sv-SE")
elseif(CONFIG_LANGUAGE_SR_RS)
set(LANG_DIR "sr-RS")
endif()
# Define generation path
set(LANG_JSON "${XIAOZHI_MAIN_DIR}/assets/locales/${LANG_DIR}/language.json")
set(LANG_HEADER "${XIAOZHI_MAIN_DIR}/assets/lang_config.h")
# Collect current language audio files
file(GLOB LANG_SOUNDS ${XIAOZHI_MAIN_DIR}/assets/locales/${LANG_DIR}/*.ogg)
# If not en-US, collect en-US audio files as fallback for missing files
if(NOT LANG_DIR STREQUAL "en-US")
file(GLOB EN_US_SOUNDS ${XIAOZHI_MAIN_DIR}/assets/locales/en-US/*.ogg)
# Extract filenames (without path) from current language
set(EXISTING_NAMES "")
foreach(SOUND_FILE ${LANG_SOUNDS})
get_filename_component(FILENAME ${SOUND_FILE} NAME)
list(APPEND EXISTING_NAMES ${FILENAME})
endforeach()
# Only add en-US audio files that are missing in current language
foreach(EN_SOUND ${EN_US_SOUNDS})
get_filename_component(FILENAME ${EN_SOUND} NAME)
if(NOT ${FILENAME} IN_LIST EXISTING_NAMES)
list(APPEND LANG_SOUNDS ${EN_SOUND})
message(STATUS "Using en-US fallback for missing audio: ${FILENAME}")
endif()
endforeach()
endif()
# file(GLOB COMMON_SOUNDS ${XIAOZHI_MAIN_DIR}/assets/common/*.ogg)
file(GLOB COMMON_SOUNDS
${XIAOZHI_MAIN_DIR}/assets/common/*.ogg
assets/sfx/*.ogg
)
# If target chip is ESP32, exclude specific files to avoid build errors
if(CONFIG_IDF_TARGET_ESP32)
set(ESP32_EXCLUDE_FILES
"audio/codecs/box_audio_codec.cc"
"audio/codecs/es8388_audio_codec.cc"
"audio/codecs/es8389_audio_codec.cc"
"led/gpio_led.cc"
"boards/common/esp32_camera.cc"
"display/lvgl_display/jpg/image_to_jpeg.cpp"
)
list(TRANSFORM ESP32_EXCLUDE_FILES PREPEND "${XIAOZHI_MAIN_DIR}/")
list(REMOVE_ITEM SOURCES ${ESP32_EXCLUDE_FILES})
endif()
idf_component_register(SRCS ${SOURCES}
EMBED_FILES ${LANG_SOUNDS} ${COMMON_SOUNDS}
INCLUDE_DIRS ${INCLUDE_DIRS}
WHOLE_ARCHIVE
)
# Use target_compile_definitions to define BOARD_TYPE, BOARD_NAME
# If BOARD_NAME is empty, use BOARD_TYPE
if(NOT BOARD_NAME)
set(BOARD_NAME ${BOARD_TYPE})
endif()
target_compile_definitions(${COMPONENT_LIB}
PRIVATE BOARD_TYPE=\"${BOARD_TYPE}\" BOARD_NAME=\"${BOARD_NAME}\"
PRIVATE BUILTIN_TEXT_FONT=${BUILTIN_TEXT_FONT} BUILTIN_ICON_FONT=${BUILTIN_ICON_FONT}
)
# Add generation rules
add_custom_command(
OUTPUT ${LANG_HEADER}
COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/../xiaozhi-esp32/scripts/gen_lang.py
--language "${LANG_DIR}"
--output "${LANG_HEADER}"
DEPENDS
${LANG_JSON}
${CMAKE_CURRENT_SOURCE_DIR}/../xiaozhi-esp32/scripts/gen_lang.py
COMMENT "Generating ${LANG_DIR} language config"
)
# Force build generation dependencies
add_custom_target(lang_header ALL
DEPENDS ${LANG_HEADER}
)
# Find ESP-SR component dynamically
find_component_by_pattern("espressif__esp-sr" ESP_SR_COMPONENT ESP_SR_COMPONENT_PATH)
if(ESP_SR_COMPONENT_PATH)
set(ESP_SR_MODEL_PATH "${ESP_SR_COMPONENT_PATH}/model")
endif()
# Find xiaozhi-fonts component dynamically
find_component_by_pattern("xiaozhi-fonts" XIAOZHI_FONTS_COMPONENT XIAOZHI_FONTS_COMPONENT_PATH)
if(XIAOZHI_FONTS_COMPONENT_PATH)
set(XIAOZHI_FONTS_PATH "${XIAOZHI_FONTS_COMPONENT_PATH}")
endif()
if(CONFIG_BOARD_TYPE_ESP_HI)
set(URL "https://github.com/espressif2022/image_player/raw/main/test_apps/test_8bit")
set(EMOJI_DIR "${CMAKE_BINARY_DIR}/emoji")
file(MAKE_DIRECTORY ${EMOJI_DIR})
# List all files to download
set(FILES_TO_DOWNLOAD "")
list(APPEND FILES_TO_DOWNLOAD "Anger_enter.aaf" "Anger_loop.aaf" "Anger_return.aaf")
list(APPEND FILES_TO_DOWNLOAD "happy_enter.aaf" "happy_loop.aaf" "happ_return.aaf")
list(APPEND FILES_TO_DOWNLOAD "sad_enter.aaf" "sad_loop.aaf" "sad_return.aaf")
list(APPEND FILES_TO_DOWNLOAD "scorn_enter.aaf" "scorn_loop.aaf" "scorn_return.aaf")
list(APPEND FILES_TO_DOWNLOAD "left_enter.aaf" "left_loop.aaf" "left_return.aaf")
list(APPEND FILES_TO_DOWNLOAD "right_enter.aaf" "right_loop.aaf" "right_return.aaf")
list(APPEND FILES_TO_DOWNLOAD "asking.aaf" "blink_once.aaf" "blink_quick.aaf")
list(APPEND FILES_TO_DOWNLOAD "connecting.aaf" "panic_enter.aaf" "panic_loop.aaf")
list(APPEND FILES_TO_DOWNLOAD "panic_return.aaf" "wake.aaf")
foreach(FILENAME IN LISTS FILES_TO_DOWNLOAD)
set(REMOTE_FILE "${URL}/${FILENAME}")
set(LOCAL_FILE "${EMOJI_DIR}/${FILENAME}")
# Check if local file exists
if(EXISTS ${LOCAL_FILE})
message(STATUS "File ${FILENAME} already exists, skipping download")
else()
message(STATUS "Downloading ${FILENAME}")
file(DOWNLOAD ${REMOTE_FILE} ${LOCAL_FILE}
STATUS DOWNLOAD_STATUS)
list(GET DOWNLOAD_STATUS 0 STATUS_CODE)
if(NOT STATUS_CODE EQUAL 0)
message(FATAL_ERROR "Failed to download ${FILENAME} from ${URL}")
endif()
endif()
endforeach()
endif()
# Function to build default assets based on configuration
function(build_default_assets_bin)
# Set output path for generated assets.bin
set(GENERATED_ASSETS_BIN "${CMAKE_BINARY_DIR}/generated_assets.bin")
# Prepare arguments for build script
set(BUILD_ARGS
"--sdkconfig" "${SDKCONFIG}"
"--output" "${GENERATED_ASSETS_BIN}"
)
# Add builtin text font if defined
if(BUILTIN_TEXT_FONT)
list(APPEND BUILD_ARGS "--builtin_text_font" "${BUILTIN_TEXT_FONT}")
endif()
# Add default emoji collection if defined
if(DEFAULT_EMOJI_COLLECTION)
list(APPEND BUILD_ARGS "--emoji_collection" "${DEFAULT_EMOJI_COLLECTION}")
endif()
# Add default assets extra files if defined
if(DEFAULT_ASSETS_EXTRA_FILES)
list(APPEND BUILD_ARGS "--extra_files" "${DEFAULT_ASSETS_EXTRA_FILES}")
endif()
list(APPEND BUILD_ARGS "--esp_sr_model_path" "${ESP_SR_MODEL_PATH}")
list(APPEND BUILD_ARGS "--xiaozhi_fonts_path" "${XIAOZHI_FONTS_PATH}")
# Create custom command to build assets
add_custom_command(
OUTPUT ${GENERATED_ASSETS_BIN}
COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/../xiaozhi-esp32/scripts/build_default_assets.py ${BUILD_ARGS}
DEPENDS
${SDKCONFIG}
${CMAKE_CURRENT_SOURCE_DIR}/../xiaozhi-esp32/scripts/build_default_assets.py
COMMENT "Building default assets.bin based on configuration"
VERBATIM
)
# Create target for generated assets
add_custom_target(generated_default_assets ALL
DEPENDS ${GENERATED_ASSETS_BIN}
)
# Set the generated file path in parent scope
set(GENERATED_ASSETS_LOCAL_FILE ${GENERATED_ASSETS_BIN} PARENT_SCOPE)
message(STATUS "Default assets build configured: ${GENERATED_ASSETS_BIN}")
endfunction()
# Function to get local assets file path (handles both URL and local file)
function(get_assets_local_file assets_source assets_local_file_var)
# Check if it's a URL (starts with http:// or https://)
if(assets_source MATCHES "^https?://")
# It's a URL, download it
get_filename_component(ASSETS_FILENAME "${assets_source}" NAME)
set(ASSETS_LOCAL_FILE "${CMAKE_BINARY_DIR}/${ASSETS_FILENAME}")
set(ASSETS_TEMP_FILE "${CMAKE_BINARY_DIR}/${ASSETS_FILENAME}.tmp")
# Check if local file exists
if(EXISTS ${ASSETS_LOCAL_FILE})
message(STATUS "Assets file ${ASSETS_FILENAME} already exists, skipping download")
else()
message(STATUS "Downloading ${ASSETS_FILENAME}")
# Clean up any existing temp file
if(EXISTS ${ASSETS_TEMP_FILE})
file(REMOVE ${ASSETS_TEMP_FILE})
endif()
# Download to temporary file first
file(DOWNLOAD ${assets_source} ${ASSETS_TEMP_FILE}
STATUS DOWNLOAD_STATUS)
list(GET DOWNLOAD_STATUS 0 STATUS_CODE)
if(NOT STATUS_CODE EQUAL 0)
# Clean up temp file on failure
if(EXISTS ${ASSETS_TEMP_FILE})
file(REMOVE ${ASSETS_TEMP_FILE})
endif()
message(FATAL_ERROR "Failed to download ${ASSETS_FILENAME} from ${assets_source}")
endif()
# Move temp file to final location (atomic operation)
file(RENAME ${ASSETS_TEMP_FILE} ${ASSETS_LOCAL_FILE})
message(STATUS "Successfully downloaded ${ASSETS_FILENAME}")
endif()
else()
# It's a local file path
if(IS_ABSOLUTE "${assets_source}")
set(ASSETS_LOCAL_FILE "${assets_source}")
else()
set(ASSETS_LOCAL_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${assets_source}")
endif()
# Check if local file exists
if(NOT EXISTS ${ASSETS_LOCAL_FILE})
message(FATAL_ERROR "Assets file not found: ${ASSETS_LOCAL_FILE}")
endif()
message(STATUS "Using assets file: ${ASSETS_LOCAL_FILE}")
endif()
set(${assets_local_file_var} ${ASSETS_LOCAL_FILE} PARENT_SCOPE)
endfunction()
partition_table_get_partition_info(size "--partition-name assets" "size")
partition_table_get_partition_info(offset "--partition-name assets" "offset")
if ("${size}" AND "${offset}")
# Flash assets based on configuration
if(CONFIG_FLASH_DEFAULT_ASSETS)
# Build default assets based on configuration
build_default_assets_bin()
esptool_py_flash_to_partition(flash "assets" "${GENERATED_ASSETS_LOCAL_FILE}")
message(STATUS "Generated default assets flash configured: ${GENERATED_ASSETS_LOCAL_FILE} -> assets partition")
elseif(CONFIG_FLASH_CUSTOM_ASSETS)
# Flash custom assets
get_assets_local_file("${CONFIG_CUSTOM_ASSETS_FILE}" ASSETS_LOCAL_FILE)
esptool_py_flash_to_partition(flash "assets" "${ASSETS_LOCAL_FILE}")
message(STATUS "Custom assets flash configured: ${ASSETS_LOCAL_FILE} -> assets partition")
elseif(CONFIG_FLASH_NONE_ASSETS)
message(STATUS "Assets flashing disabled (FLASH_NONE_ASSETS)")
endif()
else()
message(STATUS "Assets partition not found, using v1 partition table")
endif()
+839
View File
@@ -0,0 +1,839 @@
menu "Xiaozhi Assistant"
config OTA_URL
string "Default OTA URL"
default "https://api.tenclass.net/xiaozhi/ota/"
help
The application will access this URL to check for new firmwares and server address.
choice
prompt "Flash Assets"
default FLASH_DEFAULT_ASSETS
help
Select the assets to flash.
config FLASH_NONE_ASSETS
bool "Do not flash assets"
config FLASH_DEFAULT_ASSETS
bool "Flash Default Assets"
config FLASH_CUSTOM_ASSETS
bool "Flash Custom Assets"
endchoice
config CUSTOM_ASSETS_FILE
depends on FLASH_CUSTOM_ASSETS
string "Custom Assets File"
default "assets.bin"
help
The custom assets file to flash.
It can be a local file relative to the project directory or a remote url.
choice
prompt "Default Language"
default LANGUAGE_ZH_CN
help
Select device display language
config LANGUAGE_ZH_CN
bool "Chinese"
config LANGUAGE_ZH_TW
bool "Chinese Traditional"
config LANGUAGE_EN_US
bool "English"
config LANGUAGE_JA_JP
bool "Japanese"
config LANGUAGE_KO_KR
bool "Korean"
config LANGUAGE_VI_VN
bool "Vietnamese"
config LANGUAGE_TH_TH
bool "Thai"
config LANGUAGE_DE_DE
bool "German"
config LANGUAGE_FR_FR
bool "French"
config LANGUAGE_ES_ES
bool "Spanish"
config LANGUAGE_IT_IT
bool "Italian"
config LANGUAGE_RU_RU
bool "Russian"
config LANGUAGE_AR_SA
bool "Arabic"
config LANGUAGE_HI_IN
bool "Hindi"
config LANGUAGE_PT_PT
bool "Portuguese"
config LANGUAGE_PL_PL
bool "Polish"
config LANGUAGE_CS_CZ
bool "Czech"
config LANGUAGE_FI_FI
bool "Finnish"
config LANGUAGE_TR_TR
bool "Turkish"
config LANGUAGE_ID_ID
bool "Indonesian"
config LANGUAGE_UK_UA
bool "Ukrainian"
config LANGUAGE_RO_RO
bool "Romanian"
config LANGUAGE_BG_BG
bool "Bulgarian"
config LANGUAGE_CA_ES
bool "Catalan"
config LANGUAGE_DA_DK
bool "Danish"
config LANGUAGE_EL_GR
bool "Greek"
config LANGUAGE_FA_IR
bool "Persian"
config LANGUAGE_FIL_PH
bool "Filipino"
config LANGUAGE_HE_IL
bool "Hebrew"
config LANGUAGE_HR_HR
bool "Croatian"
config LANGUAGE_HU_HU
bool "Hungarian"
config LANGUAGE_MS_MY
bool "Malay"
config LANGUAGE_NB_NO
bool "Norwegian"
config LANGUAGE_NL_NL
bool "Dutch"
config LANGUAGE_SK_SK
bool "Slovak"
config LANGUAGE_SL_SI
bool "Slovenian"
config LANGUAGE_SV_SE
bool "Swedish"
config LANGUAGE_SR_RS
bool "Serbian"
endchoice
choice BOARD_TYPE
prompt "Board Type"
default BOARD_TYPE_BREAD_COMPACT_WIFI
help
Board type. 开发板类型
config BOARD_TYPE_BREAD_COMPACT_WIFI
bool "Bread Compact WiFi (面包板)"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_BREAD_COMPACT_WIFI_LCD
bool "Bread Compact WiFi + LCD (面包板)"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_BREAD_COMPACT_WIFI_CAM
bool "Bread Compact WiFi + LCD + Camera (面包板)"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_BREAD_COMPACT_ML307
bool "Bread Compact ML307/EC801E (面包板 4G)"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_BREAD_COMPACT_ESP32
bool "Bread Compact ESP32 DevKit (面包板)"
depends on IDF_TARGET_ESP32
config BOARD_TYPE_BREAD_COMPACT_ESP32_LCD
bool "Bread Compact ESP32 DevKit + LCD (面包板)"
depends on IDF_TARGET_ESP32
config BOARD_TYPE_XMINI_C3_V3
bool "Xmini C3 V3"
depends on IDF_TARGET_ESP32C3
config BOARD_TYPE_XMINI_C3_4G
bool "Xmini C3 4G"
depends on IDF_TARGET_ESP32C3
config BOARD_TYPE_XMINI_C3
bool "Xmini C3"
depends on IDF_TARGET_ESP32C3
config BOARD_TYPE_ESP_KORVO2_V3
bool "Espressif Korvo2 V3"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP_SPARKBOT
bool "Espressif SparkBot"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP_SPOT_S3
bool "Espressif Spot-S3"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP_HI
bool "Espressif ESP-HI"
depends on IDF_TARGET_ESP32C3
config BOARD_TYPE_ESP_BOX_3
bool "Espressif ESP-BOX-3"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP_BOX
bool "Espressif ESP-BOX"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP_BOX_LITE
bool "Espressif ESP-BOX-Lite"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP_P4_FUNCTION_EV_BOARD
bool "Espressif ESP-P4-Function-EV-Board"
depends on IDF_TARGET_ESP32P4
config BOARD_TYPE_ECHOEAR
bool "EchoEar"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_KEVIN_BOX_2
bool "Kevin Box 2"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_KEVIN_C3
bool "Kevin C3"
depends on IDF_TARGET_ESP32C3
config BOARD_TYPE_KEVIN_SP_V3_DEV
bool "Kevin SP V3"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_KEVIN_SP_V4_DEV
bool "Kevin SP V4"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_KEVIN_YUYING_313LCD
bool "鱼鹰科技 3.13LCD"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_CGC
bool "CGC"
depends on IDF_TARGET_ESP32
config BOARD_TYPE_CGC_144
bool "CGC 144"
depends on IDF_TARGET_ESP32
config BOARD_TYPE_LICHUANG_DEV_S3
bool "立创·实战派 ESP32-S3"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_LICHUANG_DEV_C3
bool "立创·实战派 ESP32-C3"
depends on IDF_TARGET_ESP32C3
config BOARD_TYPE_DF_K10
bool "DFRobot 行空板 k10"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_DF_S3_AI_CAM
bool "DFRobot ESP32-S3 AI智能摄像头模块"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_MAGICLICK_S3_2P4
bool "神奇按钮 Magiclick_2.4"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_MAGICLICK_S3_2P5
bool "神奇按钮 Magiclick_2.5"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_MAGICLICK_C3
bool "神奇按钮 Magiclick_C3"
depends on IDF_TARGET_ESP32C3
config BOARD_TYPE_MAGICLICK_C3_V2
bool "神奇按钮 Magiclick_C3_v2"
depends on IDF_TARGET_ESP32C3
config BOARD_TYPE_M5STACK_CORE_S3
bool "M5Stack CoreS3"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_M5STACK_STACK_CHAN
bool "M5Stack StackChan"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_M5STACK_CORE_TAB5
bool "M5Stack Tab5"
depends on IDF_TARGET_ESP32P4
config BOARD_TYPE_M5STACK_ATOM_S3_ECHO_BASE
bool "M5Stack AtomS3 + Echo Base"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_M5STACK_ATOM_S3R_ECHO_BASE
bool "M5Stack AtomS3R + Echo Base"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_M5STACK_ATOM_S3R_CAM_M12_ECHO_BASE
bool "M5Stack AtomS3R CAM/M12 + Echo Base"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_M5STACK_ATOM_ECHOS3R
bool "M5Stack AtomEchoS3R"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_M5STACK_ATOM_MATRIX_ECHO_BASE
bool "M5Stack AtomMatrix + Echo Base"
depends on IDF_TARGET_ESP32
config BOARD_TYPE_WAVESHARE_S3_AUDIO_BOARD
bool "Waveshare ESP32-S3-Audio-Board"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_1_8
bool "Waveshare ESP32-S3-Touch-AMOLED-1.8"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_2_06
bool "Waveshare ESP32-S3-Touch-AMOLED-2.06"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_1_75
bool "Waveshare ESP32-S3-Touch-AMOLED-1.75"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_83
bool "Waveshare ESP32-S3-Touch-LCD-1.83"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_4B
bool "Waveshare ESP32-S3-Touch-LCD-4B"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_85C
bool "Waveshare ESP32-S3-Touch-LCD-1.85C"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_85
bool "Waveshare ESP32-S3-Touch-LCD-1.85"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_46
bool "Waveshare ESP32-S3-Touch-LCD-1.46"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_C6_LCD_1_69
bool "Waveshare ESP32-C6-LCD-1.69"
depends on IDF_TARGET_ESP32C6
config BOARD_TYPE_WAVESHARE_C6_TOUCH_AMOLED_1_43
bool "Waveshare ESP32-C6-Touch-AMOLOED-1.43"
depends on IDF_TARGET_ESP32C6
config BOARD_TYPE_WAVESHARE_C6_TOUCH_AMOLED_1_32
bool "Waveshare ESP32-C6-Touch-AMOLOED-1.32"
depends on IDF_TARGET_ESP32C6
config BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_1_32
bool "Waveshare ESP32-S3-Touch-AMOLOED-1.32"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_49
bool "Waveshare ESP32-S3-Touch-LCD-3.49"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_5
bool "Waveshare ESP32-S3-Touch-LCD-3.5"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_5B
bool "Waveshare ESP32-S3-Touch-LCD-3.5B"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WAVESHARE_P4_NANO
bool "Waveshare ESP32-P4-NANO"
depends on IDF_TARGET_ESP32P4
config BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_4B
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-4B"
depends on IDF_TARGET_ESP32P4
config BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_7B
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-7B"
depends on IDF_TARGET_ESP32P4
config BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_XC
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-3.4C or ESP32-P4-WIFI6-Touch-LCD-4C"
depends on IDF_TARGET_ESP32P4
config BOARD_TYPE_TUDOUZI
bool "土豆子"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_LILYGO_T_CIRCLE_S3
bool "LILYGO T-Circle-S3"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_LILYGO_T_CAMERAPLUS_S3_V1_0_V1_1
bool "LILYGO T-CameraPlus-S3_V1_0_V1_1"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_LILYGO_T_CAMERAPLUS_S3_V1_2
bool "LILYGO T-CameraPlus-S3_V1_2"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_LILYGO_T_DISPLAY_S3_PRO_MVSRLORA
bool "LILYGO T-Display-S3-Pro-MVSRLora"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_LILYGO_T_DISPLAY_S3_PRO_MVSRLORA_NO_BATTERY
bool "LILYGO T-Display-S3-Pro-MVSRLora_No_Battery"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_LILYGO_T_DISPLAY_P4
bool "LILYGO T-Display-P4"
depends on IDF_TARGET_ESP32P4
config BOARD_TYPE_MOVECALL_MOJI_ESP32S3
bool "Movecall Moji 小智AI衍生版"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_MOVECALL_CUICAN_ESP32S3
bool "Movecall CuiCan 璀璨·AI吊坠"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ATK_DNESP32S3
bool "正点原子DNESP32S3开发板"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ATK_DNESP32S3_BOX
bool "正点原子DNESP32S3-BOX"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ATK_DNESP32S3_BOX0
bool "正点原子DNESP32S3-BOX0"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ATK_DNESP32S3_BOX2_WIFI
bool "正点原子DNESP32S3-BOX2-WIFI"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ATK_DNESP32S3_BOX2_4G
bool "正点原子DNESP32S3-BOX2-4G"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ATK_DNESP32S3M_WIFI
bool "正点原子DNESP32S3M-WIFI"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ATK_DNESP32S3M_4G
bool "正点原子DNESP32S3M-4G"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_DU_CHATX
bool "嘟嘟开发板CHATX(wifi)"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_TAIJI_PI_S3
bool "太极小派esp32s3"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_XINGZHI_CUBE_0_85TFT_WIFI
bool "无名科技星智0.85(WIFI)"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_XINGZHI_CUBE_0_85TFT_ML307
bool "无名科技星智0.85(ML307)"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_XINGZHI_CUBE_0_96OLED_WIFI
bool "无名科技星智0.96(WIFI)"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_XINGZHI_CUBE_0_96OLED_ML307
bool "无名科技星智0.96(ML307)"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_XINGZHI_CUBE_1_54TFT_WIFI
bool "无名科技星智1.54(WIFI)"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_XINGZHI_CUBE_1_54TFT_ML307
bool "无名科技星智1.54(ML307)"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_SEEED_STUDIO_SENSECAP_WATCHER
bool "Seeed Studio SenseCAP Watcher"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_DOIT_S3_AIBOX
bool "四博智联AI陪伴盒子"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_MIXGO_NOVA
bool "元控·青春"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_GENJUTECH_S3_1_54TFT
bool "亘具科技1.54(s3)"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP_S3_LCD_EV_Board
bool "乐鑫ESP S3 LCD EV Board开发板"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ESP_S3_LCD_EV_Board_2
bool "乐鑫ESP S3 LCD EV Board 2开发板"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ZHENGCHEN_1_54TFT_WIFI
bool "征辰科技1.54(WIFI)"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ZHENGCHEN_1_54TFT_ML307
bool "征辰科技1.54(ML307)"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_MINSI_K08_DUAL
bool "敏思科技K08(DUAL)"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_SPOTPEAR_ESP32_S3_1_54_MUMA
bool "Spotpear ESP32-S3-1.54-MUMA"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_SPOTPEAR_ESP32_S3_1_28_BOX
bool "Spotpear ESP32-S3-1.28-BOX"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_OTTO_ROBOT
bool "ottoRobot"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_ELECTRON_BOT
bool "electronBot"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_JIUCHUAN
bool "九川智能"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_LABPLUS_MPYTHON_V3
bool "labplus mpython_v3 board"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_LABPLUS_LEDONG_V2
bool "labplus ledong_v2 board"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_SURFER_C3_1_14TFT
bool "Surfer-C3-1.14TFT"
depends on IDF_TARGET_ESP32C3
config BOARD_TYPE_YUNLIAO_S3
bool "小智云聊-S3"
depends on IDF_TARGET_ESP32S3
config BOARD_TYPE_WIRELESS_TAG_WTP4C5MP07S
bool "Wireless-Tag WTP4C5MP07S"
depends on IDF_TARGET_ESP32P4
config BOARD_TYPE_AIPI_LITE
bool "AIPI-Lite"
depends on IDF_TARGET_ESP32S3
endchoice
choice
depends on BOARD_TYPE_LILYGO_T_DISPLAY_P4
prompt "Select the screen type"
default SCREEN_TYPE_HI8561
config SCREEN_TYPE_HI8561
bool "HI8561"
config SCREEN_TYPE_RM69A10
bool "RM69A10"
endchoice
choice
depends on BOARD_TYPE_LILYGO_T_DISPLAY_P4
prompt "Select the color format of the screen"
default SCREEN_PIXEL_FORMAT_RGB565
config SCREEN_PIXEL_FORMAT_RGB565
bool "RGB565"
config SCREEN_PIXEL_FORMAT_RGB888
bool "RGB888"
endchoice
choice ESP_S3_LCD_EV_Board_Version_TYPE
depends on BOARD_TYPE_ESP_S3_LCD_EV_Board
prompt "EV_BOARD Type"
default ESP_S3_LCD_EV_Board_1p4
config ESP_S3_LCD_EV_Board_1p4
bool "乐鑫ESP32_S3_LCD_EV_Board-MB_V1.4"
config ESP_S3_LCD_EV_Board_1p5
bool "乐鑫ESP32_S3_LCD_EV_Board-MB_V1.5"
endchoice
choice DISPLAY_OLED_TYPE
depends on BOARD_TYPE_BREAD_COMPACT_WIFI || BOARD_TYPE_BREAD_COMPACT_ML307 || BOARD_TYPE_BREAD_COMPACT_ESP32
prompt "OLED Type"
default OLED_SSD1306_128X32
help
OLED Monochrome Display Type
config OLED_SSD1306_128X32
bool "SSD1306 128*32"
config OLED_SSD1306_128X64
bool "SSD1306 128*64"
config OLED_SH1106_128X64
bool "SH1106 128*64"
endchoice
choice DISPLAY_LCD_TYPE
depends on BOARD_TYPE_BREAD_COMPACT_WIFI_LCD || BOARD_TYPE_BREAD_COMPACT_ESP32_LCD || BOARD_TYPE_CGC || BOARD_TYPE_WAVESHARE_P4_NANO || BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_XC || BOARD_TYPE_BREAD_COMPACT_WIFI_CAM
prompt "LCD Type"
default LCD_ST7789_240X320
help
LCD Display Type
config LCD_ST7789_240X320
bool "ST7789 240*320, IPS"
config LCD_ST7789_240X320_NO_IPS
bool "ST7789 240*320, Non-IPS"
config LCD_ST7789_170X320
bool "ST7789 170*320"
config LCD_ST7789_172X320
bool "ST7789 172*320"
config LCD_ST7789_240X280
bool "ST7789 240*280"
config LCD_ST7789_240X240
bool "ST7789 240*240"
config LCD_ST7789_240X240_7PIN
bool "ST7789 240*240, 7PIN"
config LCD_ST7789_240X135
bool "ST7789 240*135"
config LCD_ST7735_128X160
bool "ST7735 128*160"
config LCD_ST7735_128X128
bool "ST7735 128*128"
config LCD_ST7796_320X480
bool "ST7796 320*480 IPS"
config LCD_ST7796_320X480_NO_IPS
bool "ST7796 320*480, Non-IPS"
config LCD_ILI9341_240X320
bool "ILI9341 240*320"
config LCD_ILI9341_240X320_NO_IPS
bool "ILI9341 240*320, Non-IPS"
config LCD_GC9A01_240X240
bool "GC9A01 240*240 Circle"
config LCD_TYPE_800_1280_10_1_INCH
bool "Waveshare 101M-8001280-IPS-CT-K Display"
config LCD_TYPE_800_1280_10_1_INCH_A
bool "Waveshare 10.1-DSI-TOUCH-A Display"
config LCD_TYPE_800_800_3_4_INCH
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-3.4C with 800*800 3.4inch round display"
config LCD_TYPE_720_720_4_INCH
bool "Waveshare ESP32-P4-WIFI6-Touch-LCD-4C with 720*720 4inch round display"
config LCD_CUSTOM
bool "Custom LCD (自定义屏幕参数)"
endchoice
choice DISPLAY_ESP32S3_KORVO2_V3
depends on BOARD_TYPE_ESP_KORVO2_V3
prompt "ESP32S3_KORVO2_V3 LCD Type"
default ESP32S3_KORVO2_V3_LCD_ST7789
help
LCD Display Type
config ESP32S3_KORVO2_V3_LCD_ST7789
bool "ST7789 240*280"
config ESP32S3_KORVO2_V3_LCD_ILI9341
bool "ILI9341 240*320"
endchoice
choice DISPLAY_ESP32S3_AUDIO_BOARD
depends on BOARD_TYPE_WAVESHARE_S3_AUDIO_BOARD
prompt "ESP32S3_AUDIO_BOARD LCD Type"
default AUDIO_BOARD_LCD_JD9853
help
LCD Display Type
config AUDIO_BOARD_LCD_JD9853
bool "JD9853 320*172"
config AUDIO_BOARD_LCD_ST7789
bool "ST7789 240*320"
endchoice
choice DISPLAY_STYLE
prompt "Select display style"
default USE_DEFAULT_MESSAGE_STYLE
help
Select display style for Xiaozhi device
config USE_DEFAULT_MESSAGE_STYLE
bool "Enable default message style"
config USE_WECHAT_MESSAGE_STYLE
bool "Enable WeChat Message Style"
config USE_EMOTE_MESSAGE_STYLE
bool "Emote animation style"
depends on BOARD_TYPE_ESP_BOX_3 || BOARD_TYPE_ECHOEAR || BOARD_TYPE_LICHUANG_DEV_S3
endchoice
choice WAKE_WORD_TYPE
prompt "Wake Word Implementation Type"
default USE_AFE_WAKE_WORD if (IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4) && SPIRAM
default WAKE_WORD_DISABLED
help
Choose the type of wake word implementation to use
config WAKE_WORD_DISABLED
bool "Disabled"
help
Disable wake word detection
config USE_ESP_WAKE_WORD
bool "Wakenet model without AFE"
depends on IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C5 || IDF_TARGET_ESP32C6 || (IDF_TARGET_ESP32 && SPIRAM)
help
Support ESP32 C3、ESP32 C5 与 ESP32 C6, and (ESP32 with PSRAM)
config USE_AFE_WAKE_WORD
bool "Wakenet model with AFE"
depends on (IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4) && SPIRAM
help
Support AEC if available, requires ESP32 S3 and PSRAM
config USE_CUSTOM_WAKE_WORD
bool "Multinet model (Custom Wake Word)"
depends on (IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4) && SPIRAM
help
Requires ESP32 S3 and PSRAM
endchoice
config CUSTOM_WAKE_WORD
string "Custom Wake Word"
default "xiao tu dou"
depends on USE_CUSTOM_WAKE_WORD
help
Custom Wake Word, use pinyin for Chinese, separated by spaces
config CUSTOM_WAKE_WORD_DISPLAY
string "Custom Wake Word Display"
default "小土豆"
depends on USE_CUSTOM_WAKE_WORD
help
Greeting sent to the server after wake word detection
config CUSTOM_WAKE_WORD_THRESHOLD
int "Custom Wake Word Threshold (%)"
default 20
range 1 99
depends on USE_CUSTOM_WAKE_WORD
help
Custom Wake Word Threshold, range 1-99, the smaller the more sensitive, default 20
config SEND_WAKE_WORD_DATA
bool "Send Wake Word Data"
default y
depends on USE_AFE_WAKE_WORD || USE_CUSTOM_WAKE_WORD
help
Send wake word data to the server as the first message of the conversation and wait for response
config USE_AUDIO_PROCESSOR
bool "Enable Audio Noise Reduction"
default y
depends on (IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4) && SPIRAM
help
Requires ESP32 S3 and PSRAM
config USE_DEVICE_AEC
bool "Enable Device-Side AEC"
default n
depends on USE_AUDIO_PROCESSOR && (BOARD_TYPE_ESP_BOX_3 || BOARD_TYPE_ESP_BOX || BOARD_TYPE_ESP_BOX_LITE \
|| BOARD_TYPE_LICHUANG_DEV_S3 || BOARD_TYPE_ESP_KORVO2_V3 || BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_1_75 || BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_1_83\
|| BOARD_TYPE_WAVESHARE_S3_TOUCH_AMOLED_2_06 || BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_4B || BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_4B || BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_7B \
|| BOARD_TYPE_WAVESHARE_P4_WIFI6_TOUCH_LCD_XC || BOARD_TYPE_ESP_S3_LCD_EV_Board_2 || BOARD_TYPE_YUNLIAO_S3 \
|| BOARD_TYPE_ECHOEAR || BOARD_TYPE_WAVESHARE_S3_TOUCH_LCD_3_49)
help
To work properly, device-side AEC requires a clean output reference path from the speaker signal and physical acoustic isolation between the microphone and speaker.
config USE_SERVER_AEC
bool "Enable Server-Side AEC (Unstable)"
default n
depends on USE_AUDIO_PROCESSOR
help
To work perperly, server-side AEC requires server support
config USE_AUDIO_DEBUGGER
bool "Enable Audio Debugger"
default n
help
Enable audio debugger, send audio data through UDP to the host machine
config AUDIO_DEBUG_UDP_SERVER
string "Audio Debug UDP Server Address"
default "192.168.2.100:8000"
depends on USE_AUDIO_DEBUGGER
help
UDP server address, format: IP:PORT, used to receive audio debugging data
config USE_ACOUSTIC_WIFI_PROVISIONING
bool "Enable Acoustic WiFi Provisioning"
default n
help
Enable acoustic WiFi provisioning, use audio signal to transmit WiFi configuration data
config RECEIVE_CUSTOM_MESSAGE
bool "Enable Custom Message Reception"
default n
help
Enable custom message reception, allow the device to receive custom messages from the server (preferably through the MQTT protocol)
menu "Camera Configuration"
depends on !IDF_TARGET_ESP32
comment "Warning: Please read the help text before modifying these settings."
config XIAOZHI_ENABLE_HARDWARE_JPEG_ENCODER
bool "Enable Hardware JPEG Encoder"
default y
depends on SOC_JPEG_ENCODE_SUPPORTED
help
Use hardware JPEG encoder on ESP32-P4 to encode image to JPEG.
See https://docs.espressif.com/projects/esp-idf/en/stable/esp32p4/api-reference/peripherals/jpeg.html for more details.
config XIAOZHI_ENABLE_CAMERA_DEBUG_MODE
bool "Enable Camera Debug Mode"
default n
help
Enable camera debug mode, print camera debug information to the console.
Only works on boards that support camera.
config XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP
bool "Enable software camera buffer endianness swapping (USE WITH CAUTION)"
default n
depends on !CAMERA_SENSOR_SWAP_PIXEL_BYTE_ORDER
help
This option treats the camera buffer as a uint16_t[] array and performs byte-swapping (endianness conversion) on each element.
Should only be modified by development board integration engineers.
**Incorrect usage may result in incorrect image colors!**
ATTENTION: If the option CAMERA_SENSOR_SWAP_PIXEL_BYTE_ORDER is available for your sensor, please use that instead.
menuconfig XIAOZHI_ENABLE_ROTATE_CAMERA_IMAGE
bool "Enable Camera Image Rotation"
default n
help
Enable camera image rotation, rotate the camera image to the correct orientation.
- On ESP32-P4, rotation is handled by PPA hardware.
- On other chips, rotation is done in software with performance cost.
- For 180° rotation, use HFlip + VFlip instead of this option.
if XIAOZHI_ENABLE_ROTATE_CAMERA_IMAGE
choice XIAOZHI_CAMERA_IMAGE_ROTATION_ANGLE
prompt "Camera Image Rotation Angle (clockwise)"
default XIAOZHI_CAMERA_IMAGE_ROTATION_ANGLE_90
help
Camera image rotation angle.
config XIAOZHI_CAMERA_IMAGE_ROTATION_ANGLE_90
bool "90°"
config XIAOZHI_CAMERA_IMAGE_ROTATION_ANGLE_270
bool "270°"
comment "For 180° rotation, use HFlip + VFlip instead of this option"
endchoice
endif
endmenu
menu "TAIJIPAI_S3_CONFIG"
depends on BOARD_TYPE_TAIJI_PI_S3
choice I2S_TYPE_TAIJIPI_S3
prompt "taiji-pi-S3 I2S Type"
default TAIJIPAI_I2S_TYPE_STD
help
I2S 类型选择
config TAIJIPAI_I2S_TYPE_STD
bool "I2S Type STD"
config TAIJIPAI_I2S_TYPE_PDM
bool "I2S Type PDM"
endchoice
config I2S_USE_2SLOT
bool "Enable I2S 2 Slot"
default y
help
启动双声道
endmenu
endmenu
menu "BLE prph Configuration"
choice EXAMPLE_USE_IO_TYPE
prompt "I/O Capability"
default BLE_SM_IO_CAP_NO_IO
help
I/O capability of device.
config BLE_SM_IO_CAP_DISP_ONLY
bool "DISPLAY ONLY"
config BLE_SM_IO_CAP_DISP_YES_NO
bool "DISPLAY YESNO"
config BLE_SM_IO_CAP_KEYBOARD_ONLY
bool "KEYBOARD ONLY"
config BLE_SM_IO_CAP_NO_IO
bool "Just works"
config BLE_SM_IO_CAP_KEYBOARD_DISP
bool "Both KEYBOARD & DISPLAY"
endchoice
config EXAMPLE_IO_TYPE
int
default 0 if BLE_SM_IO_CAP_DISP_ONLY
default 1 if BLE_SM_IO_CAP_DISP_YES_NO
default 2 if BLE_SM_IO_CAP_KEYBOARD_ONLY
default 3 if BLE_SM_IO_CAP_NO_IO
default 4 if BLE_SM_IO_CAP_KEYBOARD_DISP
config EXAMPLE_BONDING
bool
default n
prompt "Use Bonding"
help
Use this option to enable/disable bonding.
config EXAMPLE_MITM
bool
default n
prompt "MITM security"
help
Use this option to enable/disable MITM security.
config EXAMPLE_USE_SC
bool
depends on BT_NIMBLE_SM_SC
default n
prompt "Use Secure Connection feature"
help
Use this option to enable/disable Security Manager Secure Connection 4.2 feature.
config EXAMPLE_EXTENDED_ADV
bool
depends on SOC_BLE_50_SUPPORTED && BT_NIMBLE_50_FEATURE_SUPPORT
default y if SOC_ESP_NIMBLE_CONTROLLER
select BT_NIMBLE_EXT_ADV
prompt "Enable Extended Adv"
help
Use this option to enable extended advertising in the example.
If this option is disabled, ensure config BT_NIMBLE_EXT_ADV is
also disabled from Nimble stack menuconfig
config EXAMPLE_RANDOM_ADDR
bool
prompt "Advertise RANDOM Address"
help
Use this option to advertise a random address instead of public address
config EXAMPLE_ENCRYPTION
bool
prompt "Enable Link Encryption"
help
This adds Encrypted Read and Write permissions in the custom GATT server.
config EXAMPLE_RESOLVE_PEER_ADDR
bool
prompt "Enable resolving peer address"
help
Use this option to enable resolving peer's address.
endmenu
@@ -0,0 +1,52 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "app_ai_agent.h"
#include <hal/hal.h>
#include <mooncake.h>
#include <mooncake_log.h>
#include <assets/assets.h>
#include <smooth_lvgl.hpp>
using namespace mooncake;
using namespace smooth_ui_toolkit::lvgl_cpp;
AppAiAgent::AppAiAgent()
{
// Configure App name
setAppInfo().name = "AI.AGENT";
// Configure App icon
setAppInfo().icon = (void*)&icon_ai_agent;
// Configure App theme color
static uint32_t theme_color = 0x33CC99;
setAppInfo().userData = (void*)&theme_color;
}
// Called when the App is installed
void AppAiAgent::onCreate()
{
mclog::tagInfo(getAppInfo().name, "on create");
}
// Called when the App is opened
// You can construct UI, initialize operations, etc. here
void AppAiAgent::onOpen()
{
mclog::tagInfo(getAppInfo().name, "on open");
GetHAL().startXiaozhi();
}
// Called repeatedly while the App is running
void AppAiAgent::onRunning()
{
}
// Called when the App is closed
// You can destroy UI, release resources, etc. here
void AppAiAgent::onClose()
{
mclog::tagInfo(getAppInfo().name, "on close");
}
@@ -0,0 +1,22 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <mooncake.h>
/**
* @brief Derived App
*
*/
class AppAiAgent : public mooncake::AppAbility {
public:
AppAiAgent();
// Override lifecycle callbacks
void onCreate() override;
void onOpen() override;
void onRunning() override;
void onClose() override;
};
@@ -0,0 +1,255 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "app_avatar.h"
#include "view/ws_call.h"
#include <hal/hal.h>
#include <mooncake.h>
#include <mooncake_log.h>
#include <assets/assets.h>
#include <smooth_lvgl.hpp>
#include <stackchan/stackchan.h>
#include <string_view>
#include <cstdint>
#include <memory>
using namespace mooncake;
using namespace smooth_ui_toolkit::lvgl_cpp;
using namespace stackchan;
#include <string>
#include <sstream>
#include <unordered_set>
static bool contains_word(const std::string& text, const std::unordered_set<std::string>& words)
{
auto to_lower = [](std::string s) {
std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::tolower(c); });
return s;
};
std::istringstream iss(text);
std::string token;
while (iss >> token) {
token = to_lower(token);
if (words.find(token) != words.end()) {
return true;
}
}
return false;
}
AppAvatar::AppAvatar()
{
// 配置 App 名
setAppInfo().name = "AVATAR";
// 配置 App 图标
setAppInfo().icon = (void*)&icon_sentinel;
// 配置 App 主题颜色
static uint32_t theme_color = 0xFF6699;
setAppInfo().userData = (void*)&theme_color;
}
// App 被安装时会被调用
void AppAvatar::onCreate()
{
mclog::tagInfo(getAppInfo().name, "on create");
}
void AppAvatar::onOpen()
{
mclog::tagInfo(getAppInfo().name, "on open");
// GetHAL().startBleServer();
GetHAL().startWebSocketAvatar();
LvglLockGuard lock;
// Create default avatar
auto avatar = std::make_unique<avatar::DefaultAvatar>();
avatar->init(lv_screen_active());
GetStackChan().attachAvatar(std::move(avatar));
/* ------------------------------- BLE events ------------------------------- */
_ble_avatar_data.callback_id = GetHAL().onBleAvatarData.connect([&](const char* data) {
std::lock_guard<std::mutex> lock(_mutex);
if (_ble_avatar_data.update_flag) {
return;
}
_ble_avatar_data.update_flag = true;
_ble_avatar_data.data_ptr = (char*)data;
});
_ble_motion_data.callback_id = GetHAL().onBleMotionData.connect([&](const char* data) {
std::lock_guard<std::mutex> lock(_mutex);
if (_ble_motion_data.update_flag) {
return;
}
_ble_motion_data.update_flag = true;
_ble_motion_data.data_ptr = (char*)data;
});
/* ---------------------------- Websocket events ---------------------------- */
// Avatar control
_ws_callback_ids.avatar_id = GetHAL().onWsAvatarData.connect([&](std::string_view data) {
LvglLockGuard lvgl_lock;
GetStackChan().updateAvatarFromJson(data.data());
});
// Motion control
_ws_callback_ids.motion_id = GetHAL().onWsMotionData.connect([&](std::string_view data) {
LvglLockGuard lvgl_lock;
check_auto_angle_sync_mode();
GetStackChan().updateMotionFromJson(data.data());
});
// Phone call handling
_ws_callback_ids.call_req_id = GetHAL().onWsCallRequest.connect([&](std::string caller) {
if (_ws_call_view_id >= 0) {
mclog::tagWarn(getAppInfo().name, "ws call view already exists");
return;
}
LvglLockGuard lvgl_lock;
auto& avatar = GetStackChan().avatar();
avatar.setSpeech("");
avatar.leftEye().setVisible(false);
avatar.rightEye().setVisible(false);
avatar.mouth().setVisible(false);
auto view = std::make_unique<view::WsCallView>(lv_screen_active(), caller);
view->onAccept = []() {
auto& avatar = GetStackChan().avatar();
avatar.setSpeech("");
avatar.leftEye().setVisible(true);
avatar.rightEye().setVisible(true);
avatar.mouth().setVisible(true);
GetHAL().onWsCallResponse.emit(true);
};
view->onDecline = []() {
auto& avatar = GetStackChan().avatar();
avatar.setSpeech("");
avatar.leftEye().setVisible(true);
avatar.rightEye().setVisible(true);
avatar.mouth().setVisible(true);
GetHAL().onWsCallResponse.emit(false);
};
view->onEnd = []() { GetHAL().onWsCallEnd.emit(WsSignalSource::Local); };
view->onDestory = [&]() { _ws_call_view_id = -1; };
_ws_call_view_id = avatar.addDecorator(std::move(view));
});
_ws_callback_ids.call_end_id = GetHAL().onWsCallEnd.connect([&](WsSignalSource source) {
if (source != WsSignalSource::Remote) {
return;
}
LvglLockGuard lvgl_lock;
if (_ws_call_view_id < 0) {
mclog::tagWarn(getAppInfo().name, "ws call view does not exist");
return;
}
auto& avatar = GetStackChan().avatar();
avatar.setSpeech("");
avatar.leftEye().setVisible(true);
avatar.rightEye().setVisible(true);
avatar.mouth().setVisible(true);
avatar.removeDecorator(_ws_call_view_id);
_ws_call_view_id = -1;
});
// Text message handling
_ws_callback_ids.text_msg_id = GetHAL().onWsTextMessage.connect([&](const WsTextMessage_t& message) {
LvglLockGuard lvgl_lock;
auto& stackchan = GetStackChan();
auto& avatar = stackchan.avatar();
stackchan.addModifier(
std::make_unique<TimedSpeechModifier>(fmt::format("{} says: {}", message.name, message.content), 6000));
stackchan.addModifier(std::make_unique<SpeakingModifier>(2000));
// Special handling
if (contains_word(message.content, {"hello", "hi"})) {
stackchan.addModifier(std::make_unique<TimedEmotionModifier>(avatar::Emotion::Happy, 2000));
} else if (contains_word(message.content, {"love"})) {
stackchan.addModifier(std::make_unique<TimedEmotionModifier>(avatar::Emotion::Happy, 2000));
}
});
_ws_callback_ids.dance_data_id = GetHAL().onWsDanceData.connect([&](std::string_view data) {
LvglLockGuard lvgl_lock;
auto sequence = stackchan::animation::parse_sequence_from_json(data.data());
if (!sequence.empty()) {
GetStackChan().addModifier(std::make_unique<DanceModifier>(sequence));
}
});
/* ------------------------------ Video window ------------------------------ */
_video_window = std::make_unique<view::VideoWindow>(lv_screen_active());
}
void AppAvatar::onRunning()
{
std::lock_guard<std::mutex> lock(_mutex);
LvglLockGuard lvgl_lock;
if (_ble_avatar_data.update_flag) {
GetStackChan().updateAvatarFromJson(_ble_avatar_data.data_ptr);
_ble_avatar_data.update_flag = false;
_ble_avatar_data.data_ptr = nullptr;
}
if (_ble_motion_data.update_flag) {
check_auto_angle_sync_mode();
GetStackChan().updateMotionFromJson(_ble_motion_data.data_ptr);
_ble_motion_data.update_flag = false;
_ble_motion_data.data_ptr = nullptr;
}
GetStackChan().update();
}
void AppAvatar::onClose()
{
mclog::tagInfo(getAppInfo().name, "on close");
LvglLockGuard lock;
GetStackChan().resetAvatar();
_video_window.reset();
GetHAL().onBleAvatarData.disconnect(_ble_avatar_data.callback_id);
GetHAL().onBleMotionData.disconnect(_ble_motion_data.callback_id);
GetHAL().onWsAvatarData.disconnect(_ws_callback_ids.avatar_id);
GetHAL().onWsMotionData.disconnect(_ws_callback_ids.motion_id);
GetHAL().onWsCallRequest.disconnect(_ws_callback_ids.call_req_id);
GetHAL().onWsCallEnd.disconnect(_ws_callback_ids.call_end_id);
GetHAL().onWsTextMessage.disconnect(_ws_callback_ids.text_msg_id);
GetHAL().onWsDanceData.disconnect(_ws_callback_ids.dance_data_id);
}
void AppAvatar::check_auto_angle_sync_mode()
{
auto& motion = GetStackChan().motion();
// If far from last command, enable auto angle sync
if (GetHAL().millis() - _last_motion_cmd_tick > 2000) {
motion.setAutoAngleSyncEnabled(true);
} else {
motion.setAutoAngleSyncEnabled(false);
}
_last_motion_cmd_tick = GetHAL().millis();
}
@@ -0,0 +1,56 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "view/video_window.hpp"
#include <mooncake.h>
#include <cstdint>
#include <memory>
#include <mutex>
#include <vector>
/**
* @brief 派生 App
*
*/
class AppAvatar : public mooncake::AppAbility {
public:
AppAvatar();
// 重写生命周期回调
void onCreate() override;
void onOpen() override;
void onRunning() override;
void onClose() override;
private:
std::mutex _mutex;
struct BleHandlerData_t {
bool update_flag = false;
char* data_ptr = nullptr;
int callback_id = -1;
};
BleHandlerData_t _ble_avatar_data;
BleHandlerData_t _ble_motion_data;
struct WsCallbackIds_t {
int avatar_id = -1;
int motion_id = -1;
int call_req_id = -1;
int call_end_id = -1;
int text_msg_id = -1;
int dance_data_id = -1;
};
WsCallbackIds_t _ws_callback_ids;
int _ws_call_view_id = -1;
uint32_t _last_motion_cmd_tick = 0;
std::unique_ptr<view::VideoWindow> _video_window;
void check_auto_angle_sync_mode();
};
@@ -0,0 +1,240 @@
#ifdef __has_include
#if __has_include("lvgl.h")
#ifndef LV_LVGL_H_INCLUDE_SIMPLE
#define LV_LVGL_H_INCLUDE_SIMPLE
#endif
#endif
#endif
#if defined(LV_LVGL_H_INCLUDE_SIMPLE)
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#ifndef LV_ATTRIBUTE_MEM_ALIGN
#define LV_ATTRIBUTE_MEM_ALIGN
#endif
#ifndef LV_ATTRIBUTE_IMAGE_ICON_PHONE
#define LV_ATTRIBUTE_IMAGE_ICON_PHONE
#endif
const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMAGE_ICON_PHONE uint8_t icon_phone_map[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x80, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff,
0xff, 0xff, 0xbf, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x40, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xff, 0xff, 0xff,
0xff, 0xff, 0xbf, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
const lv_image_dsc_t icon_phone = {
.header.cf = LV_COLOR_FORMAT_RGB565A8,
.header.magic = LV_IMAGE_HEADER_MAGIC,
.header.w = 36,
.header.h = 36,
.data_size = 1296 * 3,
.data = icon_phone_map,
};
@@ -0,0 +1,55 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <lvgl.h>
#include <hal/hal.h>
#include <smooth_lvgl.hpp>
#include <uitk/short_namespace.hpp>
#include <memory>
namespace view {
class VideoWindow {
public:
VideoWindow(lv_obj_t* parent)
{
_image = std::make_unique<uitk::lvgl_cpp::Image>(parent);
_image->align(LV_ALIGN_CENTER, 0, 0);
_image->setSize(320, 240);
_image->setHidden(true);
_on_ws_video_mode_change_id = GetHAL().onWsVideoModeChange.connect([this](bool enabled) {
LvglLockGuard lock;
if (enabled) {
_image->setHidden(false);
} else {
_image->setHidden(true);
}
});
_on_ws_video_frame_id = GetHAL().onWsVideoFrame.connect([this](std::shared_ptr<LvglImage> img) {
LvglLockGuard lock;
_image_cached = img;
auto img_dsc = _image_cached->image_dsc();
_image->setSrc(img_dsc);
});
}
~VideoWindow()
{
GetHAL().onWsVideoModeChange.disconnect(_on_ws_video_mode_change_id);
GetHAL().onWsVideoFrame.disconnect(_on_ws_video_frame_id);
}
private:
std::unique_ptr<uitk::lvgl_cpp::Image> _image;
std::shared_ptr<LvglImage> _image_cached;
int _on_ws_video_mode_change_id = -1;
int _on_ws_video_frame_id = -1;
};
} // namespace view
@@ -0,0 +1,259 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "ws_call.h"
#include <smooth_ui_toolkit.hpp>
#include <mooncake_log.h>
#include <functional>
#include <cstdint>
#include <memory>
using namespace smooth_ui_toolkit::lvgl_cpp;
using namespace smooth_ui_toolkit;
using namespace view;
LV_IMAGE_DECLARE(icon_phone);
/**
* @brief
*
*/
class IncomingPanel : public Container {
public:
std::function<void(void)> onAccept;
std::function<void(void)> onDecline;
IncomingPanel(lv_obj_t* parent, std::string caller) : Container(parent)
{
setSize(320, 240);
align(LV_ALIGN_CENTER, 0, 0);
setBorderWidth(0);
setBgOpa(0);
_label_caller = std::make_unique<Label>(get());
_label_caller->setTextFont(&lv_font_montserrat_24);
_label_caller->setTextColor(lv_color_hex(0xFFFFFF));
_label_caller->align(LV_ALIGN_CENTER, 0, -63);
_label_caller->setText(caller);
_button_decline = std::make_unique<Button>(get());
_button_decline->align(LV_ALIGN_CENTER, -73, 30);
_button_decline->setBgColor(lv_color_hex(0xEB5545));
_button_decline->setRadius(LV_RADIUS_CIRCLE);
_button_decline->setShadowWidth(0);
_button_decline->setBorderWidth(0);
_button_decline->setSize(64, 64);
_button_decline->onClick().connect([&]() {
if (onDecline) {
onDecline();
}
});
_img_decline = std::make_unique<Image>(_button_decline->get());
_img_decline->align(LV_ALIGN_CENTER, 0, 0);
_img_decline->setRotation(1325);
_img_decline->setSrc(&icon_phone);
_label_decline = std::make_unique<Label>(get());
_label_decline->setTextFont(&lv_font_montserrat_14);
_label_decline->setTextColor(lv_color_hex(0xFFFFFF));
_label_decline->align(LV_ALIGN_CENTER, -73, 77);
_label_decline->setText("Decline");
_button_accept = std::make_unique<Button>(get());
_button_accept->align(LV_ALIGN_CENTER, 73, 30);
_button_accept->setBgColor(lv_color_hex(0x67CE67));
_button_accept->setRadius(LV_RADIUS_CIRCLE);
_button_accept->setShadowWidth(0);
_button_accept->setBorderWidth(0);
_button_accept->setSize(64, 64);
_button_accept->onClick().connect([&]() {
if (onAccept) {
onAccept();
}
});
_img_accept = std::make_unique<Image>(_button_accept->get());
_img_accept->align(LV_ALIGN_CENTER, 0, 0);
_img_accept->setSrc(&icon_phone);
_label_accept = std::make_unique<Label>(get());
_label_accept->setTextFont(&lv_font_montserrat_14);
_label_accept->setTextColor(lv_color_hex(0xFFFFFF));
_label_accept->align(LV_ALIGN_CENTER, 73, 77);
_label_accept->setText("Accept");
}
void update()
{
if (GetHAL().millis() - _time_count > 600) {
_anim_flag = !_anim_flag;
if (_anim_flag) {
_img_accept->setRotation(-200);
} else {
_img_accept->setRotation(0);
}
_time_count = GetHAL().millis();
}
}
private:
std::unique_ptr<Label> _label_caller;
std::unique_ptr<Label> _label_decline;
std::unique_ptr<Label> _label_accept;
std::unique_ptr<Button> _button_decline;
std::unique_ptr<Button> _button_accept;
std::unique_ptr<Image> _img_decline;
std::unique_ptr<Image> _img_accept;
uint32_t _time_count = 0;
bool _anim_flag = false;
};
/**
* @brief
*
*/
class ConnectingPanel : public Container {
public:
std::function<void(void)> onEnd;
ConnectingPanel(lv_obj_t* parent, std::string caller) : Container(parent)
{
setSize(320, 240);
align(LV_ALIGN_CENTER, 0, 0);
setPadding(0, 0, 0, 0);
setBorderWidth(0);
setBgOpa(0);
_label_caller = std::make_unique<Label>(get());
_label_caller->setTextFont(&lv_font_montserrat_16);
_label_caller->setTextColor(lv_color_hex(0xFFFFFF));
_label_caller->align(LV_ALIGN_LEFT_MID, 13, 85);
_label_caller->setText(caller);
_label_timer = std::make_unique<Label>(get());
_label_timer->setTextFont(&lv_font_montserrat_14);
_label_timer->setTextColor(lv_color_hex(0x67CE67));
_label_timer->align(LV_ALIGN_LEFT_MID, 13, 104);
_button_end = std::make_unique<Button>(get());
_button_end->align(LV_ALIGN_CENTER, 116, 94);
_button_end->setBgColor(lv_color_hex(0xEB5545));
_button_end->setRadius(10);
_button_end->setShadowWidth(0);
_button_end->setBorderWidth(0);
_button_end->setSize(72, 36);
_button_end->onClick().connect([&]() {
if (onEnd) {
onEnd();
}
});
_button_end->label().setTextFont(&lv_font_montserrat_14);
_button_end->label().setTextColor(lv_color_hex(0xFFFFFF));
_button_end->label().setText("End");
}
void reset()
{
_connect_time_count = GetHAL().millis();
update_timer_label();
}
void update_timer_label()
{
uint32_t elapsed = (GetHAL().millis() - _connect_time_count) / 1000;
uint32_t min = elapsed / 60;
uint32_t sec = elapsed % 60;
_label_timer->setText(fmt::format("{:02}:{:02}", min, sec));
}
void update()
{
if (GetHAL().millis() - _time_count > 1000) {
update_timer_label();
_time_count = GetHAL().millis();
}
}
private:
std::unique_ptr<Label> _label_caller;
std::unique_ptr<Label> _label_timer;
std::unique_ptr<Button> _button_end;
uint32_t _time_count = 0;
uint32_t _connect_time_count = 0;
};
WsCallView::WsCallView(lv_obj_t* parent, std::string caller)
{
auto panel_incoming = std::make_unique<IncomingPanel>(parent, caller);
panel_incoming->onAccept = [&]() { handle_accept(); };
panel_incoming->onDecline = [&]() { handle_decline(); };
auto panel_connecting = std::make_unique<ConnectingPanel>(parent, caller);
panel_connecting->onEnd = [&]() { handle_end(); };
panel_connecting->setHidden(true);
_panel_incoming = std::move(panel_incoming);
_panel_connecting = std::move(panel_connecting);
_state = State::Incoming;
}
void WsCallView::_update()
{
switch (_state) {
case State::Incoming: {
auto icoming_panel = static_cast<IncomingPanel*>(_panel_incoming.get());
icoming_panel->update();
break;
}
case State::Connecting: {
auto connecting_panel = static_cast<ConnectingPanel*>(_panel_connecting.get());
if (_panel_incoming) {
_panel_incoming.reset();
connecting_panel->setHidden(false);
connecting_panel->reset();
}
connecting_panel->update();
break;
}
default:
break;
}
}
void WsCallView::handle_accept()
{
_state = State::Connecting;
if (onAccept) {
onAccept();
}
}
void WsCallView::handle_decline()
{
if (onDecline) {
onDecline();
}
if (onDestory) {
onDestory();
}
requestDestroy();
}
void WsCallView::handle_end()
{
if (onEnd) {
onEnd();
}
if (onDestory) {
onDestory();
}
requestDestroy();
}
@@ -0,0 +1,45 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <lvgl.h>
#include <smooth_lvgl.hpp>
#include <uitk/short_namespace.hpp>
#include <stackchan/stackchan.h>
#include <memory>
namespace view {
/**
* @brief
*
*/
class WsCallView : public stackchan::avatar::Decorator {
public:
std::function<void(void)> onAccept;
std::function<void(void)> onDecline;
std::function<void(void)> onEnd;
std::function<void(void)> onDestory;
enum class State {
Incoming = 0,
Connecting,
};
WsCallView(lv_obj_t* parent, std::string caller);
private:
State _state = State::Incoming;
std::unique_ptr<uitk::lvgl_cpp::Container> _panel_incoming;
std::unique_ptr<uitk::lvgl_cpp::Container> _panel_connecting;
void _update() override;
void handle_accept();
void handle_decline();
void handle_end();
};
} // namespace view
@@ -0,0 +1,188 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "app_espnow_ctrl.h"
#include "view/page_selector.h"
#include <hal/hal.h>
#include <mooncake.h>
#include <mooncake_log.h>
#include <assets/assets.h>
#include <smooth_lvgl.hpp>
#include <stackchan/stackchan.h>
#include <cstdint>
#include <mutex>
#include <string>
using namespace mooncake;
using namespace smooth_ui_toolkit::lvgl_cpp;
using namespace stackchan;
AppEspnowControl::AppEspnowControl()
{
// 配置 App 名
setAppInfo().name = "ESPNOW.REMOTE";
// 配置 App 图标
setAppInfo().icon = (void*)&icon_controller;
// 配置 App 主题颜色
static uint32_t theme_color = 0xCCCC33;
setAppInfo().userData = (void*)&theme_color;
}
void AppEspnowControl::onCreate()
{
mclog::tagInfo(getAppInfo().name, "on create");
}
static std::mutex _mutex;
static std::vector<uint8_t> _received_data;
static int _receiver_id = 0;
static bool _is_receiver = false;
void AppEspnowControl::onOpen()
{
mclog::tagInfo(getAppInfo().name, "on open");
// Get role
std::vector<std::string> role_options = {"Receiver", "Sender"};
int role_selection = view::create_page_selector_and_wait("Select Role", role_options);
_is_receiver = (role_selection == 0);
mclog::tagInfo(getAppInfo().name, "selected role: {}", _is_receiver ? "Receiver" : "Sender");
// Get channel
std::vector<std::string> channel_options;
for (int i = 0; i < 13; i++) {
channel_options.push_back(std::to_string(i + 1));
}
auto wifi_channel = view::create_page_selector_and_wait("Select WiFi Channel", channel_options) + 1;
mclog::tagInfo(getAppInfo().name, "selected wifi channel: {}", wifi_channel);
// Get id
std::vector<std::string> id_options;
for (int i = 0; i < 255; i++) {
id_options.push_back(std::to_string(i));
}
_receiver_id = view::create_page_selector_and_wait("Select ID", id_options);
mclog::tagInfo(getAppInfo().name, "selected id: {}", _receiver_id);
// Start espnow
GetHAL().startEspNow(wifi_channel);
GetHAL().onEspNowData.connect([](const std::vector<uint8_t>& data) {
std::lock_guard<std::mutex> lock(_mutex);
_received_data = data;
});
// Normal avatar
LvglLockGuard lock;
auto& stackchan = GetStackChan();
auto avatar = std::make_unique<avatar::DefaultAvatar>();
avatar->init(lv_screen_active());
stackchan.attachAvatar(std::move(avatar));
stackchan.addModifier(std::make_unique<BreathModifier>());
stackchan.addModifier(std::make_unique<BlinkModifier>());
// Diable auto angle sync to prevent jitter
stackchan.motion().setAutoAngleSyncEnabled(false);
GetHAL().setLaserEnabled(false);
}
void handle_received_data()
{
std::lock_guard<std::mutex> lock(_mutex);
// [target-id (uint8)] [yaw-angle (int16)] [pitch-angle (int16)] [speed (int16)] [laser-enabled (uint8)]
// id: 0 for broadcast
// yaw: -1280 ~ 1280
// pitch: 0 ~ 900
// speed: 0 ~ 1000, suggest 600
// laser-enabled: 0 = off, 1 = on
if (_received_data.size() >= 8) {
uint8_t target_id = _received_data[0];
if (target_id != 0 && target_id != _receiver_id) {
mclog::info("not me, target id: {}", target_id);
_received_data.clear();
return;
}
int16_t yaw_angle = static_cast<int16_t>(_received_data[1] | (_received_data[2] << 8));
int16_t pitch_angle = static_cast<int16_t>(_received_data[3] | (_received_data[4] << 8));
int16_t speed = static_cast<int16_t>(_received_data[5] | (_received_data[6] << 8));
bool laser_enabled = (_received_data[7] != 0);
mclog::info("yaw: {}, pitch: {}, speed: {}, laser: {}", yaw_angle, pitch_angle, speed, laser_enabled);
auto& motion = GetStackChan().motion();
motion.moveWithSpeed(yaw_angle, pitch_angle, speed);
GetHAL().setLaserEnabled(laser_enabled);
}
_received_data.clear();
}
void handle_send_pose()
{
static uint32_t last_send_tick = 0;
if (GetHAL().millis() - last_send_tick < 50) {
return;
}
last_send_tick = GetHAL().millis();
// [target-id (uint8)] [yaw-angle (int16)] [pitch-angle (int16)] [speed (int16)] [laser-enabled (uint8)]
// id: 0 for broadcast
// yaw: -1280 ~ 1280
// pitch: 0 ~ 900
// speed: 0 ~ 1000, suggest 600
// laser-enabled: 0 = off, 1 = on
auto& motion = GetStackChan().motion();
int16_t yaw_angle = motion.getCurrentYawAngle();
int16_t pitch_angle = motion.getCurrentPitchAngle();
const int16_t speed = 800;
std::vector<uint8_t> data;
data.reserve(8); // 预留空间提高效率
// [0] target-id
data.push_back(_receiver_id);
// [1-2] yaw-angle (小端序:先发低位,再发高位)
data.push_back(static_cast<uint8_t>(yaw_angle & 0xFF));
data.push_back(static_cast<uint8_t>((yaw_angle >> 8) & 0xFF));
// [3-4] pitch-angle
data.push_back(static_cast<uint8_t>(pitch_angle & 0xFF));
data.push_back(static_cast<uint8_t>((pitch_angle >> 8) & 0xFF));
// [5-6] speed
data.push_back(static_cast<uint8_t>(speed & 0xFF));
data.push_back(static_cast<uint8_t>((speed >> 8) & 0xFF));
// [7] laser-enabled
data.push_back(0); // always off for sender
GetHAL().espNowSend(data);
}
void AppEspnowControl::onRunning()
{
LvglLockGuard lock;
if (_is_receiver) {
handle_received_data();
} else {
handle_send_pose();
}
GetStackChan().update();
}
void AppEspnowControl::onClose()
{
mclog::tagInfo(getAppInfo().name, "on close");
LvglLockGuard lock;
}
@@ -0,0 +1,22 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <mooncake.h>
/**
* @brief 派生 App
*
*/
class AppEspnowControl : public mooncake::AppAbility {
public:
AppEspnowControl();
// 重写生命周期回调
void onCreate() override;
void onOpen() override;
void onRunning() override;
void onClose() override;
};
@@ -0,0 +1,88 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <memory>
#include <smooth_lvgl.hpp>
#include <uitk/short_namespace.hpp>
#include <hal/hal.h>
#include <vector>
#include <string>
#include <string_view>
namespace view {
class PageSelector {
public:
PageSelector(std::string_view label, const std::vector<std::string> options)
{
_panel = std::make_unique<uitk::lvgl_cpp::Container>(lv_screen_active());
_panel->setPadding(0, 0, 0, 0);
_panel->setSize(320, 240);
_label = std::make_unique<uitk::lvgl_cpp::Label>(_panel->get());
_label->setText(label);
_label->setTextFont(&lv_font_montserrat_24);
_label->align(LV_ALIGN_CENTER, 0, -80);
_roller = std::make_unique<uitk::lvgl_cpp::Roller>(_panel->get());
_roller->setSize(200, 150);
_roller->setOptions(options);
_roller->align(LV_ALIGN_CENTER, -45, 35);
_roller->onValueChanged().connect([&](uint32_t index) { _selected_index = index; });
_roller->setTextFont(&lv_font_montserrat_24);
_btn_confirm = std::make_unique<uitk::lvgl_cpp::Button>(_panel->get());
_btn_confirm->label().setText("ok");
_btn_confirm->setSize(70, 110);
_btn_confirm->align(LV_ALIGN_CENTER, 110, 40);
_btn_confirm->onClick().connect([&]() { _is_selected = true; });
}
bool update()
{
return _is_selected;
}
int getSelectedIndex() const
{
return _selected_index;
}
private:
std::unique_ptr<uitk::lvgl_cpp::Container> _panel;
std::unique_ptr<uitk::lvgl_cpp::Roller> _roller;
std::unique_ptr<uitk::lvgl_cpp::Button> _btn_confirm;
std::unique_ptr<uitk::lvgl_cpp::Label> _label;
bool _is_selected = false;
int _selected_index = 0;
};
static inline int create_page_selector_and_wait(std::string_view label, const std::vector<std::string> options)
{
GetHAL().lvglLock();
auto page_selector = std::make_unique<view::PageSelector>(label, options);
GetHAL().lvglUnlock();
int index = 0;
while (1) {
GetHAL().delay(50);
LvglLockGuard lock;
if (page_selector->update()) {
index = page_selector->getSelectedIndex();
break;
}
}
{
LvglLockGuard lock;
page_selector.reset();
}
return index;
}
} // namespace view
@@ -0,0 +1,81 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "app_launcher.h"
#include <hal/hal.h>
#include <mooncake.h>
#include <mooncake_log.h>
#include <stackchan/stackchan.h>
#include <cstdint>
using namespace mooncake;
void AppLauncher::onLauncherCreate()
{
mclog::tagInfo(getAppInfo().name, "on create");
// 打开自己
open();
}
void AppLauncher::onLauncherOpen()
{
mclog::tagInfo(getAppInfo().name, "on open");
LvglLockGuard lock;
_view = std::make_unique<view::LauncherView>();
_view->init(getAppProps());
_view->onAppClicked = [&](int appID) {
mclog::tagInfo(getAppInfo().name, "handle open app, app id: {}", appID);
openApp(appID);
};
}
void AppLauncher::onLauncherRunning()
{
LvglLockGuard lock;
_view->update();
screensaver_update();
GetStackChan().update();
}
void AppLauncher::onLauncherClose()
{
mclog::tagInfo(getAppInfo().name, "on close");
LvglLockGuard lock;
_view.reset();
}
void AppLauncher::onLauncherDestroy()
{
mclog::tagInfo(getAppInfo().name, "on close");
}
void AppLauncher::screensaver_update()
{
const uint32_t SCREENSAVER_TIMEOUT_MS = 30000;
uint32_t idle_time = lv_display_get_inactive_time(NULL);
if (idle_time >= SCREENSAVER_TIMEOUT_MS) {
if (!_screensaver) {
_screensaver = std::make_unique<view::Screensaver>();
_screensaver->init();
}
} else if (_screensaver) {
_screensaver.reset();
}
// Update in 30ms interval
if (_screensaver && GetHAL().millis() - _screensaver_timecount > 30) {
_screensaver_timecount = GetHAL().millis();
_screensaver->update();
}
}
@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "view/view.h"
#include <mooncake.h>
#include <mooncake_templates.h>
#include <cstdint>
#include <memory>
class AppLauncher : public mooncake::templates::AppLauncherBase {
public:
void onLauncherCreate() override;
void onLauncherOpen() override;
void onLauncherRunning() override;
void onLauncherClose() override;
void onLauncherDestroy() override;
private:
std::unique_ptr<view::LauncherView> _view;
std::unique_ptr<view::Screensaver> _screensaver;
uint32_t _screensaver_timecount = 0;
void screensaver_update();
};
@@ -0,0 +1,102 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "view.h"
#include <cstdint>
#include <memory>
using namespace view;
using namespace uitk;
using namespace uitk::lvgl_cpp;
using namespace uitk::games;
using namespace uitk::games::dvd_screensaver;
static const Vector2 _screen_size = {320, 240};
static const Vector2 _logo_size = {64, 48};
static const int _logo_id = 666;
static const std::vector<uint32_t> _logo_colors = {
0xffffff, 0xfffa01, 0xff8300, 0x00feff, 0xff2600, 0xbe00ff, 0x0026ff, 0xff008b,
};
static const uint32_t _bg_color = 0x000000;
Screensaver::~Screensaver()
{
_prev_screen->load();
}
void Screensaver::onInit()
{
_prev_screen = std::make_unique<ScreenActive>();
_screen = std::make_unique<Screen>();
_screen->setBgColor(lv_color_hex(_bg_color));
_screen->removeFlag(LV_OBJ_FLAG_SCROLLABLE);
_screen->setPadding(0, 0, 0, 0);
_screen->load();
_logo = std::make_unique<Container>(_screen->get());
_logo->setSize(_logo_size.width, _logo_size.height);
_logo->setBgColor(lv_color_hex(_logo_colors[0]));
_logo->align(LV_ALIGN_TOP_LEFT, 2333, 2333);
_logo->removeFlag(LV_OBJ_FLAG_SCROLLABLE);
_logo->setPadding(0, 0, 0, 0);
_logo->setBorderWidth(0);
_logo->setRadius(0);
_left_eye = std::make_unique<Container>(_logo->get());
_left_eye->align(LV_ALIGN_CENTER, -15, -3);
_left_eye->setBgColor(lv_color_hex(_bg_color));
_left_eye->removeFlag(LV_OBJ_FLAG_SCROLLABLE);
_left_eye->setRadius(LV_RADIUS_CIRCLE);
_left_eye->setBorderWidth(0);
_left_eye->setSize(6, 6);
_right_eye = std::make_unique<Container>(_logo->get());
_right_eye->align(LV_ALIGN_CENTER, 15, -3);
_right_eye->setBgColor(lv_color_hex(_bg_color));
_right_eye->removeFlag(LV_OBJ_FLAG_SCROLLABLE);
_right_eye->setRadius(LV_RADIUS_CIRCLE);
_right_eye->setBorderWidth(0);
_right_eye->setSize(6, 6);
_mouth = std::make_unique<Container>(_logo->get());
_mouth->align(LV_ALIGN_CENTER, 0, 5);
_mouth->setBgColor(lv_color_hex(_bg_color));
_mouth->removeFlag(LV_OBJ_FLAG_SCROLLABLE);
_mouth->setBorderWidth(0);
_mouth->setSize(18, 2);
_mouth->setRadius(0);
}
void Screensaver::onBuildLevel()
{
addScreenFrameAsWall(_screen_size);
auto& random = Random::getInstance();
Vector2 direction = {random.getFloat(0.3, 0.7), random.getFloat(0.3, 0.7)};
direction = direction.normalized();
addLogo(_logo_id, {_screen_size.width / 2, _screen_size.height / 2}, _logo_size, direction, 110);
}
void Screensaver::onRender(float dt)
{
getWorld().forEachObject([&](GameObject* obj) {
if (obj->groupId == _logo_id) {
auto p = obj->get<Transform>()->position;
_logo->setPos((int)p.x - _logo_size.width / 2, (int)p.y - _logo_size.height / 2);
}
});
}
void Screensaver::onLogoCollide(int logoGroupId)
{
_color_index++;
if (_color_index >= _logo_colors.size()) {
_color_index = 0;
}
_logo->setBgColor(lv_color_hex(_logo_colors[_color_index]));
}
@@ -0,0 +1,513 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "view.h"
#include <mooncake_log.h>
#include <assets/assets.h>
#include <functional>
#include <cstdint>
#include <vector>
using namespace view;
using namespace uitk;
using namespace uitk::lvgl_cpp;
/* -------------------------------------------------------------------------- */
/* Dynamic backgroud color handle class */
/* -------------------------------------------------------------------------- */
class DynamicBgColor {
public:
std::function<void(const uint32_t& bgColor)> onBgColorChanged;
void init(const std::vector<uint32_t>& stepColors, int stepGap)
{
_step_colors = stepColors;
_step_gap = stepGap;
_bg_color.duration = 0.3;
_bg_color.begin();
jumpTo(0);
}
void jumpTo(int index)
{
if (index < 0 || index >= _step_colors.size()) {
return;
}
_bg_color.teleport(_step_colors[index]);
_current_index = index;
if (onBgColorChanged) {
onBgColorChanged(_step_colors[index]);
}
}
void update(int scrollValue)
{
_last_index = _current_index;
// Update current index
_current_index = (scrollValue + _step_gap / 2) / _step_gap;
if (_current_index < 0) {
_current_index = 0;
}
if (_current_index >= _step_colors.size()) {
_current_index = _step_colors.size() - 1;
}
// If index changed
if (_last_index != _current_index) {
// mclog::tagInfo(_tag, "index changed from {} to {}", _last_index, _current_index);
_bg_color = _step_colors[_current_index];
}
// Update background color
_bg_color.update();
if (!_bg_color.done()) {
if (onBgColorChanged) {
onBgColorChanged(_bg_color.toHex());
}
}
}
private:
std::vector<uint32_t> _step_colors;
int _current_index = 0;
int _last_index = 0;
int _step_gap = 0;
color::AnimateRgb_t _bg_color;
};
/* -------------------------------------------------------------------------- */
/* Page indicator */
/* -------------------------------------------------------------------------- */
class PageIndicator {
public:
const int dot_size = 8;
const int dot_size_big = 14;
const int dot_gap = 16;
void init(int pageNum, int pageGap, lv_obj_t* parent, int posX, int posY)
{
_page_num = pageNum;
_page_gap = pageGap;
_panel = std::make_unique<Container>(parent);
_panel->removeFlag(LV_OBJ_FLAG_SCROLLABLE);
_panel->addFlag(LV_OBJ_FLAG_FLOATING);
_panel->setAlign(LV_ALIGN_CENTER);
_panel->setPadding(0, 0, 24, 24);
_panel->setPos(posX, posY);
_panel->setBorderWidth(0);
_panel->setHeight(24);
_panel->setWidth((pageNum * dot_size) + (pageNum - 1) * (dot_gap - dot_size) + 24 * 2);
_panel->setBgOpa(0);
for (int i = 0; i < pageNum; i++) {
_dots.push_back(std::make_unique<Container>(_panel->get()));
_dots.back()->setAlign(LV_ALIGN_CENTER);
_dots.back()->setPos(i * dot_gap - (pageNum - 1) * dot_gap / 2, 0);
_dots.back()->setBgColor(lv_color_hex(0xFFFFFF));
_dots.back()->removeFlag(LV_OBJ_FLAG_SCROLLABLE);
_dots.back()->setRadius(LV_RADIUS_CIRCLE);
_dots.back()->setSize(dot_size, dot_size);
_dots.back()->setBorderWidth(0);
}
jumpTo(0);
}
void jumpTo(int index)
{
if (index < 0 || index >= _page_num) {
return;
}
_current_index = index;
_last_index = index;
update_dots();
}
void update(int scrollValue)
{
_last_index = _current_index;
_current_index = (scrollValue + _page_gap / 2) / _page_gap;
if (_current_index < 0) {
_current_index = 0;
}
if (_current_index >= _page_num) {
_current_index = _page_num - 1;
}
if (_last_index != _current_index) {
update_dots();
}
}
private:
int _page_num = 0;
int _page_gap = 0;
int _current_index = 0;
int _last_index = 0;
std::unique_ptr<Container> _panel;
std::vector<std::unique_ptr<Container>> _dots;
void update_dots()
{
for (int i = 0; i < _page_num; i++) {
if (i == _current_index) {
_dots[i]->setSize(dot_size_big, dot_size_big);
_dots[i]->setOpa(255);
} else {
_dots[i]->setSize(dot_size, dot_size);
_dots[i]->setOpa(128);
}
}
}
};
/* -------------------------------------------------------------------------- */
/* Dynamic icon label */
/* -------------------------------------------------------------------------- */
class DynamicIconLabel {
public:
const int show_range = 50;
const int hidden_pos_y = -150;
const int visible_pos_y = -99;
const int transition_zone = 30;
void init(const std::vector<std::string>& iconLabelTexts, int iconGap, lv_obj_t* parent)
{
_icon_label_texts = iconLabelTexts;
_icon_gap = iconGap;
// Create floating label
_label = std::make_unique<Label>(parent);
_label->setTextColor(lv_color_hex(0x000000));
_label->setTextFont(&MontserratSemiBold26);
_label->setAlign(LV_ALIGN_CENTER);
_label->addFlag(LV_OBJ_FLAG_FLOATING);
_label->setOpa(233);
// Setup animation
_pos_y_anim = std::make_unique<AnimateValue>();
_pos_y_anim->springOptions().visualDuration = 0.3;
_pos_y_anim->springOptions().bounce = 0.1;
_pos_y_anim->begin();
jumpTo(0);
}
void jumpTo(int index)
{
if (index < 0 || index >= _icon_label_texts.size()) {
return;
}
_current_index = index;
_last_index = index;
_is_visible = true;
// Update label
_label->setText(_icon_label_texts[index]);
_label->setPos(0, visible_pos_y);
_pos_y_anim->teleport(visible_pos_y);
}
void update(int scrollValue)
{
_last_index = _current_index;
// Calculate current icon index and distance to icon center
_current_index = (scrollValue + _icon_gap / 2) / _icon_gap;
int icon_center_pos_x = _current_index * _icon_gap;
int distance_to_icon = std::abs(scrollValue - icon_center_pos_x);
// Clamp index
if (_current_index < 0) {
_current_index = 0;
}
if (_current_index >= _icon_label_texts.size()) {
_current_index = _icon_label_texts.size() - 1;
}
// Check if label should be visible
bool should_be_visible = (distance_to_icon <= show_range);
// If index changed, update label text
if (_last_index != _current_index) {
_label->setText(_icon_label_texts[_current_index]);
}
// Handle visibility state change
if (should_be_visible && !_is_visible) {
// Show label
_pos_y_anim->move(visible_pos_y);
_is_visible = true;
} else if (!should_be_visible && _is_visible) {
// Hide label
_pos_y_anim->move(hidden_pos_y);
_is_visible = false;
}
// Update animation and apply position
_pos_y_anim->update();
_label->setY(_pos_y_anim->directValue());
// Update opacity based on distance when in transition zone
if (should_be_visible && distance_to_icon > (show_range - transition_zone)) {
// Fade out as approaching edge
float fade_ratio = 1.0f - (float)(distance_to_icon - (show_range - transition_zone)) / transition_zone;
_label->setOpa(233 * fade_ratio);
} else if (should_be_visible) {
_label->setOpa(233);
}
}
private:
std::vector<std::string> _icon_label_texts;
int _icon_gap = 0;
int _current_index = 0;
int _last_index = 0;
bool _is_visible = false;
std::unique_ptr<Label> _label;
std::unique_ptr<AnimateValue> _pos_y_anim;
};
static std::string _tag = "LauncherView";
static constexpr int _icon_gap = 320;
static int _last_clicked_icon_pos_x = -1;
static std::unique_ptr<DynamicBgColor> _dynamic_bg_color;
static std::unique_ptr<PageIndicator> _page_indicator;
static std::unique_ptr<DynamicIconLabel> _dynamic_icon_label;
LauncherView::~LauncherView()
{
_icon_images.clear();
_icon_panels.clear();
_lr_indicators_images.clear();
_lr_indicator_panels.clear();
_panel.reset();
_dynamic_bg_color.reset();
_page_indicator.reset();
_dynamic_icon_label.reset();
}
void LauncherView::init(std::vector<mooncake::AppProps_t> appPorps)
{
mclog::tagInfo(_tag, "init");
/* ------------------------------ Screen setup ------------------------------ */
ScreenActive screen;
screen.removeFlag(LV_OBJ_FLAG_SCROLLABLE);
/* ---------------------------------- Panel --------------------------------- */
_panel = std::make_unique<Container>(lv_screen_active());
_panel->setAlign(LV_ALIGN_CENTER);
_panel->setSize(320, 240);
_panel->setRadius(0);
_panel->setBorderWidth(0);
_panel->setScrollbarMode(LV_SCROLLBAR_MODE_OFF);
_panel->setBgColor(lv_color_hex(0x33CC99));
_panel->addFlag(LV_OBJ_FLAG_SCROLL_ONE);
lv_obj_set_scroll_snap_x(_panel->get(), LV_SCROLL_SNAP_CENTER);
/* ---------------------------------- Icons --------------------------------- */
int icon_x = 0;
int icon_y = 0;
std::vector<std::string> icon_label_texts;
for (const auto& props : appPorps) {
// mclog::tagInfo(_tag, "name: {}, id: {}", props.info.name, props.appID);
// Icon panel
_icon_panels.push_back(std::make_unique<Container>(_panel->get()));
_icon_panels.back()->setAlign(LV_ALIGN_CENTER);
_icon_panels.back()->setSize(190, 160);
_icon_panels.back()->setPos(icon_x, icon_y);
_icon_panels.back()->setBorderWidth(0);
_icon_panels.back()->removeFlag(LV_OBJ_FLAG_SCROLLABLE);
_icon_panels.back()->setBgOpa(0);
// Icon click callback
auto app_id = props.appID;
auto pos_x = icon_x;
_icon_panels.back()->onClick().connect([&, app_id, pos_x]() {
_clicked_app_id = app_id;
_last_clicked_icon_pos_x = pos_x;
});
// Collect icon label texts
icon_label_texts.push_back(props.info.name);
// Icon image
if (props.info.icon != nullptr) {
_icon_images.push_back(std::make_unique<Image>(_icon_panels.back()->get()));
_icon_images.back()->setSrc(props.info.icon);
_icon_images.back()->setAlign(LV_ALIGN_CENTER);
}
icon_x += _icon_gap;
}
/* ------------------------------ LR indicators ----------------------------- */
// Scroll to nearby icon handler with wrap-around
int total_icons = appPorps.size();
auto scroll_to_nearby_icon = [&, total_icons](int direction) {
auto current_scroll_x = _panel->getScrollX();
int current_index = (current_scroll_x + _icon_gap / 2) / _icon_gap;
int target_index = current_index + direction;
// Wrap around at boundaries
if (target_index < 0) {
target_index = total_icons - 1;
} else if (target_index >= total_icons) {
target_index = 0;
}
int target_x = target_index * _icon_gap;
int scroll_distance = target_x - current_scroll_x;
_panel->scrollBy(-scroll_distance, 0, LV_ANIM_ON);
};
// Go left indicator
_lr_indicator_panels.push_back(std::make_unique<Container>(_panel->get()));
_lr_indicator_panels.back()->setAlign(LV_ALIGN_CENTER);
_lr_indicator_panels.back()->setSize(52, 160);
_lr_indicator_panels.back()->setPos(-134, 0);
_lr_indicator_panels.back()->setBorderWidth(0);
_lr_indicator_panels.back()->addFlag(LV_OBJ_FLAG_FLOATING);
_lr_indicator_panels.back()->removeFlag(LV_OBJ_FLAG_SCROLLABLE);
_lr_indicator_panels.back()->setBgOpa(0);
_lr_indicator_panels.back()->onClick().connect([scroll_to_nearby_icon]() { scroll_to_nearby_icon(-1); });
_lr_indicators_images.push_back(std::make_unique<Image>(_lr_indicator_panels.back()->get()));
_lr_indicators_images.back()->setSrc(&icon_indicator_left);
_lr_indicators_images.back()->align(LV_ALIGN_CENTER, 0, 0);
// Go right indicator
_lr_indicator_panels.push_back(std::make_unique<Container>(_panel->get()));
_lr_indicator_panels.back()->setAlign(LV_ALIGN_CENTER);
_lr_indicator_panels.back()->setSize(52, 160);
_lr_indicator_panels.back()->setPos(134, 0);
_lr_indicator_panels.back()->setBorderWidth(0);
_lr_indicator_panels.back()->addFlag(LV_OBJ_FLAG_FLOATING);
_lr_indicator_panels.back()->removeFlag(LV_OBJ_FLAG_SCROLLABLE);
_lr_indicator_panels.back()->setBgOpa(0);
_lr_indicator_panels.back()->onClick().connect([scroll_to_nearby_icon]() { scroll_to_nearby_icon(1); });
_lr_indicators_images.push_back(std::make_unique<Image>(_lr_indicator_panels.back()->get()));
_lr_indicators_images.back()->setSrc(&icon_indicator_right);
_lr_indicators_images.back()->align(LV_ALIGN_CENTER, 0, 0);
/* ---------------------------- Dynamic bg color ---------------------------- */
_dynamic_bg_color = std::make_unique<DynamicBgColor>();
std::vector<uint32_t> step_colors;
step_colors.resize(appPorps.size());
for (size_t i = 0; i < appPorps.size(); i++) {
uint32_t color = 0xDADADA;
if (appPorps[i].info.userData != nullptr) {
color = *(uint32_t*)appPorps[i].info.userData;
}
step_colors[i] = color;
}
_dynamic_bg_color->onBgColorChanged = [&](const uint32_t& bgColor) {
// mclog::tagInfo(_tag, "bg color changed to {:06X}", bgColor);
_panel->setBgColor(lv_color_hex(bgColor));
};
_dynamic_bg_color->init(step_colors, _icon_gap);
/* ------------------------------ Page indicator ---------------------------- */
_page_indicator = std::make_unique<PageIndicator>();
_page_indicator->init(appPorps.size(), _icon_gap, _panel->get(), 0, 103);
/* --------------------------- Dynamic icon label --------------------------- */
_dynamic_icon_label = std::make_unique<DynamicIconLabel>();
_dynamic_icon_label->init(icon_label_texts, _icon_gap, _panel->get());
/* ----------------------------- History restore ---------------------------- */
if (_last_clicked_icon_pos_x != -1) {
// mclog::tagInfo(_tag, "navigate to last clicked icon, pos x: {}", _last_clicked_icon_pos_x);
_panel->scrollBy(-_last_clicked_icon_pos_x, 0, LV_ANIM_OFF);
_dynamic_bg_color->jumpTo(_last_clicked_icon_pos_x / _icon_gap);
_page_indicator->jumpTo(_last_clicked_icon_pos_x / _icon_gap);
_dynamic_icon_label->jumpTo(_last_clicked_icon_pos_x / _icon_gap);
_last_clicked_icon_pos_x = -1;
_state = STATE_NORMAL;
}
// If first create
else {
// Setup startup animation
// x for pos_y, y for radius
_startup_anim = std::make_unique<AnimateVector2>();
_startup_anim->x.springOptions().damping = 12.0;
_startup_anim->y.delay = 0.15;
_startup_anim->y.springOptions().visualDuration = 0.4;
_startup_anim->y.springOptions().bounce = 0.05;
_startup_anim->teleport(240, 120);
_panel->setY(_startup_anim->directValue().x);
_panel->setRadius(_startup_anim->directValue().y);
_startup_anim->move(0, 0);
_state = STATE_STARTUP;
}
}
void LauncherView::update()
{
switch (_state) {
case STATE_STARTUP:
handle_state_startup();
break;
case STATE_NORMAL:
handle_state_normal();
break;
default:
break;
}
}
void LauncherView::handle_state_startup()
{
_startup_anim->update();
_panel->setY(_startup_anim->directValue().x);
_panel->setRadius(_startup_anim->directValue().y);
if (_startup_anim->done()) {
_startup_anim.reset();
_state = STATE_NORMAL;
}
}
void LauncherView::handle_state_normal()
{
if (_clicked_app_id != -1) {
if (onAppClicked) {
onAppClicked(_clicked_app_id);
}
_clicked_app_id = -1;
}
int scroll_x = _panel->getScrollX();
// mclog::tagInfo(_tag, "scroll x: {}", scroll_x);
_dynamic_bg_color->update(scroll_x);
_page_indicator->update(scroll_x);
_dynamic_icon_label->update(scroll_x);
}
@@ -0,0 +1,75 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <mooncake.h>
#include <smooth_ui_toolkit.hpp>
#include <uitk/short_namespace.hpp>
#include <games/dvd_screensaver/dvd_screensaver.hpp>
#include <smooth_lvgl.hpp>
#include <functional>
#include <vector>
#include <memory>
namespace view {
/**
* @brief
*
*/
class LauncherView {
public:
~LauncherView();
enum State_t {
STATE_STARTUP,
STATE_NORMAL,
};
std::function<void(int appID)> onAppClicked;
void init(std::vector<mooncake::AppProps_t> appPorps);
void update();
private:
std::unique_ptr<uitk::lvgl_cpp::Container> _panel;
std::vector<std::unique_ptr<uitk::lvgl_cpp::Container>> _icon_panels;
std::vector<std::unique_ptr<uitk::lvgl_cpp::Image>> _icon_images;
std::vector<std::unique_ptr<uitk::lvgl_cpp::Container>> _lr_indicator_panels;
std::vector<std::unique_ptr<uitk::lvgl_cpp::Image>> _lr_indicators_images;
std::unique_ptr<uitk::AnimateVector2> _startup_anim;
int _clicked_app_id = -1;
State_t _state = STATE_STARTUP;
void handle_state_startup();
void handle_state_normal();
};
/**
* @brief
*
*/
class Screensaver : public uitk::games::dvd_screensaver::DvdScreensaver {
public:
~Screensaver();
void onInit() override;
void onBuildLevel() override;
void onRender(float dt) override;
void onLogoCollide(int logoGroupId) override;
private:
std::unique_ptr<uitk::lvgl_cpp::ScreenActive> _prev_screen;
std::unique_ptr<uitk::lvgl_cpp::Screen> _screen;
std::unique_ptr<uitk::lvgl_cpp::Container> _logo;
std::unique_ptr<uitk::lvgl_cpp::Container> _left_eye;
std::unique_ptr<uitk::lvgl_cpp::Container> _right_eye;
std::unique_ptr<uitk::lvgl_cpp::Container> _mouth;
int _color_index = 0;
};
} // namespace view
+111
View File
@@ -0,0 +1,111 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "app_setup.h"
#include <hal/hal.h>
#include <mooncake.h>
#include <mooncake_log.h>
#include <assets/assets.h>
#include <stackchan/stackchan.h>
#include <apps/common/common.h>
using namespace mooncake;
using namespace view;
using namespace setup_workers;
AppSetup::AppSetup()
{
// 配置 App 名
setAppInfo().name = "SETUP";
// 配置 App 图标
setAppInfo().icon = (void*)&icon_setup;
// 配置 App 主题颜色
static uint32_t theme_color = 0xB3B3B3;
setAppInfo().userData = (void*)&theme_color;
}
void AppSetup::onCreate()
{
mclog::tagInfo(getAppInfo().name, "on create");
// open();
}
void AppSetup::onOpen()
{
mclog::tagInfo(getAppInfo().name, "on open");
LvglLockGuard lock;
_menu_sections = {{
"Connectivity",
{
// {"Set Up Wi-Fi",
// [&]() {
// _destroy_menu = true;
// _worker = std::make_unique<WifiSetupWorker>();
// }},
{"App Bind Code",
[&]() {
_destroy_menu = true;
_worker = std::make_unique<AppBindCodeWorker>();
}}},
},
{
"Servo",
{{"Zero Calibration",
[&]() {
_destroy_menu = true;
_worker = std::make_unique<ZeroCalibrationWorker>();
}},
{"LED Strips Test",
[&]() {
_destroy_menu = true;
_worker = std::make_unique<RgbTestWorker>();
}}},
},
{
"About",
{{fmt::format("FW Version: {}", common::FirmwareVersion), nullptr}},
},
{
"End",
{{"Quit", [&]() { close(); }}},
}};
_menu_page = std::make_unique<view::SelectMenuPage>(_menu_sections);
}
void AppSetup::onRunning()
{
LvglLockGuard lock;
if (_menu_page) {
_menu_page->update();
}
if (_destroy_menu) {
_menu_page.reset();
_destroy_menu = false;
}
if (_worker) {
_worker->update();
if (_worker->isDone()) {
_worker.reset();
_menu_page = std::make_unique<view::SelectMenuPage>(_menu_sections);
}
}
GetStackChan().update();
}
void AppSetup::onClose()
{
mclog::tagInfo(getAppInfo().name, "on close");
LvglLockGuard lock;
_menu_page.reset();
}
+32
View File
@@ -0,0 +1,32 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "view/view.h"
#include "workers/workers.h"
#include <mooncake.h>
#include <cstdint>
#include <memory>
/**
* @brief 派生 App
*
*/
class AppSetup : public mooncake::AppAbility {
public:
AppSetup();
// 重写生命周期回调
void onCreate() override;
void onOpen() override;
void onRunning() override;
void onClose() override;
private:
std::vector<view::SelectMenuPage::MenuSection> _menu_sections;
std::unique_ptr<view::SelectMenuPage> _menu_page;
std::unique_ptr<setup_workers::WorkerBase> _worker;
bool _destroy_menu = false;
};
@@ -0,0 +1,90 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "view.h"
using namespace view;
using namespace uitk::lvgl_cpp;
SelectMenuPage::SelectMenuPage(std::vector<MenuSection> sections) : _sections(std::move(sections))
{
_pannel = std::make_unique<uitk::lvgl_cpp::Container>(lv_screen_active());
_pannel->setSize(320, 240);
_pannel->setBgColor(lv_color_hex(0xffffff));
_pannel->setPadding(10, 24, 0, 0);
_pannel->setBorderWidth(0);
_pannel->setRadius(0);
_pannel->setScrollDir(LV_DIR_VER);
int cursor_y = 10;
for (int i = 0; i < _sections.size(); ++i) {
const auto& section = _sections[i];
create_selection_label(20, cursor_y, section.title);
cursor_y += 24 + 12;
for (int j = 0; j < section.items.size(); ++j) {
const auto& item = section.items[j];
create_item_button(cursor_y, item, i, j);
cursor_y += 48 + 12;
}
cursor_y += 8;
}
cursor_y += 20;
}
void SelectMenuPage::update()
{
if (_pending_section_index >= 0 && _pending_item_index >= 0) {
if (_pending_section_index < _sections.size()) {
auto& section = _sections[_pending_section_index];
if (_pending_item_index < section.items.size()) {
auto& item = section.items[_pending_item_index];
if (item.onClick) {
item.onClick();
}
}
}
_pending_section_index = -1;
_pending_item_index = -1;
}
}
void SelectMenuPage::create_selection_label(int x, int y, std::string_view text)
{
auto label = std::make_unique<uitk::lvgl_cpp::Label>(*_pannel);
label->setText(text);
label->setTextFont(&lv_font_montserrat_16);
label->setTextColor(lv_color_hex(0x6A6882));
label->setPos(x, y);
_labels.push_back(std::move(label));
}
void SelectMenuPage::create_item_button(int y, const MenuItem& item, int section_idx, int item_idx)
{
auto btn = std::make_unique<uitk::lvgl_cpp::Button>(*_pannel);
btn->setSize(282, 48);
btn->align(LV_ALIGN_TOP_MID, 0, y);
btn->setBgColor(lv_color_hex(0xB8D3FD));
btn->setBorderWidth(0);
btn->setShadowWidth(0);
btn->setRadius(12);
btn->label().setText(item.label);
btn->label().setTextFont(&lv_font_montserrat_24);
btn->label().setTextColor(lv_color_hex(0x26206A));
btn->label().align(LV_ALIGN_CENTER, 0, 0);
btn->label().setWidth(256);
btn->label().setTextAlign(LV_TEXT_ALIGN_CENTER);
btn->label().setLongMode(LV_LABEL_LONG_MODE_SCROLL_CIRCULAR);
if (item.onClick) {
btn->onClick().connect([this, section_idx, item_idx]() {
_pending_section_index = section_idx;
_pending_item_index = item_idx;
});
}
_buttons.push_back(std::move(btn));
}
+43
View File
@@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <smooth_lvgl.hpp>
#include <uitk/short_namespace.hpp>
#include <string_view>
#include <memory>
#include <vector>
namespace view {
class SelectMenuPage {
public:
struct MenuItem {
std::string label;
std::function<void()> onClick;
};
struct MenuSection {
std::string title;
std::vector<MenuItem> items;
};
SelectMenuPage(std::vector<MenuSection> sections);
void update();
private:
std::vector<MenuSection> _sections;
std::unique_ptr<uitk::lvgl_cpp::Container> _pannel;
std::vector<std::unique_ptr<uitk::lvgl_cpp::Label>> _labels;
std::vector<std::unique_ptr<uitk::lvgl_cpp::Button>> _buttons;
int _pending_section_index = -1;
int _pending_item_index = -1;
void create_selection_label(int x, int y, std::string_view text);
void create_item_button(int y, const MenuItem& item, int section_idx, int item_idx);
};
} // namespace view
@@ -0,0 +1,22 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <smooth_lvgl.hpp>
#include <uitk/short_namespace.hpp>
namespace setup_workers {
inline void apply_button_common_style(uitk::lvgl_cpp::Button& btn)
{
btn.setBgColor(lv_color_hex(0xB8D3FD));
btn.setBorderWidth(0);
btn.setShadowWidth(0);
btn.setRadius(18);
btn.label().setTextFont(&lv_font_montserrat_24);
btn.label().setTextColor(lv_color_hex(0x26206A));
}
} // namespace setup_workers
@@ -0,0 +1,273 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "workers.h"
#include <stackchan/stackchan.h>
#include <ArduinoJson.hpp>
#include <mooncake_log.h>
#include <hal/hal.h>
#include <memory>
using namespace smooth_ui_toolkit::lvgl_cpp;
using namespace setup_workers;
using namespace stackchan;
static std::string _tag = "Setup-Connectivity";
WifiSetupWorker::WifiSetupWorker()
{
_state = State::AppDownload;
_last_state = State::None;
_is_first_in = true;
// Create default avatar
auto avatar = std::make_unique<avatar::DefaultAvatar>();
avatar->init(lv_screen_active(), &lv_font_montserrat_24);
GetStackChan().attachAvatar(std::move(avatar));
_app_config_signal_id =
GetHAL().onAppConfigEvent.connect([this](AppConfigEvent event) { _last_app_config_event = event; });
GetHAL().startAppConfigServer();
}
WifiSetupWorker::~WifiSetupWorker()
{
GetHAL().onAppConfigEvent.disconnect(_app_config_signal_id);
GetStackChan().resetAvatar();
}
void WifiSetupWorker::update()
{
cleanup_ui();
update_state();
}
void WifiSetupWorker::update_state()
{
switch (_state) {
case State::AppDownload: {
if (_is_first_in) {
_is_first_in = false;
auto& avatar = GetStackChan().avatar();
avatar.leftEye().setVisible(false);
avatar.rightEye().setVisible(false);
avatar.mouth().setVisible(false);
avatar.setSpeech("Scan the QR code to download the \"StackChan\" app.");
auto& data = _state_app_download_data;
std::string qrcode_text = "todotodotodotodotodotodotodlotodotodotodoto";
data.qrcode = std::make_unique<Qrcode>(lv_screen_active());
data.qrcode->setSize(150);
data.qrcode->setDarkColor(lv_color_white());
data.qrcode->setLightColor(lv_color_black());
data.qrcode->update(qrcode_text);
data.qrcode->align(LV_ALIGN_CENTER, -60, -25);
data.btn = std::make_unique<Button>(lv_screen_active());
apply_button_common_style(*data.btn);
data.btn->align(LV_ALIGN_CENTER, 90, 0);
data.btn->setSize(100, 60);
data.btn->label().setText("Next");
data.btn->onClick().connect([this]() { _state_app_download_data.is_clicked = true; });
}
if (_state_app_download_data.is_clicked) {
switch_state(State::WaitAppConnection);
}
// Check events
if (_last_app_config_event != AppConfigEvent::None) {
if (_last_app_config_event == AppConfigEvent::AppConnected) {
switch_state(State::AppConnected);
}
_last_app_config_event = AppConfigEvent::None;
}
break;
}
case State::WaitAppConnection: {
if (_is_first_in) {
_is_first_in = false;
auto& avatar = GetStackChan().avatar();
avatar.leftEye().setVisible(false);
avatar.rightEye().setVisible(false);
avatar.mouth().setVisible(false);
avatar.setSpeech("Look for me in \"StackChan\" app to start the setup.");
avatar.addDecorator(std::make_unique<avatar::HeartDecorator>(lv_screen_active(), 3000));
auto& data = _state_wait_app_connection_data;
data.id_btn = std::make_unique<Button>(lv_screen_active());
apply_button_common_style(*data.id_btn);
data.id_btn->align(LV_ALIGN_CENTER, 0, 0);
data.id_btn->setSize(262, 52);
data.id_btn->onClick().connect([]() {
auto& avatar = GetStackChan().avatar();
avatar.clearDecorators();
avatar.addDecorator(std::make_unique<avatar::HeartDecorator>(lv_screen_active(), 3000));
});
data.id_btn->label().setText(fmt::format("ID: {}", GetHAL().getFactoryMacString()));
}
// Check events
if (_last_app_config_event != AppConfigEvent::None) {
if (_last_app_config_event == AppConfigEvent::AppConnected) {
switch_state(State::AppConnected);
}
_last_app_config_event = AppConfigEvent::None;
}
break;
}
case State::AppConnected: {
if (_is_first_in) {
_is_first_in = false;
auto& avatar = GetStackChan().avatar();
avatar.leftEye().setVisible(true);
avatar.rightEye().setVisible(true);
avatar.mouth().setVisible(true);
avatar.setSpeech("Ready to Configure ~");
GetStackChan().addModifier(std::make_unique<TimedEmotionModifier>(avatar::Emotion::Happy, 4000));
GetStackChan().addModifier(std::make_unique<BreathModifier>());
GetStackChan().addModifier(std::make_unique<BlinkModifier>());
GetStackChan().addModifier(std::make_unique<SpeakingModifier>(2000, 180, false));
}
// Check events
if (_last_app_config_event != AppConfigEvent::None) {
if (_last_app_config_event == AppConfigEvent::AppDisconnected) {
switch_state(State::WaitAppConnection);
} else if (_last_app_config_event == AppConfigEvent::TryWifiConnect) {
auto& avatar = GetStackChan().avatar();
avatar.setSpeech("Verifying...");
GetStackChan().addModifier(std::make_unique<SpeakingModifier>(2000, 180, false));
} else if (_last_app_config_event == AppConfigEvent::WifiConnectFailed) {
GetStackChan().addModifier(std::make_unique<TimedEmotionModifier>(avatar::Emotion::Sad, 4000));
GetStackChan().addModifier(
std::make_unique<TimedSpeechModifier>("Connect Failed. Try again?", 6000));
GetStackChan().addModifier(std::make_unique<SpeakingModifier>(3000, 180, false));
} else if (_last_app_config_event == AppConfigEvent::WifiConnected) {
switch_state(State::Done);
}
_last_app_config_event = AppConfigEvent::None;
}
break;
}
case State::Done: {
if (_is_first_in) {
_is_first_in = false;
auto& avatar = GetStackChan().avatar();
avatar.leftEye().setVisible(true);
avatar.rightEye().setVisible(true);
avatar.mouth().setVisible(true);
avatar.setEmotion(avatar::Emotion::Happy);
GetStackChan().addModifier(std::make_unique<SpeakingModifier>(1500, 180, false));
_state_done_data.reboot_count = 4;
}
if (GetHAL().millis() - _last_tick > 1000) {
_last_tick = GetHAL().millis();
if (_state_done_data.reboot_count > 0) {
_state_done_data.reboot_count--;
auto& avatar = GetStackChan().avatar();
avatar.setSpeech(fmt::format("Done! Reboot in {}s.", _state_done_data.reboot_count));
} else {
mclog::tagInfo(_tag, "rebooting...");
GetHAL().delay(100);
GetHAL().reboot();
}
}
break;
}
default:
break;
}
}
void WifiSetupWorker::cleanup_ui()
{
if (_last_state == State::None) {
return;
}
switch (_last_state) {
case State::AppDownload: {
_state_app_download_data.reset();
GetStackChan().avatar().setSpeech("");
break;
}
case State::WaitAppConnection: {
_state_wait_app_connection_data.reset();
GetStackChan().avatar().setSpeech("");
break;
}
case State::AppConnected: {
GetStackChan().avatar().setSpeech("");
GetStackChan().clearModifiers();
break;
}
case State::Done: {
break;
}
default:
break;
}
_last_state = State::None;
}
void WifiSetupWorker::switch_state(State newState)
{
_last_state = _state;
_state = newState;
_is_first_in = true;
}
AppBindCodeWorker::AppBindCodeWorker()
{
// Create default avatar
auto avatar = std::make_unique<avatar::DefaultAvatar>();
avatar->init(lv_screen_active(), &lv_font_montserrat_24);
avatar->leftEye().setVisible(false);
avatar->rightEye().setVisible(false);
avatar->mouth().setVisible(false);
avatar->setSpeech("Scan the QR code with the StackChan APP to bind.");
GetStackChan().attachAvatar(std::move(avatar));
std::string qrcode_text;
ArduinoJson::JsonDocument doc;
doc["mac"] = GetHAL().getFactoryMacString();
ArduinoJson::serializeJson(doc, qrcode_text);
mclog::tagInfo(_tag, "qr code text: {}", qrcode_text);
_qrcode = std::make_unique<Qrcode>(lv_screen_active());
_qrcode->setSize(150);
_qrcode->setDarkColor(lv_color_white());
_qrcode->setLightColor(lv_color_black());
_qrcode->update(qrcode_text);
_qrcode->align(LV_ALIGN_CENTER, -60, -25);
_btn_quit = std::make_unique<Button>(lv_screen_active());
apply_button_common_style(*_btn_quit);
_btn_quit->align(LV_ALIGN_CENTER, 90, 0);
_btn_quit->setSize(100, 60);
_btn_quit->label().setText("Back");
_btn_quit->onClick().connect([this]() { _is_done = true; });
}
AppBindCodeWorker::~AppBindCodeWorker()
{
GetStackChan().resetAvatar();
}
@@ -0,0 +1,127 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "workers.h"
#include <stackchan/stackchan.h>
#include <mooncake_log.h>
#include <hal/hal.h>
using namespace smooth_ui_toolkit::lvgl_cpp;
using namespace setup_workers;
static std::string _tag = "Setup-Servo";
ZeroCalibrationWorker::ZeroCalibrationWorker()
{
_pannel = std::make_unique<Container>(lv_screen_active());
_pannel->setBgColor(lv_color_hex(0xFFFFFF));
_pannel->removeFlag(LV_OBJ_FLAG_SCROLLABLE);
_pannel->align(LV_ALIGN_CENTER, 0, 0);
_pannel->setBorderWidth(0);
_pannel->setSize(320, 240);
_pannel->setRadius(0);
_btn_go_home = std::make_unique<Button>(lv_screen_active());
apply_button_common_style(*_btn_go_home);
_btn_go_home->setAlign(LV_ALIGN_CENTER);
_btn_go_home->setPos(0, -85);
_btn_go_home->setSize(230, 55);
_btn_go_home->label().setText("Move To Home");
_btn_go_home->onClick().connect([this]() { _go_home_flag = true; });
_btn_confirm = std::make_unique<Button>(lv_screen_active());
apply_button_common_style(*_btn_confirm);
_btn_confirm->setAlign(LV_ALIGN_CENTER);
_btn_confirm->setPos(0, 0);
_btn_confirm->setSize(290, 70);
_btn_confirm->label().setText("Set Current Position\nAs Home");
_btn_confirm->label().setTextAlign(LV_TEXT_ALIGN_CENTER);
_btn_confirm->onClick().connect([this]() { _confirm_flag = true; });
_btn_quit = std::make_unique<Button>(lv_screen_active());
apply_button_common_style(*_btn_quit);
_btn_quit->setAlign(LV_ALIGN_CENTER);
_btn_quit->setPos(0, 85);
_btn_quit->setSize(230, 55);
_btn_quit->label().setText("Done");
_btn_quit->onClick().connect([this]() { _is_done = true; });
auto& motion = GetStackChan().motion();
motion.setAutoAngleSyncEnabled(true);
}
void ZeroCalibrationWorker::update()
{
if (_confirm_flag) {
_confirm_flag = false;
mclog::tagInfo(_tag, "set current angle as zero");
auto& motion = GetStackChan().motion();
motion.yawServo().setCurrentAngleAsZero();
motion.pitchServo().setCurrentAngleAsZero();
}
if (_go_home_flag) {
_go_home_flag = false;
mclog::tagInfo(_tag, "go home");
auto& motion = GetStackChan().motion();
motion.goHome(300);
}
}
struct RgbColorEntry {
std::string name;
uint8_t r;
uint8_t g;
uint8_t b;
};
static const std::vector<RgbColorEntry> _rgb_colors = {
{"Red", 255, 0, 0}, {"Green", 0, 255, 0}, {"Blue", 0, 0, 255}, {"Yellow", 255, 255, 0},
{"Cyan", 0, 255, 255}, {"Magenta", 255, 0, 255}, {"White", 255, 255, 255}, {"Off", 0, 0, 0},
};
RgbTestWorker::RgbTestWorker()
{
_pannel = std::make_unique<Container>(lv_screen_active());
_pannel->setBgColor(lv_color_hex(0xFFFFFF));
_pannel->align(LV_ALIGN_CENTER, 0, 0);
_pannel->setBorderWidth(0);
_pannel->setSize(320, 240);
_pannel->setRadius(0);
_pannel->setFlexFlow(LV_FLEX_FLOW_COLUMN);
_pannel->setFlexAlign(LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
_pannel->setPadding(20, 20, 20, 20);
_pannel->setPadRow(15);
for (const auto& color : _rgb_colors) {
auto btn = std::make_unique<Button>(*_pannel);
apply_button_common_style(*btn);
btn->setSize(200, 50);
btn->label().setText(color.name);
uint8_t r = color.r;
uint8_t g = color.g;
uint8_t b = color.b;
btn->onClick().connect([r, g, b]() { GetHAL().showRgbColor(r, g, b); });
_buttons.push_back(std::move(btn));
}
auto btn_quit = std::make_unique<Button>(*_pannel);
apply_button_common_style(*btn_quit);
btn_quit->setSize(200, 50);
btn_quit->label().setText("Quit");
btn_quit->onClick().connect([this]() { _is_done = true; });
_buttons.push_back(std::move(btn_quit));
}
RgbTestWorker::~RgbTestWorker()
{
GetHAL().showRgbColor(0, 0, 0);
}
@@ -0,0 +1,141 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "common.h"
#include <smooth_lvgl.hpp>
#include <uitk/short_namespace.hpp>
#include <hal/hal.h>
#include <cstdint>
#include <memory>
namespace setup_workers {
/**
* @brief
*
*/
class WorkerBase {
public:
virtual ~WorkerBase() = default;
virtual void update()
{
}
bool isDone() const
{
return _is_done;
}
protected:
bool _is_done = false;
};
/**
* @brief
*
*/
class ZeroCalibrationWorker : public WorkerBase {
public:
ZeroCalibrationWorker();
void update() override;
private:
std::unique_ptr<uitk::lvgl_cpp::Container> _pannel;
std::unique_ptr<uitk::lvgl_cpp::Button> _btn_quit;
std::unique_ptr<uitk::lvgl_cpp::Button> _btn_confirm;
std::unique_ptr<uitk::lvgl_cpp::Button> _btn_go_home;
bool _confirm_flag = false;
bool _go_home_flag = false;
};
/**
* @brief
*
*/
class WifiSetupWorker : public WorkerBase {
public:
WifiSetupWorker();
~WifiSetupWorker();
void update() override;
private:
enum class State {
None,
AppDownload,
WaitAppConnection,
AppConnected,
Done,
};
State _state = State::AppDownload;
State _last_state = State::None;
uint32_t _last_tick = 0;
bool _is_first_in = false;
AppConfigEvent _last_app_config_event = AppConfigEvent::None;
int _app_config_signal_id = -1;
struct StateAppDownloadData {
std::unique_ptr<uitk::lvgl_cpp::Qrcode> qrcode;
std::unique_ptr<uitk::lvgl_cpp::Button> btn;
bool is_clicked = false;
void reset()
{
qrcode.reset();
btn.reset();
is_clicked = false;
}
};
StateAppDownloadData _state_app_download_data;
struct StateWaitAppConnectionData {
std::unique_ptr<uitk::lvgl_cpp::Button> id_btn;
void reset()
{
id_btn.reset();
}
};
StateWaitAppConnectionData _state_wait_app_connection_data;
struct StateDoneData {
int reboot_count = 0;
};
StateDoneData _state_done_data;
void update_state();
void cleanup_ui();
void switch_state(State newState);
};
/**
* @brief
*
*/
class AppBindCodeWorker : public WorkerBase {
public:
AppBindCodeWorker();
~AppBindCodeWorker();
private:
std::unique_ptr<uitk::lvgl_cpp::Qrcode> _qrcode;
std::unique_ptr<uitk::lvgl_cpp::Button> _btn_quit;
};
class RgbTestWorker : public WorkerBase {
public:
RgbTestWorker();
~RgbTestWorker();
private:
std::unique_ptr<uitk::lvgl_cpp::Container> _pannel;
std::vector<std::unique_ptr<uitk::lvgl_cpp::Button>> _buttons;
};
} // namespace setup_workers
@@ -0,0 +1,78 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "app_template.h"
#include <hal/hal.h>
#include <mooncake.h>
#include <mooncake_log.h>
#include <assets/assets.h>
#include <smooth_lvgl.hpp>
using namespace mooncake;
using namespace smooth_ui_toolkit::lvgl_cpp;
AppTemplate::AppTemplate()
{
// Configure App name
setAppInfo().name = "AppTemplate";
// Configure App icon
// setAppInfo().icon = (void*)&icon_app_dummy;
}
// Called when the App is installed
void AppTemplate::onCreate()
{
mclog::tagInfo(getAppInfo().name, "on create");
}
static std::unique_ptr<Button> _button_quit;
static uint32_t _time_count = 0;
// Called when the App is opened
// You can construct UI, initialize operations, etc. here
void AppTemplate::onOpen()
{
mclog::tagInfo(getAppInfo().name, "on open");
// Lock before Lvgl operations to avoid conflict with lvgl thread
// GetHAL().lvglLock(); to lock, GetHAL().lvglUnlock(); to unlock
// You can also use LvglLockGuard for automatic locking and unlocking
LvglLockGuard lock;
// Create a quit button
// Using lvgl cpp wrapper here
// Same as using c method directly, lv_button_create...
_button_quit = std::make_unique<Button>(lv_screen_active());
_button_quit->setAlign(LV_ALIGN_CENTER);
_button_quit->label().setText("QUIT");
_button_quit->onClick().connect([this]() {
// Call close() to close the App
close();
});
}
// Called repeatedly while the App is running
void AppTemplate::onRunning()
{
// mclog::tagInfo(getAppInfo().name, "on running");
// Print "hi" every 1 second
if (GetHAL().millis() - _time_count > 1000) {
mclog::tagInfo(getAppInfo().name, "hi");
_time_count = GetHAL().millis();
}
}
// Called when the App is closed
// You can destroy UI, release resources, etc. here
void AppTemplate::onClose()
{
mclog::tagInfo(getAppInfo().name, "on close");
LvglLockGuard lock;
// Destroy button
_button_quit.reset();
}
@@ -0,0 +1,22 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <mooncake.h>
/**
* @brief Derived App
*
*/
class AppTemplate : public mooncake::AppAbility {
public:
AppTemplate();
// Override lifecycle callbacks
void onCreate() override;
void onOpen() override;
void onRunning() override;
void onClose() override;
};
+11
View File
@@ -0,0 +1,11 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "app_launcher/app_launcher.h"
#include "app_ai_agent/app_ai_agent.h"
#include "app_avatar/app_avatar.h"
#include "app_setup/app_setup.h"
#include "app_espnow_ctrl/app_espnow_ctrl.h"
+13
View File
@@ -0,0 +1,13 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <string_view>
namespace common {
inline constexpr std::string_view FirmwareVersion = "V0.11";
}
+26
View File
@@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <lvgl.h>
#include <string_view>
LV_FONT_DECLARE(MontserratSemiBold26);
LV_IMG_DECLARE(icon_ai_agent);
LV_IMG_DECLARE(icon_controller);
LV_IMG_DECLARE(icon_indicator_left);
LV_IMG_DECLARE(icon_indicator_right);
LV_IMG_DECLARE(icon_sentinel);
LV_IMG_DECLARE(icon_setup);
LV_IMG_DECLARE(icon_uiflow);
LV_IMG_DECLARE(icon_calibrate);
LV_IMG_DECLARE(icon_remote);
extern const char ogg_camera_shutter_start[] asm("_binary_camera_shutter_ogg_start");
extern const char ogg_camera_shutter_end[] asm("_binary_camera_shutter_ogg_end");
static const std::string_view OGG_CAMERA_SHUTTER{
static_cast<const char*>(ogg_camera_shutter_start),
static_cast<size_t>(ogg_camera_shutter_end - ogg_camera_shutter_start)};
@@ -0,0 +1,717 @@
/*******************************************************************************
* Size: 26 px
* Bpp: 2
* Opts: --bpp 2 --size 26 --no-compress --stride 1 --align 1 --font Montserrat-SemiBold.ttf --symbols
*!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ --format lvgl -o
*MontserratSemiBold26.c
******************************************************************************/
#ifdef __has_include
#if __has_include("lvgl.h")
#ifndef LV_LVGL_H_INCLUDE_SIMPLE
#define LV_LVGL_H_INCLUDE_SIMPLE
#endif
#endif
#endif
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#ifndef MONTSERRATSEMIBOLD26
#define MONTSERRATSEMIBOLD26 1
#endif
#if MONTSERRATSEMIBOLD26
/*-----------------
* BITMAPS
*----------------*/
/*Store the image of the glyphs*/
static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
/* U+0020 " " */
/* U+0021 "!" */
0x7f, 0x8f, 0xd3, 0xf4, 0xfd, 0x3f, 0x4f, 0xd3, 0xf0, 0xfc, 0x3f, 0xf, 0xc2, 0xf0, 0xbc, 0x0, 0x0, 0x2, 0xf1, 0xfe,
0x7f, 0x8b, 0xc0,
/* U+0022 "\"" */
0xbd, 0x2f, 0x6f, 0x7, 0xc7, 0xc1, 0xf1, 0xf0, 0x7c, 0x7c, 0x1f, 0x1f, 0x7, 0xc7, 0xc1, 0xf0, 0x0, 0x0,
/* U+0023 "#" */
0x0, 0xf, 0x0, 0xbc, 0x0, 0x1, 0xf0, 0xb, 0x80, 0x0, 0x1f, 0x0, 0xf8, 0x0, 0x2, 0xf0, 0xf, 0x40, 0x2f, 0xff, 0xff,
0xff, 0xf2, 0xff, 0xff, 0xff, 0xff, 0x5, 0x7e, 0x56, 0xf5, 0x50, 0x3, 0xd0, 0x1f, 0x0, 0x0, 0x7c, 0x2, 0xf0, 0x0,
0x7, 0xc0, 0x2e, 0x0, 0x0, 0xbc, 0x2, 0xe0, 0x7, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xc1, 0x5f, 0x95,
0x7e, 0x54, 0x0, 0xf4, 0x3, 0xc0, 0x0, 0xf, 0x0, 0x7c, 0x0, 0x1, 0xf0, 0x7, 0xc0, 0x0, 0x1f, 0x0, 0xbc, 0x0,
/* U+0024 "$" */
0x0, 0x1, 0x80, 0x0, 0x0, 0x2, 0xd0, 0x0, 0x0, 0x2, 0xd0, 0x0, 0x0, 0x2, 0xd0, 0x0, 0x0, 0x6f, 0xfe, 0x40, 0x2,
0xff, 0xff, 0xf4, 0xf, 0xff, 0xff, 0xf4, 0x1f, 0xe2, 0xd0, 0xb0, 0x2f, 0xc2, 0xd0, 0x0, 0x2f, 0x82, 0xd0, 0x0, 0x2f,
0xd2, 0xd0, 0x0, 0xf, 0xff, 0xd0, 0x0, 0x3, 0xff, 0xfe, 0x0, 0x0, 0x6f, 0xff, 0xe0, 0x0, 0x3, 0xff, 0xfc, 0x0, 0x2,
0xd2, 0xfd, 0x0, 0x2, 0xd0, 0xfd, 0x4, 0x2, 0xd0, 0xfd, 0x1f, 0x42, 0xd2, 0xfc, 0x3f, 0xff, 0xff, 0xf8, 0xf, 0xff,
0xff, 0xe0, 0x0, 0xbf, 0xfe, 0x0, 0x0, 0x2, 0xd0, 0x0, 0x0, 0x2, 0xd0, 0x0, 0x0, 0x2, 0xd0, 0x0,
/* U+0025 "%" */
0x2, 0xfd, 0x0, 0x0, 0xf4, 0x0, 0xfe, 0xf4, 0x0, 0x3e, 0x0, 0x2e, 0x3, 0xc0, 0xb, 0xc0, 0x3, 0xc0, 0x2d, 0x1, 0xf4,
0x0, 0x3c, 0x2, 0xe0, 0x3e, 0x0, 0x3, 0xc0, 0x2e, 0xb, 0xc0, 0x0, 0x3d, 0x3, 0xd1, 0xf0, 0x0, 0x2, 0xf0, 0xbc, 0x3d,
0x0, 0x0, 0xf, 0xff, 0x4b, 0xc1, 0xf8, 0x0, 0x1f, 0x81, 0xf0, 0xff, 0xf4, 0x0, 0x0, 0x3d, 0x2f, 0xb, 0xc0, 0x0, 0xf,
0x83, 0xc0, 0x3d, 0x0, 0x2, 0xf0, 0x3c, 0x2, 0xd0, 0x0, 0x3d, 0x3, 0xc0, 0x2d, 0x0, 0xf, 0x80, 0x3c, 0x3, 0xd0, 0x2,
0xf0, 0x2, 0xe0, 0x7c, 0x0, 0x7d, 0x0, 0xf, 0xef, 0x40, 0xf, 0x80, 0x0, 0x2f, 0xd0,
/* U+0026 "&" */
0x0, 0x6f, 0xe4, 0x0, 0x0, 0xbf, 0xff, 0x80, 0x0, 0x7f, 0x57, 0xf0, 0x0, 0x2f, 0x40, 0x7d, 0x0, 0xb, 0xd0, 0x1f,
0x40, 0x1, 0xf8, 0x1f, 0xc0, 0x0, 0x3f, 0xaf, 0xd0, 0x0, 0x3, 0xff, 0xc0, 0x0, 0x2, 0xff, 0xc0, 0x0, 0x3, 0xff,
0xfc, 0x6, 0x43, 0xf8, 0x3f, 0xc3, 0xf2, 0xf8, 0x3, 0xfd, 0xfc, 0xfd, 0x0, 0x3f, 0xfd, 0x3f, 0x40, 0x2, 0xff, 0xb,
0xf0, 0x0, 0xbf, 0xd1, 0xff, 0xeb, 0xff, 0xfd, 0x1f, 0xff, 0xff, 0x2f, 0x40, 0x7f, 0xf9, 0x1, 0x80, 0x0, 0x0, 0x0,
0x0,
/* U+0027 "'" */
0xbd, 0xbc, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x0,
/* U+0028 "(" */
0x0, 0x50, 0xf, 0xc0, 0xbe, 0x3, 0xf0, 0x1f, 0xc0, 0xfd, 0x3, 0xf0, 0x1f, 0xc0, 0x7e, 0x2, 0xf8, 0xb, 0xd0, 0x3f,
0x40, 0xfd, 0x3, 0xf4, 0xf, 0xd0, 0x2f, 0x80, 0xbe, 0x1, 0xfc, 0x3, 0xf0, 0xf, 0xc0, 0x2f, 0x80, 0x7f, 0x0, 0xfc,
0x1, 0xf8, 0x3, 0xf0,
/* U+0029 ")" */
0x14, 0x0, 0xfc, 0x2, 0xf8, 0x3, 0xf0, 0xb, 0xe0, 0x1f, 0xc0, 0x3f, 0x0, 0xfd, 0x2, 0xf8, 0xb, 0xe0, 0x1f, 0x80,
0x7f, 0x1, 0xfc, 0x7, 0xf0, 0x1f, 0xc0, 0x7e, 0x2, 0xf8, 0xb, 0xd0, 0x3f, 0x40, 0xfc, 0x7, 0xe0, 0x3f, 0x40, 0xfc,
0xb, 0xe0, 0x3f, 0x0,
/* U+002A "*" */
0x0, 0xb4, 0x0, 0x2, 0xd0, 0x3, 0xcb, 0x5f, 0x1f, 0xff, 0xfc, 0xb, 0xff, 0x40, 0x1f, 0xfd, 0x7, 0xff, 0xff, 0xf,
0x2d, 0x7c, 0x0, 0xb4, 0x0, 0x2, 0xd0, 0x0,
/* U+002B "+" */
0x0, 0x2f, 0x0, 0x0, 0xb, 0xc0, 0x0, 0x2, 0xf0, 0x0, 0x0, 0xbc, 0x0, 0x2a, 0xbf, 0xaa, 0x5f, 0xff, 0xff, 0xe7, 0xff,
0xff, 0xf8, 0x0, 0xbc, 0x0, 0x0, 0x2f, 0x0, 0x0, 0xb, 0xc0, 0x0, 0x2, 0xf0, 0x0, 0x0, 0x68, 0x0,
/* U+002C "," */
0x0, 0x1f, 0x8f, 0xf3, 0xfc, 0x3f, 0xf, 0x83, 0xd1, 0xf0, 0xb8, 0x0,
/* U+002D "-" */
0x6a, 0xa9, 0xbf, 0xfe, 0xbf, 0xfe,
/* U+002E "." */
0x4, 0x1f, 0xcf, 0xf7, 0xfc, 0x3d, 0x0,
/* U+002F "/" */
0x0, 0x0, 0x29, 0x0, 0x0, 0xbd, 0x0, 0x0, 0xfc, 0x0, 0x1, 0xf8, 0x0, 0x2, 0xf4, 0x0, 0x3, 0xf0, 0x0, 0x7, 0xe0, 0x0,
0xb, 0xd0, 0x0, 0xf, 0xc0, 0x0, 0x1f, 0x80, 0x0, 0x2f, 0x0, 0x0, 0x3f, 0x0, 0x0, 0x7e, 0x0, 0x0, 0xfc, 0x0, 0x0,
0xfc, 0x0, 0x1, 0xf4, 0x0, 0x3, 0xf0, 0x0, 0x3, 0xf0, 0x0, 0xb, 0xd0, 0x0, 0xf, 0xc0, 0x0, 0xf, 0x80, 0x0, 0x2f,
0x40, 0x0, 0x3f, 0x0, 0x0, 0x7e, 0x0, 0x0, 0xbd, 0x0, 0x0,
/* U+0030 "0" */
0x0, 0x6f, 0xf8, 0x0, 0x2, 0xff, 0xff, 0x40, 0xf, 0xff, 0xff, 0xd0, 0x2f, 0xe0, 0x1f, 0xf0, 0x3f, 0x80, 0x3, 0xf8,
0x7f, 0x0, 0x2, 0xfc, 0xbf, 0x0, 0x1, 0xfc, 0xfe, 0x0, 0x0, 0xfd, 0xfe, 0x0, 0x0, 0xfd, 0xfe, 0x0, 0x0, 0xfd, 0xfe,
0x0, 0x0, 0xfd, 0xbf, 0x0, 0x1, 0xfc, 0x7f, 0x0, 0x2, 0xfc, 0x3f, 0x80, 0x3, 0xf8, 0x2f, 0xe0, 0x1f, 0xf0, 0xf,
0xff, 0xff, 0xd0, 0x2, 0xff, 0xff, 0x40, 0x0, 0x6f, 0xf4, 0x0,
/* U+0031 "1" */
0xff, 0xfd, 0xff, 0xfd, 0xbf, 0xfd, 0x0, 0xfd, 0x0, 0xfd, 0x0, 0xfd, 0x0, 0xfd, 0x0, 0xfd, 0x0, 0xfd, 0x0, 0xfd,
0x0, 0xfd, 0x0, 0xfd, 0x0, 0xfd, 0x0, 0xfd, 0x0, 0xfd, 0x0, 0xfd, 0x0, 0xfd, 0x0, 0xfd,
/* U+0032 "2" */
0x1, 0xbf, 0xe4, 0x0, 0x7f, 0xff, 0xfc, 0x7, 0xff, 0xff, 0xfc, 0xf, 0xd0, 0xb, 0xf4, 0x8, 0x0, 0xf, 0xe0, 0x0, 0x0,
0x3f, 0x80, 0x0, 0x0, 0xfd, 0x0, 0x0, 0x7, 0xf0, 0x0, 0x0, 0x7f, 0x80, 0x0, 0x7, 0xf8, 0x0, 0x0, 0x7f, 0x80, 0x0,
0x7, 0xf8, 0x0, 0x0, 0xbf, 0x80, 0x0, 0xb, 0xf8, 0x0, 0x0, 0xbf, 0x40, 0x0, 0xf, 0xff, 0xff, 0xfd, 0x3f, 0xff, 0xff,
0xf4, 0xff, 0xff, 0xff, 0xd0,
/* U+0033 "3" */
0x3f, 0xff, 0xff, 0xd0, 0xff, 0xff, 0xff, 0x43, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x1f, 0xc0, 0x0, 0x1, 0xfd, 0x0, 0x0,
0x1f, 0xd0, 0x0, 0x0, 0xfd, 0x0, 0x0, 0xf, 0xfe, 0x0, 0x0, 0x3f, 0xff, 0x40, 0x0, 0xab, 0xff, 0x40, 0x0, 0x1, 0xff,
0x0, 0x0, 0x2, 0xfc, 0x0, 0x0, 0x7, 0xf0, 0x40, 0x0, 0x2f, 0xc3, 0xe4, 0x2, 0xfe, 0x2f, 0xff, 0xff, 0xf0, 0x3f,
0xff, 0xff, 0x0, 0xb, 0xff, 0x90, 0x0,
/* U+0034 "4" */
0x0, 0x0, 0x2f, 0xc0, 0x0, 0x0, 0x7, 0xf4, 0x0, 0x0, 0x0, 0xfe, 0x0, 0x0, 0x0, 0x3f, 0xc0, 0x0, 0x0, 0xb, 0xf0, 0x0,
0x0, 0x1, 0xfd, 0x0, 0x0, 0x0, 0x3f, 0x40, 0x0, 0x0, 0xf, 0xe0, 0x2a, 0x0, 0x2, 0xfc, 0x3, 0xf0, 0x0, 0xbf, 0x0,
0x3f, 0x0, 0x1f, 0xd0, 0x3, 0xf0, 0x3, 0xff, 0xff, 0xff, 0xfd, 0x3f, 0xff, 0xff, 0xff, 0xd3, 0xff, 0xff, 0xff, 0xfd,
0x0, 0x0, 0x3, 0xf0, 0x0, 0x0, 0x0, 0x3f, 0x0, 0x0, 0x0, 0x3, 0xf0, 0x0, 0x0, 0x0, 0x3f, 0x0,
/* U+0035 "5" */
0x7, 0xff, 0xff, 0xd0, 0x2f, 0xff, 0xff, 0x40, 0xbf, 0xff, 0xfd, 0x2, 0xf4, 0x0, 0x0, 0xf, 0xd0, 0x0, 0x0, 0x3f,
0x0, 0x0, 0x0, 0xfc, 0x0, 0x0, 0x3, 0xff, 0xfe, 0x0, 0xf, 0xff, 0xff, 0x80, 0x3f, 0xff, 0xff, 0x80, 0x0, 0x1, 0xff,
0x0, 0x0, 0x1, 0xfd, 0x0, 0x0, 0x3, 0xf4, 0x0, 0x0, 0x1f, 0xc3, 0xe4, 0x1, 0xff, 0x1f, 0xff, 0xff, 0xf4, 0x2f, 0xff,
0xff, 0x40, 0x6, 0xff, 0xd0, 0x0,
/* U+0036 "6" */
0x0, 0x1b, 0xff, 0x40, 0x7, 0xff, 0xff, 0x80, 0x7f, 0xff, 0xfc, 0x7, 0xfd, 0x0, 0x10, 0x3f, 0xc0, 0x0, 0x1, 0xfc,
0x0, 0x0, 0xb, 0xf0, 0x6a, 0x40, 0x2f, 0xaf, 0xff, 0xd0, 0xff, 0xff, 0xff, 0xd3, 0xff, 0x80, 0x7f, 0xcf, 0xf8, 0x0,
0x3f, 0x6f, 0xc0, 0x0, 0xbe, 0x7f, 0x0, 0x2, 0xf8, 0xfd, 0x0, 0xf, 0xd2, 0xfd, 0x0, 0xbf, 0x3, 0xff, 0xaf, 0xf8,
0x3, 0xff, 0xff, 0x80, 0x1, 0xbf, 0xe0, 0x0,
/* U+0037 "7" */
0x7f, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xdf, 0xc0, 0x1, 0xfd, 0x7f, 0x0, 0xb, 0xf0, 0xfc,
0x0, 0x3f, 0x40, 0x0, 0x2, 0xfc, 0x0, 0x0, 0xf, 0xe0, 0x0, 0x0, 0xbf, 0x0, 0x0, 0x3, 0xf8, 0x0, 0x0, 0x1f, 0xc0,
0x0, 0x0, 0xfe, 0x0, 0x0, 0x7, 0xf4, 0x0, 0x0, 0x3f, 0xc0, 0x0, 0x0, 0xfd, 0x0, 0x0, 0xb, 0xf0, 0x0, 0x0, 0x3f,
0x40, 0x0, 0x2, 0xfc, 0x0, 0x0,
/* U+0038 "8" */
0x1, 0xbf, 0xf8, 0x0, 0x2f, 0xff, 0xfe, 0x2, 0xff, 0xab, 0xfe, 0xf, 0xe0, 0x2, 0xfc, 0x7f, 0x0, 0x3, 0xf0, 0xfc,
0x0, 0xf, 0xc3, 0xfd, 0x1, 0xff, 0x3, 0xff, 0xff, 0xf0, 0xb, 0xff, 0xff, 0x80, 0xff, 0x95, 0xbf, 0xcb, 0xf0, 0x0,
0x7f, 0xbf, 0x80, 0x0, 0xbf, 0xfd, 0x0, 0x2, 0xff, 0xf8, 0x0, 0xf, 0xfb, 0xf8, 0x0, 0xbf, 0x4f, 0xfe, 0xaf, 0xfc,
0xf, 0xff, 0xff, 0x80, 0x6, 0xff, 0xe4, 0x0,
/* U+0039 "9" */
0x0, 0xbf, 0xf4, 0x0, 0x7, 0xff, 0xff, 0x40, 0x1f, 0xfa, 0xbf, 0xd0, 0x3f, 0x80, 0xb, 0xf0, 0x7f, 0x0, 0x3, 0xf4,
0x7f, 0x0, 0x3, 0xfc, 0x7f, 0x0, 0x3, 0xfc, 0x3f, 0xd0, 0x1f, 0xfc, 0x1f, 0xff, 0xff, 0xfc, 0x7, 0xff, 0xfd, 0xfc,
0x0, 0x6a, 0x81, 0xfc, 0x0, 0x0, 0x2, 0xfc, 0x0, 0x0, 0x3, 0xf8, 0x0, 0x0, 0xb, 0xf0, 0x5, 0x0, 0x7f, 0xe0, 0xf,
0xff, 0xff, 0x80, 0x1f, 0xff, 0xfe, 0x0, 0x6, 0xff, 0xe0, 0x0,
/* U+003A ":" */
0x7e, 0x3f, 0xcf, 0xf5, 0xfc, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x7, 0xf3, 0xfd, 0xff, 0xf, 0x40,
/* U+003B ";" */
0x7e, 0x3f, 0xcf, 0xf5, 0xfc, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xe3, 0xfc, 0xff, 0xf, 0xc3, 0xe0, 0xf4, 0x7c,
0x2e, 0x0,
/* U+003C "<" */
0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xa0, 0x0, 0x7, 0xf8, 0x0, 0x6f, 0xfd, 0x2, 0xff, 0xf4, 0xf, 0xff, 0x80, 0x7, 0xf9,
0x0, 0x1, 0xff, 0x40, 0x0, 0x2f, 0xfe, 0x40, 0x0, 0x7f, 0xfe, 0x0, 0x0, 0xbf, 0xf8, 0x0, 0x1, 0xbe, 0x0, 0x0, 0x2,
0x80,
/* U+003D "=" */
0x7f, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xe2, 0xaa, 0xaa, 0xa4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xaa,
0xaa, 0xa5, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0x80,
/* U+003E ">" */
0x0, 0x0, 0x0, 0x1d, 0x0, 0x0, 0x7, 0xf8, 0x0, 0x0, 0xff, 0xf4, 0x0, 0x6, 0xff, 0xe4, 0x0, 0x7, 0xff, 0xd0, 0x0,
0xb, 0xf8, 0x0, 0x6, 0xfe, 0x0, 0x2f, 0xff, 0x41, 0xff, 0xf8, 0x3, 0xff, 0x90, 0x1, 0xfd, 0x0, 0x0, 0x64, 0x0, 0x0,
0x0,
/* U+003F "?" */
0x1, 0xbf, 0xe4, 0x1, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xc7, 0xf4, 0x2, 0xfd, 0x4, 0x0, 0xf, 0xe0, 0x0, 0x0,
0xfd, 0x0, 0x0, 0x1f, 0xc0, 0x0, 0x7, 0xf4, 0x0, 0x2, 0xfd, 0x0, 0x0, 0x7f, 0x40, 0x0, 0xf, 0xd0, 0x0, 0x0, 0xfc,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0x80, 0x0, 0x2, 0xfd, 0x0, 0x0, 0x2f, 0xd0, 0x0, 0x0, 0xf8, 0x0,
/* U+0040 "@" */
0x0, 0x0, 0x6f, 0xfe, 0x40, 0x0, 0x0, 0x2, 0xff, 0xff, 0xfe, 0x0, 0x0, 0xb, 0xfe, 0x40, 0x5b, 0xf8, 0x0, 0xb, 0xf0,
0x0, 0x0, 0x2f, 0x80, 0xb, 0xe0, 0x0, 0x0, 0x1, 0xf8, 0x7, 0xe0, 0xb, 0xfd, 0x3f, 0x1f, 0x43, 0xf0, 0x1f, 0xff,
0xef, 0xc2, 0xf0, 0xf4, 0x1f, 0xf5, 0xbf, 0xf0, 0x3c, 0xbc, 0xf, 0xe0, 0x3, 0xfc, 0xf, 0x6e, 0x3, 0xf0, 0x0, 0x3f,
0x2, 0xef, 0x81, 0xf8, 0x0, 0xf, 0xc0, 0x7b, 0xe0, 0x7d, 0x0, 0x3, 0xf0, 0x1f, 0xf8, 0x1f, 0x80, 0x0, 0xfc, 0xb,
0xae, 0x3, 0xf0, 0x0, 0x7f, 0x2, 0xe7, 0xc0, 0xfe, 0x0, 0x3f, 0xc0, 0xf0, 0xf4, 0xf, 0xf9, 0xbf, 0xfd, 0xfc, 0x3f,
0x1, 0xff, 0xff, 0x3f, 0xfc, 0x3, 0xe0, 0xb, 0xfd, 0x7, 0xf8, 0x0, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xf0, 0x0,
0x0, 0x0, 0x0, 0x0, 0xbf, 0xd4, 0x6, 0xf0, 0x0, 0x0, 0x2, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x6, 0xff, 0xe4, 0x0,
0x0,
/* U+0041 "A" */
0x0, 0x0, 0x3f, 0x80, 0x0, 0x0, 0x0, 0x2f, 0xf0, 0x0, 0x0, 0x0, 0xf, 0xfe, 0x0, 0x0, 0x0, 0xb, 0xff, 0xc0, 0x0, 0x0,
0x3, 0xf3, 0xf4, 0x0, 0x0, 0x1, 0xfc, 0x7f, 0x0, 0x0, 0x0, 0xfd, 0xf, 0xd0, 0x0, 0x0, 0x7f, 0x1, 0xfc, 0x0, 0x0,
0x3f, 0x40, 0x3f, 0x40, 0x0, 0x1f, 0xc0, 0xb, 0xe0, 0x0, 0xb, 0xe0, 0x0, 0xfc, 0x0, 0x3, 0xff, 0xff, 0xff, 0x80,
0x2, 0xff, 0xff, 0xff, 0xf0, 0x0, 0xfe, 0xaa, 0xaa, 0xfe, 0x0, 0xbf, 0x0, 0x0, 0x1f, 0xc0, 0x3f, 0x40, 0x0, 0x3,
0xf4, 0x1f, 0xc0, 0x0, 0x0, 0xbf, 0xf, 0xe0, 0x0, 0x0, 0xf, 0xd0,
/* U+0042 "B" */
0xbf, 0xff, 0xff, 0x40, 0x2f, 0xff, 0xff, 0xfd, 0xb, 0xfa, 0xaa, 0xff, 0xc2, 0xfc, 0x0, 0x7, 0xf8, 0xbf, 0x0, 0x0,
0xfe, 0x2f, 0xc0, 0x0, 0x3f, 0x8b, 0xf0, 0x0, 0x1f, 0xc2, 0xfe, 0xaa, 0xbf, 0xd0, 0xbf, 0xff, 0xff, 0xf0, 0x2f,
0xff, 0xff, 0xff, 0x4b, 0xf0, 0x0, 0x1f, 0xf2, 0xfc, 0x0, 0x0, 0xfd, 0xbf, 0x0, 0x0, 0x3f, 0xaf, 0xc0, 0x0, 0xf,
0xeb, 0xf0, 0x0, 0xb, 0xf6, 0xfe, 0xaa, 0xaf, 0xfc, 0xbf, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xe4, 0x0,
/* U+0043 "C" */
0x0, 0x7, 0xff, 0x90, 0x0, 0xb, 0xff, 0xff, 0xd0, 0x3, 0xff, 0xff, 0xff, 0x80, 0xff, 0xd0, 0x7, 0xf8, 0x2f, 0xe0,
0x0, 0x9, 0x3, 0xf8, 0x0, 0x0, 0x0, 0xbf, 0x0, 0x0, 0x0, 0xb, 0xe0, 0x0, 0x0, 0x0, 0xfe, 0x0, 0x0, 0x0, 0xf, 0xe0,
0x0, 0x0, 0x0, 0xbe, 0x0, 0x0, 0x0, 0xb, 0xf0, 0x0, 0x0, 0x0, 0x3f, 0x80, 0x0, 0x0, 0x2, 0xfe, 0x0, 0x0, 0x90, 0xf,
0xfd, 0x0, 0x7f, 0x80, 0x3f, 0xff, 0xff, 0xf8, 0x0, 0xbf, 0xff, 0xfd, 0x0, 0x0, 0x7f, 0xf9, 0x0,
/* U+0044 "D" */
0xbf, 0xff, 0xfe, 0x40, 0x2, 0xff, 0xff, 0xff, 0xd0, 0xb, 0xff, 0xff, 0xff, 0xe0, 0x2f, 0xc0, 0x0, 0xbf, 0xe0, 0xbf,
0x0, 0x0, 0x3f, 0xc2, 0xfc, 0x0, 0x0, 0x3f, 0x8b, 0xf0, 0x0, 0x0, 0xbf, 0x2f, 0xc0, 0x0, 0x0, 0xfc, 0xbf, 0x0, 0x0,
0x3, 0xf6, 0xfc, 0x0, 0x0, 0xf, 0xdb, 0xf0, 0x0, 0x0, 0x3f, 0x2f, 0xc0, 0x0, 0x2, 0xfc, 0xbf, 0x0, 0x0, 0xf, 0xe2,
0xfc, 0x0, 0x0, 0xff, 0xb, 0xf0, 0x0, 0x2f, 0xf8, 0x2f, 0xff, 0xff, 0xff, 0x80, 0xbf, 0xff, 0xff, 0xf4, 0x2, 0xff,
0xff, 0xf9, 0x0, 0x0,
/* U+0045 "E" */
0xbf, 0xff, 0xff, 0xe2, 0xff, 0xff, 0xff, 0x8b, 0xff, 0xff, 0xfe, 0x2f, 0xc0, 0x0, 0x0, 0xbf, 0x0, 0x0, 0x2, 0xfc,
0x0, 0x0, 0xb, 0xf0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xd0, 0xbf, 0xff, 0xff, 0x82, 0xff, 0xff, 0xfe, 0xb, 0xf0, 0x0,
0x0, 0x2f, 0xc0, 0x0, 0x0, 0xbf, 0x0, 0x0, 0x2, 0xfc, 0x0, 0x0, 0xb, 0xf0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xfc, 0xbf,
0xff, 0xff, 0xf2, 0xff, 0xff, 0xff, 0xc0,
/* U+0046 "F" */
0xbf, 0xff, 0xff, 0xeb, 0xff, 0xff, 0xfe, 0xbf, 0xff, 0xff, 0xeb, 0xf0, 0x0, 0x0, 0xbf, 0x0, 0x0, 0xb, 0xf0, 0x0,
0x0, 0xbf, 0x0, 0x0, 0xb, 0xf0, 0x0, 0x0, 0xbf, 0xff, 0xff, 0x8b, 0xff, 0xff, 0xf8, 0xbf, 0xff, 0xff, 0x8b, 0xf0,
0x0, 0x0, 0xbf, 0x0, 0x0, 0xb, 0xf0, 0x0, 0x0, 0xbf, 0x0, 0x0, 0xb, 0xf0, 0x0, 0x0, 0xbf, 0x0, 0x0, 0xb, 0xf0, 0x0,
0x0,
/* U+0047 "G" */
0x0, 0x6, 0xff, 0x90, 0x0, 0xb, 0xff, 0xff, 0xe0, 0x3, 0xff, 0xff, 0xff, 0xc0, 0xff, 0xd0, 0x6, 0xf8, 0x2f, 0xe0,
0x0, 0x6, 0x3, 0xf8, 0x0, 0x0, 0x0, 0xbf, 0x0, 0x0, 0x0, 0xb, 0xe0, 0x0, 0x0, 0x0, 0xfe, 0x0, 0x0, 0x0, 0xf, 0xe0,
0x0, 0x0, 0xfc, 0xbe, 0x0, 0x0, 0xf, 0xcb, 0xf0, 0x0, 0x0, 0xfc, 0x3f, 0x80, 0x0, 0xf, 0xc2, 0xfe, 0x0, 0x0, 0xfc,
0xf, 0xfd, 0x0, 0x6f, 0xc0, 0x3f, 0xff, 0xff, 0xfc, 0x0, 0xbf, 0xff, 0xfe, 0x0, 0x0, 0x7f, 0xf9, 0x0,
/* U+0048 "H" */
0xbf, 0x0, 0x0, 0x3f, 0xaf, 0xc0, 0x0, 0xf, 0xeb, 0xf0, 0x0, 0x3, 0xfa, 0xfc, 0x0, 0x0, 0xfe, 0xbf, 0x0, 0x0, 0x3f,
0xaf, 0xc0, 0x0, 0xf, 0xeb, 0xf0, 0x0, 0x3, 0xfa, 0xff, 0xff, 0xff, 0xfe, 0xbf, 0xff, 0xff, 0xff, 0xaf, 0xff, 0xff,
0xff, 0xeb, 0xf0, 0x0, 0x3, 0xfa, 0xfc, 0x0, 0x0, 0xfe, 0xbf, 0x0, 0x0, 0x3f, 0xaf, 0xc0, 0x0, 0xf, 0xeb, 0xf0, 0x0,
0x3, 0xfa, 0xfc, 0x0, 0x0, 0xfe, 0xbf, 0x0, 0x0, 0x3f, 0xaf, 0xc0, 0x0, 0xf, 0xe0,
/* U+0049 "I" */
0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
/* U+004A "J" */
0x7, 0xff, 0xff, 0x41, 0xff, 0xff, 0xd0, 0x7f, 0xff, 0xf4, 0x0, 0x0, 0xfd, 0x0, 0x0, 0x3f, 0x40, 0x0, 0xf, 0xd0,
0x0, 0x3, 0xf4, 0x0, 0x0, 0xfd, 0x0, 0x0, 0x3f, 0x40, 0x0, 0xf, 0xd0, 0x0, 0x3, 0xf4, 0x0, 0x0, 0xfd, 0x0, 0x0,
0x3f, 0x42, 0x0, 0xf, 0xd2, 0xf0, 0xf, 0xf0, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xf8, 0x0, 0x7f, 0xe4, 0x0,
/* U+004B "K" */
0xbf, 0x0, 0x0, 0xbf, 0xb, 0xf0, 0x0, 0x2f, 0xc0, 0xbf, 0x0, 0xb, 0xf4, 0xb, 0xf0, 0x2, 0xfd, 0x0, 0xbf, 0x0, 0xbf,
0x40, 0xb, 0xf0, 0x2f, 0xd0, 0x0, 0xbf, 0xb, 0xf4, 0x0, 0xb, 0xf1, 0xfd, 0x0, 0x0, 0xbf, 0x7f, 0xd0, 0x0, 0xb, 0xff,
0xff, 0x0, 0x0, 0xbf, 0xfb, 0xfc, 0x0, 0xb, 0xfe, 0x1f, 0xf0, 0x0, 0xbf, 0x80, 0xbf, 0x80, 0xb, 0xf0, 0x2, 0xfd,
0x0, 0xbf, 0x0, 0xf, 0xf0, 0xb, 0xf0, 0x0, 0x3f, 0xc0, 0xbf, 0x0, 0x0, 0xff, 0xb, 0xf0, 0x0, 0x7, 0xf8,
/* U+004C "L" */
0xbf, 0x0, 0x0, 0xb, 0xf0, 0x0, 0x0, 0xbf, 0x0, 0x0, 0xb, 0xf0, 0x0, 0x0, 0xbf, 0x0, 0x0, 0xb, 0xf0, 0x0, 0x0, 0xbf,
0x0, 0x0, 0xb, 0xf0, 0x0, 0x0, 0xbf, 0x0, 0x0, 0xb, 0xf0, 0x0, 0x0, 0xbf, 0x0, 0x0, 0xb, 0xf0, 0x0, 0x0, 0xbf, 0x0,
0x0, 0xb, 0xf0, 0x0, 0x0, 0xbf, 0x0, 0x0, 0xb, 0xff, 0xff, 0xfd, 0xbf, 0xff, 0xff, 0xdb, 0xff, 0xff, 0xfd,
/* U+004D "M" */
0xbe, 0x0, 0x0, 0x0, 0x3f, 0x6f, 0xc0, 0x0, 0x0, 0x1f, 0xdb, 0xf8, 0x0, 0x0, 0xf, 0xf6, 0xff, 0x40, 0x0, 0xb, 0xfd,
0xbf, 0xf0, 0x0, 0x3, 0xff, 0x6f, 0xfe, 0x0, 0x2, 0xff, 0xdb, 0xff, 0xc0, 0x1, 0xff, 0xf6, 0xfa, 0xfc, 0x0, 0xfc,
0xfd, 0xbe, 0x3f, 0x40, 0xbe, 0x3f, 0x6f, 0x87, 0xf0, 0x3f, 0xf, 0xdb, 0xe0, 0xbe, 0x2f, 0x43, 0xf6, 0xf8, 0xf,
0xef, 0xc0, 0xfd, 0xbe, 0x1, 0xff, 0xc0, 0x3f, 0x6f, 0x80, 0x3f, 0xe0, 0xf, 0xdb, 0xe0, 0x3, 0xf0, 0x3, 0xf6, 0xf8,
0x0, 0xb4, 0x0, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x3f, 0x6f, 0x80, 0x0, 0x0, 0xf, 0xd0,
/* U+004E "N" */
0xbe, 0x0, 0x0, 0x2f, 0xaf, 0xd0, 0x0, 0xb, 0xeb, 0xfd, 0x0, 0x2, 0xfa, 0xff, 0xc0, 0x0, 0xbe, 0xbf, 0xfc, 0x0,
0x2f, 0xaf, 0xff, 0x80, 0xb, 0xeb, 0xfb, 0xf8, 0x2, 0xfa, 0xfc, 0xbf, 0x40, 0xbe, 0xbf, 0xf, 0xf0, 0x2f, 0xaf, 0xc0,
0xff, 0xb, 0xeb, 0xf0, 0x1f, 0xf2, 0xfa, 0xfc, 0x1, 0xfe, 0xbe, 0xbf, 0x0, 0x2f, 0xff, 0xaf, 0xc0, 0x3, 0xff, 0xeb,
0xf0, 0x0, 0x3f, 0xfa, 0xfc, 0x0, 0x3, 0xfe, 0xbf, 0x0, 0x0, 0x7f, 0xaf, 0xc0, 0x0, 0xb, 0xe0,
/* U+004F "O" */
0x0, 0x6, 0xff, 0x90, 0x0, 0x0, 0xbf, 0xff, 0xfe, 0x0, 0x3, 0xff, 0xff, 0xff, 0xc0, 0xf, 0xfd, 0x0, 0x7f, 0xf0,
0x2f, 0xe0, 0x0, 0xb, 0xf8, 0x3f, 0x80, 0x0, 0x3, 0xfc, 0xbf, 0x0, 0x0, 0x0, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0xfe, 0xfe,
0x0, 0x0, 0x0, 0xbe, 0xfe, 0x0, 0x0, 0x0, 0xbe, 0xbe, 0x0, 0x0, 0x0, 0xfe, 0xbf, 0x0, 0x0, 0x0, 0xfd, 0x3f, 0x80,
0x0, 0x3, 0xfc, 0x2f, 0xe0, 0x0, 0xb, 0xf8, 0xf, 0xfd, 0x0, 0x7f, 0xf0, 0x3, 0xff, 0xff, 0xff, 0xc0, 0x0, 0xbf,
0xff, 0xfe, 0x0, 0x0, 0x6, 0xff, 0x90, 0x0,
/* U+0050 "P" */
0xbf, 0xff, 0xf9, 0x0, 0xbf, 0xff, 0xff, 0xd0, 0xbf, 0xff, 0xff, 0xf4, 0xbf, 0x0, 0x7, 0xfc, 0xbf, 0x0, 0x0, 0xfd,
0xbf, 0x0, 0x0, 0xfe, 0xbf, 0x0, 0x0, 0xbe, 0xbf, 0x0, 0x0, 0xfe, 0xbf, 0x0, 0x1, 0xfd, 0xbf, 0x0, 0xb, 0xfc, 0xbf,
0xff, 0xff, 0xf4, 0xbf, 0xff, 0xff, 0xc0, 0xbf, 0xff, 0xe9, 0x0, 0xbf, 0x0, 0x0, 0x0, 0xbf, 0x0, 0x0, 0x0, 0xbf,
0x0, 0x0, 0x0, 0xbf, 0x0, 0x0, 0x0, 0xbf, 0x0, 0x0, 0x0,
/* U+0051 "Q" */
0x0, 0x6, 0xff, 0x90, 0x0, 0x0, 0x2f, 0xff, 0xff, 0x80, 0x0, 0x3f, 0xff, 0xff, 0xfc, 0x0, 0x3f, 0xf4, 0x1, 0xff,
0xc0, 0x2f, 0xe0, 0x0, 0xb, 0xf8, 0xf, 0xe0, 0x0, 0x0, 0xff, 0xb, 0xf0, 0x0, 0x0, 0xf, 0xd2, 0xf8, 0x0, 0x0, 0x3,
0xf8, 0xfe, 0x0, 0x0, 0x0, 0xbe, 0x3f, 0x80, 0x0, 0x0, 0x2f, 0x8b, 0xe0, 0x0, 0x0, 0xf, 0xe2, 0xfc, 0x0, 0x0, 0x3,
0xf4, 0x3f, 0x80, 0x0, 0x3, 0xfc, 0xb, 0xf8, 0x0, 0x2, 0xfe, 0x0, 0xff, 0xd0, 0x7, 0xff, 0x0, 0xf, 0xff, 0xff, 0xff,
0x0, 0x0, 0xbf, 0xff, 0xfe, 0x0, 0x0, 0x1, 0xbf, 0xf8, 0x0, 0x0, 0x0, 0x2, 0xff, 0x41, 0xf0, 0x0, 0x0, 0x1f, 0xff,
0xfd, 0x0, 0x0, 0x0, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x1, 0xa4, 0x0,
/* U+0052 "R" */
0xbf, 0xff, 0xf9, 0x0, 0xbf, 0xff, 0xff, 0xd0, 0xbf, 0xff, 0xff, 0xf4, 0xbf, 0x0, 0x7, 0xfc, 0xbf, 0x0, 0x0, 0xfd,
0xbf, 0x0, 0x0, 0xfe, 0xbf, 0x0, 0x0, 0xbe, 0xbf, 0x0, 0x0, 0xfe, 0xbf, 0x0, 0x1, 0xfd, 0xbf, 0x0, 0xb, 0xfc, 0xbf,
0xff, 0xff, 0xf0, 0xbf, 0xff, 0xff, 0xc0, 0xbf, 0xff, 0xff, 0x0, 0xbf, 0x0, 0x3f, 0xc0, 0xbf, 0x0, 0xf, 0xe0, 0xbf,
0x0, 0x7, 0xf0, 0xbf, 0x0, 0x2, 0xfc, 0xbf, 0x0, 0x0, 0xfe,
/* U+0053 "S" */
0x0, 0x6f, 0xfe, 0x40, 0x2, 0xff, 0xff, 0xf4, 0xf, 0xff, 0xff, 0xf4, 0x1f, 0xe0, 0x0, 0xb0, 0x2f, 0xc0, 0x0, 0x0,
0x2f, 0x80, 0x0, 0x0, 0x2f, 0xd0, 0x0, 0x0, 0xf, 0xfe, 0x40, 0x0, 0x3, 0xff, 0xfe, 0x0, 0x0, 0x6f, 0xff, 0xe0, 0x0,
0x1, 0xbf, 0xfc, 0x0, 0x0, 0x2, 0xfd, 0x0, 0x0, 0x0, 0xfd, 0x4, 0x0, 0x0, 0xfd, 0x1f, 0x40, 0x2, 0xfc, 0x3f, 0xff,
0xff, 0xf8, 0xf, 0xff, 0xff, 0xe0, 0x0, 0xbf, 0xfe, 0x0,
/* U+0054 "T" */
0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0x0, 0xf, 0xe0, 0x0, 0x0, 0xf, 0xe0, 0x0,
0x0, 0xf, 0xe0, 0x0, 0x0, 0xf, 0xe0, 0x0, 0x0, 0xf, 0xe0, 0x0, 0x0, 0xf, 0xe0, 0x0, 0x0, 0xf, 0xe0, 0x0, 0x0, 0xf,
0xe0, 0x0, 0x0, 0xf, 0xe0, 0x0, 0x0, 0xf, 0xe0, 0x0, 0x0, 0xf, 0xe0, 0x0, 0x0, 0xf, 0xe0, 0x0, 0x0, 0xf, 0xe0, 0x0,
0x0, 0xf, 0xe0, 0x0, 0x0, 0xf, 0xe0, 0x0,
/* U+0055 "U" */
0xbe, 0x0, 0x0, 0x3f, 0x2f, 0x80, 0x0, 0xf, 0xcb, 0xe0, 0x0, 0x3, 0xf2, 0xf8, 0x0, 0x0, 0xfc, 0xbe, 0x0, 0x0, 0x3f,
0x2f, 0x80, 0x0, 0xf, 0xcb, 0xe0, 0x0, 0x3, 0xf2, 0xf8, 0x0, 0x0, 0xfc, 0xbe, 0x0, 0x0, 0x3f, 0x2f, 0x80, 0x0, 0xf,
0xcb, 0xe0, 0x0, 0x3, 0xf2, 0xfc, 0x0, 0x1, 0xfc, 0x7f, 0x0, 0x0, 0xbf, 0xf, 0xe0, 0x0, 0x3f, 0x82, 0xfe, 0x0, 0x7f,
0xc0, 0x3f, 0xff, 0xff, 0xd0, 0x3, 0xff, 0xff, 0xd0, 0x0, 0x1b, 0xff, 0x80, 0x0,
/* U+0056 "V" */
0x3f, 0x80, 0x0, 0x0, 0xbf, 0x7, 0xf0, 0x0, 0x0, 0x3f, 0x40, 0xfe, 0x0, 0x0, 0x1f, 0xc0, 0x2f, 0xc0, 0x0, 0xf, 0xe0,
0x3, 0xf4, 0x0, 0x7, 0xf0, 0x0, 0xbf, 0x0, 0x2, 0xf8, 0x0, 0x1f, 0xd0, 0x0, 0xfc, 0x0, 0x3, 0xfc, 0x0, 0xbf, 0x0,
0x0, 0x7f, 0x0, 0x3f, 0x40, 0x0, 0xf, 0xe0, 0x1f, 0xc0, 0x0, 0x1, 0xfc, 0xf, 0xd0, 0x0, 0x0, 0x3f, 0x87, 0xf0, 0x0,
0x0, 0xb, 0xf3, 0xf8, 0x0, 0x0, 0x0, 0xfe, 0xfc, 0x0, 0x0, 0x0, 0x2f, 0xfe, 0x0, 0x0, 0x0, 0x7, 0xff, 0x40, 0x0,
0x0, 0x0, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x1f, 0xd0, 0x0, 0x0,
/* U+0057 "W" */
0x3f, 0x40, 0x0, 0x2f, 0x80, 0x0, 0x1f, 0xc3, 0xf8, 0x0, 0x3, 0xfc, 0x0, 0x2, 0xf8, 0x1f, 0xc0, 0x0, 0x7f, 0xd0,
0x0, 0x3f, 0x0, 0xfd, 0x0, 0xf, 0xfe, 0x0, 0x7, 0xf0, 0xf, 0xe0, 0x0, 0xff, 0xf0, 0x0, 0xbe, 0x0, 0x7f, 0x0, 0x1f,
0xbf, 0x40, 0xf, 0xc0, 0x3, 0xf4, 0x3, 0xf5, 0xf8, 0x1, 0xfc, 0x0, 0x3f, 0x80, 0x3f, 0xf, 0xc0, 0x2f, 0x80, 0x1,
0xfc, 0x7, 0xe0, 0xfd, 0x3, 0xf0, 0x0, 0xf, 0xd0, 0xfd, 0x7, 0xe0, 0x7f, 0x0, 0x0, 0xfe, 0xf, 0xc0, 0x3f, 0xb, 0xe0,
0x0, 0x7, 0xf2, 0xf8, 0x3, 0xf4, 0xfc, 0x0, 0x0, 0x3f, 0x7f, 0x0, 0x1f, 0x9f, 0xc0, 0x0, 0x3, 0xff, 0xf0, 0x0, 0xff,
0xf8, 0x0, 0x0, 0x1f, 0xfe, 0x0, 0xf, 0xff, 0x0, 0x0, 0x0, 0xff, 0xc0, 0x0, 0x7f, 0xf0, 0x0, 0x0, 0xf, 0xfc, 0x0,
0x3, 0xfe, 0x0, 0x0, 0x0, 0x7f, 0x80, 0x0, 0x3f, 0xc0, 0x0,
/* U+0058 "X" */
0x3f, 0xc0, 0x0, 0x2f, 0xc1, 0xfe, 0x0, 0x7, 0xf4, 0xb, 0xf4, 0x0, 0xfe, 0x0, 0x3f, 0xc0, 0x3f, 0xc0, 0x0, 0xfe,
0xb, 0xf0, 0x0, 0x7, 0xf5, 0xfd, 0x0, 0x0, 0x2f, 0xff, 0x80, 0x0, 0x0, 0xff, 0xf0, 0x0, 0x0, 0x7, 0xfc, 0x0, 0x0,
0x0, 0xbf, 0xe0, 0x0, 0x0, 0x1f, 0xff, 0x40, 0x0, 0x3, 0xfb, 0xfc, 0x0, 0x0, 0xbf, 0xf, 0xf0, 0x0, 0x1f, 0xd0, 0x7f,
0x80, 0x3, 0xf8, 0x2, 0xfd, 0x0, 0xff, 0x0, 0xf, 0xf0, 0x2f, 0xc0, 0x0, 0x3f, 0x87, 0xf4, 0x0, 0x1, 0xfd,
/* U+0059 "Y" */
0x3f, 0x80, 0x0, 0x3, 0xf0, 0x7f, 0x40, 0x0, 0x3f, 0x80, 0xbf, 0x0, 0x1, 0xfc, 0x0, 0xfe, 0x0, 0xf, 0xd0, 0x1, 0xfc,
0x0, 0xbe, 0x0, 0x3, 0xf8, 0x7, 0xf0, 0x0, 0x7, 0xf4, 0x3f, 0x40, 0x0, 0xb, 0xf2, 0xfc, 0x0, 0x0, 0xf, 0xef, 0xc0,
0x0, 0x0, 0x1f, 0xfe, 0x0, 0x0, 0x0, 0x3f, 0xf0, 0x0, 0x0, 0x0, 0x7f, 0x40, 0x0, 0x0, 0x0, 0xfd, 0x0, 0x0, 0x0, 0x3,
0xf4, 0x0, 0x0, 0x0, 0xf, 0xd0, 0x0, 0x0, 0x0, 0x3f, 0x40, 0x0, 0x0, 0x0, 0xfd, 0x0, 0x0, 0x0, 0x3, 0xf4, 0x0, 0x0,
/* U+005A "Z" */
0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xbf, 0xff, 0xff, 0xfc, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x2f, 0xd0,
0x0, 0x0, 0x7f, 0x80, 0x0, 0x1, 0xfe, 0x0, 0x0, 0x3, 0xfc, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x2f, 0xd0, 0x0, 0x0,
0xbf, 0x40, 0x0, 0x1, 0xfe, 0x0, 0x0, 0x7, 0xf8, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x3f, 0xc0, 0x0, 0x0, 0xbf, 0xff,
0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe,
/* U+005B "[" */
0xbf, 0xfa, 0xff, 0xeb, 0xfa, 0x6f, 0x80, 0xbe, 0x2, 0xf8, 0xb, 0xe0, 0x2f, 0x80, 0xbe, 0x2, 0xf8, 0xb, 0xe0, 0x2f,
0x80, 0xbe, 0x2, 0xf8, 0xb, 0xe0, 0x2f, 0x80, 0xbe, 0x2, 0xf8, 0xb, 0xe0, 0x2f, 0x80, 0xbe, 0x2, 0xfe, 0x9b, 0xff,
0xaf, 0xfe,
/* U+005C "\\" */
0x19, 0x0, 0x0, 0xb, 0xc0, 0x0, 0x1, 0xf8, 0x0, 0x0, 0x3f, 0x0, 0x0, 0xb, 0xd0, 0x0, 0x1, 0xf8, 0x0, 0x0, 0x3f, 0x0,
0x0, 0xb, 0xd0, 0x0, 0x0, 0xf8, 0x0, 0x0, 0x3f, 0x0, 0x0, 0xb, 0xd0, 0x0, 0x0, 0xf8, 0x0, 0x0, 0x3f, 0x0, 0x0, 0x7,
0xd0, 0x0, 0x0, 0xfc, 0x0, 0x0, 0x3f, 0x0, 0x0, 0x7, 0xd0, 0x0, 0x0, 0xfc, 0x0, 0x0, 0x2f, 0x0, 0x0, 0x7, 0xe0, 0x0,
0x0, 0xfc, 0x0, 0x0, 0x2f, 0x0, 0x0, 0x7, 0xe0, 0x0, 0x0, 0xfc, 0x0, 0x0, 0x2f, 0x40,
/* U+005D "]" */
0xbf, 0xfa, 0xff, 0xe6, 0xbf, 0x80, 0xbe, 0x2, 0xf8, 0xb, 0xe0, 0x2f, 0x80, 0xbe, 0x2, 0xf8, 0xb, 0xe0, 0x2f, 0x80,
0xbe, 0x2, 0xf8, 0xb, 0xe0, 0x2f, 0x80, 0xbe, 0x2, 0xf8, 0xb, 0xe0, 0x2f, 0x80, 0xbe, 0x2, 0xf9, 0xaf, 0xeb, 0xff,
0xaf, 0xfe,
/* U+005E "^" */
0x0, 0x3f, 0x0, 0x0, 0x1f, 0xe0, 0x0, 0xb, 0xfc, 0x0, 0x3, 0xdf, 0x40, 0x2, 0xf2, 0xf0, 0x0, 0xf8, 0x3d, 0x0, 0x7c,
0xb, 0xc0, 0x3e, 0x1, 0xf0, 0xf, 0x40, 0x3e, 0xb, 0xc0, 0xb, 0xc3, 0xd0, 0x0, 0xf4,
/* U+005F "_" */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0,
/* U+0060 "`" */
0x1a, 0x40, 0xf, 0xd0, 0x2, 0xf4, 0x0, 0x7d,
/* U+0061 "a" */
0x6, 0xff, 0xd0, 0xf, 0xff, 0xff, 0x3, 0xfe, 0xbf, 0xf0, 0x60, 0x1, 0xfd, 0x0, 0x0, 0x2f, 0x80, 0x0, 0xb, 0xe0,
0xbf, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xbf, 0x0, 0x2f, 0xff, 0x40, 0xb, 0xff, 0xd0, 0x3, 0xfd, 0xfd, 0x7, 0xff, 0x3f,
0xff, 0xef, 0xc1, 0xff, 0x97, 0xf0,
/* U+0062 "b" */
0x54, 0x0, 0x0, 0x3, 0xf4, 0x0, 0x0, 0xf, 0xd0, 0x0, 0x0, 0x3f, 0x40, 0x0, 0x0, 0xfd, 0x0, 0x0, 0x3, 0xf4, 0x0, 0x0,
0xf, 0xd2, 0xff, 0x80, 0x3f, 0xbf, 0xff, 0xd0, 0xff, 0xff, 0xff, 0xd3, 0xff, 0x0, 0x7f, 0xcf, 0xf0, 0x0, 0x3f, 0x7f,
0x80, 0x0, 0xbe, 0xfd, 0x0, 0x1, 0xff, 0xf4, 0x0, 0x7, 0xff, 0xe0, 0x0, 0x2f, 0xbf, 0xc0, 0x0, 0xfd, 0xff, 0xc0,
0x1f, 0xf3, 0xff, 0xff, 0xff, 0x4f, 0xef, 0xff, 0xf4, 0x3f, 0xb, 0xfe, 0x0,
/* U+0063 "c" */
0x0, 0x1f, 0xfd, 0x0, 0x7, 0xff, 0xff, 0x0, 0x7f, 0xff, 0xff, 0x3, 0xfc, 0x1, 0xf8, 0x2f, 0xc0, 0x0, 0x40, 0xfd,
0x0, 0x0, 0x3, 0xf4, 0x0, 0x0, 0xf, 0xd0, 0x0, 0x0, 0x3f, 0x80, 0x0, 0x0, 0xbf, 0x0, 0x1, 0x0, 0xff, 0x0, 0x7f, 0x1,
0xff, 0xff, 0xfc, 0x1, 0xff, 0xff, 0xc0, 0x0, 0x7f, 0xf4, 0x0,
/* U+0064 "d" */
0x0, 0x0, 0x0, 0x15, 0x0, 0x0, 0x0, 0xbe, 0x0, 0x0, 0x0, 0xbe, 0x0, 0x0, 0x0, 0xbe, 0x0, 0x0, 0x0, 0xbe, 0x0, 0x0,
0x0, 0xbe, 0x0, 0x2f, 0xf8, 0xbe, 0x2, 0xff, 0xff, 0xbe, 0xb, 0xff, 0xff, 0xfe, 0xf, 0xf0, 0x7, 0xfe, 0x2f, 0xc0,
0x0, 0xfe, 0x3f, 0x80, 0x0, 0xbe, 0x3f, 0x40, 0x0, 0xbe, 0x3f, 0x40, 0x0, 0xbe, 0x3f, 0x80, 0x0, 0xbe, 0x2f, 0xc0,
0x0, 0xfe, 0xf, 0xf0, 0x7, 0xfe, 0xb, 0xff, 0xff, 0xfe, 0x1, 0xff, 0xff, 0xbe, 0x0, 0x2f, 0xf8, 0x7e,
/* U+0065 "e" */
0x0, 0x2f, 0xf9, 0x0, 0x1, 0xff, 0xff, 0x80, 0x7, 0xfe, 0xbf, 0xe0, 0xf, 0xe0, 0x7, 0xf4, 0x2f, 0x80, 0x1, 0xfc,
0x3f, 0x40, 0x0, 0xfc, 0x3f, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xfc, 0x3f, 0x40, 0x0, 0x0, 0x2f, 0xc0, 0x0, 0x0,
0xf, 0xf0, 0x1, 0xc0, 0x7, 0xff, 0xff, 0xf0, 0x1, 0xff, 0xff, 0xd0, 0x0, 0x1f, 0xfe, 0x0,
/* U+0066 "f" */
0x0, 0x1a, 0x90, 0x3, 0xff, 0xd0, 0x2f, 0xff, 0x0, 0xfd, 0x4, 0x7, 0xf0, 0x0, 0x1f, 0x80, 0xb, 0xff, 0xfe, 0x2f,
0xff, 0xf8, 0x6f, 0xfa, 0x90, 0x1f, 0xc0, 0x0, 0x7f, 0x0, 0x1, 0xfc, 0x0, 0x7, 0xf0, 0x0, 0x1f, 0xc0, 0x0, 0x7f,
0x0, 0x1, 0xfc, 0x0, 0x7, 0xf0, 0x0, 0x1f, 0xc0, 0x0, 0x7f, 0x0, 0x1, 0xfc, 0x0,
/* U+0067 "g" */
0x0, 0x2f, 0xf8, 0x3f, 0x2, 0xff, 0xff, 0xbf, 0xb, 0xfe, 0xaf, 0xff, 0x1f, 0xe0, 0x2, 0xff, 0x2f, 0xc0, 0x0, 0xff,
0x3f, 0x40, 0x0, 0x7f, 0x3f, 0x40, 0x0, 0x7f, 0x3f, 0x40, 0x0, 0x7f, 0x2f, 0xc0, 0x0, 0xff, 0x1f, 0xf0, 0x3, 0xff,
0xb, 0xff, 0xff, 0xff, 0x2, 0xff, 0xff, 0xbf, 0x0, 0x2f, 0xf8, 0x7f, 0x0, 0x0, 0x0, 0xbf, 0x0, 0x0, 0x0, 0xfe, 0x7,
0x80, 0x2, 0xfc, 0xf, 0xff, 0xbf, 0xf8, 0xb, 0xff, 0xff, 0xe0, 0x0, 0x6f, 0xfe, 0x0,
/* U+0068 "h" */
0x0, 0x0, 0x0, 0xf, 0xd0, 0x0, 0x0, 0xfd, 0x0, 0x0, 0xf, 0xd0, 0x0, 0x0, 0xfd, 0x0, 0x0, 0xf, 0xd0, 0x0, 0x0, 0xfd,
0x2f, 0xf8, 0xf, 0xef, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xcf, 0xfc, 0x2, 0xfd, 0xff, 0x0, 0xf, 0xef, 0xe0, 0x0, 0xbf,
0xfd, 0x0, 0x7, 0xff, 0xd0, 0x0, 0x7f, 0xfd, 0x0, 0x7, 0xff, 0xd0, 0x0, 0x7f, 0xfd, 0x0, 0x7, 0xff, 0xd0, 0x0, 0x7f,
0xfd, 0x0, 0x7, 0xff, 0xd0, 0x0, 0x7f,
/* U+0069 "i" */
0x2f, 0xf, 0xf3, 0xf8, 0x78, 0x0, 0x0, 0x3, 0xf4, 0xfd, 0x3f, 0x4f, 0xd3, 0xf4, 0xfd, 0x3f, 0x4f, 0xd3, 0xf4, 0xfd,
0x3f, 0x4f, 0xd3, 0xf4, 0xfd,
/* U+006A "j" */
0x0, 0x1f, 0x40, 0xf, 0xf0, 0x3, 0xfc, 0x0, 0x7c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xf8, 0x0, 0xbe, 0x0, 0x2f, 0x80,
0xb, 0xe0, 0x2, 0xf8, 0x0, 0xbe, 0x0, 0x2f, 0x80, 0xb, 0xe0, 0x2, 0xf8, 0x0, 0xbe, 0x0, 0x2f, 0x80, 0xb, 0xe0, 0x2,
0xf8, 0x0, 0xbe, 0x0, 0x3f, 0x80, 0xf, 0xd3, 0xef, 0xf0, 0xff, 0xf4, 0x2f, 0xe4, 0x0,
/* U+006B "k" */
0x0, 0x0, 0x0, 0x3, 0xf4, 0x0, 0x0, 0xf, 0xd0, 0x0, 0x0, 0x3f, 0x40, 0x0, 0x0, 0xfd, 0x0, 0x0, 0x3, 0xf4, 0x0, 0x0,
0xf, 0xd0, 0x1, 0xfe, 0x3f, 0x40, 0x1f, 0xe0, 0xfd, 0x2, 0xfe, 0x3, 0xf4, 0x2f, 0xe0, 0xf, 0xd2, 0xfe, 0x0, 0x3f,
0x6f, 0xe0, 0x0, 0xff, 0xff, 0x80, 0x3, 0xff, 0xff, 0x40, 0xf, 0xfd, 0xff, 0x40, 0x3f, 0xd0, 0xff, 0x0, 0xfd, 0x0,
0xff, 0x3, 0xf4, 0x1, 0xfe, 0xf, 0xd0, 0x2, 0xfd, 0x3f, 0x40, 0x3, 0xfc,
/* U+006C "l" */
0x0, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd,
0xfd,
/* U+006D "m" */
0xfc, 0x2f, 0xf4, 0x6, 0xff, 0x40, 0xfe, 0xff, 0xff, 0x2f, 0xff, 0xe0, 0xff, 0xfa, 0xff, 0xff, 0xaf, 0xf8, 0xff,
0x80, 0x3f, 0xf8, 0x3, 0xfc, 0xff, 0x0, 0xf, 0xf0, 0x0, 0xfc, 0xfe, 0x0, 0xf, 0xe0, 0x0, 0xfd, 0xfd, 0x0, 0xf, 0xd0,
0x0, 0xfd, 0xfd, 0x0, 0xf, 0xd0, 0x0, 0xfd, 0xfd, 0x0, 0xf, 0xd0, 0x0, 0xfd, 0xfd, 0x0, 0xf, 0xd0, 0x0, 0xfd, 0xfd,
0x0, 0xf, 0xd0, 0x0, 0xfd, 0xfd, 0x0, 0xf, 0xd0, 0x0, 0xfd, 0xfd, 0x0, 0xf, 0xd0, 0x0, 0xfd, 0xfd, 0x0, 0xf, 0xd0,
0x0, 0xfd,
/* U+006E "n" */
0xfc, 0x2f, 0xf8, 0xf, 0xef, 0xff, 0xf0, 0xff, 0xfa, 0xff, 0xcf, 0xf8, 0x1, 0xfd, 0xff, 0x0, 0xf, 0xef, 0xe0, 0x0,
0xbf, 0xfd, 0x0, 0x7, 0xff, 0xd0, 0x0, 0x7f, 0xfd, 0x0, 0x7, 0xff, 0xd0, 0x0, 0x7f, 0xfd, 0x0, 0x7, 0xff, 0xd0, 0x0,
0x7f, 0xfd, 0x0, 0x7, 0xff, 0xd0, 0x0, 0x7f,
/* U+006F "o" */
0x0, 0x2f, 0xf9, 0x0, 0x1, 0xff, 0xff, 0xc0, 0x7, 0xff, 0xff, 0xf0, 0xf, 0xf0, 0x7, 0xfc, 0x2f, 0xc0, 0x0, 0xfd,
0x3f, 0x40, 0x0, 0xbe, 0x3f, 0x40, 0x0, 0xbf, 0x3f, 0x40, 0x0, 0xbe, 0x3f, 0x80, 0x0, 0xbe, 0x2f, 0xc0, 0x0, 0xfd,
0xf, 0xf0, 0x7, 0xfc, 0x7, 0xff, 0xff, 0xf0, 0x1, 0xff, 0xff, 0xc0, 0x0, 0x1f, 0xf9, 0x0,
/* U+0070 "p" */
0xfc, 0x2f, 0xf8, 0x3, 0xfb, 0xff, 0xfd, 0xf, 0xff, 0xff, 0xfd, 0x3f, 0xf0, 0x7, 0xfc, 0xff, 0x0, 0x3, 0xf7, 0xf8,
0x0, 0xb, 0xef, 0xd0, 0x0, 0x1f, 0xff, 0x40, 0x0, 0x7f, 0xfe, 0x0, 0x2, 0xfb, 0xfc, 0x0, 0xf, 0xdf, 0xfc, 0x1, 0xff,
0x3f, 0xff, 0xff, 0xf4, 0xfe, 0xff, 0xff, 0x43, 0xf4, 0xbf, 0xe0, 0xf, 0xd0, 0x0, 0x0, 0x3f, 0x40, 0x0, 0x0, 0xfd,
0x0, 0x0, 0x3, 0xf4, 0x0, 0x0, 0xf, 0xd0, 0x0, 0x0, 0x0,
/* U+0071 "q" */
0x0, 0x2f, 0xf8, 0x7e, 0x2, 0xff, 0xff, 0xbe, 0xb, 0xff, 0xff, 0xfe, 0xf, 0xf0, 0x7, 0xfe, 0x2f, 0xc0, 0x0, 0xfe,
0x3f, 0x40, 0x0, 0xbe, 0x3f, 0x40, 0x0, 0xbe, 0x3f, 0x40, 0x0, 0xbe, 0x3f, 0x80, 0x0, 0xbe, 0x2f, 0xc0, 0x0, 0xfe,
0xf, 0xf0, 0x7, 0xfe, 0xb, 0xff, 0xff, 0xfe, 0x2, 0xff, 0xff, 0xbe, 0x0, 0x2f, 0xf8, 0xbe, 0x0, 0x0, 0x0, 0xbe, 0x0,
0x0, 0x0, 0xbe, 0x0, 0x0, 0x0, 0xbe, 0x0, 0x0, 0x0, 0xbe, 0x0, 0x0, 0x0, 0xbe,
/* U+0072 "r" */
0xfc, 0x2f, 0x3f, 0xbf, 0xcf, 0xff, 0xf3, 0xff, 0x40, 0xff, 0x0, 0x3f, 0x80, 0xf, 0xd0, 0x3, 0xf4, 0x0, 0xfd, 0x0,
0x3f, 0x40, 0xf, 0xd0, 0x3, 0xf4, 0x0, 0xfd, 0x0, 0x3f, 0x40, 0x0,
/* U+0073 "s" */
0x1, 0xbf, 0xf8, 0x2, 0xff, 0xff, 0xc2, 0xff, 0xaf, 0xe0, 0xfd, 0x0, 0x10, 0x3f, 0x0, 0x0, 0xf, 0xf9, 0x0, 0x1,
0xff, 0xff, 0x40, 0xb, 0xff, 0xfc, 0x0, 0x5, 0xbf, 0x80, 0x0, 0xb, 0xe1, 0x80, 0x2, 0xf8, 0xff, 0xab, 0xfd, 0x3f,
0xff, 0xfd, 0x1, 0xbf, 0xf8, 0x0,
/* U+0074 "t" */
0x7, 0xf0, 0x0, 0x1f, 0xc0, 0x0, 0x7f, 0x0, 0x2f, 0xff, 0xf8, 0xbf, 0xff, 0xe1, 0xbf, 0xea, 0x40, 0x7f, 0x0, 0x1,
0xfc, 0x0, 0x7, 0xf0, 0x0, 0x1f, 0xc0, 0x0, 0x7f, 0x0, 0x1, 0xfc, 0x0, 0x7, 0xf0, 0x0, 0x1f, 0xc0, 0x0, 0x3f, 0xef,
0x0, 0x7f, 0xfd, 0x0, 0x7f, 0xe0,
/* U+0075 "u" */
0xfd, 0x0, 0xb, 0xef, 0xd0, 0x0, 0xbe, 0xfd, 0x0, 0xb, 0xef, 0xd0, 0x0, 0xbe, 0xfd, 0x0, 0xb, 0xef, 0xd0, 0x0, 0xbe,
0xfd, 0x0, 0xb, 0xef, 0xd0, 0x0, 0xbe, 0xfd, 0x0, 0xf, 0xef, 0xe0, 0x1, 0xfe, 0xbf, 0x40, 0x7f, 0xe3, 0xff, 0xff,
0xfe, 0x1f, 0xff, 0xfb, 0xe0, 0x2f, 0xf4, 0xbe,
/* U+0076 "v" */
0x3f, 0x40, 0x0, 0x3f, 0x7, 0xf0, 0x0, 0x2f, 0x40, 0xfd, 0x0, 0xf, 0xc0, 0x2f, 0x80, 0x7, 0xe0, 0x3, 0xf0, 0x3,
0xf0, 0x0, 0xfe, 0x1, 0xfc, 0x0, 0x1f, 0xc0, 0xfd, 0x0, 0x3, 0xf4, 0x3f, 0x0, 0x0, 0xbf, 0x2f, 0x80, 0x0, 0xf, 0xdf,
0xc0, 0x0, 0x2, 0xff, 0xe0, 0x0, 0x0, 0x3f, 0xf0, 0x0, 0x0, 0xf, 0xfc, 0x0, 0x0, 0x1, 0xfd, 0x0, 0x0,
/* U+0077 "w" */
0xbd, 0x0, 0xb, 0xe0, 0x0, 0x7e, 0x7e, 0x0, 0xf, 0xf0, 0x0, 0xbd, 0x3f, 0x0, 0x1f, 0xf4, 0x0, 0xfc, 0x2f, 0x40,
0x2f, 0xf8, 0x1, 0xf8, 0x1f, 0xc0, 0x3f, 0xfc, 0x2, 0xf0, 0xf, 0xc0, 0x7e, 0xbd, 0x3, 0xf0, 0xb, 0xd0, 0xfc, 0x3e,
0x7, 0xd0, 0x3, 0xf0, 0xfc, 0x3f, 0xf, 0xc0, 0x3, 0xf1, 0xf4, 0x2f, 0x4f, 0x80, 0x1, 0xfb, 0xf0, 0xf, 0xef, 0x40,
0x0, 0xff, 0xe0, 0xf, 0xff, 0x0, 0x0, 0xbf, 0xd0, 0x7, 0xfe, 0x0, 0x0, 0x7f, 0xc0, 0x3, 0xfc, 0x0, 0x0, 0x3f, 0x80,
0x2, 0xfc, 0x0,
/* U+0078 "x" */
0x3f, 0x40, 0x7, 0xf0, 0x7f, 0x0, 0x3f, 0x40, 0xbf, 0x3, 0xf8, 0x0, 0xfe, 0x2f, 0x80, 0x0, 0xff, 0xfc, 0x0, 0x1,
0xff, 0xc0, 0x0, 0x2, 0xfd, 0x0, 0x0, 0xf, 0xf8, 0x0, 0x0, 0xbf, 0xf4, 0x0, 0x7, 0xfb, 0xf0, 0x0, 0x3f, 0x4b, 0xf0,
0x3, 0xf8, 0xf, 0xe0, 0x2f, 0xc0, 0xf, 0xe1, 0xfc, 0x0, 0x1f, 0xd0,
/* U+0079 "y" */
0x3f, 0x40, 0x0, 0x3f, 0x7, 0xf0, 0x0, 0x2f, 0x40, 0xfd, 0x0, 0xf, 0xc0, 0x2f, 0x80, 0x7, 0xe0, 0x3, 0xf0, 0x3,
0xf0, 0x0, 0xbe, 0x1, 0xf8, 0x0, 0x1f, 0xc0, 0xfd, 0x0, 0x3, 0xf4, 0x3f, 0x0, 0x0, 0x7f, 0x2f, 0x40, 0x0, 0xf, 0xdf,
0xc0, 0x0, 0x2, 0xff, 0xe0, 0x0, 0x0, 0x3f, 0xf0, 0x0, 0x0, 0xb, 0xf8, 0x0, 0x0, 0x0, 0xfc, 0x0, 0x0, 0x0, 0x7f,
0x0, 0x0, 0x0, 0x3f, 0x40, 0x0, 0x3f, 0xbf, 0xc0, 0x0, 0x1f, 0xff, 0xc0, 0x0, 0x1, 0xbf, 0x80, 0x0, 0x0,
/* U+007A "z" */
0x3f, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xe2, 0xaa, 0xaf, 0xf4, 0x0, 0x3, 0xf8, 0x0, 0x3, 0xf8, 0x0, 0x2, 0xfc, 0x0,
0x2, 0xfc, 0x0, 0x1, 0xfd, 0x0, 0x0, 0xfd, 0x0, 0x0, 0xfe, 0x0, 0x0, 0xff, 0x0, 0x0, 0xbf, 0xaa, 0xaa, 0x3f, 0xff,
0xff, 0xcf, 0xff, 0xff, 0xf0,
/* U+007B "{" */
0x0, 0xbf, 0x0, 0xff, 0xc0, 0x7f, 0xe0, 0x2f, 0xc0, 0xb, 0xe0, 0x2, 0xf8, 0x0, 0xbe, 0x0, 0x2f, 0x80, 0xb, 0xe0,
0x2, 0xf8, 0x6, 0xfe, 0x2, 0xfe, 0x0, 0xbf, 0xd0, 0x3, 0xf8, 0x0, 0xbe, 0x0, 0x2f, 0x80, 0xb, 0xe0, 0x2, 0xf8, 0x0,
0xbe, 0x0, 0x2f, 0x80, 0x7, 0xf0, 0x1, 0xff, 0x80, 0x2f, 0xf0, 0x2, 0xfc,
/* U+007C "|" */
0x14, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
/* U+007D "}" */
0xbf, 0x40, 0x2f, 0xf4, 0x6, 0xff, 0x0, 0x1f, 0xc0, 0x3, 0xf0, 0x0, 0xfc, 0x0, 0x3f, 0x0, 0xf, 0xc0, 0x3, 0xf0, 0x0,
0xfd, 0x0, 0x3f, 0xe0, 0x3, 0xfc, 0x2, 0xff, 0x0, 0xfd, 0x0, 0x3f, 0x0, 0xf, 0xc0, 0x3, 0xf0, 0x0, 0xfc, 0x0, 0x3f,
0x0, 0xf, 0xc0, 0x7, 0xf0, 0x1b, 0xfc, 0xb, 0xfd, 0x2, 0xfd, 0x0,
/* U+007E "~" */
0xb, 0xe0, 0x3, 0xcb, 0xff, 0x41, 0xf3, 0xeb, 0xfa, 0xf9, 0xf0, 0x3f, 0xfc, 0xb8, 0x2, 0xfc, 0x0};
/*---------------------
* GLYPH DESCRIPTION
*--------------------*/
static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
{.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */,
{.bitmap_index = 0, .adv_w = 115, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 0, .adv_w = 116, .box_w = 5, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 23, .adv_w = 172, .box_w = 9, .box_h = 8, .ofs_x = 1, .ofs_y = 10},
{.bitmap_index = 41, .adv_w = 296, .box_w = 18, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 122, .adv_w = 262, .box_w = 16, .box_h = 25, .ofs_x = 0, .ofs_y = -3},
{.bitmap_index = 222, .adv_w = 358, .box_w = 22, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 321, .adv_w = 294, .box_w = 17, .box_h = 19, .ofs_x = 1, .ofs_y = -1},
{.bitmap_index = 402, .adv_w = 92, .box_w = 4, .box_h = 8, .ofs_x = 1, .ofs_y = 10},
{.bitmap_index = 410, .adv_w = 144, .box_w = 7, .box_h = 25, .ofs_x = 2, .ofs_y = -5},
{.bitmap_index = 454, .adv_w = 145, .box_w = 7, .box_h = 25, .ofs_x = 0, .ofs_y = -5},
{.bitmap_index = 498, .adv_w = 173, .box_w = 11, .box_h = 10, .ofs_x = 0, .ofs_y = 9},
{.bitmap_index = 526, .adv_w = 245, .box_w = 13, .box_h = 12, .ofs_x = 1, .ofs_y = 3},
{.bitmap_index = 565, .adv_w = 102, .box_w = 5, .box_h = 9, .ofs_x = 1, .ofs_y = -4},
{.bitmap_index = 577, .adv_w = 160, .box_w = 8, .box_h = 3, .ofs_x = 1, .ofs_y = 6},
{.bitmap_index = 583, .adv_w = 102, .box_w = 5, .box_h = 5, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 590, .adv_w = 154, .box_w = 12, .box_h = 25, .ofs_x = -1, .ofs_y = -3},
{.bitmap_index = 665, .adv_w = 280, .box_w = 16, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 737, .adv_w = 158, .box_w = 8, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 773, .adv_w = 242, .box_w = 15, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 841, .adv_w = 242, .box_w = 15, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 909, .adv_w = 282, .box_w = 18, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 990, .adv_w = 243, .box_w = 15, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 1058, .adv_w = 261, .box_w = 15, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1126, .adv_w = 253, .box_w = 15, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 1194, .adv_w = 271, .box_w = 15, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1262, .adv_w = 261, .box_w = 16, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 1334, .adv_w = 102, .box_w = 5, .box_h = 14, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1352, .adv_w = 102, .box_w = 5, .box_h = 18, .ofs_x = 1, .ofs_y = -4},
{.bitmap_index = 1375, .adv_w = 245, .box_w = 13, .box_h = 13, .ofs_x = 1, .ofs_y = 3},
{.bitmap_index = 1418, .adv_w = 245, .box_w = 13, .box_h = 9, .ofs_x = 1, .ofs_y = 5},
{.bitmap_index = 1448, .adv_w = 245, .box_w = 13, .box_h = 13, .ofs_x = 1, .ofs_y = 3},
{.bitmap_index = 1491, .adv_w = 242, .box_w = 14, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 1554, .adv_w = 430, .box_w = 25, .box_h = 23, .ofs_x = 1, .ofs_y = -5},
{.bitmap_index = 1698, .adv_w = 312, .box_w = 21, .box_h = 18, .ofs_x = -1, .ofs_y = 0},
{.bitmap_index = 1793, .adv_w = 317, .box_w = 17, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 1870, .adv_w = 299, .box_w = 18, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 1951, .adv_w = 344, .box_w = 19, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 2037, .adv_w = 279, .box_w = 15, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 2105, .adv_w = 265, .box_w = 14, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 2168, .adv_w = 321, .box_w = 18, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 2249, .adv_w = 337, .box_w = 17, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 2326, .adv_w = 133, .box_w = 4, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 2344, .adv_w = 219, .box_w = 13, .box_h = 18, .ofs_x = -1, .ofs_y = 0},
{.bitmap_index = 2403, .adv_w = 303, .box_w = 18, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 2484, .adv_w = 249, .box_w = 14, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 2547, .adv_w = 397, .box_w = 21, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 2642, .adv_w = 337, .box_w = 17, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 2719, .adv_w = 350, .box_w = 20, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 2809, .adv_w = 302, .box_w = 16, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 2881, .adv_w = 350, .box_w = 21, .box_h = 22, .ofs_x = 1, .ofs_y = -4},
{.bitmap_index = 2997, .adv_w = 304, .box_w = 16, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 3069, .adv_w = 262, .box_w = 16, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 3141, .adv_w = 250, .box_w = 16, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 3213, .adv_w = 328, .box_w = 17, .box_h = 18, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 3290, .adv_w = 303, .box_w = 21, .box_h = 18, .ofs_x = -1, .ofs_y = 0},
{.bitmap_index = 3385, .adv_w = 476, .box_w = 30, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 3520, .adv_w = 288, .box_w = 18, .box_h = 18, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 3601, .adv_w = 275, .box_w = 19, .box_h = 18, .ofs_x = -1, .ofs_y = 0},
{.bitmap_index = 3687, .adv_w = 276, .box_w = 16, .box_h = 18, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 3759, .adv_w = 146, .box_w = 7, .box_h = 24, .ofs_x = 2, .ofs_y = -5},
{.bitmap_index = 3801, .adv_w = 154, .box_w = 13, .box_h = 25, .ofs_x = -2, .ofs_y = -3},
{.bitmap_index = 3883, .adv_w = 146, .box_w = 7, .box_h = 24, .ofs_x = 0, .ofs_y = -5},
{.bitmap_index = 3925, .adv_w = 246, .box_w = 13, .box_h = 11, .ofs_x = 1, .ofs_y = 4},
{.bitmap_index = 3961, .adv_w = 208, .box_w = 13, .box_h = 2, .ofs_x = 0, .ofs_y = -2},
{.bitmap_index = 3968, .adv_w = 250, .box_w = 8, .box_h = 4, .ofs_x = 2, .ofs_y = 16},
{.bitmap_index = 3976, .adv_w = 253, .box_w = 13, .box_h = 14, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 4022, .adv_w = 285, .box_w = 15, .box_h = 20, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 4097, .adv_w = 242, .box_w = 15, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 4150, .adv_w = 286, .box_w = 16, .box_h = 20, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 4230, .adv_w = 259, .box_w = 16, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 4286, .adv_w = 154, .box_w = 11, .box_h = 20, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 4341, .adv_w = 289, .box_w = 16, .box_h = 19, .ofs_x = 0, .ofs_y = -5},
{.bitmap_index = 4417, .adv_w = 285, .box_w = 14, .box_h = 20, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 4487, .adv_w = 120, .box_w = 5, .box_h = 20, .ofs_x = 1, .ofs_y = 0},
{.bitmap_index = 4512, .adv_w = 123, .box_w = 9, .box_h = 25, .ofs_x = -3, .ofs_y = -5},
{.bitmap_index = 4569, .adv_w = 264, .box_w = 15, .box_h = 20, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 4644, .adv_w = 120, .box_w = 4, .box_h = 20, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 4664, .adv_w = 438, .box_w = 24, .box_h = 14, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 4748, .adv_w = 285, .box_w = 14, .box_h = 14, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 4797, .adv_w = 268, .box_w = 16, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 4853, .adv_w = 285, .box_w = 15, .box_h = 19, .ofs_x = 2, .ofs_y = -5},
{.bitmap_index = 4925, .adv_w = 285, .box_w = 16, .box_h = 19, .ofs_x = 0, .ofs_y = -5},
{.bitmap_index = 5001, .adv_w = 175, .box_w = 9, .box_h = 14, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 5033, .adv_w = 214, .box_w = 13, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 5079, .adv_w = 176, .box_w = 11, .box_h = 17, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 5126, .adv_w = 283, .box_w = 14, .box_h = 14, .ofs_x = 2, .ofs_y = 0},
{.bitmap_index = 5175, .adv_w = 240, .box_w = 17, .box_h = 14, .ofs_x = -1, .ofs_y = 0},
{.bitmap_index = 5235, .adv_w = 382, .box_w = 24, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 5319, .adv_w = 238, .box_w = 15, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 5372, .adv_w = 240, .box_w = 17, .box_h = 19, .ofs_x = -1, .ofs_y = -5},
{.bitmap_index = 5453, .adv_w = 221, .box_w = 13, .box_h = 14, .ofs_x = 0, .ofs_y = 0},
{.bitmap_index = 5499, .adv_w = 154, .box_w = 9, .box_h = 24, .ofs_x = 1, .ofs_y = -5},
{.bitmap_index = 5553, .adv_w = 126, .box_w = 4, .box_h = 25, .ofs_x = 2, .ofs_y = -5},
{.bitmap_index = 5578, .adv_w = 154, .box_w = 9, .box_h = 24, .ofs_x = 0, .ofs_y = -5},
{.bitmap_index = 5632, .adv_w = 245, .box_w = 13, .box_h = 5, .ofs_x = 1, .ofs_y = 7}};
/*---------------------
* CHARACTER MAPPING
*--------------------*/
/*Collect the unicode lists and glyph_id offsets*/
static const lv_font_fmt_txt_cmap_t cmaps[] = {{.range_start = 32,
.range_length = 95,
.glyph_id_start = 1,
.unicode_list = NULL,
.glyph_id_ofs_list = NULL,
.list_length = 0,
.type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY}};
/*--------------------
* ALL CUSTOM DATA
*--------------------*/
#if LVGL_VERSION_MAJOR == 8
/*Store all the custom data of the font*/
static lv_font_fmt_txt_glyph_cache_t cache;
#endif
#if LVGL_VERSION_MAJOR >= 8
static const lv_font_fmt_txt_dsc_t font_dsc = {
#else
static lv_font_fmt_txt_dsc_t font_dsc = {
#endif
.glyph_bitmap = glyph_bitmap,
.glyph_dsc = glyph_dsc,
.cmaps = cmaps,
.kern_dsc = NULL,
.kern_scale = 0,
.cmap_num = 1,
.bpp = 2,
.kern_classes = 0,
.bitmap_format = 0,
#if LVGL_VERSION_MAJOR == 8
.cache = &cache
#endif
};
/*-----------------
* PUBLIC FONT
*----------------*/
/*Initialize a public general font descriptor*/
#if LVGL_VERSION_MAJOR >= 8
const lv_font_t MontserratSemiBold26 = {
#else
lv_font_t MontserratSemiBold26 = {
#endif
.get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/
.get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/
.line_height = 27, /*The maximum line height required by the font*/
.base_line = 5, /*Baseline measured from the bottom of the line*/
#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0)
.subpx = LV_FONT_SUBPX_NONE,
#endif
#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8
.underline_position = -3,
.underline_thickness = 1,
#endif
.static_bitmap = 0,
.dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */
#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9
.fallback = NULL,
#endif
.user_data = NULL,
};
#endif /*#if MONTSERRATSEMIBOLD26*/
+1
View File
@@ -0,0 +1 @@
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,407 @@
#ifdef __has_include
#if __has_include("lvgl.h")
#ifndef LV_LVGL_H_INCLUDE_SIMPLE
#define LV_LVGL_H_INCLUDE_SIMPLE
#endif
#endif
#endif
#if defined(LV_LVGL_H_INCLUDE_SIMPLE)
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#ifndef LV_ATTRIBUTE_MEM_ALIGN
#define LV_ATTRIBUTE_MEM_ALIGN
#endif
#ifndef LV_ATTRIBUTE_IMAGE_ICON_INDICATOR_LEFT
#define LV_ATTRIBUTE_IMAGE_ICON_INDICATOR_LEFT
#endif
const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMAGE_ICON_INDICATOR_LEFT uint8_t
icon_indicator_left_map[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7d, 0xef, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbe, 0xf7, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb, 0xde, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xf7,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7a, 0xd6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbe, 0xf7, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1c, 0xe7, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfe, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdf, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xde, 0xdf, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x75, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0xde, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0x75, 0xad, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1c, 0xe7, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0xd6, 0xdf, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0x75, 0xad,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0xd6, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xfb, 0xde, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0x75, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfe, 0xf7, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7d, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x84, 0xbe, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xbe, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7e, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xbe, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xfb, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xfb, 0xde, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7e, 0xf7,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xbe, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xfb, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xde, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x9e, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x9e, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xfb, 0xde,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xfb, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xfe, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0x9e, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x9e, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xbe, 0xf7, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbe, 0xf7,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x9e, 0xf7, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xbf, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x84,
0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xbe, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0x7d, 0xef, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xde, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x1e, 0x5a, 0x53, 0x0c, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x27, 0x85, 0xbf, 0xb0, 0x60, 0x13, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x2d, 0x7a, 0xd7, 0xf8, 0xec, 0xb8, 0x58, 0x1a, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x05, 0x28, 0x77, 0xde, 0xf9, 0xff, 0xfe, 0xf2, 0xbb, 0x4f, 0x09,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, 0x83, 0xd9, 0xf9, 0xfe, 0xff, 0xff, 0xfc, 0xec, 0x8c, 0x26,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x26, 0x87, 0xd1, 0xf8, 0xfe, 0xff, 0xff, 0xff, 0xf5, 0xc3, 0x5c, 0x10,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x07, 0x2c, 0x7b, 0xd7, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xc4, 0x6b, 0x22, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x05, 0x27, 0x74, 0xde, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xf4, 0xc5, 0x71, 0x16, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x06, 0x20, 0x81, 0xd9, 0xf8, 0xfe, 0xff, 0xff, 0xfe, 0xf8, 0xc2, 0x6d, 0x17, 0x03, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x06, 0x24, 0x87, 0xd1, 0xf8, 0xfe, 0xff, 0xff, 0xff, 0xf5, 0xc3, 0x67, 0x1f, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x2b, 0x7c, 0xd5, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xc3, 0x6a, 0x23, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
0x29, 0x74, 0xdd, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xc5, 0x70, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x22,
0x7f, 0xda, 0xf8, 0xfe, 0xff, 0xff, 0xfe, 0xf8, 0xc2, 0x6e, 0x17, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x23, 0x87,
0xd2, 0xf9, 0xfe, 0xff, 0xff, 0xff, 0xf6, 0xc4, 0x67, 0x1d, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x2a, 0x7d, 0xd3,
0xf7, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xc3, 0x69, 0x23, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x2a, 0x74, 0xdb, 0xf9,
0xff, 0xff, 0xff, 0xff, 0xf2, 0xc5, 0x70, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x23, 0x7d, 0xdb, 0xf8, 0xfe,
0xff, 0xff, 0xfe, 0xf8, 0xc3, 0x6f, 0x17, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x22, 0x87, 0xd3, 0xf9, 0xfe, 0xff,
0xff, 0xff, 0xf7, 0xc5, 0x68, 0x1c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x29, 0x7f, 0xd2, 0xf7, 0xff, 0xff, 0xff,
0xff, 0xf1, 0xc3, 0x68, 0x23, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x2b, 0x74, 0xda, 0xf9, 0xff, 0xff, 0xff, 0xff,
0xf1, 0xc6, 0x6f, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x24, 0x7c, 0xdd, 0xf8, 0xfe, 0xff, 0xff, 0xfe, 0xf7,
0xc3, 0x6f, 0x17, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x87, 0xd4, 0xfa, 0xfe, 0xff, 0xff, 0xff, 0xf8, 0xc5,
0x68, 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x27, 0x80, 0xd1, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xf2, 0xc3, 0x68,
0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x2b, 0x74, 0xd8, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xc5, 0x6f, 0x1c,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x06, 0x25, 0x7a, 0xdd, 0xf8, 0xfe, 0xff, 0xff, 0xfe, 0xf6, 0xc3, 0x70, 0x17, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x05, 0x1f, 0x86, 0xd6, 0xfa, 0xfe, 0xff, 0xff, 0xff, 0xf8, 0xc4, 0x69, 0x17, 0x03, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0x27, 0x82, 0xd0, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xc2, 0x67, 0x23, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x07, 0x2c, 0x75, 0xd7, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xc5, 0x6e, 0x1d, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x05, 0x26, 0x79, 0xdd, 0xf9, 0xfe, 0xff, 0xff, 0xfe, 0xf5, 0xc3, 0x70, 0x17, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1e, 0x84, 0xd6, 0xf9, 0xfe, 0xff, 0xff, 0xff, 0xf9, 0xc4, 0x6a, 0x16, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x5d, 0xc0, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xed, 0x80, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x57, 0xb4, 0xee, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xed, 0x8a, 0x35, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0d, 0x65, 0xbd, 0xf3, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xe0, 0x89, 0x28, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x15, 0x5c, 0xc1, 0xf3, 0xfe, 0xff, 0xff, 0xfe, 0xfa, 0xda, 0x94, 0x27, 0x07, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x1c, 0x5b, 0xbd, 0xef, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xda, 0x8d, 0x30, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x16, 0x65, 0xba, 0xee, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xdc, 0x83, 0x35, 0x06, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x0e, 0x67, 0xbd, 0xf4, 0xfd, 0xff, 0xff, 0xff, 0xfb, 0xe1, 0x87, 0x29, 0x08, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x5d, 0xc1, 0xf2, 0xfe, 0xff, 0xff, 0xfe, 0xfa, 0xda, 0x93, 0x28, 0x07,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1c, 0x59, 0xbe, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xd9, 0x8f, 0x2e,
0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x16, 0x64, 0xbb, 0xed, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xdb, 0x84,
0x36, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x68, 0xbd, 0xf4, 0xfd, 0xff, 0xff, 0xff, 0xfb, 0xe3,
0x87, 0x2a, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x5f, 0xc0, 0xf2, 0xfd, 0xff, 0xff, 0xfe, 0xfb,
0xda, 0x92, 0x28, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1b, 0x58, 0xbe, 0xf0, 0xff, 0xff, 0xff, 0xff,
0xf8, 0xd9, 0x91, 0x2c, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x18, 0x63, 0xbb, 0xed, 0xff, 0xff, 0xff,
0xff, 0xf8, 0xdb, 0x85, 0x36, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0f, 0x68, 0xbd, 0xf2, 0xfd, 0xff,
0xff, 0xff, 0xfb, 0xe3, 0x85, 0x2c, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x12, 0x60, 0xbf, 0xf2, 0xfd,
0xff, 0xff, 0xfe, 0xfb, 0xdb, 0x91, 0x28, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1a, 0x58, 0xbe, 0xf1,
0xff, 0xff, 0xff, 0xff, 0xf8, 0xd9, 0x92, 0x2a, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x19, 0x61, 0xbb,
0xed, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xda, 0x87, 0x36, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x68,
0xbb, 0xf1, 0xfd, 0xff, 0xff, 0xff, 0xfb, 0xe3, 0x84, 0x2e, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10,
0x61, 0xbe, 0xf2, 0xfd, 0xff, 0xff, 0xfe, 0xfb, 0xdb, 0x8f, 0x27, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x19, 0x58, 0xbf, 0xf2, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xd9, 0x94, 0x29, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x1a, 0x60, 0xbd, 0xed, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xda, 0x88, 0x35, 0x07, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x12, 0x68, 0xbb, 0xf0, 0xfd, 0xff, 0xff, 0xff, 0xfa, 0xe1, 0x83, 0x30, 0x07, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0x0f, 0x63, 0xbe, 0xf2, 0xfd, 0xff, 0xff, 0xfe, 0xfb, 0xdd, 0x8f, 0x28, 0x08, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x18, 0x58, 0xc0, 0xf4, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xdb, 0x96, 0x29, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x1c, 0x60, 0xbe, 0xee, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xdb, 0x8b, 0x35, 0x05,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x14, 0x69, 0xbc, 0xf0, 0xfe, 0xff, 0xff, 0xff, 0xfa, 0xdf, 0x6c, 0x13,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x65, 0xbf, 0xf3, 0xfd, 0xff, 0xff, 0xfb, 0xe5, 0x82, 0x20,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x17, 0x5b, 0xc2, 0xf4, 0xff, 0xfe, 0xea, 0x91, 0x39, 0x07,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1d, 0x5f, 0xbe, 0xee, 0xde, 0x95, 0x3c, 0x0f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x15, 0x67, 0xa5, 0x94, 0x3d, 0x0a, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0d, 0x31, 0x30, 0x07, 0x01, 0x00, 0x00,
};
const lv_image_dsc_t icon_indicator_left = {
.header.cf = LV_COLOR_FORMAT_RGB565A8,
.header.magic = LV_IMAGE_HEADER_MAGIC,
.header.w = 36,
.header.h = 62,
.data_size = 2232 * 3,
.data = icon_indicator_left_map,
};
@@ -0,0 +1,407 @@
#ifdef __has_include
#if __has_include("lvgl.h")
#ifndef LV_LVGL_H_INCLUDE_SIMPLE
#define LV_LVGL_H_INCLUDE_SIMPLE
#endif
#endif
#endif
#if defined(LV_LVGL_H_INCLUDE_SIMPLE)
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#ifndef LV_ATTRIBUTE_MEM_ALIGN
#define LV_ATTRIBUTE_MEM_ALIGN
#endif
#ifndef LV_ATTRIBUTE_IMAGE_ICON_INDICATOR_RIGHT
#define LV_ATTRIBUTE_IMAGE_ICON_INDICATOR_RIGHT
#endif
const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMAGE_ICON_INDICATOR_RIGHT uint8_t
icon_indicator_right_map[] = {
0x00, 0x00, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x5d, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7d, 0xef, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0x9e, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5d, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x9e, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x7d, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x7d, 0xef, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x1c, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x9e, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x10, 0x84, 0x9e, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5d, 0xef, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1c, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7d, 0xef,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x9e, 0xf7, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x84, 0x9e, 0xf7, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1c, 0xe7,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1c, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7e, 0xf7, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7a, 0xd6,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdf, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0xd6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xbb, 0xde, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0xc6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x75, 0xad, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0xc6, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0a, 0x29, 0x6d, 0x35, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x08, 0x3f, 0x97, 0xc9, 0x9b, 0x4a, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0a, 0x3f, 0x93, 0xe6, 0xf9, 0xe4, 0x9e, 0x43, 0x0d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2b, 0x98, 0xe6, 0xfd, 0xff, 0xfe, 0xe5, 0xa8, 0x39, 0x0d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x74, 0xcd, 0xfa, 0xff, 0xff, 0xff, 0xfb, 0xe7, 0xa7, 0x3f, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3b, 0xa2, 0xe9, 0xfe, 0xff, 0xff, 0xff, 0xfb, 0xe5, 0xa0, 0x49, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0b, 0x50, 0xa5, 0xea, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xe4, 0x9d, 0x44, 0x0d, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x08, 0x49, 0xb1, 0xea, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xe6, 0xa7, 0x39, 0x0d, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x10, 0x3f, 0xb0, 0xe9, 0xfd, 0xff, 0xff, 0xff, 0xfb, 0xe7, 0xa7, 0x3d, 0x0b, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x10, 0x45, 0xa8, 0xe9, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xe5, 0xa2, 0x48, 0x05, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x0c, 0x50, 0xa4, 0xea, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xe5, 0x9d, 0x46, 0x0c, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x4b, 0xb0, 0xea, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xe5, 0xa5, 0x3b, 0x0d,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0f, 0x3f, 0xb0, 0xe9, 0xfd, 0xff, 0xff, 0xff, 0xfb, 0xe6, 0xa7, 0x3c,
0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x43, 0xaa, 0xea, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xe5, 0xa4,
0x48, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0d, 0x4f, 0xa4, 0xea, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xe5,
0x9d, 0x48, 0x0c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x4d, 0xae, 0xe9, 0xfb, 0xff, 0xff, 0xff, 0xff,
0xe5, 0xa4, 0x3c, 0x0d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0f, 0x41, 0xb0, 0xe9, 0xfc, 0xff, 0xff, 0xff,
0xfc, 0xe5, 0xa7, 0x3a, 0x0c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x42, 0xac, 0xea, 0xff, 0xff, 0xff,
0xff, 0xfb, 0xe6, 0xa5, 0x46, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x4f, 0xa4, 0xea, 0xfc, 0xff,
0xff, 0xff, 0xfb, 0xe5, 0x9d, 0x48, 0x0b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x4f, 0xac, 0xe9, 0xfb,
0xff, 0xff, 0xff, 0xff, 0xe5, 0xa2, 0x3d, 0x0d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x42, 0xb0, 0xe9,
0xfc, 0xff, 0xff, 0xff, 0xfc, 0xe5, 0xa7, 0x39, 0x0d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x41, 0xae,
0xea, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xe7, 0xa7, 0x44, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x4d,
0xa4, 0xea, 0xfd, 0xff, 0xff, 0xff, 0xfb, 0xe6, 0x9d, 0x49, 0x09, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08,
0x4f, 0xaa, 0xe9, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xe4, 0xa0, 0x3f, 0x0d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x0d, 0x43, 0xb0, 0xea, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xe5, 0xa7, 0x39, 0x0d, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x0f, 0x3f, 0xb0, 0xea, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xe7, 0xa8, 0x43, 0x05, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0x0f, 0x4b, 0xa4, 0xe9, 0xfd, 0xff, 0xff, 0xff, 0xfb, 0xe5, 0x9e, 0x4a, 0x08, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x08, 0x50, 0xa9, 0xe9, 0xfc, 0xff, 0xff, 0xff, 0xfe, 0xe4, 0xa0, 0x40, 0x0d, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0c, 0x46, 0xb1, 0xeb, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xe5, 0xa8, 0x3a, 0x0e, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x40, 0xb2, 0xeb, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xe7, 0xa8, 0x41, 0x05,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x64, 0xc6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xe4, 0x7a, 0x1c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x1f, 0x6e, 0xca, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xd3, 0x72, 0x1b,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x04, 0x1d, 0x5e, 0xce, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xd9, 0x7f, 0x2a, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x1c, 0x62, 0xcc, 0xf4, 0xfe, 0xff, 0xff, 0xff, 0xfc, 0xd4, 0x80, 0x26, 0x07, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0x1a, 0x6c, 0xc2, 0xf4, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xcd, 0x80, 0x2b, 0x07, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x05, 0x1e, 0x67, 0xbe, 0xf8, 0xfe, 0xff, 0xff, 0xff, 0xf8, 0xd3, 0x7f, 0x31, 0x03, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x1d, 0x5e, 0xcc, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xd9, 0x7f, 0x2c, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x1d, 0x61, 0xcc, 0xf4, 0xfe, 0xff, 0xff, 0xff, 0xfb, 0xd4, 0x7f, 0x26, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x1a,
0x6b, 0xc4, 0xf4, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xce, 0x7f, 0x2b, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x1e, 0x68,
0xbe, 0xf8, 0xfe, 0xff, 0xff, 0xff, 0xf8, 0xd2, 0x7f, 0x30, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x1c, 0x5d, 0xcb,
0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xd9, 0x7f, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1e, 0x60, 0xcc, 0xf4,
0xfe, 0xff, 0xff, 0xff, 0xfa, 0xd5, 0x7f, 0x26, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x1a, 0x6b, 0xc6, 0xf3, 0xfe,
0xff, 0xff, 0xff, 0xff, 0xce, 0x7f, 0x2a, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x1e, 0x6a, 0xbe, 0xf8, 0xfe, 0xff,
0xff, 0xff, 0xf9, 0xd1, 0x7f, 0x30, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x1c, 0x5f, 0xc8, 0xf8, 0xff, 0xff, 0xff,
0xff, 0xf8, 0xd8, 0x7f, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x1e, 0x5f, 0xcc, 0xf4, 0xfe, 0xff, 0xff, 0xff,
0xfa, 0xd6, 0x7f, 0x27, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1a, 0x6a, 0xc9, 0xf4, 0xfd, 0xff, 0xff, 0xff, 0xff,
0xcf, 0x7f, 0x29, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x1e, 0x6b, 0xbe, 0xf8, 0xfe, 0xff, 0xff, 0xff, 0xf9, 0xd0,
0x7f, 0x2f, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x1c, 0x60, 0xc7, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xd7, 0x7f,
0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x1e, 0x5e, 0xcd, 0xf4, 0xfe, 0xff, 0xff, 0xff, 0xf9, 0xd7, 0x80, 0x28,
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x1a, 0x68, 0xcb, 0xf4, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x80, 0x28, 0x07,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x05, 0x1d, 0x6c, 0xbe, 0xf8, 0xfe, 0xff, 0xff, 0xff, 0xfa, 0xcf, 0x7f, 0x2f, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x06, 0x1d, 0x62, 0xc4, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xd6, 0x7f, 0x2f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x04, 0x1e, 0x5e, 0xcd, 0xf4, 0xfe, 0xff, 0xff, 0xff, 0xf9, 0xd8, 0x7f, 0x29, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x1a, 0x68, 0xcd, 0xf4, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xd1, 0x7f, 0x27, 0x07, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1c, 0x6c, 0xbf, 0xf7, 0xfe, 0xff, 0xff, 0xff, 0xfa, 0xce, 0x7f, 0x2d, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x49, 0xb8, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xd5, 0x7f, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x69, 0xc5, 0xf7, 0xff, 0xff, 0xff, 0xf8, 0xd9, 0x7f, 0x2a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1c, 0x79, 0xce, 0xfd, 0xff, 0xff, 0xd2, 0x7f, 0x26, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x2b, 0x77, 0xcd, 0xf3, 0xce, 0x7f, 0x2c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x2a, 0x76, 0xb2, 0x7a, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x04, 0x14, 0x3f, 0x1d, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
const lv_image_dsc_t icon_indicator_right = {
.header.cf = LV_COLOR_FORMAT_RGB565A8,
.header.magic = LV_IMAGE_HEADER_MAGIC,
.header.w = 36,
.header.h = 62,
.data_size = 2232 * 3,
.data = icon_indicator_right_map,
};
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.
+66
View File
@@ -0,0 +1,66 @@
#ifndef _BOARD_CONFIG_H_
#define _BOARD_CONFIG_H_
// M5Stack StackChan Board configuration
#include <driver/gpio.h>
#define AUDIO_INPUT_REFERENCE true
#define AUDIO_INPUT_SAMPLE_RATE 24000
#define AUDIO_OUTPUT_SAMPLE_RATE 24000
#define AUDIO_I2S_GPIO_MCLK GPIO_NUM_0
#define AUDIO_I2S_GPIO_WS GPIO_NUM_33
#define AUDIO_I2S_GPIO_BCLK GPIO_NUM_34
#define AUDIO_I2S_GPIO_DIN GPIO_NUM_14
#define AUDIO_I2S_GPIO_DOUT GPIO_NUM_13
#define AUDIO_CODEC_I2C_SDA_PIN GPIO_NUM_12
#define AUDIO_CODEC_I2C_SCL_PIN GPIO_NUM_11
#define AUDIO_CODEC_AW88298_ADDR AW88298_CODEC_DEFAULT_ADDR
#define AUDIO_CODEC_ES7210_ADDR ES7210_CODEC_DEFAULT_ADDR
#define BUILTIN_LED_GPIO GPIO_NUM_NC
#define BOOT_BUTTON_GPIO GPIO_NUM_0
#define VOLUME_UP_BUTTON_GPIO GPIO_NUM_NC
#define VOLUME_DOWN_BUTTON_GPIO GPIO_NUM_NC
#define DISPLAY_SDA_PIN GPIO_NUM_NC
#define DISPLAY_SCL_PIN GPIO_NUM_NC
#define DISPLAY_WIDTH 320
#define DISPLAY_HEIGHT 240
#define DISPLAY_MIRROR_X false
#define DISPLAY_MIRROR_Y false
#define DISPLAY_SWAP_XY false
#define DISPLAY_OFFSET_X 0
#define DISPLAY_OFFSET_Y 0
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_NC
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT true
/* Camera pins */
#define CAMERA_PIN_PWDN GPIO_NUM_NC
#define CAMERA_PIN_RESET GPIO_NUM_NC
#define CAMERA_PIN_XCLK GPIO_NUM_NC // 像素时钟 (固定由 20MHz 外部晶振输入)
#define CAMERA_PIN_SIOD GPIO_NUM_NC // 串行时钟 Using existing I2C port
#define CAMERA_PIN_SIOC GPIO_NUM_NC // 串行时钟 Using existing I2C port
#define CAMERA_PIN_D0 GPIO_NUM_39
#define CAMERA_PIN_D1 GPIO_NUM_40
#define CAMERA_PIN_D2 GPIO_NUM_41
#define CAMERA_PIN_D3 GPIO_NUM_42
#define CAMERA_PIN_D4 GPIO_NUM_15
#define CAMERA_PIN_D5 GPIO_NUM_16
#define CAMERA_PIN_D6 GPIO_NUM_48
#define CAMERA_PIN_D7 GPIO_NUM_47
#define CAMERA_PIN_VSYNC GPIO_NUM_46
#define CAMERA_PIN_HREF GPIO_NUM_38
#define CAMERA_PIN_PCLK GPIO_NUM_45
#define XCLK_FREQ_HZ 20000000
#endif // _BOARD_CONFIG_H_
@@ -0,0 +1,244 @@
#include "cores3_audio_codec.h"
#include <esp_log.h>
#include <driver/i2c_master.h>
#include <driver/i2s_tdm.h>
#define TAG "CoreS3AudioCodec"
CoreS3AudioCodec::CoreS3AudioCodec(void* i2c_master_handle, int input_sample_rate, int output_sample_rate,
gpio_num_t mclk, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout, gpio_num_t din,
uint8_t aw88298_addr, uint8_t es7210_addr, bool input_reference) {
duplex_ = true; // 是否双工
input_reference_ = input_reference; // 是否使用参考输入,实现回声消除
input_channels_ = input_reference_ ? 2 : 1; // 输入通道数
input_sample_rate_ = input_sample_rate;
output_sample_rate_ = output_sample_rate;
input_gain_ = 30;
CreateDuplexChannels(mclk, bclk, ws, dout, din);
// Do initialize of related interface: data_if, ctrl_if and gpio_if
audio_codec_i2s_cfg_t i2s_cfg = {
.port = I2S_NUM_0,
.rx_handle = rx_handle_,
.tx_handle = tx_handle_,
};
data_if_ = audio_codec_new_i2s_data(&i2s_cfg);
assert(data_if_ != NULL);
// Audio Output(Speaker)
audio_codec_i2c_cfg_t i2c_cfg = {
.port = (i2c_port_t)1,
.addr = aw88298_addr,
.bus_handle = i2c_master_handle,
};
out_ctrl_if_ = audio_codec_new_i2c_ctrl(&i2c_cfg);
assert(out_ctrl_if_ != NULL);
gpio_if_ = audio_codec_new_gpio();
assert(gpio_if_ != NULL);
aw88298_codec_cfg_t aw88298_cfg = {};
aw88298_cfg.ctrl_if = out_ctrl_if_;
aw88298_cfg.gpio_if = gpio_if_;
aw88298_cfg.reset_pin = GPIO_NUM_NC;
aw88298_cfg.hw_gain.pa_voltage = 5.0;
aw88298_cfg.hw_gain.codec_dac_voltage = 3.3;
aw88298_cfg.hw_gain.pa_gain = 1;
out_codec_if_ = aw88298_codec_new(&aw88298_cfg);
assert(out_codec_if_ != NULL);
esp_codec_dev_cfg_t dev_cfg = {
.dev_type = ESP_CODEC_DEV_TYPE_OUT,
.codec_if = out_codec_if_,
.data_if = data_if_,
};
output_dev_ = esp_codec_dev_new(&dev_cfg);
assert(output_dev_ != NULL);
// Audio Input(Microphone)
i2c_cfg.addr = es7210_addr;
in_ctrl_if_ = audio_codec_new_i2c_ctrl(&i2c_cfg);
assert(in_ctrl_if_ != NULL);
es7210_codec_cfg_t es7210_cfg = {};
es7210_cfg.ctrl_if = in_ctrl_if_;
es7210_cfg.mic_selected = ES7210_SEL_MIC1 | ES7210_SEL_MIC2 | ES7210_SEL_MIC3;
in_codec_if_ = es7210_codec_new(&es7210_cfg);
assert(in_codec_if_ != NULL);
dev_cfg.dev_type = ESP_CODEC_DEV_TYPE_IN;
dev_cfg.codec_if = in_codec_if_;
input_dev_ = esp_codec_dev_new(&dev_cfg);
assert(input_dev_ != NULL);
ESP_LOGI(TAG, "CoreS3AudioCodec initialized");
}
CoreS3AudioCodec::~CoreS3AudioCodec() {
ESP_ERROR_CHECK(esp_codec_dev_close(output_dev_));
esp_codec_dev_delete(output_dev_);
ESP_ERROR_CHECK(esp_codec_dev_close(input_dev_));
esp_codec_dev_delete(input_dev_);
audio_codec_delete_codec_if(in_codec_if_);
audio_codec_delete_ctrl_if(in_ctrl_if_);
audio_codec_delete_codec_if(out_codec_if_);
audio_codec_delete_ctrl_if(out_ctrl_if_);
audio_codec_delete_gpio_if(gpio_if_);
audio_codec_delete_data_if(data_if_);
}
void CoreS3AudioCodec::CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout, gpio_num_t din) {
assert(input_sample_rate_ == output_sample_rate_);
ESP_LOGI(TAG, "Audio IOs: mclk: %d, bclk: %d, ws: %d, dout: %d, din: %d", mclk, bclk, ws, dout, din);
i2s_chan_config_t chan_cfg = {
.id = I2S_NUM_0,
.role = I2S_ROLE_MASTER,
.dma_desc_num = AUDIO_CODEC_DMA_DESC_NUM,
.dma_frame_num = AUDIO_CODEC_DMA_FRAME_NUM,
.auto_clear_after_cb = true,
.auto_clear_before_cb = false,
.intr_priority = 0,
};
ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle_, &rx_handle_));
i2s_std_config_t std_cfg = {
.clk_cfg = {
.sample_rate_hz = (uint32_t)output_sample_rate_,
.clk_src = I2S_CLK_SRC_DEFAULT,
.ext_clk_freq_hz = 0,
.mclk_multiple = I2S_MCLK_MULTIPLE_256
},
.slot_cfg = {
.data_bit_width = I2S_DATA_BIT_WIDTH_16BIT,
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO,
.slot_mode = I2S_SLOT_MODE_STEREO,
.slot_mask = I2S_STD_SLOT_BOTH,
.ws_width = I2S_DATA_BIT_WIDTH_16BIT,
.ws_pol = false,
.bit_shift = true,
.left_align = true,
.big_endian = false,
.bit_order_lsb = false
},
.gpio_cfg = {
.mclk = mclk,
.bclk = bclk,
.ws = ws,
.dout = dout,
.din = I2S_GPIO_UNUSED,
.invert_flags = {
.mclk_inv = false,
.bclk_inv = false,
.ws_inv = false
}
}
};
i2s_tdm_config_t tdm_cfg = {
.clk_cfg = {
.sample_rate_hz = (uint32_t)input_sample_rate_,
.clk_src = I2S_CLK_SRC_DEFAULT,
.ext_clk_freq_hz = 0,
.mclk_multiple = I2S_MCLK_MULTIPLE_256,
.bclk_div = 8,
},
.slot_cfg = {
.data_bit_width = I2S_DATA_BIT_WIDTH_16BIT,
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO,
.slot_mode = I2S_SLOT_MODE_STEREO,
.slot_mask = i2s_tdm_slot_mask_t(I2S_TDM_SLOT0 | I2S_TDM_SLOT1 | I2S_TDM_SLOT2 | I2S_TDM_SLOT3),
.ws_width = I2S_TDM_AUTO_WS_WIDTH,
.ws_pol = false,
.bit_shift = true,
.left_align = false,
.big_endian = false,
.bit_order_lsb = false,
.skip_mask = false,
.total_slot = I2S_TDM_AUTO_SLOT_NUM
},
.gpio_cfg = {
.mclk = mclk,
.bclk = bclk,
.ws = ws,
.dout = I2S_GPIO_UNUSED,
.din = din,
.invert_flags = {
.mclk_inv = false,
.bclk_inv = false,
.ws_inv = false
}
}
};
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle_, &std_cfg));
ESP_ERROR_CHECK(i2s_channel_init_tdm_mode(rx_handle_, &tdm_cfg));
ESP_LOGI(TAG, "Duplex channels created");
}
void CoreS3AudioCodec::SetOutputVolume(int volume) {
ESP_ERROR_CHECK(esp_codec_dev_set_out_vol(output_dev_, volume));
AudioCodec::SetOutputVolume(volume);
}
void CoreS3AudioCodec::EnableInput(bool enable) {
if (enable == input_enabled_) {
return;
}
if (enable) {
esp_codec_dev_sample_info_t fs = {
.bits_per_sample = 16,
.channel = 2,
.channel_mask = ESP_CODEC_DEV_MAKE_CHANNEL_MASK(0),
.sample_rate = (uint32_t)output_sample_rate_,
.mclk_multiple = 0,
};
if (input_reference_) {
fs.channel_mask |= ESP_CODEC_DEV_MAKE_CHANNEL_MASK(1);
}
ESP_ERROR_CHECK(esp_codec_dev_open(input_dev_, &fs));
ESP_ERROR_CHECK(esp_codec_dev_set_in_channel_gain(input_dev_, ESP_CODEC_DEV_MAKE_CHANNEL_MASK(0), input_gain_));
} else {
ESP_ERROR_CHECK(esp_codec_dev_close(input_dev_));
}
AudioCodec::EnableInput(enable);
}
void CoreS3AudioCodec::EnableOutput(bool enable) {
if (enable == output_enabled_) {
return;
}
if (enable) {
// Play 16bit 1 channel
esp_codec_dev_sample_info_t fs = {
.bits_per_sample = 16,
.channel = 1,
.channel_mask = 0,
.sample_rate = (uint32_t)output_sample_rate_,
.mclk_multiple = 0,
};
ESP_ERROR_CHECK(esp_codec_dev_open(output_dev_, &fs));
ESP_ERROR_CHECK(esp_codec_dev_set_out_vol(output_dev_, output_volume_));
} else {
ESP_ERROR_CHECK(esp_codec_dev_close(output_dev_));
}
AudioCodec::EnableOutput(enable);
}
int CoreS3AudioCodec::Read(int16_t* dest, int samples) {
if (input_enabled_) {
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_codec_dev_read(input_dev_, (void*)dest, samples * sizeof(int16_t)));
}
return samples;
}
int CoreS3AudioCodec::Write(const int16_t* data, int samples) {
if (output_enabled_) {
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_codec_dev_write(output_dev_, (void*)data, samples * sizeof(int16_t)));
}
return samples;
}
@@ -0,0 +1,37 @@
#ifndef _BOX_AUDIO_CODEC_H
#define _BOX_AUDIO_CODEC_H
#include "audio_codec.h"
#include <esp_codec_dev.h>
#include <esp_codec_dev_defaults.h>
class CoreS3AudioCodec : public AudioCodec {
private:
const audio_codec_data_if_t* data_if_ = nullptr;
const audio_codec_ctrl_if_t* out_ctrl_if_ = nullptr;
const audio_codec_if_t* out_codec_if_ = nullptr;
const audio_codec_ctrl_if_t* in_ctrl_if_ = nullptr;
const audio_codec_if_t* in_codec_if_ = nullptr;
const audio_codec_gpio_if_t* gpio_if_ = nullptr;
esp_codec_dev_handle_t output_dev_ = nullptr;
esp_codec_dev_handle_t input_dev_ = nullptr;
void CreateDuplexChannels(gpio_num_t mclk, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout, gpio_num_t din);
virtual int Read(int16_t* dest, int samples) override;
virtual int Write(const int16_t* data, int samples) override;
public:
CoreS3AudioCodec(void* i2c_master_handle, int input_sample_rate, int output_sample_rate,
gpio_num_t mclk, gpio_num_t bclk, gpio_num_t ws, gpio_num_t dout, gpio_num_t din,
uint8_t aw88298_addr, uint8_t es7210_addr, bool input_reference);
virtual ~CoreS3AudioCodec();
virtual void SetOutputVolume(int volume) override;
virtual void EnableInput(bool enable) override;
virtual void EnableOutput(bool enable) override;
};
#endif // _BOX_AUDIO_CODEC_H
+134
View File
@@ -0,0 +1,134 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "hal_bridge.h"
#include "stackchan_display.h"
#include <esp_log.h>
#include <esp_err.h>
#include <nvs.h>
#include <nvs_flash.h>
#include <driver/gpio.h>
#include <esp_event.h>
#include <application.h>
#include <board.h>
#include <display.h>
#include <mutex>
#include <assets.h>
static const char* _tag = "HAL_BRIDGE";
namespace hal_bridge {
/* -------------------------------------------------------------------------- */
/* State and touch point */
/* -------------------------------------------------------------------------- */
static std::mutex _mutex;
static Data_t _data;
void lock()
{
_mutex.lock();
}
void unlock()
{
_mutex.unlock();
}
Data_t& get_data()
{
return _data;
}
void set_touch_point(int num, int x, int y)
{
std::lock_guard<std::mutex> lock(_mutex);
_data.touchPoint.num = num;
_data.touchPoint.x = x;
_data.touchPoint.y = y;
}
TouchPoint_t get_touch_point()
{
std::lock_guard<std::mutex> lock(_mutex);
return _data.touchPoint;
}
bool is_xiaozhi_mode()
{
std::lock_guard<std::mutex> lock(_mutex);
return _data.isXiaozhiMode;
}
void set_xiaozhi_mode(bool mode)
{
std::lock_guard<std::mutex> lock(_mutex);
_data.isXiaozhiMode = mode;
}
/* -------------------------------------------------------------------------- */
/* Display */
/* -------------------------------------------------------------------------- */
#define DISPLAY_TYPE StackChanAvatarDisplay
lv_disp_t* display_get_lvgl_display()
{
auto display = static_cast<DISPLAY_TYPE*>(Board::GetInstance().GetDisplay());
return display->GetLvglDisplay();
}
void disply_lvgl_lock()
{
auto display = static_cast<DISPLAY_TYPE*>(Board::GetInstance().GetDisplay());
display->LvglLock();
}
void disply_lvgl_unlock()
{
auto display = static_cast<DISPLAY_TYPE*>(Board::GetInstance().GetDisplay());
display->LvglUnlock();
}
void display_setup_xiaozhi_ui()
{
auto display = static_cast<DISPLAY_TYPE*>(Board::GetInstance().GetDisplay());
display->SetupXiaoZhiUI();
}
/* -------------------------------------------------------------------------- */
/* Application */
/* -------------------------------------------------------------------------- */
void xiaozhi_board_init()
{
// Initialize the default event loop
ESP_ERROR_CHECK(esp_event_loop_create_default());
// Init board
auto& board = Board::GetInstance();
// test
board.GetBacklight()->SetBrightness(100);
}
void start_xiaozhi_app()
{
display_setup_xiaozhi_ui();
set_xiaozhi_mode(true);
// Launch the application
auto& app = Application::GetInstance();
app.Start();
}
void app_play_sound(const std::string_view& sound)
{
auto& app = Application::GetInstance();
app.PlaySound(sound);
}
} // namespace hal_bridge
+49
View File
@@ -0,0 +1,49 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "stackchan_camera.h"
#include <lvgl.h>
#include <driver/i2c_master.h>
#include <string_view>
namespace hal_bridge {
struct TouchPoint_t {
int num = 0;
int x = -1;
int y = -1;
};
struct Data_t {
TouchPoint_t touchPoint;
bool isXiaozhiMode = false;
};
void lock();
void unlock();
Data_t& get_data();
void set_touch_point(int num, int x, int y);
TouchPoint_t get_touch_point();
bool is_xiaozhi_mode();
void set_xiaozhi_mode(bool mode);
void disply_lvgl_lock();
void disply_lvgl_unlock();
lv_disp_t* display_get_lvgl_display();
void display_setup_xiaozhi_ui();
void xiaozhi_board_init();
void start_xiaozhi_app();
i2c_master_bus_handle_t board_get_i2c_bus();
StackChanCamera* board_get_camera();
void app_play_sound(const std::string_view& sound);
} // namespace hal_bridge
+497
View File
@@ -0,0 +1,497 @@
#include "wifi_board.h"
#include "cores3_audio_codec.h"
#include "display/lcd_display.h"
#include "stackchan_display.h"
#include "application.h"
#include "config.h"
#include "power_save_timer.h"
#include "i2c_device.h"
#include "axp2101.h"
#include <esp_log.h>
#include <driver/i2c_master.h>
#include <wifi_station.h>
#include <esp_lcd_panel_io.h>
#include <esp_lcd_panel_ops.h>
#include <esp_lcd_ili9341.h>
#include <esp_timer.h>
// #include "esp32_camera.h"
#include "stackchan_camera.h"
#include "hal_bridge.h"
#define TAG "M5Stack-StackChan-Board"
#define XPOWERS_AXP2101_ICC_CHG_SET (0x62)
class Pmic : public Axp2101 {
public:
/**
* @brief axp2101 charge currnet voltage parameters.
*/
typedef enum __xpowers_axp2101_chg_curr {
XPOWERS_AXP2101_CHG_CUR_0MA,
XPOWERS_AXP2101_CHG_CUR_100MA = 4,
XPOWERS_AXP2101_CHG_CUR_125MA,
XPOWERS_AXP2101_CHG_CUR_150MA,
XPOWERS_AXP2101_CHG_CUR_175MA,
XPOWERS_AXP2101_CHG_CUR_200MA,
XPOWERS_AXP2101_CHG_CUR_300MA,
XPOWERS_AXP2101_CHG_CUR_400MA,
XPOWERS_AXP2101_CHG_CUR_500MA,
XPOWERS_AXP2101_CHG_CUR_600MA,
XPOWERS_AXP2101_CHG_CUR_700MA,
XPOWERS_AXP2101_CHG_CUR_800MA,
XPOWERS_AXP2101_CHG_CUR_900MA,
XPOWERS_AXP2101_CHG_CUR_1000MA,
} xpowers_axp2101_chg_curr_t;
// Power Init
Pmic(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : Axp2101(i2c_bus, addr)
{
uint8_t data = ReadReg(0x90);
data |= 0b10110100;
WriteReg(0x90, data);
WriteReg(0x99, (0b11110 - 5));
WriteReg(0x97, (0b11110 - 2));
WriteReg(0x69, 0b00110101);
WriteReg(0x30, 0b111111);
WriteReg(0x90, 0xBF);
WriteReg(0x94, 33 - 5);
WriteReg(0x95, 33 - 5);
auto ret = setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_700MA);
if (!ret) {
ESP_LOGE(TAG, "Set charge current failed");
} else {
ESP_LOGI(TAG, "Set charge current success");
}
}
void SetBrightness(uint8_t brightness)
{
brightness = ((brightness + 641) >> 5);
WriteReg(0x99, brightness);
}
/**
* @brief Set charge current.
* @param opt: See xpowers_axp2101_chg_curr_t enum for details.
* @retval
*/
bool setChargerConstantCurr(uint8_t opt)
{
if (opt > XPOWERS_AXP2101_CHG_CUR_1000MA) {
return false;
}
int val = ReadReg(XPOWERS_AXP2101_ICC_CHG_SET);
if (val == -1) {
return false;
}
val &= 0xE0;
WriteReg(XPOWERS_AXP2101_ICC_CHG_SET, val | opt);
return true;
}
};
class CustomBacklight : public Backlight {
public:
CustomBacklight(Pmic* pmic) : pmic_(pmic)
{
}
void SetBrightnessImpl(uint8_t brightness) override
{
pmic_->SetBrightness(target_brightness_);
brightness_ = target_brightness_;
}
private:
Pmic* pmic_;
};
class Aw9523 : public I2cDevice {
public:
// Exanpd IO Init
Aw9523(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : I2cDevice(i2c_bus, addr)
{
WriteReg(0x02, 0b00000111); // P0
WriteReg(0x03, 0b10001111); // P1
WriteReg(0x04, 0b00011000); // CONFIG_P0
WriteReg(0x05, 0b00001100); // CONFIG_P1
WriteReg(0x11, 0b00010000); // GCR P0 port is Push-Pull mode.
WriteReg(0x12, 0b11111111); // LEDMODE_P0
WriteReg(0x13, 0b11111111); // LEDMODE_P1
}
void ResetAw88298()
{
ESP_LOGI(TAG, "Reset AW88298");
WriteReg(0x02, 0b00000011);
vTaskDelay(pdMS_TO_TICKS(10));
WriteReg(0x02, 0b00000111);
vTaskDelay(pdMS_TO_TICKS(50));
}
void ResetIli9342()
{
ESP_LOGI(TAG, "Reset IlI9342");
WriteReg(0x03, 0b10000001);
vTaskDelay(pdMS_TO_TICKS(20));
WriteReg(0x03, 0b10000011);
vTaskDelay(pdMS_TO_TICKS(10));
}
};
class Ft6336 : public I2cDevice {
public:
struct TouchPoint_t {
int num = 0;
int x = -1;
int y = -1;
};
Ft6336(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : I2cDevice(i2c_bus, addr)
{
uint8_t chip_id = ReadReg(0xA3);
ESP_LOGI(TAG, "Get chip ID: 0x%02X", chip_id);
read_buffer_ = new uint8_t[6];
}
~Ft6336()
{
delete[] read_buffer_;
}
void UpdateTouchPoint()
{
ReadRegs(0x02, read_buffer_, 6);
tp_.num = read_buffer_[0] & 0x0F;
tp_.x = ((read_buffer_[1] & 0x0F) << 8) | read_buffer_[2];
tp_.y = ((read_buffer_[3] & 0x0F) << 8) | read_buffer_[4];
}
inline const TouchPoint_t& GetTouchPoint()
{
return tp_;
}
private:
uint8_t* read_buffer_ = nullptr;
TouchPoint_t tp_;
};
class M5StackCoreS3Board : public WifiBoard {
private:
i2c_master_bus_handle_t i2c_bus_;
Pmic* pmic_;
Aw9523* aw9523_;
Ft6336* ft6336_;
LvglDisplay* display_;
StackChanCamera* camera_;
esp_timer_handle_t touchpad_timer_;
PowerSaveTimer* power_save_timer_;
void InitializePowerSaveTimer()
{
power_save_timer_ = new PowerSaveTimer(-1, 300, 600);
power_save_timer_->OnEnterSleepMode([this]() {
GetDisplay()->SetPowerSaveMode(true);
// GetBacklight()->SetBrightness(10);
});
power_save_timer_->OnExitSleepMode([this]() {
GetDisplay()->SetPowerSaveMode(false);
GetBacklight()->RestoreBrightness();
});
power_save_timer_->OnShutdownRequest([this]() { pmic_->PowerOff(); });
power_save_timer_->SetEnabled(true);
}
void InitializeI2c()
{
// Initialize I2C peripheral
i2c_master_bus_config_t i2c_bus_cfg = {
.i2c_port = (i2c_port_t)1,
.sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
.scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
.clk_source = I2C_CLK_SRC_DEFAULT,
.glitch_ignore_cnt = 7,
.intr_priority = 0,
.trans_queue_depth = 0,
.flags =
{
.enable_internal_pullup = 1,
},
};
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));
}
void I2cDetect()
{
uint8_t address;
printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\r\n");
for (int i = 0; i < 128; i += 16) {
printf("%02x: ", i);
for (int j = 0; j < 16; j++) {
fflush(stdout);
address = i + j;
esp_err_t ret = i2c_master_probe(i2c_bus_, address, pdMS_TO_TICKS(200));
if (ret == ESP_OK) {
printf("%02x ", address);
} else if (ret == ESP_ERR_TIMEOUT) {
printf("UU ");
} else {
printf("-- ");
}
}
printf("\r\n");
}
}
void InitializeAxp2101()
{
ESP_LOGI(TAG, "Init AXP2101");
pmic_ = new Pmic(i2c_bus_, 0x34);
}
void InitializeAw9523()
{
ESP_LOGI(TAG, "Init AW9523");
aw9523_ = new Aw9523(i2c_bus_, 0x58);
vTaskDelay(pdMS_TO_TICKS(50));
}
void PollTouchpad()
{
static bool was_touched = false;
static int64_t touch_start_time = 0;
const int64_t TOUCH_THRESHOLD_MS = 500; // 触摸时长阈值,超过500ms视为长按
ft6336_->UpdateTouchPoint();
auto& touch_point = ft6336_->GetTouchPoint();
if (!hal_bridge::is_xiaozhi_mode()) {
hal_bridge::set_touch_point(touch_point.num, touch_point.x, touch_point.y);
return;
}
// 检测触摸开始
if (touch_point.num > 0 && !was_touched) {
was_touched = true;
touch_start_time = esp_timer_get_time() / 1000; // 转换为毫秒
}
// 检测触摸释放
else if (touch_point.num == 0 && was_touched) {
was_touched = false;
int64_t touch_duration = (esp_timer_get_time() / 1000) - touch_start_time;
// 只有短触才触发
if (touch_duration < TOUCH_THRESHOLD_MS) {
auto& app = Application::GetInstance();
if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
ResetWifiConfiguration();
}
app.ToggleChatState();
}
}
}
void InitializeFt6336TouchPad()
{
ESP_LOGI(TAG, "Init FT6336");
ft6336_ = new Ft6336(i2c_bus_, 0x38);
// 创建定时器,20ms 间隔
esp_timer_create_args_t timer_args = {
.callback =
[](void* arg) {
M5StackCoreS3Board* board = (M5StackCoreS3Board*)arg;
board->PollTouchpad();
},
.arg = this,
.dispatch_method = ESP_TIMER_TASK,
.name = "touchpad_timer",
.skip_unhandled_events = true,
};
ESP_ERROR_CHECK(esp_timer_create(&timer_args, &touchpad_timer_));
ESP_ERROR_CHECK(esp_timer_start_periodic(touchpad_timer_, 20 * 1000));
}
void InitializeSpi()
{
spi_bus_config_t buscfg = {};
buscfg.mosi_io_num = GPIO_NUM_37;
buscfg.miso_io_num = GPIO_NUM_NC;
buscfg.sclk_io_num = GPIO_NUM_36;
buscfg.quadwp_io_num = GPIO_NUM_NC;
buscfg.quadhd_io_num = GPIO_NUM_NC;
buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO));
}
void InitializeIli9342Display()
{
ESP_LOGI(TAG, "Init IlI9342");
esp_lcd_panel_io_handle_t panel_io = nullptr;
esp_lcd_panel_handle_t panel = nullptr;
ESP_LOGD(TAG, "Install panel IO");
esp_lcd_panel_io_spi_config_t io_config = {};
io_config.cs_gpio_num = GPIO_NUM_3;
io_config.dc_gpio_num = GPIO_NUM_35;
io_config.spi_mode = 2;
io_config.pclk_hz = 40 * 1000 * 1000;
io_config.trans_queue_depth = 10;
io_config.lcd_cmd_bits = 8;
io_config.lcd_param_bits = 8;
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI3_HOST, &io_config, &panel_io));
ESP_LOGD(TAG, "Install LCD driver");
esp_lcd_panel_dev_config_t panel_config = {};
panel_config.reset_gpio_num = GPIO_NUM_NC;
panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR;
panel_config.bits_per_pixel = 16;
ESP_ERROR_CHECK(esp_lcd_new_panel_ili9341(panel_io, &panel_config, &panel));
esp_lcd_panel_reset(panel);
aw9523_->ResetIli9342();
esp_lcd_panel_init(panel);
esp_lcd_panel_invert_color(panel, true);
esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY);
esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);
// display_ = new StackChanLcdDisplay(panel_io, panel, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X,
// DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
display_ = new StackChanAvatarDisplay(panel_io, panel, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X,
DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
}
void InitializeCamera()
{
ESP_LOGI(TAG, "Init Camera");
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = {
.data_width = CAM_CTLR_DATA_WIDTH_8,
.data_io =
{
[0] = CAMERA_PIN_D0,
[1] = CAMERA_PIN_D1,
[2] = CAMERA_PIN_D2,
[3] = CAMERA_PIN_D3,
[4] = CAMERA_PIN_D4,
[5] = CAMERA_PIN_D5,
[6] = CAMERA_PIN_D6,
[7] = CAMERA_PIN_D7,
},
.vsync_io = CAMERA_PIN_VSYNC,
.de_io = CAMERA_PIN_HREF,
.pclk_io = CAMERA_PIN_PCLK,
.xclk_io = CAMERA_PIN_XCLK,
};
esp_video_init_sccb_config_t sccb_config = {
.init_sccb = false,
.i2c_handle = i2c_bus_,
.freq = 100000,
};
esp_video_init_dvp_config_t dvp_config = {
.sccb_config = sccb_config,
.reset_pin = CAMERA_PIN_RESET,
.pwdn_pin = CAMERA_PIN_PWDN,
.dvp_pin = dvp_pin_config,
.xclk_freq = XCLK_FREQ_HZ,
};
esp_video_init_config_t video_config = {
.dvp = &dvp_config,
};
camera_ = new StackChanCamera(video_config);
camera_->SetHMirror(false);
}
public:
M5StackCoreS3Board()
{
InitializePowerSaveTimer();
InitializeI2c();
InitializeAxp2101();
InitializeAw9523();
I2cDetect();
InitializeSpi();
InitializeIli9342Display();
InitializeCamera();
InitializeFt6336TouchPad();
GetBacklight()->RestoreBrightness();
}
virtual AudioCodec* GetAudioCodec() override
{
static CoreS3AudioCodec audio_codec(i2c_bus_, AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
AUDIO_I2S_GPIO_MCLK, AUDIO_I2S_GPIO_BCLK, AUDIO_I2S_GPIO_WS,
AUDIO_I2S_GPIO_DOUT, AUDIO_I2S_GPIO_DIN, AUDIO_CODEC_AW88298_ADDR,
AUDIO_CODEC_ES7210_ADDR, AUDIO_INPUT_REFERENCE);
return &audio_codec;
}
virtual Display* GetDisplay() override
{
return display_;
}
virtual Camera* GetCamera() override
{
return camera_;
}
virtual bool GetBatteryLevel(int& level, bool& charging, bool& discharging) override
{
static bool last_discharging = false;
charging = pmic_->IsCharging();
discharging = pmic_->IsDischarging();
if (discharging != last_discharging) {
power_save_timer_->SetEnabled(discharging);
last_discharging = discharging;
}
level = pmic_->GetBatteryLevel();
return true;
}
virtual void SetPowerSaveMode(bool enabled) override
{
if (!enabled) {
power_save_timer_->WakeUp();
}
WifiBoard::SetPowerSaveMode(enabled);
}
virtual Backlight* GetBacklight() override
{
static CustomBacklight backlight(pmic_);
return &backlight;
}
i2c_master_bus_handle_t GetI2cBus()
{
return i2c_bus_;
}
};
DECLARE_BOARD(M5StackCoreS3Board);
i2c_master_bus_handle_t hal_bridge::board_get_i2c_bus()
{
auto& board = (M5StackCoreS3Board&)Board::GetInstance();
return board.GetI2cBus();
}
StackChanCamera* hal_bridge::board_get_camera()
{
auto& board = Board::GetInstance();
auto camera = (StackChanCamera*)board.GetCamera();
return camera;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,82 @@
#pragma once
#include "sdkconfig.h"
#ifndef CONFIG_IDF_TARGET_ESP32
#include <lvgl.h>
#include <thread>
#include <memory>
#include <vector>
#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
#include "camera.h"
#include "jpg/image_to_jpeg.h"
#include "esp_video_init.h"
struct JpegChunk {
uint8_t* data;
size_t len;
};
class StackChanCamera : public Camera {
private:
struct FrameBuffer {
uint8_t* data = nullptr;
size_t len = 0;
uint16_t width = 0;
uint16_t height = 0;
v4l2_pix_fmt_t format = 0;
} frame_;
v4l2_pix_fmt_t sensor_format_ = 0;
#ifdef CONFIG_XIAOZHI_ENABLE_ROTATE_CAMERA_IMAGE
uint16_t sensor_width_ = 0;
uint16_t sensor_height_ = 0;
#endif // CONFIG_XIAOZHI_ENABLE_ROTATE_CAMERA_IMAGE
int video_fd_ = -1;
bool streaming_on_ = false;
struct MmapBuffer {
void* start = nullptr;
size_t length = 0;
};
std::vector<MmapBuffer> mmap_buffers_;
std::string explain_url_;
std::string explain_token_;
std::thread encoder_thread_;
public:
StackChanCamera(const esp_video_init_config_t& config);
~StackChanCamera();
virtual void SetExplainUrl(const std::string& url, const std::string& token);
virtual bool Capture() override;
bool StreamCaptures();
// 翻转控制函数
virtual bool SetHMirror(bool enabled) override;
virtual bool SetVFlip(bool enabled) override;
virtual std::string Explain(const std::string& question);
const uint8_t* GetFrameData()
{
return frame_.data;
}
size_t GetFrameSize()
{
return frame_.len;
}
int GetFrameWidth()
{
return frame_.width;
}
int GetFrameHeight()
{
return frame_.height;
}
int GetFrameFormat()
{
return frame_.format;
}
};
#endif // ndef CONFIG_IDF_TARGET_ESP32
@@ -0,0 +1,462 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "stackchan_display.h"
#include <esp_log.h>
#include <esp_err.h>
#include <esp_lvgl_port.h>
#include <esp_psram.h>
#include <vector>
#include <cstring>
#include <settings.h>
#include <lvgl.h>
#include <lvgl_theme.h>
#include <stackchan/stackchan.h>
#include <assets/lang_config.h>
#include <hal/hal.h>
using namespace stackchan;
using namespace stackchan::avatar;
#define TAG "StackChanAvatarDisplay"
LV_FONT_DECLARE(BUILTIN_TEXT_FONT);
LV_FONT_DECLARE(BUILTIN_ICON_FONT);
LV_FONT_DECLARE(font_awesome_30_4);
// Have to register themes, so the asset apply can update the text font
void StackChanAvatarDisplay::InitializeLcdThemes()
{
auto text_font = std::make_shared<LvglBuiltInFont>(&BUILTIN_TEXT_FONT);
auto icon_font = std::make_shared<LvglBuiltInFont>(&BUILTIN_ICON_FONT);
auto large_icon_font = std::make_shared<LvglBuiltInFont>(&font_awesome_30_4);
// light theme
auto light_theme = new LvglTheme("light");
light_theme->set_background_color(lv_color_hex(0xFFFFFF)); // rgb(255, 255, 255)
light_theme->set_text_color(lv_color_hex(0x000000)); // rgb(0, 0, 0)
light_theme->set_chat_background_color(lv_color_hex(0xE0E0E0)); // rgb(224, 224, 224)
light_theme->set_user_bubble_color(lv_color_hex(0x00FF00)); // rgb(0, 128, 0)
light_theme->set_assistant_bubble_color(lv_color_hex(0xDDDDDD)); // rgb(221, 221, 221)
light_theme->set_system_bubble_color(lv_color_hex(0xFFFFFF)); // rgb(255, 255, 255)
light_theme->set_system_text_color(lv_color_hex(0x000000)); // rgb(0, 0, 0)
light_theme->set_border_color(lv_color_hex(0x000000)); // rgb(0, 0, 0)
light_theme->set_low_battery_color(lv_color_hex(0x000000)); // rgb(0, 0, 0)
light_theme->set_text_font(text_font);
light_theme->set_icon_font(icon_font);
light_theme->set_large_icon_font(large_icon_font);
// dark theme
auto dark_theme = new LvglTheme("dark");
dark_theme->set_background_color(lv_color_hex(0x000000)); // rgb(0, 0, 0)
dark_theme->set_text_color(lv_color_hex(0xFFFFFF)); // rgb(255, 255, 255)
dark_theme->set_chat_background_color(lv_color_hex(0x1F1F1F)); // rgb(31, 31, 31)
dark_theme->set_user_bubble_color(lv_color_hex(0x00FF00)); // rgb(0, 128, 0)
dark_theme->set_assistant_bubble_color(lv_color_hex(0x222222)); // rgb(34, 34, 34)
dark_theme->set_system_bubble_color(lv_color_hex(0x000000)); // rgb(0, 0, 0)
dark_theme->set_system_text_color(lv_color_hex(0xFFFFFF)); // rgb(255, 255, 255)
dark_theme->set_border_color(lv_color_hex(0xFFFFFF)); // rgb(255, 255, 255)
dark_theme->set_low_battery_color(lv_color_hex(0xFF0000)); // rgb(255, 0, 0)
dark_theme->set_text_font(text_font);
dark_theme->set_icon_font(icon_font);
dark_theme->set_large_icon_font(large_icon_font);
auto& theme_manager = LvglThemeManager::GetInstance();
theme_manager.RegisterTheme("light", light_theme);
theme_manager.RegisterTheme("dark", dark_theme);
}
StackChanAvatarDisplay::StackChanAvatarDisplay(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_handle_t panel,
int width, int height, int offset_x, int offset_y, bool mirror_x,
bool mirror_y, bool swap_xy)
: LvglDisplay(), panel_io_(panel_io), panel_(panel)
{
width_ = width;
height_ = height;
// Initialize LCD themes
InitializeLcdThemes();
// Load theme from settings
Settings settings("display", false);
std::string theme_name = settings.GetString("theme", "light");
current_theme_ = LvglThemeManager::GetInstance().GetTheme(theme_name);
// Draw white screen
std::vector<uint16_t> buffer(width_, 0xFFFF);
for (int y = 0; y < height_; y++) {
esp_lcd_panel_draw_bitmap(panel_, 0, y, width_, y + 1, buffer.data());
}
// Set the display to on
ESP_LOGI(TAG, "Turning display on");
{
esp_err_t __err = esp_lcd_panel_disp_on_off(panel_, true);
if (__err == ESP_ERR_NOT_SUPPORTED) {
ESP_LOGW(TAG, "Panel does not support disp_on_off; assuming ON");
} else {
ESP_ERROR_CHECK(__err);
}
}
ESP_LOGI(TAG, "Initialize LVGL library");
lv_init();
#if CONFIG_SPIRAM
// lv image cache, currently only PNG is supported
size_t psram_size_mb = esp_psram_get_size() / 1024 / 1024;
if (psram_size_mb >= 8) {
lv_image_cache_resize(2 * 1024 * 1024, true);
ESP_LOGI(TAG, "Use 2MB of PSRAM for image cache");
} else if (psram_size_mb >= 2) {
lv_image_cache_resize(512 * 1024, true);
ESP_LOGI(TAG, "Use 512KB of PSRAM for image cache");
}
#endif
ESP_LOGI(TAG, "Initialize LVGL port");
lvgl_port_cfg_t port_cfg = ESP_LVGL_PORT_INIT_CONFIG();
port_cfg.task_priority = 20;
#if CONFIG_SOC_CPU_CORES_NUM > 1
port_cfg.task_affinity = 1;
#endif
lvgl_port_init(&port_cfg);
ESP_LOGI(TAG, "Adding LCD display");
const lvgl_port_display_cfg_t display_cfg = {
.io_handle = panel_io_,
.panel_handle = panel_,
.control_handle = nullptr,
.buffer_size = static_cast<uint32_t>(width_ * 20),
.double_buffer = true,
.trans_size = 0,
.hres = static_cast<uint32_t>(width_),
.vres = static_cast<uint32_t>(height_),
.monochrome = false,
.rotation =
{
.swap_xy = swap_xy,
.mirror_x = mirror_x,
.mirror_y = mirror_y,
},
.color_format = LV_COLOR_FORMAT_RGB565,
.flags =
{
.buff_dma = 1,
.buff_spiram = 0,
.sw_rotate = 0,
.swap_bytes = 1,
.full_refresh = 0,
.direct_mode = 0,
},
};
display_ = lvgl_port_add_disp(&display_cfg);
if (display_ == nullptr) {
ESP_LOGE(TAG, "Failed to add display");
return;
}
if (offset_x != 0 || offset_y != 0) {
lv_display_set_offset(display_, offset_x, offset_y);
}
// Create a timer to hide the preview image
esp_timer_create_args_t preview_timer_args = {
.callback =
[](void* arg) {
StackChanAvatarDisplay* display = static_cast<StackChanAvatarDisplay*>(arg);
display->SetPreviewImage(nullptr);
},
.arg = this,
.dispatch_method = ESP_TIMER_TASK,
.name = "preview_timer",
.skip_unhandled_events = false,
};
esp_timer_create(&preview_timer_args, &preview_timer_);
// Robot will be created later in SetupXiaoZhiUI()
}
StackChanAvatarDisplay::~StackChanAvatarDisplay()
{
ESP_LOGI(TAG, "Destroying StackChanAvatarDisplay");
if (preview_timer_ != nullptr) {
esp_timer_stop(preview_timer_);
esp_timer_delete(preview_timer_);
}
if (preview_image_ != nullptr) {
lv_obj_del(preview_image_);
}
auto& stackchan = GetStackChan();
if (stackchan.hasAvatar()) {
stackchan.resetAvatar();
}
}
bool StackChanAvatarDisplay::Lock(int timeout_ms)
{
return lvgl_port_lock(timeout_ms);
}
void StackChanAvatarDisplay::Unlock()
{
lvgl_port_unlock();
}
lv_disp_t* StackChanAvatarDisplay::GetLvglDisplay()
{
return display_;
}
void StackChanAvatarDisplay::SetupXiaoZhiUI()
{
auto& stackchan = GetStackChan();
if (stackchan.hasAvatar()) {
ESP_LOGW(TAG, "Avatar already created");
return;
}
DisplayLockGuard lock(this);
ESP_LOGI(TAG, "Creating Stack-chan Avatar...");
auto avatar = std::make_unique<DefaultAvatar>();
avatar->init(lv_screen_active());
stackchan.attachAvatar(std::move(avatar));
stackchan.addModifier(std::make_unique<BreathModifier>());
blink_modifier_id_ = stackchan.addModifier(std::make_unique<BlinkModifier>());
stackchan.addModifier(std::make_unique<HeadPetModifier>());
// stackchan.addModifier(std::make_unique<IMUMotionModifier>());
preview_image_ = lv_image_create(lv_screen_active());
lv_obj_set_size(preview_image_, 192, 144);
lv_obj_align(preview_image_, LV_ALIGN_CENTER, 0, -25);
lv_obj_add_flag(preview_image_, LV_OBJ_FLAG_HIDDEN);
GetHAL().startStackChanAutoUpdate(24);
ESP_LOGI(TAG, "Avatar created and started");
}
void StackChanAvatarDisplay::LvglLock()
{
if (!Lock(30000)) {
ESP_LOGE("Display", "Failed to lock display");
}
}
void StackChanAvatarDisplay::LvglUnlock()
{
Unlock();
}
void StackChanAvatarDisplay::SetEmotion(const char* emotion)
{
auto& stackchan = GetStackChan();
if (!stackchan.hasAvatar() || !emotion) {
return;
}
DisplayLockGuard lock(this);
ESP_LOGE(TAG, "SetEmotion: %s", emotion);
auto& avatar = stackchan.avatar();
// Map emotion string to stackchan::Emotion
if (strcmp(emotion, "neutral") == 0) {
avatar.setEmotion(Emotion::Neutral);
} else if (strcmp(emotion, "happy") == 0) {
avatar.setEmotion(Emotion::Happy);
} else if (strcmp(emotion, "laughing") == 0) {
avatar.setEmotion(Emotion::Happy);
} else if (strcmp(emotion, "angry") == 0) {
avatar.setEmotion(Emotion::Angry);
} else if (strcmp(emotion, "sad") == 0) {
avatar.setEmotion(Emotion::Sad);
} else if (strcmp(emotion, "crying") == 0) {
avatar.setEmotion(Emotion::Sad);
} else if (strcmp(emotion, "sleepy") == 0) {
avatar.setEmotion(Emotion::Sleepy);
avatar.setSpeech("Zzz…");
is_sleeping_ = true;
// avatar.mouth().setWeight(10);
// Stop idle motion
ESP_LOGW(TAG, "Stop idle motion");
if (idle_motion_modifier_id_ >= 0) {
stackchan.removeModifier(idle_motion_modifier_id_);
idle_motion_modifier_id_ = -1;
}
// Return to default pose
auto& motion = GetStackChan().motion();
motion.pitchServo().moveWithSpeed(0, 80);
} else if (strcmp(emotion, "doubtful") == 0) {
avatar.setEmotion(Emotion::Doubt);
} else {
ESP_LOGW(TAG, "Unknown emotion: %s, using NEUTRAL", emotion);
avatar.setEmotion(Emotion::Neutral);
}
// Resync blink modifier base eye weights
auto blink_modifier = static_cast<BlinkModifier*>(stackchan.getModifier(blink_modifier_id_));
if (blink_modifier) {
blink_modifier->resyncEyeWeights();
}
}
void StackChanAvatarDisplay::SetChatMessage(const char* role, const char* content)
{
auto& stackchan = GetStackChan();
if (!stackchan.hasAvatar()) {
return;
}
ESP_LOGE(TAG, "SetChatMessage: role=%s, content=%s", role ? role : "null", content ? content : "null");
DisplayLockGuard lock(this);
if (strcmp(role, "system") == 0) {
stackchan.avatar().setSpeech(content);
} else if (strcmp(role, "assistant") == 0) {
stackchan.avatar().setSpeech(content);
}
}
void StackChanAvatarDisplay::SetPreviewImage(std::unique_ptr<LvglImage> image)
{
DisplayLockGuard lock(this);
if (preview_image_ == nullptr) {
return;
}
if (image == nullptr) {
esp_timer_stop(preview_timer_);
lv_obj_add_flag(preview_image_, LV_OBJ_FLAG_HIDDEN);
preview_image_cached_.reset();
return;
}
preview_image_cached_ = std::move(image);
auto img_dsc = preview_image_cached_->image_dsc();
// Set image source and show preview image
lv_image_set_src(preview_image_, img_dsc);
if (img_dsc->header.w > 0 && img_dsc->header.h > 0) {
// Scale to fit width
lv_image_set_scale(preview_image_, 256 * width_ / img_dsc->header.w);
}
lv_obj_remove_flag(preview_image_, LV_OBJ_FLAG_HIDDEN);
lv_obj_move_foreground(preview_image_);
esp_timer_stop(preview_timer_);
ESP_ERROR_CHECK(esp_timer_start_once(preview_timer_, 6000 * 1000));
}
void StackChanAvatarDisplay::SetTheme(Theme* theme)
{
ESP_LOGI(TAG, "SetTheme: %s", theme->name().c_str());
auto& stackchan = GetStackChan();
if (!stackchan.hasAvatar()) {
ESP_LOGE(TAG, "Avatar is invalid");
return;
}
DisplayLockGuard lock(this);
auto lvgl_theme = static_cast<LvglTheme*>(theme);
auto text_font = lvgl_theme->text_font()->font();
stackchan.avatar().setSpeechTextFont((void*)text_font);
}
void StackChanAvatarDisplay::SetStatus(const char* status)
{
ESP_LOGE(TAG, "SetStatus: %s", status);
LvglDisplay::SetStatus(status);
auto& stackchan = GetStackChan();
if (!stackchan.hasAvatar()) {
ESP_LOGE(TAG, "Avatar is invalid");
return;
}
auto& avatar = stackchan.avatar();
auto& motion = stackchan.motion();
DisplayLockGuard lock(this);
bool is_idle = false;
bool is_listening = false;
if (strcmp(status, Lang::Strings::LISTENING) == 0) {
if (speaking_modifier_id_ >= 0) {
// Start speaking
stackchan.removeModifier(speaking_modifier_id_);
avatar.mouth().setWeight(0);
speaking_modifier_id_ = -1;
}
GetHAL().setRgbColor(0, 0, 50, 0);
GetHAL().refreshRgb();
} else if (strcmp(status, Lang::Strings::STANDBY) == 0) {
if (speaking_modifier_id_ >= 0) {
// Stop speaking
stackchan.removeModifier(speaking_modifier_id_);
avatar.mouth().setWeight(0);
speaking_modifier_id_ = -1;
}
is_idle = true;
GetHAL().setRgbColor(0, 0, 0, 0);
GetHAL().refreshRgb();
} else if (strcmp(status, Lang::Strings::SPEAKING) == 0) {
if (speaking_modifier_id_ < 0) {
speaking_modifier_id_ = stackchan.addModifier(std::make_unique<SpeakingModifier>());
}
GetHAL().setRgbColor(0, 0, 0, 50);
GetHAL().refreshRgb();
}
if (is_idle) {
// Start idle motion
ESP_LOGW(TAG, "Start idle motion");
if (idle_motion_modifier_id_ < 0) {
idle_motion_modifier_id_ = stackchan.addModifier(std::make_unique<IdleMotionModifier>());
}
} else {
// Stop idle motion
ESP_LOGW(TAG, "Stop idle motion");
if (idle_motion_modifier_id_ >= 0) {
stackchan.removeModifier(idle_motion_modifier_id_);
idle_motion_modifier_id_ = -1;
}
// if (!is_listening) {
// // Return to default pose
// motion.pitchServo().moveWithSpeed(200, 350);
// motion.yawServo().moveWithSpeed(0, 350);
// }
}
// Clear sleep state
if (is_sleeping_) {
avatar.setSpeech("");
}
}
@@ -0,0 +1,48 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <display/lvgl_display/lvgl_display.h>
#include <esp_lcd_panel_io.h>
#include <esp_lcd_panel_ops.h>
#include <esp_timer.h>
#include <memory>
class StackChanAvatarDisplay : public LvglDisplay {
private:
esp_lcd_panel_io_handle_t panel_io_ = nullptr;
esp_lcd_panel_handle_t panel_ = nullptr;
int speaking_modifier_id_ = -1;
int idle_motion_modifier_id_ = -1;
int blink_modifier_id_ = -1;
bool is_sleeping_ = false;
lv_obj_t* preview_image_ = nullptr;
esp_timer_handle_t preview_timer_ = nullptr;
std::unique_ptr<LvglImage> preview_image_cached_ = nullptr;
protected:
virtual bool Lock(int timeout_ms = 0) override;
virtual void Unlock() override;
public:
StackChanAvatarDisplay(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_handle_t panel, int width, int height,
int offset_x, int offset_y, bool mirror_x, bool mirror_y, bool swap_xy);
virtual ~StackChanAvatarDisplay();
void InitializeLcdThemes();
// Override Display methods to control Robot
virtual void SetEmotion(const char* emotion) override;
virtual void SetChatMessage(const char* role, const char* content) override;
virtual void SetPreviewImage(std::unique_ptr<LvglImage> image) override;
virtual void SetTheme(Theme* theme) override;
virtual void SetStatus(const char* status) override;
void SetupXiaoZhiUI();
void LvglLock();
void LvglUnlock();
lv_disp_t* GetLvglDisplay();
};
@@ -0,0 +1,358 @@
#include "PY32IOExpander_Class.hpp"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <cstring>
static const char* TAG = "PY32IOExpander";
namespace m5 {
// Register definitions
static constexpr uint8_t REG_UID_L = 0x00;
static constexpr uint8_t REG_UID_H = 0x01;
static constexpr uint8_t REG_VERSION = 0x02;
static constexpr uint8_t REG_GPIO_M_L = 0x03;
static constexpr uint8_t REG_GPIO_M_H = 0x04;
static constexpr uint8_t REG_GPIO_O_L = 0x05;
static constexpr uint8_t REG_GPIO_O_H = 0x06;
static constexpr uint8_t REG_GPIO_I_L = 0x07;
static constexpr uint8_t REG_GPIO_I_H = 0x08;
static constexpr uint8_t REG_GPIO_PU_L = 0x09;
static constexpr uint8_t REG_GPIO_PU_H = 0x0A;
static constexpr uint8_t REG_GPIO_PD_L = 0x0B;
static constexpr uint8_t REG_GPIO_PD_H = 0x0C;
static constexpr uint8_t REG_GPIO_IE_L = 0x0D;
static constexpr uint8_t REG_GPIO_IE_H = 0x0E;
static constexpr uint8_t REG_GPIO_IT_L = 0x0F;
static constexpr uint8_t REG_GPIO_IT_H = 0x10;
static constexpr uint8_t REG_GPIO_IS_L = 0x11;
static constexpr uint8_t REG_GPIO_IS_H = 0x12;
static constexpr uint8_t REG_GPIO_DRV_L = 0x13;
static constexpr uint8_t REG_GPIO_DRV_H = 0x14;
static constexpr uint8_t REG_ADC_CTRL = 0x15;
static constexpr uint8_t REG_ADC_D_L = 0x16;
static constexpr uint8_t REG_ADC_D_H = 0x17;
static constexpr uint8_t REG_PWM_FREQ_L = 0x25;
static constexpr uint8_t REG_PWM_FREQ_H = 0x26;
static constexpr uint8_t REG_LED_CFG = 0x24;
static constexpr uint8_t REG_LED_RAM_START = 0x30;
// PWM Duty Registers
static constexpr uint8_t REG_PWM1_DUTY_L = 0x1B;
static constexpr uint8_t REG_PWM1_DUTY_H = 0x1C;
static constexpr uint8_t REG_PWM2_DUTY_L = 0x1D;
static constexpr uint8_t REG_PWM2_DUTY_H = 0x1E;
static constexpr uint8_t REG_PWM3_DUTY_L = 0x1F;
static constexpr uint8_t REG_PWM3_DUTY_H = 0x20;
static constexpr uint8_t REG_PWM4_DUTY_L = 0x21;
static constexpr uint8_t REG_PWM4_DUTY_H = 0x22;
PY32IOExpander_Class::PY32IOExpander_Class(i2c_master_bus_handle_t i2c_bus_handle, uint8_t addr)
: _addr(addr), _initialized(false)
{
i2c_device_config_t dev_cfg = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = _addr,
.scl_speed_hz = 100000,
};
ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c_bus_handle, &dev_cfg, &_i2c_dev));
}
PY32IOExpander_Class::~PY32IOExpander_Class()
{
if (_i2c_dev) {
i2c_master_bus_rm_device(_i2c_dev);
}
}
esp_err_t PY32IOExpander_Class::writeRegister8(uint8_t reg, uint8_t value)
{
uint8_t buf[2] = {reg, value};
return i2c_master_transmit(_i2c_dev, buf, sizeof(buf), 1000);
}
uint8_t PY32IOExpander_Class::readRegister8(uint8_t reg)
{
uint8_t val = 0;
esp_err_t err = i2c_master_transmit_receive(_i2c_dev, &reg, 1, &val, 1, 1000);
if (err != ESP_OK) {
ESP_LOGE(TAG, "readRegister8 failed: %s", esp_err_to_name(err));
return 0;
}
return val;
}
esp_err_t PY32IOExpander_Class::writeRegister(uint8_t reg, const uint8_t* data, size_t len)
{
if (len == 0) return ESP_OK;
// Allocate buffer for reg + data
uint8_t* buf = (uint8_t*)malloc(len + 1);
if (!buf) return ESP_ERR_NO_MEM;
buf[0] = reg;
memcpy(buf + 1, data, len);
esp_err_t err = i2c_master_transmit(_i2c_dev, buf, len + 1, 1000);
free(buf);
return err;
}
esp_err_t PY32IOExpander_Class::readRegister(uint8_t reg, uint8_t* data, size_t len)
{
return i2c_master_transmit_receive(_i2c_dev, &reg, 1, data, len, 1000);
}
esp_err_t PY32IOExpander_Class::bitOn(uint8_t reg, uint8_t mask)
{
uint8_t val = readRegister8(reg);
val |= mask;
return writeRegister8(reg, val);
}
esp_err_t PY32IOExpander_Class::bitOff(uint8_t reg, uint8_t mask)
{
uint8_t val = readRegister8(reg);
val &= ~mask;
return writeRegister8(reg, val);
}
void PY32IOExpander_Class::_writeBit(uint8_t reg_l, uint8_t reg_h, uint8_t pin, bool value)
{
if (pin < 8) {
if (value)
bitOn(reg_l, 1 << pin);
else
bitOff(reg_l, 1 << pin);
} else {
if (value)
bitOn(reg_h, 1 << (pin - 8));
else
bitOff(reg_h, 1 << (pin - 8));
}
}
bool PY32IOExpander_Class::_readBit(uint8_t reg_l, uint8_t reg_h, uint8_t pin)
{
if (pin < 8) {
return (readRegister8(reg_l) & (1 << pin)) != 0;
} else {
return (readRegister8(reg_h) & (1 << (pin - 8))) != 0;
}
}
bool PY32IOExpander_Class::begin()
{
uint8_t version = readRegister8(REG_VERSION);
if (version == 0 || version == 0xFF) {
ESP_LOGE(TAG, "Invalid version: 0x%02X", version);
return false;
}
ESP_LOGI(TAG, "Version: 0x%02X", version);
_initialized = true;
return true;
}
void PY32IOExpander_Class::setDirection(uint8_t pin, bool direction)
{
// direction: false=input (0), true=output (1)
_writeBit(REG_GPIO_M_L, REG_GPIO_M_H, pin, direction);
}
void PY32IOExpander_Class::enablePull(uint8_t pin, bool enablePull)
{
if (enablePull) {
// Enable Pull Up by default if neither is set
bool pu = _readBit(REG_GPIO_PU_L, REG_GPIO_PU_H, pin);
bool pd = _readBit(REG_GPIO_PD_L, REG_GPIO_PD_H, pin);
if (!pu && !pd) {
_writeBit(REG_GPIO_PU_L, REG_GPIO_PU_H, pin, true);
}
// If one is already set, leave it.
} else {
// Disable both
_writeBit(REG_GPIO_PU_L, REG_GPIO_PU_H, pin, false);
_writeBit(REG_GPIO_PD_L, REG_GPIO_PD_H, pin, false);
}
}
void PY32IOExpander_Class::setPullMode(uint8_t pin, bool mode)
{
// mode: false=down, true=up
if (mode) {
// Pull Up
_writeBit(REG_GPIO_PD_L, REG_GPIO_PD_H, pin, false);
_writeBit(REG_GPIO_PU_L, REG_GPIO_PU_H, pin, true);
} else {
// Pull Down
_writeBit(REG_GPIO_PU_L, REG_GPIO_PU_H, pin, false);
_writeBit(REG_GPIO_PD_L, REG_GPIO_PD_H, pin, true);
}
}
void PY32IOExpander_Class::setDriveMode(uint8_t pin, bool openDrain)
{
// openDrain: false=push-pull (0), true=open-drain (1)
_writeBit(REG_GPIO_DRV_L, REG_GPIO_DRV_H, pin, openDrain);
}
void PY32IOExpander_Class::setHighImpedance(uint8_t pin, bool enable)
{
if (enable) {
// Input mode
setDirection(pin, false);
// Disable pulls
enablePull(pin, false);
}
}
bool PY32IOExpander_Class::getWriteValue(uint8_t pin)
{
return _readBit(REG_GPIO_O_L, REG_GPIO_O_H, pin);
}
void PY32IOExpander_Class::digitalWrite(uint8_t pin, bool level)
{
_writeBit(REG_GPIO_O_L, REG_GPIO_O_H, pin, level);
}
bool PY32IOExpander_Class::digitalRead(uint8_t pin)
{
return _readBit(REG_GPIO_I_L, REG_GPIO_I_H, pin);
}
void PY32IOExpander_Class::resetIrq()
{
// Clear all interrupts by writing 1s to IS registers
writeRegister8(REG_GPIO_IS_L, 0xFF);
writeRegister8(REG_GPIO_IS_H, 0xFF); // Only bits 0-5 used for high byte (pins 8-13)
}
void PY32IOExpander_Class::disableIrq()
{
// Disable all interrupts
writeRegister8(REG_GPIO_IE_L, 0x00);
writeRegister8(REG_GPIO_IE_H, 0x00);
}
void PY32IOExpander_Class::enableIrq()
{
// Enable all interrupts
writeRegister8(REG_GPIO_IE_L, 0xFF);
writeRegister8(REG_GPIO_IE_H, 0x3F); // Pins 8-13
}
uint16_t PY32IOExpander_Class::readDeviceUID()
{
uint8_t l = readRegister8(REG_UID_L);
uint8_t h = readRegister8(REG_UID_H);
return (h << 8) | l;
}
uint8_t PY32IOExpander_Class::readVersion()
{
return readRegister8(REG_VERSION);
}
uint16_t PY32IOExpander_Class::analogRead(uint8_t channel)
{
if (channel < 1 || channel > 4) return 0;
// Start conversion
// REG_ADC_CTRL: [7:Busy] [6:Start] [2:0:Channel]
// Channel mapping: 1->1, 2->2, 3->3, 4->4
writeRegister8(REG_ADC_CTRL, (1 << 6) | (channel & 0x07));
// Wait for busy bit to clear
// Simple polling with timeout
for (int i = 0; i < 100; i++) {
uint8_t ctrl = readRegister8(REG_ADC_CTRL);
if (!(ctrl & (1 << 7))) {
break;
}
vTaskDelay(pdMS_TO_TICKS(1));
}
uint8_t l = readRegister8(REG_ADC_D_L);
uint8_t h = readRegister8(REG_ADC_D_H);
return (h << 8) | l;
}
void PY32IOExpander_Class::setPwmDuty(uint8_t channel, uint8_t duty)
{
if (channel > 3) return;
// Calculate register address
// Channel 0 -> PWM1 (0x1B)
// Channel 1 -> PWM2 (0x1D)
// Channel 2 -> PWM3 (0x1F)
// Channel 3 -> PWM4 (0x21)
uint8_t reg_l = REG_PWM1_DUTY_L + (channel * 2);
uint8_t reg_h = reg_l + 1;
// Duty is 8-bit percentage (0-100)? Or 0-255?
// m5_io_py32ioexpander uses percentage (0-100) or 12-bit raw.
// Let's assume 0-255 for standard Arduino style, but map to 12-bit (0-4095).
// 255 -> 4095. val * 4095 / 255 = val * 16 approx.
uint16_t duty12 = (uint16_t)duty * 16;
if (duty12 > 4095) duty12 = 4095;
// High byte contains Enable(7) and Polarity(6) bits.
// We need to preserve them or set defaults.
// Let's enable by default, polarity normal (0).
uint8_t h_val = (duty12 >> 8) & 0x0F;
h_val |= (1 << 7); // Enable
writeRegister8(reg_l, duty12 & 0xFF);
writeRegister8(reg_h, h_val);
}
void PY32IOExpander_Class::setPwmFrequency(uint16_t freq)
{
writeRegister8(REG_PWM_FREQ_L, freq & 0xFF);
writeRegister8(REG_PWM_FREQ_H, (freq >> 8) & 0xFF);
}
void PY32IOExpander_Class::setLedCount(uint8_t count)
{
if (count > 32) count = 32;
writeRegister8(REG_LED_CFG, count & 0x3F);
}
void PY32IOExpander_Class::setLedColor(uint8_t index, uint16_t color565)
{
if (index >= 32) return;
uint8_t data[2] = {(uint8_t)(color565 & 0xFF), (uint8_t)((color565 >> 8) & 0xFF)};
writeRegister(REG_LED_RAM_START + index * 2, data, 2);
}
void PY32IOExpander_Class::setLedColor(uint8_t index, uint8_t r, uint8_t g, uint8_t b)
{
// RGB888 to RGB565: RRRRRGGG GGGBBBBB
uint16_t val = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
setLedColor(index, val);
}
void PY32IOExpander_Class::setLedColor(uint8_t index, uint32_t color)
{
setLedColor(index, (uint8_t)((color >> 16) & 0xFF), (uint8_t)((color >> 8) & 0xFF), (uint8_t)(color & 0xFF));
}
void PY32IOExpander_Class::setLedData(const uint8_t* data, size_t len)
{
if (!data || len == 0) return;
if (len > 64) len = 64; // Max 32 LEDs * 2 bytes
writeRegister(REG_LED_RAM_START, data, len);
}
void PY32IOExpander_Class::refreshLeds()
{
uint8_t val = readRegister8(REG_LED_CFG);
writeRegister8(REG_LED_CFG, val | (1 << 6));
}
} // namespace m5
@@ -0,0 +1,88 @@
#pragma once
#include <cstdint>
#include "driver/i2c_master.h"
#include "esp_err.h"
namespace m5 {
class PY32IOExpander_Class {
public:
static constexpr uint8_t DEFAULT_ADDRESS = 0x6F;
PY32IOExpander_Class(i2c_master_bus_handle_t i2c_bus_handle, uint8_t addr = DEFAULT_ADDRESS);
~PY32IOExpander_Class();
/**
* @brief Initialize the device
*
* @return true if successful
* @return false if failed
*/
bool begin();
// IOExpander methods
// false input, true output
void setDirection(uint8_t pin, bool direction);
void enablePull(uint8_t pin, bool enablePull);
// false down, true up
void setPullMode(uint8_t pin, bool mode);
// false push-pull, true open-drain
void setDriveMode(uint8_t pin, bool openDrain);
void setHighImpedance(uint8_t pin, bool enable);
bool getWriteValue(uint8_t pin);
void digitalWrite(uint8_t pin, bool level);
bool digitalRead(uint8_t pin);
void resetIrq();
void disableIrq();
void enableIrq();
// Extended functionality
uint16_t readDeviceUID();
uint8_t readVersion();
// ADC
// channel: 1-4
uint16_t analogRead(uint8_t channel);
// PWM
// channel: 0-3
void setPwmDuty(uint8_t channel, uint8_t duty);
void setPwmFrequency(uint16_t freq);
// LED
void setLedCount(uint8_t count);
void setLedColor(uint8_t index, uint16_t color565);
void setLedColor(uint8_t index, uint8_t r, uint8_t g, uint8_t b);
void setLedColor(uint8_t index, uint32_t color);
void setLedData(const uint8_t* data, size_t len);
void refreshLeds();
private:
i2c_master_dev_handle_t _i2c_dev;
uint8_t _addr;
bool _initialized;
esp_err_t writeRegister8(uint8_t reg, uint8_t value);
uint8_t readRegister8(uint8_t reg);
esp_err_t writeRegister(uint8_t reg, const uint8_t* data, size_t len);
esp_err_t readRegister(uint8_t reg, uint8_t* data, size_t len);
esp_err_t bitOn(uint8_t reg, uint8_t mask);
esp_err_t bitOff(uint8_t reg, uint8_t mask);
void _writeBit(uint8_t reg_l, uint8_t reg_h, uint8_t pin, bool value);
bool _readBit(uint8_t reg_l, uint8_t reg_h, uint8_t pin);
};
} // namespace m5
@@ -0,0 +1,12 @@
idf_component_register(
SRCS
"src/SCS.cpp"
"src/SCSCL.cpp"
"src/SCSerial.cpp"
INCLUDE_DIRS
"src"
REQUIRES
driver
esp_timer
)
@@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.
@@ -0,0 +1,40 @@
/*
* INST.h
* FIT serial servo protocol command definition
*/
#ifndef _INST_H
#define _INST_H
#include <stdint.h>
typedef int8_t s8;
typedef uint8_t u8;
typedef uint16_t u16;
typedef int16_t s16;
typedef uint32_t u32;
typedef int32_t s32;
#define INST_PING 0x01
#define INST_READ 0x02
#define INST_WRITE 0x03
#define INST_REG_WRITE 0x04
#define INST_REG_ACTION 0x05
#define INST_SYNC_READ 0x82
#define INST_SYNC_WRITE 0x83
// Baud rate definition
#define _1M 0
#define _0_5M 1
#define _250K 2
#define _128K 3
#define _115200 4
#define _76800 5
#define _57600 6
#define _38400 7
#define _19200 8
#define _14400 9
#define _9600 10
#define _4800 11
#endif
@@ -0,0 +1,369 @@
/*
* SCS.cpp
* FIT serial servo communication layer protocol program
*/
#include <stddef.h>
#include "SCS.h"
SCS::SCS()
{
Level = 1; // All commands except broadcast commands return responses
Error = 0;
}
SCS::SCS(u8 End)
{
Level = 1;
this->End = End;
Error = 0;
}
SCS::SCS(u8 End, u8 Level)
{
this->Level = Level;
this->End = End;
Error = 0;
}
// Split a 16-bit number into two 8-bit numbers
// DataL is the low bit, DataH is the high bit
void SCS::Host2SCS(u8 *DataL, u8 *DataH, u16 Data)
{
if (End) {
*DataL = (Data >> 8);
*DataH = (Data & 0xff);
} else {
*DataH = (Data >> 8);
*DataL = (Data & 0xff);
}
}
// 8-bit numbers are combined into a 16-bit number
// DataL is the low bit, DataH is the high bit
u16 SCS::SCS2Host(u8 DataL, u8 DataH)
{
u16 Data;
if (End) {
Data = DataL;
Data <<= 8;
Data |= DataH;
} else {
Data = DataH;
Data <<= 8;
Data |= DataL;
}
return Data;
}
void SCS::writeBuf(u8 ID, u8 MemAddr, u8 *nDat, u8 nLen, u8 Fun)
{
u8 msgLen = 2;
u8 bBuf[6];
u8 CheckSum = 0;
bBuf[0] = 0xff;
bBuf[1] = 0xff;
bBuf[2] = ID;
bBuf[4] = Fun;
if (nDat) {
msgLen += nLen + 1;
bBuf[3] = msgLen;
bBuf[5] = MemAddr;
writeSCS(bBuf, 6);
} else {
bBuf[3] = msgLen;
writeSCS(bBuf, 5);
}
CheckSum = ID + msgLen + Fun + MemAddr;
u8 i = 0;
if (nDat) {
for (i = 0; i < nLen; i++) {
CheckSum += nDat[i];
}
writeSCS(nDat, nLen);
}
writeSCS(~CheckSum);
}
// Normal write command
// Servo ID, MemAddr memory table address, write data, write length
int SCS::genWrite(u8 ID, u8 MemAddr, u8 *nDat, u8 nLen)
{
rFlushSCS();
writeBuf(ID, MemAddr, nDat, nLen, INST_WRITE);
wFlushSCS();
return Ack(ID);
}
// Asynchronous write command
// Servo ID, MemAddr memory table address, write data, write length
int SCS::regWrite(u8 ID, u8 MemAddr, u8 *nDat, u8 nLen)
{
rFlushSCS();
writeBuf(ID, MemAddr, nDat, nLen, INST_REG_WRITE);
wFlushSCS();
return Ack(ID);
}
// Asynchronous write execution command
// Servo ID
int SCS::RegWriteAction(u8 ID)
{
rFlushSCS();
writeBuf(ID, 0, NULL, 0, INST_REG_ACTION);
wFlushSCS();
return Ack(ID);
}
// Synchronous write command
// Servo ID[] array, IDN array length, MemAddr memory table address, write data, write length
void SCS::syncWrite(u8 ID[], u8 IDN, u8 MemAddr, u8 *nDat, u8 nLen)
{
rFlushSCS();
u8 mesLen = ((nLen + 1) * IDN + 4);
u8 Sum = 0;
u8 bBuf[7];
bBuf[0] = 0xff;
bBuf[1] = 0xff;
bBuf[2] = 0xfe;
bBuf[3] = mesLen;
bBuf[4] = INST_SYNC_WRITE;
bBuf[5] = MemAddr;
bBuf[6] = nLen;
writeSCS(bBuf, 7);
Sum = 0xfe + mesLen + INST_SYNC_WRITE + MemAddr + nLen;
u8 i, j;
for (i = 0; i < IDN; i++) {
writeSCS(ID[i]);
writeSCS(nDat + i * nLen, nLen);
Sum += ID[i];
for (j = 0; j < nLen; j++) {
Sum += nDat[i * nLen + j];
}
}
writeSCS(~Sum);
wFlushSCS();
}
int SCS::writeByte(u8 ID, u8 MemAddr, u8 bDat)
{
rFlushSCS();
writeBuf(ID, MemAddr, &bDat, 1, INST_WRITE);
wFlushSCS();
return Ack(ID);
}
int SCS::writeWord(u8 ID, u8 MemAddr, u16 wDat)
{
u8 bBuf[2];
Host2SCS(bBuf + 0, bBuf + 1, wDat);
rFlushSCS();
writeBuf(ID, MemAddr, bBuf, 2, INST_WRITE);
wFlushSCS();
return Ack(ID);
}
// Read command
// Servo ID, MemAddr memory table address, return data nData, data length nLen
int SCS::Read(u8 ID, u8 MemAddr, u8 *nData, u8 nLen)
{
rFlushSCS();
writeBuf(ID, MemAddr, &nLen, 1, INST_READ);
wFlushSCS();
if (!checkHead()) {
return 0;
}
u8 bBuf[4];
Error = 0;
if (readSCS(bBuf, 3) != 3) {
return 0;
}
int Size = readSCS(nData, nLen);
if (Size != nLen) {
return 0;
}
if (readSCS(bBuf + 3, 1) != 1) {
return 0;
}
u8 calSum = bBuf[0] + bBuf[1] + bBuf[2];
u8 i;
for (i = 0; i < Size; i++) {
calSum += nData[i];
}
calSum = ~calSum;
if (calSum != bBuf[3]) {
return 0;
}
Error = bBuf[2];
return Size;
}
// Read 1 byte, return -1 if timeout
int SCS::readByte(u8 ID, u8 MemAddr)
{
u8 bDat;
int Size = Read(ID, MemAddr, &bDat, 1);
if (Size != 1) {
return -1;
} else {
return bDat;
}
}
// Read 2 bytes, return -1 if timeout
int SCS::readWord(u8 ID, u8 MemAddr)
{
u8 nDat[2];
int Size;
u16 wDat;
Size = Read(ID, MemAddr, nDat, 2);
if (Size != 2) return -1;
wDat = SCS2Host(nDat[0], nDat[1]);
return wDat;
}
// Ping command, return the servo ID, timeout returns -1
int SCS::Ping(u8 ID)
{
rFlushSCS();
writeBuf(ID, 0, NULL, 0, INST_PING);
wFlushSCS();
Error = 0;
if (!checkHead()) {
return -1;
}
u8 bBuf[4];
if (readSCS(bBuf, 4) != 4) {
return -1;
}
if (bBuf[0] != ID && ID != 0xfe) {
return -1;
}
if (bBuf[1] != 2) {
return -1;
}
u8 calSum = ~(bBuf[0] + bBuf[1] + bBuf[2]);
if (calSum != bBuf[3]) {
return -1;
}
Error = bBuf[2];
return bBuf[0];
}
int SCS::checkHead()
{
u8 bDat;
u8 bBuf[2] = {0, 0};
u8 Cnt = 0;
while (1) {
if (!readSCS(&bDat, 1)) {
return 0;
}
bBuf[1] = bBuf[0];
bBuf[0] = bDat;
if (bBuf[0] == 0xff && bBuf[1] == 0xff) {
break;
}
Cnt++;
if (Cnt > 10) {
return 0;
}
}
return 1;
}
int SCS::Ack(u8 ID)
{
Error = 0;
if (ID != 0xfe && Level) {
if (!checkHead()) {
return 0;
}
u8 bBuf[4];
if (readSCS(bBuf, 4) != 4) {
return 0;
}
if (bBuf[0] != ID) {
return 0;
}
if (bBuf[1] != 2) {
return 0;
}
u8 calSum = ~(bBuf[0] + bBuf[1] + bBuf[2]);
if (calSum != bBuf[3]) {
return 0;
}
Error = bBuf[2];
}
return 1;
}
int SCS::syncReadPacketTx(u8 ID[], u8 IDN, u8 MemAddr, u8 nLen)
{
syncReadRxPacketLen = nLen;
u8 checkSum = (4 + 0xfe) + IDN + MemAddr + nLen + INST_SYNC_READ;
u8 i;
writeSCS(0xff);
writeSCS(0xff);
writeSCS(0xfe);
writeSCS(IDN + 4);
writeSCS(INST_SYNC_READ);
writeSCS(MemAddr);
writeSCS(nLen);
for (i = 0; i < IDN; i++) {
writeSCS(ID[i]);
checkSum += ID[i];
}
checkSum = ~checkSum;
writeSCS(checkSum);
return nLen;
}
int SCS::syncReadPacketRx(u8 ID, u8 *nDat)
{
syncReadRxPacket = nDat;
syncReadRxPacketIndex = 0;
u8 bBuf[4];
if (!checkHead()) {
return 0;
}
if (readSCS(bBuf, 3) != 3) {
return 0;
}
if (bBuf[0] != ID) {
return 0;
}
if (bBuf[1] != (syncReadRxPacketLen + 2)) {
return 0;
}
Error = bBuf[2];
if (readSCS(nDat, syncReadRxPacketLen) != syncReadRxPacketLen) {
return 0;
}
return syncReadRxPacketLen;
}
int SCS::syncReadRxPacketToByte()
{
if (syncReadRxPacketIndex >= syncReadRxPacketLen) {
return -1;
}
return syncReadRxPacket[syncReadRxPacketIndex++];
}
int SCS::syncReadRxPacketToWrod(u8 negBit)
{
if ((syncReadRxPacketIndex + 1) >= syncReadRxPacketLen) {
return -1;
}
int Word = SCS2Host(syncReadRxPacket[syncReadRxPacketIndex], syncReadRxPacket[syncReadRxPacketIndex + 1]);
syncReadRxPacketIndex += 2;
if (negBit) {
if (Word & (1 << negBit)) {
Word = -(Word & ~(1 << negBit));
}
}
return Word;
}
@@ -0,0 +1,56 @@
/*
* SCS.h
* FIT serial servo communication layer protocol program
*/
#ifndef _SCS_H
#define _SCS_H
#include "INST.h"
class SCS {
public:
SCS();
SCS(u8 End);
SCS(u8 End, u8 Level);
int genWrite(u8 ID, u8 MemAddr, u8 *nDat, u8 nLen); // Normal write instruction
int regWrite(u8 ID, u8 MemAddr, u8 *nDat, u8 nLen); // Asynchronous write command
int RegWriteAction(u8 ID = 0xfe); // Asynchronous write execution instruction
void syncWrite(u8 ID[], u8 IDN, u8 MemAddr, u8 *nDat, u8 nLen); // Synchronous write instruction
int writeByte(u8 ID, u8 MemAddr, u8 bDat); // Write 1 byte
int writeWord(u8 ID, u8 MemAddr, u16 wDat); // Write 2 bytes
int Read(u8 ID, u8 MemAddr, u8 *nData, u8 nLen); // Read instruction
int readByte(u8 ID, u8 MemAddr); // Read 1 byte
int readWord(u8 ID, u8 MemAddr); // Read 2 bytes
int Ping(u8 ID); // Ping Command
int syncReadPacketTx(u8 ID[], u8 IDN, u8 MemAddr, u8 nLen); // Synchronous read instruction packet sending
int syncReadPacketRx(
u8 ID,
u8 *nDat); // Synchronous read return packet reception, successful return memory byte count, failed return 0
int syncReadRxPacketToByte(); // Decode a byte
int syncReadRxPacketToWrod(
u8 negBit = 0); // Decode two bytes, negBit is the direction, negBit=0 means no direction
public:
u8 Level; // Servo return level
u8 End; // Processor endian structure
u8 Error; // Servo status
u8 syncReadRxPacketIndex;
u8 syncReadRxPacketLen;
u8 *syncReadRxPacket;
protected:
virtual int writeSCS(unsigned char *nDat, int nLen) = 0;
virtual int readSCS(unsigned char *nDat, int nLen) = 0;
virtual int writeSCS(unsigned char bDat) = 0;
virtual void rFlushSCS() = 0;
virtual void wFlushSCS() = 0;
protected:
void writeBuf(u8 ID, u8 MemAddr, u8 *nDat, u8 nLen, u8 Fun);
void Host2SCS(u8 *DataL, u8 *DataH, u16 Data); // Split a 16-digit number into two 8-digit numbers
u16 SCS2Host(u8 DataL, u8 DataH); // Two 8-digit numbers combined into a 16-digit number
int Ack(u8 ID); // Return Response
int checkHead(); // Frame header detection
};
#endif
@@ -0,0 +1,319 @@
/*
* SCSCL.cpp
* FIT SCSCL series serial servo application layer program
*/
#include "SCSCL.h"
SCSCL::SCSCL()
{
End = 1;
}
SCSCL::SCSCL(u8 End) : SCSerial(End)
{
}
SCSCL::SCSCL(u8 End, u8 Level) : SCSerial(End, Level)
{
}
int SCSCL::WritePos(u8 ID, u16 Position, u16 Time, u16 Speed)
{
u8 bBuf[6];
Host2SCS(bBuf + 0, bBuf + 1, Position);
Host2SCS(bBuf + 2, bBuf + 3, Time);
Host2SCS(bBuf + 4, bBuf + 5, Speed);
return genWrite(ID, SCSCL_GOAL_POSITION_L, bBuf, 6);
}
int SCSCL::WritePosEx(u8 ID, s16 Position, u16 Speed, u8 ACC)
{
(void)ACC; // ACC parameter is not used in this implementation
u16 Time = 0;
u8 bBuf[6];
Host2SCS(bBuf + 0, bBuf + 1, Position);
Host2SCS(bBuf + 2, bBuf + 3, Time);
Host2SCS(bBuf + 4, bBuf + 5, Speed);
return genWrite(ID, SCSCL_GOAL_POSITION_L, bBuf, 6);
}
int SCSCL::RegWritePos(u8 ID, u16 Position, u16 Time, u16 Speed)
{
u8 bBuf[6];
Host2SCS(bBuf + 0, bBuf + 1, Position);
Host2SCS(bBuf + 2, bBuf + 3, Time);
Host2SCS(bBuf + 4, bBuf + 5, Speed);
return regWrite(ID, SCSCL_GOAL_POSITION_L, bBuf, 6);
}
int SCSCL::CalibrationOfs(u8 ID)
{
return -1;
}
void SCSCL::SyncWritePos(u8 ID[], u8 IDN, u16 Position[], u16 Time[], u16 Speed[])
{
u8 offbuf[6 * IDN];
for (u8 i = 0; i < IDN; i++) {
u16 T, V;
if (Time) {
T = Time[i];
} else {
T = 0;
}
if (Speed) {
V = Speed[i];
} else {
V = 0;
}
Host2SCS(offbuf + i * 6 + 0, offbuf + i * 6 + 1, Position[i]);
Host2SCS(offbuf + i * 6 + 2, offbuf + i * 6 + 3, T);
Host2SCS(offbuf + i * 6 + 4, offbuf + i * 6 + 5, V);
}
syncWrite(ID, IDN, SCSCL_GOAL_POSITION_L, offbuf, 6);
}
int SCSCL::PWMMode(u8 ID)
{
u8 bBuf[4];
bBuf[0] = 0;
bBuf[1] = 0;
bBuf[2] = 0;
bBuf[3] = 0;
return genWrite(ID, SCSCL_MIN_ANGLE_LIMIT_L, bBuf, 4);
}
int SCSCL::WritePWM(u8 ID, s16 pwmOut)
{
if (pwmOut < 0) {
pwmOut = -pwmOut;
pwmOut |= (1 << 10);
}
u8 bBuf[2];
Host2SCS(bBuf + 0, bBuf + 1, pwmOut);
return genWrite(ID, SCSCL_GOAL_TIME_L, bBuf, 2);
}
/**
* Switch between position mode and PWM mode PWM模式
* ID: Servo ID
* mode: 0 for position mode, 1 for PWM mode 01PWM模式
* Return: Result of the operation
*/
int SCSCL::SwitchMode(int ID, uint8_t mode)
{
if (ID < 0 || ID > 1) {
return -1; // Invalid ID
}
if (mode > 1) {
return -2; // Invalid mode
}
if (mode == 1) { // PWM mode
// Store current angle limits
min_angle[ID] = readWord(ID, SCSCL_MIN_ANGLE_LIMIT_L);
max_angle[ID] = readWord(ID, SCSCL_MAX_ANGLE_LIMIT_L);
if (min_angle[ID] == -1 || max_angle[ID] == -1) {
return -3; // Failed to read angle limits
}
PWMMode(ID); // Switch to PWM mode
return 0;
} else { // Position mode (mode == 0)
if (writeWord(ID, SCSCL_MIN_ANGLE_LIMIT_L, (uint16_t)min_angle[ID]) != 1) {
return -4; // Failed to write min angle limit
}
if (writeWord(ID, SCSCL_MAX_ANGLE_LIMIT_L, (uint16_t)max_angle[ID]) != 1) {
return -5; // Failed to write max angle limit
}
return 0;
}
}
/**
* Enable or disable torque
* ID: Servo ID
* Enable: 1 to enable, 0 to disable 2 to damping 1使02
* Return: Result of the operation
*/
int SCSCL::EnableTorque(u8 ID, u8 Enable)
{
return writeByte(ID, SCSCL_TORQUE_ENABLE, Enable);
}
int SCSCL::unLockEprom(u8 ID)
{
return writeByte(ID, SCSCL_LOCK, 0);
}
int SCSCL::LockEprom(u8 ID)
{
return writeByte(ID, SCSCL_LOCK, 1);
}
int SCSCL::FeedBack(int ID)
{
int nLen = Read(ID, SCSCL_PRESENT_POSITION_L, Mem, sizeof(Mem));
if (nLen != sizeof(Mem)) {
Err = 1;
return -1;
}
Err = 0;
return nLen;
}
int SCSCL::ReadPos(int ID)
{
int Pos = -1;
if (ID == -1) {
Pos = Mem[SCSCL_PRESENT_POSITION_L - SCSCL_PRESENT_POSITION_L];
Pos <<= 8;
Pos |= Mem[SCSCL_PRESENT_POSITION_H - SCSCL_PRESENT_POSITION_L];
} else {
Err = 0;
Pos = readWord(ID, SCSCL_PRESENT_POSITION_L);
if (Pos == -1) {
Err = 1;
}
}
return Pos;
}
int SCSCL::ReadSpeed(int ID)
{
int Speed = -1;
if (ID == -1) {
Speed = Mem[SCSCL_PRESENT_SPEED_L - SCSCL_PRESENT_POSITION_L];
Speed <<= 8;
Speed |= Mem[SCSCL_PRESENT_SPEED_H - SCSCL_PRESENT_POSITION_L];
} else {
Err = 0;
Speed = readWord(ID, SCSCL_PRESENT_SPEED_L);
if (Speed == -1) {
Err = 1;
return -1;
}
}
if (!Err && (Speed & (1 << 15))) {
Speed = -(Speed & ~(1 << 15));
}
return Speed;
}
int SCSCL::ReadLoad(int ID)
{
int Load = -1;
if (ID == -1) {
Load = Mem[SCSCL_PRESENT_LOAD_L - SCSCL_PRESENT_POSITION_L];
Load <<= 8;
Load |= Mem[SCSCL_PRESENT_LOAD_H - SCSCL_PRESENT_POSITION_L];
} else {
Err = 0;
Load = readWord(ID, SCSCL_PRESENT_LOAD_L);
if (Load == -1) {
Err = 1;
}
}
if (!Err && (Load & (1 << 10))) {
Load = -(Load & ~(1 << 10));
}
return Load;
}
int SCSCL::ReadVoltage(int ID)
{
int Voltage = -1;
if (ID == -1) {
Voltage = Mem[SCSCL_PRESENT_VOLTAGE - SCSCL_PRESENT_POSITION_L];
} else {
Err = 0;
Voltage = readByte(ID, SCSCL_PRESENT_VOLTAGE);
if (Voltage == -1) {
Err = 1;
}
}
return Voltage;
}
int SCSCL::ReadTemper(int ID)
{
int Temper = -1;
if (ID == -1) {
Temper = Mem[SCSCL_PRESENT_TEMPERATURE - SCSCL_PRESENT_POSITION_L];
} else {
Err = 0;
Temper = readByte(ID, SCSCL_PRESENT_TEMPERATURE);
if (Temper == -1) {
Err = 1;
}
}
return Temper;
}
int SCSCL::ReadMove(int ID)
{
int Move = -1;
if (ID == -1) {
Move = Mem[SCSCL_MOVING - SCSCL_PRESENT_POSITION_L];
} else {
Err = 0;
Move = readByte(ID, SCSCL_MOVING);
if (Move == -1) {
Err = 1;
}
}
return Move;
}
int SCSCL::ReadMode(int ID)
{
int ValueRead = -1;
ValueRead = readWord(ID, SCSCL_MIN_ANGLE_LIMIT_L);
if (ValueRead == 0) {
return 1;
} else if (ValueRead > 0) {
return 0;
}
return ValueRead;
}
int SCSCL::ReadToqueEnable(int ID)
{
// return writeByte(ID, SCSCL_TORQUE_ENABLE, Enable);
int ValueRead = -1;
ValueRead = readWord(ID, SCSCL_TORQUE_ENABLE);
return ValueRead;
}
int SCSCL::ReadInfoValue(int ID, int AddInput)
{
int ValueRead = -1;
ValueRead = readWord(ID, AddInput);
return ValueRead;
}
int SCSCL::ReadCurrent(int ID)
{
int Current = -1;
if (ID == -1) {
Current = Mem[SCSCL_PRESENT_CURRENT_L - SCSCL_PRESENT_POSITION_L];
Current <<= 8;
Current |= Mem[SCSCL_PRESENT_CURRENT_H - SCSCL_PRESENT_POSITION_L];
} else {
Err = 0;
Current = readWord(ID, SCSCL_PRESENT_CURRENT_L);
if (Current == -1) {
Err = 1;
return -1;
}
}
if (!Err && (Current & (1 << 15))) {
Current = -(Current & ~(1 << 15));
}
return Current;
}
@@ -0,0 +1,86 @@
/*
* SCSCL.h
* FIT SCSCL series serial servo application layer program
*/
#ifndef _SCSCL_H
#define _SCSCL_H
// Memory table definition
//-------EPROM (read-only)--------
#define SCSCL_VERSION_L 3
#define SCSCL_VERSION_H 4
//-------EPROM (read and write)--------
#define SCSCL_ID 5
#define SCSCL_BAUD_RATE 6
#define SCSCL_MIN_ANGLE_LIMIT_L 9
#define SCSCL_MIN_ANGLE_LIMIT_H 10
#define SCSCL_MAX_ANGLE_LIMIT_L 11
#define SCSCL_MAX_ANGLE_LIMIT_H 12
#define SCSCL_CW_DEAD 26
#define SCSCL_CCW_DEAD 27
//-------SRAM (read and write)--------
#define SCSCL_TORQUE_ENABLE 40
#define SCSCL_GOAL_POSITION_L 42
#define SCSCL_GOAL_POSITION_H 43
#define SCSCL_GOAL_TIME_L 44
#define SCSCL_GOAL_TIME_H 45
#define SCSCL_GOAL_SPEED_L 46
#define SCSCL_GOAL_SPEED_H 47
#define SCSCL_LOCK 48
//-------SRAM (read only)--------
#define SCSCL_PRESENT_POSITION_L 56
#define SCSCL_PRESENT_POSITION_H 57
#define SCSCL_PRESENT_SPEED_L 58
#define SCSCL_PRESENT_SPEED_H 59
#define SCSCL_PRESENT_LOAD_L 60
#define SCSCL_PRESENT_LOAD_H 61
#define SCSCL_PRESENT_VOLTAGE 62
#define SCSCL_PRESENT_TEMPERATURE 63
#define SCSCL_MOVING 66
#define SCSCL_PRESENT_CURRENT_L 69
#define SCSCL_PRESENT_CURRENT_H 70
#include "SCSerial.h"
class SCSCL : public SCSerial {
public:
SCSCL();
SCSCL(u8 End);
SCSCL(u8 End, u8 Level);
virtual int WritePos(u8 ID, u16 Position, u16 Time, u16 Speed); // Normal write of single servo position command
virtual int WritePosEx(u8 ID, s16 Position, u16 Speed, u8 ACC); // Single servo position command
virtual int RegWritePos(
u8 ID, u16 Position, u16 Time,
u16 Speed = 0); // Asynchronously write a single servo position command (RegWriteAction takes effect)
virtual void SyncWritePos(u8 ID[], u8 IDN, u16 Position[], u16 Time[],
u16 Speed[]); // Synchronously write multiple servo position commands
virtual int PWMMode(u8 ID); // PWM output mode
virtual int WritePWM(u8 ID, s16 pwmOut); // PWM output mode command
virtual int SwitchMode(int ID, uint8_t mode); // Switch between position mode and PWM mode
virtual int EnableTorque(u8 ID, u8 Enable); // Torque control command
virtual int unLockEprom(u8 ID); // eprom unlock
virtual int LockEprom(u8 ID); // eprom lock
virtual int FeedBack(int ID); // Feedback servo information
virtual int ReadPos(int ID); // Read position
virtual int ReadSpeed(int ID); // Read speed
virtual int ReadLoad(int ID); // Read the output voltage percentage to the motor (0~1000)
virtual int ReadVoltage(int ID); // Read voltage
virtual int ReadTemper(int ID); // Read temperature
virtual int ReadMove(int ID); // Read movement status
virtual int ReadCurrent(int ID); // read current
virtual int ReadMode(int ID);
virtual int ReadToqueEnable(int ID);
virtual int CalibrationOfs(u8 ID);
virtual int ReadInfoValue(int ID, int AddInput);
private:
u8 Mem[SCSCL_PRESENT_CURRENT_H - SCSCL_PRESENT_POSITION_L + 1];
int min_angle[2];
int max_angle[2];
};
#endif
@@ -0,0 +1,152 @@
/*
* SCSerial.cpp
* FIT serial servo hardware interface layer program
*/
#include "SCSerial.h"
#include "esp_log.h"
#include "esp_timer.h"
static const char *TAG = "SCSerial";
SCSerial::SCSerial()
{
IOTimeOut = 100;
uart_num = UART_NUM_MAX;
}
SCSerial::SCSerial(u8 End) : SCS(End)
{
IOTimeOut = 100;
uart_num = UART_NUM_MAX;
}
SCSerial::SCSerial(u8 End, u8 Level) : SCS(End, Level)
{
IOTimeOut = 100;
uart_num = UART_NUM_MAX;
}
bool SCSerial::begin(uart_port_t uart_num, int baud_rate, int tx_pin, int rx_pin, int buf_size)
{
this->uart_num = uart_num;
uart_config_t uart_config = {
.baud_rate = baud_rate,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.rx_flow_ctrl_thresh = 0,
.source_clk = UART_SCLK_DEFAULT,
};
esp_err_t ret = uart_driver_install(uart_num, buf_size, buf_size, 0, NULL, 0);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to install UART driver: %s", esp_err_to_name(ret));
return false;
}
ret = uart_param_config(uart_num, &uart_config);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to configure UART: %s", esp_err_to_name(ret));
uart_driver_delete(uart_num);
return false;
}
ret = uart_set_pin(uart_num, tx_pin, rx_pin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set UART pins: %s", esp_err_to_name(ret));
uart_driver_delete(uart_num);
return false;
}
return true;
}
void SCSerial::end()
{
if (uart_num < UART_NUM_MAX) {
uart_driver_delete(uart_num);
uart_num = UART_NUM_MAX;
}
}
int SCSerial::readSCS(unsigned char *nDat, int nLen)
{
if (uart_num >= UART_NUM_MAX) {
return 0;
}
int Size = 0;
int64_t t_begin = esp_timer_get_time() / 1000; // Convert to milliseconds
int64_t t_user;
while (1) {
size_t available = 0;
uart_get_buffered_data_len(uart_num, &available);
if (available > 0) {
unsigned char byte;
int len = uart_read_bytes(uart_num, &byte, 1, 0);
if (len > 0) {
if (nDat) {
nDat[Size] = byte;
}
Size++;
t_begin = esp_timer_get_time() / 1000;
}
}
if (Size >= nLen) {
break;
}
t_user = (esp_timer_get_time() / 1000) - t_begin;
if (t_user > IOTimeOut) {
break;
}
vTaskDelay(1 / portTICK_PERIOD_MS);
}
return Size;
}
int SCSerial::writeSCS(unsigned char *nDat, int nLen)
{
if (uart_num >= UART_NUM_MAX || nDat == NULL) {
return 0;
}
int len = uart_write_bytes(uart_num, (const char *)nDat, nLen);
return len;
}
int SCSerial::writeSCS(unsigned char bDat)
{
if (uart_num >= UART_NUM_MAX) {
return 0;
}
int len = uart_write_bytes(uart_num, (const char *)&bDat, 1);
return len;
}
void SCSerial::rFlushSCS()
{
if (uart_num >= UART_NUM_MAX) {
return;
}
uart_flush_input(uart_num);
}
void SCSerial::wFlushSCS()
{
if (uart_num >= UART_NUM_MAX) {
return;
}
uart_wait_tx_done(uart_num, pdMS_TO_TICKS(100));
}
@@ -0,0 +1,46 @@
/*
* SCSerial.h
* FIT serial servo hardware interface layer program
*/
#ifndef _SCSERIAL_H
#define _SCSERIAL_H
#include "driver/uart.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <string.h>
#include "SCS.h"
class SCSerial : public SCS {
public:
SCSerial();
SCSerial(u8 End);
SCSerial(u8 End, u8 Level);
// Initialize UART
bool begin(uart_port_t uart_num, int baud_rate, int tx_pin, int rx_pin, int buf_size = 1024);
void end();
protected:
virtual int writeSCS(unsigned char *nDat, int nLen); // Output nLen bytes
virtual int readSCS(unsigned char *nDat, int nLen); // Input nLen bytes
virtual int writeSCS(unsigned char bDat); // Output 1 byte
virtual void rFlushSCS();
virtual void wFlushSCS();
public:
unsigned long int IOTimeOut; // Input and output timeout (in milliseconds)
uart_port_t uart_num; // UART port number
int Err;
public:
virtual int getErr()
{
return Err;
}
};
#endif
@@ -0,0 +1,11 @@
/*
* SCServo.h
* FIT serial servo interface
*/
#ifndef _SCSERVO_H
#define _SCSERVO_H
#include "SCSCL.h"
#endif
+310
View File
@@ -0,0 +1,310 @@
#include "Si12T.h"
#include <string.h>
#include <stdlib.h>
#include "esp_log.h"
static const char *TAG = "Si12T";
#define I2C_TIMEOUT_MS 100
/**
* @brief Si12T设备结构体
*/
struct si12t_dev_t {
i2c_master_dev_handle_t i2c_dev; /*!< I2C设备句柄 */
uint8_t dev_addr; /*!< 设备地址 */
};
uint8_t si12t_point_type[3] = {SI12T_OUTPUT_NONE, SI12T_OUTPUT_NONE, SI12T_OUTPUT_NONE};
/**
* @brief
*/
static esp_err_t si12t_i2c_write_reg(si12t_handle_t handle, uint8_t reg_addr, uint8_t value)
{
uint8_t write_buf[2] = {reg_addr, value};
return i2c_master_transmit(handle->i2c_dev, write_buf, sizeof(write_buf), I2C_TIMEOUT_MS);
}
/**
* @brief
*/
static esp_err_t si12t_i2c_read_reg(si12t_handle_t handle, uint8_t reg_addr, uint8_t *value)
{
esp_err_t ret = i2c_master_transmit_receive(handle->i2c_dev, &reg_addr, 1, value, 1, I2C_TIMEOUT_MS);
ESP_LOGD(TAG, "Read reg 0x%02x, value: 0x%02x", reg_addr, *value);
return ret;
}
/**
* @brief
*/
static esp_err_t si12t_set_sens(si12t_handle_t handle, uint8_t value)
{
esp_err_t ret = ESP_OK;
ret |= si12t_i2c_write_reg(handle, SI12T_SENSITIVITY1_ADDR, value);
ret |= si12t_i2c_write_reg(handle, SI12T_SENSITIVITY2_ADDR, value);
ret |= si12t_i2c_write_reg(handle, SI12T_SENSITIVITY3_ADDR, value);
ret |= si12t_i2c_write_reg(handle, SI12T_SENSITIVITY4_ADDR, value);
ret |= si12t_i2c_write_reg(handle, SI12T_SENSITIVITY5_ADDR, value);
return ret;
}
esp_err_t si12t_init(const si12t_config_t *config, si12t_handle_t *handle)
{
if (config == NULL || handle == NULL || config->i2c_bus == NULL) {
return ESP_ERR_INVALID_ARG;
}
si12t_handle_t dev = (si12t_handle_t)calloc(1, sizeof(struct si12t_dev_t));
if (dev == NULL) {
ESP_LOGE(TAG, "Failed to allocate memory for Si12T device");
return ESP_ERR_NO_MEM;
}
dev->dev_addr = config->dev_addr ? config->dev_addr : SI12T_GND_ADDRESS;
i2c_device_config_t dev_cfg = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = dev->dev_addr,
.scl_speed_hz = 100000, // 100kHz
};
esp_err_t ret = i2c_master_bus_add_device(config->i2c_bus, &dev_cfg, &dev->i2c_dev);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to add I2C device: %s", esp_err_to_name(ret));
free(dev);
return ret;
}
*handle = dev;
ESP_LOGI(TAG, "Si12T initialized, version: %s", SI12T_VERSION);
return ESP_OK;
}
esp_err_t si12t_setup(si12t_handle_t handle, si12t_type_t sens_type, si12t_sensitivity_level_t sens_level)
{
if (handle == NULL) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t ret = ESP_OK;
ret |= si12t_enable_channel(handle);
ret |= si12t_set_ctrl2(handle);
ret |= si12t_set_ctrl1(handle);
ret |= si12t_set_sensitivity(handle, sens_type, sens_level);
ret |= si12t_get_sensitivity(handle);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "Si12T setup done");
}
return ret;
}
esp_err_t si12t_delete(si12t_handle_t handle)
{
if (handle == NULL) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t ret = i2c_master_bus_rm_device(handle->i2c_dev);
free(handle);
return ret;
}
esp_err_t si12t_get_sensitivity(si12t_handle_t handle)
{
if (handle == NULL) {
return ESP_ERR_INVALID_ARG;
}
uint8_t data = 0;
esp_err_t ret = ESP_OK;
ret |= si12t_i2c_read_reg(handle, SI12T_SENSITIVITY1_ADDR, &data);
ret |= si12t_i2c_read_reg(handle, SI12T_SENSITIVITY2_ADDR, &data);
ret |= si12t_i2c_read_reg(handle, SI12T_SENSITIVITY3_ADDR, &data);
ret |= si12t_i2c_read_reg(handle, SI12T_SENSITIVITY4_ADDR, &data);
ret |= si12t_i2c_read_reg(handle, SI12T_SENSITIVITY5_ADDR, &data);
return ret;
}
esp_err_t si12t_set_sensitivity(si12t_handle_t handle, si12t_type_t sens_type, si12t_sensitivity_level_t sens_level)
{
if (handle == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (sens_type != SI12T_TYPE_LOW && sens_type != SI12T_TYPE_HIGH) {
return ESP_ERR_INVALID_ARG;
}
uint8_t value = 0x00;
if (sens_type == SI12T_TYPE_HIGH) {
switch (sens_level) {
case SI12T_SENSITIVITY_LEVEL_0:
value = 0x88;
break;
case SI12T_SENSITIVITY_LEVEL_1:
value = 0x99;
break;
case SI12T_SENSITIVITY_LEVEL_2:
value = 0xAA;
break;
case SI12T_SENSITIVITY_LEVEL_3:
value = 0xBB;
break;
case SI12T_SENSITIVITY_LEVEL_4:
value = 0xCC;
break;
case SI12T_SENSITIVITY_LEVEL_5:
value = 0xDD;
break;
case SI12T_SENSITIVITY_LEVEL_6:
value = 0xEE;
break;
case SI12T_SENSITIVITY_LEVEL_7:
value = 0xFF;
break;
default:
return ESP_ERR_INVALID_ARG;
}
} else {
switch (sens_level) {
case SI12T_SENSITIVITY_LEVEL_0:
value = 0x00;
break;
case SI12T_SENSITIVITY_LEVEL_1:
value = 0x11;
break;
case SI12T_SENSITIVITY_LEVEL_2:
value = 0x22;
break;
case SI12T_SENSITIVITY_LEVEL_3:
value = 0x33;
break;
case SI12T_SENSITIVITY_LEVEL_4:
value = 0x44;
break;
case SI12T_SENSITIVITY_LEVEL_5:
value = 0x55;
break;
case SI12T_SENSITIVITY_LEVEL_6:
value = 0x66;
break;
case SI12T_SENSITIVITY_LEVEL_7:
value = 0x77;
break;
default:
return ESP_ERR_INVALID_ARG;
}
}
ESP_LOGD(TAG, "Set sensitivity value: 0x%02x", value);
return si12t_set_sens(handle, value);
}
esp_err_t si12t_set_ctrl1(si12t_handle_t handle)
{
if (handle == NULL) {
return ESP_ERR_INVALID_ARG;
}
uint8_t test;
// sends register data, Auto Mode, FTC=01, Interrupt(Middle,High), Response 4 (2+2)
esp_err_t ret = si12t_i2c_write_reg(handle, SI12T_CTRL1_ADDR, 0x22);
si12t_i2c_read_reg(handle, SI12T_CTRL1_ADDR, &test);
return ret;
}
esp_err_t si12t_set_ctrl2(si12t_handle_t handle)
{
if (handle == NULL) {
return ESP_ERR_INVALID_ARG;
}
uint8_t test;
esp_err_t ret = ESP_OK;
// S/W Reset Enable, Sleep Mode Enable
ret |= si12t_i2c_write_reg(handle, SI12T_CTRL2_ADDR, 0x0F);
ret |= si12t_i2c_write_reg(handle, SI12T_CTRL2_ADDR, 0x07);
si12t_i2c_read_reg(handle, SI12T_CTRL2_ADDR, &test);
return ret;
}
esp_err_t si12t_sleep_enable(si12t_handle_t handle)
{
if (handle == NULL) {
return ESP_ERR_INVALID_ARG;
}
return si12t_i2c_write_reg(handle, SI12T_CTRL2_ADDR, 0x07); // S/W Reset Enable, Sleep Mode Enable
}
esp_err_t si12t_sleep_disable(si12t_handle_t handle)
{
if (handle == NULL) {
return ESP_ERR_INVALID_ARG;
}
return si12t_i2c_write_reg(handle, SI12T_CTRL2_ADDR, 0x03); // S/W Reset Disable, Sleep Mode Disable
}
esp_err_t si12t_enable_channel(si12t_handle_t handle)
{
if (handle == NULL) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t ret = ESP_OK;
uint8_t data = 1;
ret |= si12t_i2c_write_reg(handle, SI12T_REF_RST1_ADDR, 0x00); // channel 1-8 enable reference calibration
ret |= si12t_i2c_write_reg(handle, SI12T_REF_RST2_ADDR, 0x00); // channel 9 enable reference calibration
ret |= si12t_i2c_write_reg(handle, SI12T_CH_HOLD1_ADDR, 0x00); // channel 1-8 enable
ret |= si12t_i2c_write_reg(handle, SI12T_CH_HOLD2_ADDR, 0x00); // channel 9 enable
ret |= si12t_i2c_write_reg(handle, SI12T_CAL_HOLD1_ADDR, 0x00); // channel 1-8 enable reference calibration
ret |= si12t_i2c_write_reg(handle, SI12T_CAL_HOLD2_ADDR, 0x00); // channel 9 enable reference calibration
// Read back to verify
si12t_i2c_read_reg(handle, SI12T_REF_RST1_ADDR, &data);
si12t_i2c_read_reg(handle, SI12T_REF_RST2_ADDR, &data);
si12t_i2c_read_reg(handle, SI12T_CH_HOLD1_ADDR, &data);
si12t_i2c_read_reg(handle, SI12T_CH_HOLD2_ADDR, &data);
si12t_i2c_read_reg(handle, SI12T_CAL_HOLD1_ADDR, &data);
si12t_i2c_read_reg(handle, SI12T_CAL_HOLD2_ADDR, &data);
return ret;
}
esp_err_t si12t_read_touch_result(si12t_handle_t handle, uint8_t *touch_result)
{
if (handle == NULL || touch_result == NULL) {
return ESP_ERR_INVALID_ARG;
}
return si12t_i2c_read_reg(handle, SI12T_OUTPUT1_ADDR, touch_result);
}
void si12t_parse_touch_result(uint8_t touch_result)
{
int index = 0;
for (int j = 0; j < 6; j += 2) {
si12t_point_type[index] = (touch_result >> j) & 0x03;
index++;
}
}
void si12t_parse_touch_result_to(uint8_t touch_result, uint8_t *parsed_result)
{
int index = 0;
for (int j = 0; j < 6; j += 2) {
parsed_result[index] = (touch_result >> j) & 0x03;
index++;
}
}
+174
View File
@@ -0,0 +1,174 @@
#ifndef __SI12T_H__
#define __SI12T_H__
#include <stdint.h>
#include <stdbool.h>
#include "driver/i2c_master.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SI12T_VERSION "0.0.2"
/*LTR-507 SEL pin is "GND"*/
#define SI12T_GND_ADDRESS 0x68 // 7bit i2c address
#define SI12T_SENSITIVITY1_ADDR 0x02
#define SI12T_SENSITIVITY2_ADDR 0x03
#define SI12T_SENSITIVITY3_ADDR 0x04
#define SI12T_SENSITIVITY4_ADDR 0x05
#define SI12T_SENSITIVITY5_ADDR 0x06
#define SI12T_SENSITIVITY6_ADDR 0x07
#define SI12T_CTRL1_ADDR 0x08
#define SI12T_CTRL2_ADDR 0x09
#define SI12T_REF_RST1_ADDR 0x0A
#define SI12T_REF_RST2_ADDR 0x0B
#define SI12T_CH_HOLD1_ADDR 0x0C
#define SI12T_CH_HOLD2_ADDR 0x0D
#define SI12T_CAL_HOLD1_ADDR 0x0E
#define SI12T_CAL_HOLD2_ADDR 0x0F
#define SI12T_OUTPUT1_ADDR 0x10
#define SI12T_OUTPUT2_ADDR 0x11
#define SI12T_OUTPUT3_ADDR 0x12
typedef enum { SI12T_TYPE_LOW = 0, SI12T_TYPE_HIGH } si12t_type_t;
typedef enum {
SI12T_SENSITIVITY_LEVEL_0 = 0,
SI12T_SENSITIVITY_LEVEL_1,
SI12T_SENSITIVITY_LEVEL_2,
SI12T_SENSITIVITY_LEVEL_3,
SI12T_SENSITIVITY_LEVEL_4,
SI12T_SENSITIVITY_LEVEL_5,
SI12T_SENSITIVITY_LEVEL_6,
SI12T_SENSITIVITY_LEVEL_7,
SI12T_SENSITIVITY_LEVEL_INVALID,
} si12t_sensitivity_level_t;
typedef enum { SI12T_OUTPUT_NONE = 0, SI12T_OUTPUT_LOW, SI12T_OUTPUT_MID, SI12T_OUTPUT_HIGH } si12t_output_t;
/**
* @brief Si12T配置结构体
*/
typedef struct {
i2c_master_bus_handle_t i2c_bus; /*!< I2C总线句柄 */
uint8_t dev_addr; /*!< 设备地址,默认SI12T_GND_ADDRESS */
} si12t_config_t;
/**
* @brief Si12T设备句柄
*/
typedef struct si12t_dev_t *si12t_handle_t;
extern uint8_t si12t_point_type[3];
/**
* @brief Si12T设备
*
* @param config
* @param handle
* @return esp_err_t ESP_OK成功
*/
esp_err_t si12t_init(const si12t_config_t *config, si12t_handle_t *handle);
/**
* @brief Si12T设备使
*
* @param handle
* @param sens_type
* @param sens_level
* @return esp_err_t ESP_OK成功
*/
esp_err_t si12t_setup(si12t_handle_t handle, si12t_type_t sens_type, si12t_sensitivity_level_t sens_level);
/**
* @brief Si12T设备
*
* @param handle
* @return esp_err_t ESP_OK成功
*/
esp_err_t si12t_delete(si12t_handle_t handle);
/**
* @brief 使
*
* @param handle
* @return esp_err_t ESP_OK成功
*/
esp_err_t si12t_enable_channel(si12t_handle_t handle);
/**
* @brief
*
* @param handle
* @param sens_type
* @param sens_level
* @return esp_err_t ESP_OK成功
*/
esp_err_t si12t_set_sensitivity(si12t_handle_t handle, si12t_type_t sens_type, si12t_sensitivity_level_t sens_level);
/**
* @brief
*
* @param handle
* @return esp_err_t ESP_OK成功
*/
esp_err_t si12t_get_sensitivity(si12t_handle_t handle);
/**
* @brief Ctrl1寄存器
*
* @param handle
* @return esp_err_t ESP_OK成功
*/
esp_err_t si12t_set_ctrl1(si12t_handle_t handle);
/**
* @brief Ctrl2寄存器
*
* @param handle
* @return esp_err_t ESP_OK成功
*/
esp_err_t si12t_set_ctrl2(si12t_handle_t handle);
/**
* @brief 使
*
* @param handle
* @return esp_err_t ESP_OK成功
*/
esp_err_t si12t_sleep_enable(si12t_handle_t handle);
/**
* @brief
*
* @param handle
* @return esp_err_t ESP_OK成功
*/
esp_err_t si12t_sleep_disable(si12t_handle_t handle);
/**
* @brief
*
* @param handle
* @param touch_result
* @return esp_err_t ESP_OK成功
*/
esp_err_t si12t_read_touch_result(si12t_handle_t handle, uint8_t *touch_result);
/**
* @brief
*
* @param touch_result
*/
void si12t_parse_touch_result(uint8_t touch_result);
void si12t_parse_touch_result_to(uint8_t touch_result, uint8_t *parsed_result);
#ifdef __cplusplus
}
#endif
#endif /* __SI12T_H__ */
@@ -0,0 +1,30 @@
Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved.
BSD-3-Clause
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,172 @@
# Sensor API for the BMI2's OIS interface
## Table of Contents
- [Introduction](#Intro)
- [Integration details](#Integration)
- [Driver files information](#file)
- [Sensor interfaces](#interface)
- [Integration Examples](#examples)
### Introduction<a name=Intro></a>
This package contains Bosch Sensortec's BMI2 Sensor API.
### Integration details<a name=Integration></a>
- Integrate _bmi2.c_, _bmi2.h_, _bmi2_ois.c_, _bmi2_ois.h_, _bmi2_defs.h_ and the required variant files in your project.
- User has to include _bmi2_ois.h_ in the code to call OIS related APIs and a _variant header_ for initialization as
well as BMI2 related API calls, as shown below:
``` c
#include "bmi261.h"
#include "bmi2_ois.h"
````
### Driver files information<a name=file></a>
- *_bmi2_ois.c_*
* This file has function definitions of OIS related API interfaces.
- *_bmi2_ois.h_*
* This header file has necessary include files, function declarations, required to make OIS related API calls.
### Sensor interfaces<a name=interface></a>
#### _Host Interface_
- I2C interface
- SPI interface
_Note: By default, the interface is I2C._
#### _OIS Interface_
- SPI interface
### Integration examples<a name=examples></a>
#### Configuring SPI/I2C for host interface.
To configure host interface, an instance of the bmi2_dev structure should be
created for initializing BMI2 sensor. "_Refer **README** for initializing BMI2
sensor._"
#### Configuring SPI for OIS interface.
To configure OIS interface, an instance of the bmi2_ois_dev structure should be
created. The following parameters are required to be updated in the structure,
by the user.
Parameters | Details
--------------|-----------------------------------
_intf_ptr_ | device address reference of SPI interface
_ois_read_ | read through SPI interface
_ois_write_ | read through SPI interface
_ois_delay_us_| delay in micro seconds
_acc_en_ | for enabling accelerometer
_gyr_en_ | for enabling gyroscope
``` c
int8_t rslt = 0;
struct bmi2_ois_dev ois_dev = {
.intf_ptr = intf_ptr will contain the chip selection info of SPI CS pin,
.ois_read = user_spi_reg_read,
.ois_write = user_spi_reg_write,
.ois_delay_us = user_delay_us
};
```
>**_Important Note_**: For initializing and configuring BMI2 sensors, which is
done through host interface, the API's are to be used from bmi2.c file. Rest
of the API's, for OIS configurations and the reading of OIS data, which is done
through OIS interface, are to be used from bmi2_ois.c file.
##### Get accelerometer and gyroscope data through OIS interface
``` c
int8_t rslt;
/* Array to enable sensor through host interface */
uint8_t sens_list[2] = {BMI2_ACCEL, BMI2_GYRO};
/* Array to enable sensor through OIS interface */
uint8_t sens_sel[2] = {BMI2_OIS_ACCEL, BMI2_OIS_GYRO};
/* Initialize the configuration structure */
struct bmi2_sens_config sens_cfg = {0};
/* Initialize BMI2 */
rslt = bmi2_init(&dev);
if (rslt != BMI2_OK) {
printf("Error: %d\n", rslt);
return;
}
/* Enable accelerometer and gyroscope through host interface */
rslt = bmi2_sensor_enable(sens_list, 2, &dev);
if (rslt != BMI2_OK) {
printf("Error: %d\n", rslt);
return;
}
/* Setting of OIS Range is done through host interface */
/* Select the gyroscope sensor for OIS Range configuration */
sens_cfg.type = BMI2_GYRO;
/* Get gyroscope configuration */
rslt = bmi2_get_sensor_config(&sens_cfg, 1, &dev);
if (rslt != BMI2_OK) {
printf("Error: %d\n", rslt);
return;
}
/* Set the desired OIS Range */
sens_cfg.cfg.gyr.ois_range = BMI2_GYR_OIS_2000;
/* Set gyroscope configuration for default values */
rslt = bmi2_set_sensor_config(&sens_cfg, 1, &dev);
if (rslt != BMI2_OK) {
printf("Error: %d\n", rslt);
return;
}
/* Enable OIS through host interface */
rslt = bmi2_set_ois_interface(BMI2_ENABLE, &dev);
if (rslt != BMI2_OK) {
printf("Error: %d\n", rslt);
return;
}
/* Disable Advance Power Save Mode through host interface */
rslt = bmi2_set_adv_power_save(BMI2_DISABLE, &dev);
if (rslt != BMI2_OK) {
printf("Error: %d\n", rslt);
return;
}
/* Get configurations for OIS through OIS interface for default values */
rslt = bmi2_ois_get_config(&ois_dev);
if (rslt != BMI2_OK) {
printf("Error: %d\n", rslt);
return;
}
/* Enable accelerometer and gyroscope for reading OIS data */
ois_dev.acc_en = BMI2_ENABLE;
ois_dev.gyr_en = BMI2_ENABLE;
/* Set configurations for OIS through OIS interface */
rslt = bmi2_ois_set_config(&ois_dev);
if (rslt == BMI2_OK) {
/* Get OIS accelerometer and gyroscope data through OIS interface */
rslt = bmi2_ois_read_data(sens_sel, 2, &ois_dev);
if (rslt == BMI2_OK) {
/* Print accelerometer data */
printf("OIS Accel x-axis = %d\t", ois_dev.acc_data.x);
printf("OIS Accel y-axis= %d\t", ois_dev.acc_data.y);
printf("OIS Accel z-axis = %d\r\n", ois_dev.acc_data.z);
/* Print gyroscope data */
printf("OIS Gyro x-axis = %d\t", ois_dev.gyr_data.x);
printf("OIS Gyro y-axis= %d\t", ois_dev.gyr_data.y);
printf("OIS Gyro z-axis = %d\r\n", ois_dev.gyr_data.z);
}
}
if (rslt != BMI2_OK) {
printf("Error code: %d\n", rslt);
return;
}
/* Enable Advance Power Save Mode through host interface */
rslt = bmi2_set_adv_power_save(BMI2_ENABLE, &dev);
if (rslt != BMI2_OK) {
printf("Error: %d\n", rslt);
return;
}
```
@@ -0,0 +1,53 @@
BMI270 Sensor API
> This package contains the sensor APIs for the BMI270 sensor
## Sensor Overview
The BMI270 is a small, low power, low noise inertial measurement unit designed for use in mobile applications like augmented reality or indoor navigation which require highly accurate, real-time sensor data.
## Applications
### BMI270 (base)
- Any motion, No motion, Significant motion detectors
- Wrist worn Step counter and Step detector (Pedometer)
- Activity change recognition
- Still
- Walking
- Running
- Wrist gestures
- Push arm down
- Pivot up
- Wrist shake jiggle
- Flick in
- Flick out
- Wrist wear wake up
### BMI270 Context
- Step counter and Step detector (Pedometer)
- Activity change recognition
- Still
- Walking
- Running
### BMI270 Legacy
- Any motion, No motion, Significant motion detector
- Orientation detector (Advanced Potrait-Landscape)
- High-G, Low-G (Freefall) detector
- Flat detector
- Tap detection (Single, Double, Triple taps)
- Smartphone Step counter and Step detector (Pedometer)
- Activity change recognition
- Still
- Walking
- Running
### BMI270 Maximum FIFO
- Supports a 6kB FIFO
For more information refer product page [Link](https://www.bosch-sensortec.com/products/motion-sensors/imus/bmi270.html)
---

After

Width:  |  Height:  |  Size: 1.3 KiB

File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,420 @@
/**
* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved.
*
* BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @file bmi270.h
* @date 2023-05-03
* @version v2.86.1
*
*/
/**
* \ingroup bmi2xy
* \defgroup bmi270 BMI270
* @brief Sensor driver for BMI270 sensor
*/
#ifndef BMI270_H_
#define BMI270_H_
/*! CPP guard */
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************/
/*! Header files
****************************************************************************/
#include "bmi2.h"
/***************************************************************************/
/*! Macro definitions
****************************************************************************/
/*! @name BMI270 Chip identifier */
#define BMI270_CHIP_ID UINT8_C(0x24)
/*! @name BMI270 feature input start addresses */
#define BMI270_CONFIG_ID_STRT_ADDR UINT8_C(0x00)
#define BMI270_MAX_BURST_LEN_STRT_ADDR UINT8_C(0x02)
#define BMI270_CRT_GYRO_SELF_TEST_STRT_ADDR UINT8_C(0x03)
#define BMI270_ABORT_STRT_ADDR UINT8_C(0x03)
#define BMI270_AXIS_MAP_STRT_ADDR UINT8_C(0x04)
#define BMI270_GYRO_SELF_OFF_STRT_ADDR UINT8_C(0x05)
#define BMI270_NVM_PROG_PREP_STRT_ADDR UINT8_C(0x05)
#define BMI270_GYRO_GAIN_UPDATE_STRT_ADDR UINT8_C(0x06)
#define BMI270_ANY_MOT_STRT_ADDR UINT8_C(0x0C)
#define BMI270_NO_MOT_STRT_ADDR UINT8_C(0x00)
#define BMI270_SIG_MOT_STRT_ADDR UINT8_C(0x04)
#define BMI270_STEP_CNT_1_STRT_ADDR UINT8_C(0x00)
#define BMI270_STEP_CNT_4_STRT_ADDR UINT8_C(0x02)
#define BMI270_WRIST_GEST_STRT_ADDR UINT8_C(0x06)
#define BMI270_WRIST_WEAR_WAKE_UP_STRT_ADDR UINT8_C(0x00)
/*! @name BMI270 feature output start addresses */
#define BMI270_STEP_CNT_OUT_STRT_ADDR UINT8_C(0x00)
#define BMI270_STEP_ACT_OUT_STRT_ADDR UINT8_C(0x04)
#define BMI270_WRIST_GEST_OUT_STRT_ADDR UINT8_C(0x06)
#define BMI270_GYR_USER_GAIN_OUT_STRT_ADDR UINT8_C(0x08)
#define BMI270_GYRO_CROSS_SENSE_STRT_ADDR UINT8_C(0x0C)
#define BMI270_NVM_VFRM_OUT_STRT_ADDR UINT8_C(0x0E)
/*! @name Defines maximum number of pages */
#define BMI270_MAX_PAGE_NUM UINT8_C(8)
/*! @name Defines maximum number of feature input configurations */
#define BMI270_MAX_FEAT_IN UINT8_C(17)
/*! @name Defines maximum number of feature outputs */
#define BMI270_MAX_FEAT_OUT UINT8_C(7)
/*! @name Mask definitions for feature interrupt status bits */
#define BMI270_SIG_MOT_STATUS_MASK UINT8_C(0x01)
#define BMI270_STEP_CNT_STATUS_MASK UINT8_C(0x02)
#define BMI270_STEP_ACT_STATUS_MASK UINT8_C(0x04)
#define BMI270_WRIST_WAKE_UP_STATUS_MASK UINT8_C(0x08)
#define BMI270_WRIST_GEST_STATUS_MASK UINT8_C(0x10)
#define BMI270_NO_MOT_STATUS_MASK UINT8_C(0x20)
#define BMI270_ANY_MOT_STATUS_MASK UINT8_C(0x40)
/*! @name Mask definitions for feature interrupt mapping bits */
#define BMI270_INT_SIG_MOT_MASK UINT8_C(0x01)
#define BMI270_INT_STEP_COUNTER_MASK UINT8_C(0x02)
#define BMI270_INT_STEP_DETECTOR_MASK UINT8_C(0x02)
#define BMI270_INT_STEP_ACT_MASK UINT8_C(0x04)
#define BMI270_INT_WRIST_WEAR_WAKEUP_MASK UINT8_C(0x08)
#define BMI270_INT_WRIST_GEST_MASK UINT8_C(0x10)
#define BMI270_INT_NO_MOT_MASK UINT8_C(0x20)
#define BMI270_INT_ANY_MOT_MASK UINT8_C(0x40)
/*! @name Defines maximum number of feature interrupts */
#define BMI270_MAX_INT_MAP UINT8_C(8)
/***************************************************************************/
/*! BMI270 User Interface function prototypes
****************************************************************************/
/**
* \ingroup bmi270
* \defgroup bmi270ApiInit Initialization
* @brief Initialize the sensor and device structure
*/
/*!
* \ingroup bmi270ApiInit
* \page bmi270_api_bmi270_init bmi270_init
* \code
* int8_t bmi270_init(struct bmi2_dev *dev);
* \endcode
* @details This API:
* 1) updates the device structure with address of the configuration file.
* 2) Initializes BMI270 sensor.
* 3) Writes the configuration file.
* 4) Updates the feature offset parameters in the device structure.
* 5) Updates the maximum number of pages, in the device structure.
*
* @param[in, out] dev : Structure instance of bmi2_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_init(struct bmi2_dev *dev);
/**
* \ingroup bmi270
* \defgroup bmi270ApiSensor Feature Set
* @brief Enable / Disable features of the sensor
*/
/*!
* \ingroup bmi270ApiSensor
* \page bmi270_api_bmi270_sensor_enable bmi270_sensor_enable
* \code
* int8_t bmi270_sensor_enable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev);
* \endcode
* @details This API selects the sensors/features to be enabled.
*
* @param[in] sens_list : Pointer to select the sensor/feature.
* @param[in] n_sens : Number of sensors selected.
* @param[in, out] dev : Structure instance of bmi2_dev.
*
* @note Sensors/features that can be enabled.
*
*@verbatim
* sens_list | Values
* ----------------------------|-----------
* BMI2_ACCEL | 0
* BMI2_GYRO | 1
* BMI2_AUX | 2
* BMI2_SIG_MOTION | 3
* BMI2_ANY_MOTION | 4
* BMI2_NO_MOTION | 5
* BMI2_STEP_DETECTOR | 6
* BMI2_STEP_COUNTER | 7
* BMI2_STEP_ACTIVITY | 8
* BMI2_GYRO_GAIN_UPDATE | 9
* BMI2_WRIST_GESTURE | 19
* BMI2_WRIST_WEAR_WAKE_UP | 20
* BMI2_GYRO_SELF_OFF | 33
*@endverbatim
*
* @note :
* example uint8_t sens_list[2] = {BMI2_ACCEL, BMI2_GYRO};
* uint8_t n_sens = 2;
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_sensor_enable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev);
/*!
* \ingroup bmi270ApiSensor
* \page bmi270_api_bmi270_sensor_disable bmi270_sensor_disable
* \code
* int8_t bmi270_sensor_disable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev);
* \endcode
* @details This API selects the sensors/features to be disabled.
*
* @param[in] sens_list : Pointer to select the sensor/feature.
* @param[in] n_sens : Number of sensors selected.
* @param[in, out] dev : Structure instance of bmi2_dev.
*
* @note Sensors/features that can be disabled.
*
*@verbatim
* sens_list | Values
* ----------------------------|-----------
* BMI2_ACCEL | 0
* BMI2_GYRO | 1
* BMI2_AUX | 2
* BMI2_SIG_MOTION | 3
* BMI2_ANY_MOTION | 4
* BMI2_NO_MOTION | 5
* BMI2_STEP_DETECTOR | 6
* BMI2_STEP_COUNTER | 7
* BMI2_STEP_ACTIVITY | 8
* BMI2_GYRO_GAIN_UPDATE | 9
* BMI2_WRIST_GESTURE | 19
* BMI2_WRIST_WEAR_WAKE_UP | 20
* BMI2_GYRO_SELF_OFF | 33
*@endverbatim
*
* @note :
* example uint8_t sens_list[2] = {BMI2_ACCEL, BMI2_GYRO};
* uint8_t n_sens = 2;
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_sensor_disable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev);
/**
* \ingroup bmi270
* \defgroup bmi270ApiSensorC Sensor Configuration
* @brief Enable / Disable feature configuration of the sensor
*/
/*!
* \ingroup bmi270ApiSensorC
* \page bmi270_api_bmi270_set_sensor_config bmi270_set_sensor_config
* \code
* int8_t bmi270_set_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev);
* \endcode
* @details This API sets the sensor/feature configuration.
*
* @param[in] sens_cfg : Structure instance of bmi2_sens_config.
* @param[in] n_sens : Number of sensors selected.
* @param[in, out] dev : Structure instance of bmi2_dev.
*
* @note Sensors/features that can be configured
*
*@verbatim
* sens_list | Values
* ----------------------------|-----------
* BMI2_SIG_MOTION | 3
* BMI2_ANY_MOTION | 4
* BMI2_NO_MOTION | 5
* BMI2_STEP_DETECTOR | 6
* BMI2_STEP_COUNTER | 7
* BMI2_STEP_ACTIVITY | 8
* BMI2_WRIST_GESTURE | 19
* BMI2_WRIST_WEAR_WAKE_UP | 20
* BMI2_STEP_COUNTER_PARAMS | 28
*@endverbatim
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_set_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev);
/*!
* \ingroup bmi270ApiSensorC
* \page bmi270_api_bmi270_get_sensor_config bmi270_get_sensor_config
* \code
* int8_t bmi270_get_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev);
* \endcode
* @details This API gets the sensor/feature configuration.
*
* @param[in] sens_cfg : Structure instance of bmi2_sens_config.
* @param[in] n_sens : Number of sensors selected.
* @param[in, out] dev : Structure instance of bmi2_dev.
*
* @note Sensors/features whose configurations can be read.
*
*@verbatim
* sens_list | Values
* ----------------------------|-----------
* BMI2_SIG_MOTION | 3
* BMI2_ANY_MOTION | 4
* BMI2_NO_MOTION | 5
* BMI2_STEP_DETECTOR | 6
* BMI2_STEP_COUNTER | 7
* BMI2_STEP_ACTIVITY | 8
* BMI2_WRIST_GESTURE | 19
* BMI2_WRIST_WEAR_WAKE_UP | 20
* BMI2_STEP_COUNTER_PARAMS | 28
*@endverbatim
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_get_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev);
/**
* \ingroup bmi270
* \defgroup bmi270ApiSensorD Feature Sensor Data
* @brief Get feature sensor data
*/
/*!
* \ingroup bmi270ApiSensorD
* \page bmi270_api_bmi270_get_feature_data bmi270_get_feature_data
* \code
* int8_t bmi270_get_feature_data(struct bmi2_feat_sensor_data *feature_data, uint8_t n_sens, struct bmi2_dev *dev);
* \endcode
* @details This API gets the feature data.
*
* @param[out] feature_data : Structure instance of bmi2_feat_sensor_data.
* @param[in] n_sens : Number of sensors selected.
* @param[in] dev : Structure instance of bmi2_dev.
*
* @note Sensors/features whose data can be read
*
*@verbatim
* sens_list | Values
* ----------------------------|-----------
* BMI2_STEP_COUNTER | 7
* BMI2_STEP_ACTIVITY | 8
* BMI2_WRIST_GESTURE | 19
* BMI2_NVM_STATUS | 38
* BMI2_VFRM_STATUS | 39
*@endverbatim
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_get_feature_data(struct bmi2_feat_sensor_data *feature_data, uint8_t n_sens, struct bmi2_dev *dev);
/**
* \ingroup bmi270
* \defgroup bmi270ApiGyroUG Gyro User Gain
* @brief Set / Get Gyro User Gain of the sensor
*/
/*!
* \ingroup bmi270ApiGyroUG
* \page bmi270_api_bmi270_update_gyro_user_gain bmi270_update_gyro_user_gain
* \code
* int8_t bmi270_update_gyro_user_gain(const struct bmi2_gyro_user_gain_config *user_gain, struct bmi2_dev *dev);
* \endcode
* @details This API updates the gyroscope user-gain.
*
* @param[in] user_gain : Structure that stores user-gain configurations.
* @param[in] dev : Structure instance of bmi2_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_update_gyro_user_gain(const struct bmi2_gyro_user_gain_config *user_gain, struct bmi2_dev *dev);
/*!
* \ingroup bmi270ApiGyroUG
* \page bmi270_api_bmi270_read_gyro_user_gain bmi270_read_gyro_user_gain
* \code
* int8_t bmi270_read_gyro_user_gain(struct bmi2_gyro_user_gain_data *gyr_usr_gain, const struct bmi2_dev *dev);
* \endcode
* @details This API reads the compensated gyroscope user-gain values.
*
* @param[out] gyr_usr_gain : Structure that stores gain values.
* @param[in] dev : Structure instance of bmi2_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_read_gyro_user_gain(struct bmi2_gyro_user_gain_data *gyr_usr_gain, struct bmi2_dev *dev);
/*!
* \ingroup bmi270ApiInt
* \page bmi270_api_bmi270_map_feat_int bmi270_map_feat_int
* \code
* int8_t bmi270_map_feat_int(const struct bmi2_sens_int_config *sens_int, uint8_t n_sens, struct bmi2_dev *dev)
* \endcode
* @details This API maps/unmaps feature interrupts to that of interrupt pins.
*
* @param[in] sens_int : Structure instance of bmi2_sens_int_config.
* @param[in] n_sens : Number of interrupts to be mapped.
* @param[in] dev : Structure instance of bmi2_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_map_feat_int(const struct bmi2_sens_int_config *sens_int, uint8_t n_sens, struct bmi2_dev *dev);
/******************************************************************************/
/*! @name C++ Guard Macros */
/******************************************************************************/
#ifdef __cplusplus
}
#endif /* End of CPP guard */
#endif /* BMI270_H_ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,452 @@
/**
* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved.
*
* BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @file bmi270_context.h
* @date 2023-05-03
* @version v2.86.1
*
*/
/**
* \ingroup bmi2xy
* \defgroup bmi270_context BMI270_CONTEXT
* @brief Sensor driver for BMI270_CONTEXT sensor
*/
#ifndef BMI270_CONTEXT_H_
#define BMI270_CONTEXT_H_
/*! CPP guard */
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************/
/*! Header files
****************************************************************************/
#include "bmi2.h"
/***************************************************************************/
/*! Macro definitions
****************************************************************************/
/*! @name BMI270_CONTEXT Chip identifier */
#define BMI270_CONTEXT_CHIP_ID UINT8_C(0x24)
/*! @name BMI270_CONTEXT feature input start addresses */
#define BMI270_CONTEXT_CONFIG_ID_STRT_ADDR UINT8_C(0x06)
#define BMI270_CONTEXT_STEP_CNT_1_STRT_ADDR UINT8_C(0x00)
#define BMI270_CONTEXT_STEP_CNT_4_STRT_ADDR UINT8_C(0x02)
#define BMI270_CONTEXT_MAX_BURST_LEN_STRT_ADDR UINT8_C(0x08)
#define BMI270_CONTEXT_CRT_GYRO_SELF_TEST_STRT_ADDR UINT8_C(0x09)
#define BMI270_CONTEXT_ABORT_STRT_ADDR UINT8_C(0x09)
#define BMI270_CONTEXT_NVM_PROG_PREP_STRT_ADDR UINT8_C(0x0A)
#define BMI270_CONTEXT_ACT_RGN_SETT_STRT_ADDR UINT8_C(0x00)
#define BMI270_CONTEXT_ACT_RGN_STRT_ADDR UINT8_C(0x0A)
/*! @name BMI270_CONTEXT feature output start addresses */
#define BMI270_CONTEXT_STEP_CNT_OUT_STRT_ADDR UINT8_C(0x00)
#define BMI270_CONTEXT_GYR_USER_GAIN_OUT_STRT_ADDR UINT8_C(0x04)
#define BMI270_CONTEXT_GYRO_CROSS_SENSE_STRT_ADDR UINT8_C(0x0C)
#define BMI270_CONTEXT_NVM_VFRM_OUT_STRT_ADDR UINT8_C(0x0E)
/*! @name Defines maximum number of pages */
#define BMI270_CONTEXT_MAX_PAGE_NUM UINT8_C(8)
/*! @name Defines maximum number of feature input configurations */
#define BMI270_CONTEXT_MAX_FEAT_IN UINT8_C(10)
/*! @name Defines maximum number of feature outputs */
#define BMI270_CONTEXT_MAX_FEAT_OUT UINT8_C(5)
/*! @name Mask definitions for feature interrupt status bits */
#define BMI270_CONTEXT_STEP_CNT_STATUS_MASK UINT8_C(0x01)
/*! @name Mask definitions for feature interrupt mapping bits */
#define BMI270_C_INT_STEP_COUNTER_MASK UINT8_C(0x01)
#define BMI270_C_INT_STEP_DETECTOR_MASK UINT8_C(0x01)
/*! @name Defines maximum number of feature interrupts */
#define BMI270_C_MAX_INT_MAP UINT8_C(2)
/***************************************************************************/
/*! BMI270_CONTEXT User Interface function prototypes
****************************************************************************/
/**
* \ingroup bmi270_context
* \defgroup bmi270_contextApiInit Initialization
* @brief Initialize the sensor and device structure
*/
/*!
* \ingroup bmi270_contextApiInit
* \page bmi270_context_api_bmi270_context_init bmi270_context_init
* \code
* int8_t bmi270_context_init(struct bmi2_dev *dev);
* \endcode
* @details This API:
* 1) updates the device structure with address of the configuration file.
* 2) Initializes BMI270_CONTEXT sensor.
* 3) Writes the configuration file.
* 4) Updates the feature offset parameters in the device structure.
* 5) Updates the maximum number of pages, in the device structure.
*
* @param[in, out] dev : Structure instance of bmi2_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_context_init(struct bmi2_dev *dev);
/**
* \ingroup bmi270_context
* \defgroup bmi270_contextApiSensor Feature Set
* @brief Enable / Disable features of the sensor
*/
/*!
* \ingroup bmi270_contextApiSensor
* \page bmi270_context_api_bmi270_context_sensor_enable bmi270_context_sensor_enable
* \code
* int8_t bmi270_context_sensor_enable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev);
* \endcode
* @details This API selects the sensors/features to be enabled.
*
* @param[in] sens_list : Pointer to select the sensor/feature.
* @param[in] n_sens : Number of sensors selected.
* @param[in, out] dev : Structure instance of bmi2_dev.
*
* @note Sensors/features that can be enabled.
*
*@verbatim
* sens_list | Values
* ----------------------------|-----------
* BMI2_ACCEL | 0
* BMI2_GYRO | 1
* BMI2_AUX | 2
* BMI2_STEP_DETECTOR | 6
* BMI2_STEP_COUNTER | 7
* BMI2_GYRO_GAIN_UPDATE | 9
* BMI2_ACTIVITY_RECOGNITION | 34
*@endverbatim
*
* @note :
* example uint8_t sens_list[2] = {BMI2_ACCEL, BMI2_GYRO};
* uint8_t n_sens = 2;
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_context_sensor_enable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev);
/*!
* \ingroup bmi270_contextApiSensor
* \page bmi270_context_api_bmi270_context_sensor_disable bmi270_context_sensor_disable
* \code
* int8_t bmi270_context_sensor_disable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev);
* \endcode
* @details This API selects the sensors/features to be disabled.
*
* @param[in] sens_list : Pointer to select the sensor/feature.
* @param[in] n_sens : Number of sensors selected.
* @param[in, out] dev : Structure instance of bmi2_dev.
*
* @note Sensors/features that can be disabled.
*
*@verbatim
* sens_list | Values
* ----------------------------|-----------
* BMI2_ACCEL | 0
* BMI2_GYRO | 1
* BMI2_AUX | 2
* BMI2_STEP_DETECTOR | 6
* BMI2_STEP_COUNTER | 7
* BMI2_GYRO_GAIN_UPDATE | 9
* BMI2_ACTIVITY_RECOGNITION | 34
*@endverbatim
*
* @note :
* example uint8_t sens_list[2] = {BMI2_ACCEL, BMI2_GYRO};
* uint8_t n_sens = 2;
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_context_sensor_disable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev);
/**
* \ingroup bmi270_context
* \defgroup bmi270_contextApiSensorC Sensor Configuration
* @brief Enable / Disable feature configuration of the sensor
*/
/*!
* \ingroup bmi270_contextApiSensorC
* \page bmi270_context_api_bmi270_context_set_sensor_config bmi270_context_set_sensor_config
* \code
* int8_t bmi270_context_set_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev);
* \endcode
* @details This API sets the sensor/feature configuration.
*
* @param[in] sens_cfg : Structure instance of bmi2_sens_config.
* @param[in] n_sens : Number of sensors selected.
* @param[in, out] dev : Structure instance of bmi2_dev.
*
* @note Sensors/features that can be configured
*
*@verbatim
* sens_list | Values
* ----------------------------|-----------
* BMI2_STEP_DETECTOR | 6
* BMI2_STEP_COUNTER | 7
* BMI2_STEP_COUNTER_PARAMS | 28
*@endverbatim
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_context_set_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev);
/*!
* \ingroup bmi270_contextApiSensorC
* \page bmi270_context_api_bmi270_context_get_sensor_config bmi270_context_get_sensor_config
* \code
* int8_t bmi270_context_get_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev);
* \endcode
* @details This API gets the sensor/feature configuration.
*
* @param[in] sens_cfg : Structure instance of bmi2_sens_config.
* @param[in] n_sens : Number of sensors selected.
* @param[in, out] dev : Structure instance of bmi2_dev.
*
* @note Sensors/features whose configurations can be read.
*
*@verbatim
* sens_list | Values
* ----------------------------|-----------
* BMI2_STEP_DETECTOR | 6
* BMI2_STEP_COUNTER | 7
* BMI2_STEP_COUNTER_PARAMS | 28
*@endverbatim
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_context_get_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev);
/**
* \ingroup bmi270_context
* \defgroup bmi270_contextApiSensorD Feature Sensor Data
* @brief Get feature sensor data
*/
/*!
* \ingroup bmi270_contextApiSensorD
* \page bmi270_context_api_bmi270_context_get_feature_data bmi270_context_get_feature_data
* \code
* int8_t bmi270_context_get_feature_data(struct bmi2_feat_sensor_data *feature_data, uint8_t n_sens, struct bmi2_dev *dev);
* \endcode
* @details This API gets the feature data.
*
* @param[out] feature_data : Structure instance of bmi2_feat_sensor_data.
* @param[in] n_sens : Number of sensors selected.
* @param[in] dev : Structure instance of bmi2_dev.
*
* @note Sensors/features whose data can be read
*
*@verbatim
* sens_list | Values
* ---------------------|-----------
* BMI2_STEP_COUNTER | 7
* BMI2_NVM_STATUS | 38
* BMI2_VFRM_STATUS | 39
*@endverbatim
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_context_get_feature_data(struct bmi2_feat_sensor_data *feature_data, uint8_t n_sens,
struct bmi2_dev *dev);
/**
* \ingroup bmi270_context
* \defgroup bmi270_contextApiARecog Activity recognition settings
* @brief Set / Get activity recognition settings of the sensor
*/
/*!
* \ingroup bmi270_contextApiARecog
* \page bmi270_context_api_bmi270_context_get_act_recg_sett bmi270_context_get_act_recg_sett
* \code
* int8_t bmi270_context_get_act_recg_sett(struct bmi2_act_recg_sett *sett, struct bmi2_dev *dev);
* \endcode
* @details This api is used for retrieving the following activity recognition settings currently set.
* enable/disable post processing(0/1) by default -> 1(enable),
* Setting the min & max Gini's diversity index (GDI) threshold. min_GDI_tres(0-0XFFFF) by default ->(0x06e1)
* max_GDI_tres(0-0xFFFF) by default ->(0x0A66)
* buffer size for post processing. range (1-0x0A) default -> (0x0A)
* min segment confidence. range (1-0x0A) default -> (0x0A)
*
* @param[in] sett : Structure instance of bmi2_act_recg_sett.
* @param[in] dev : Structure instance of bmi2_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_context_get_act_recg_sett(struct bmi2_act_recg_sett *sett, struct bmi2_dev *dev);
/*!
* \ingroup bmi270_contextApiARecog
* \page bmi270_context_api_bmi270_context_set_act_recg_sett bmi270_context_set_act_recg_sett
* \code
* int8_t bmi270_context_set_act_recg_sett(const struct bmi2_act_recg_sett *sett, struct bmi2_dev *dev);
* \endcode
* @details This api is used for setting the following activity recognition settings
* enable/disable post processing(0/1) by default -> 1(enable),
* Setting the min & max Gini's diversity index (GDI) threshold. min_GDI_tres(0-0XFFFF) by default ->(0x06e1)
* max_GDI_tres(0-0xFFFF) by default ->(0x0A66)
* buffer size for post processing. range (1-0x0A) default -> (0x0A)
* min segment confidence. range (1-0x0A) default -> (0x0A)
*
* @param[in] sett : Structure instance of bmi2_act_recg_sett.
* @param[in] dev : Structure instance of bmi2_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_context_set_act_recg_sett(const struct bmi2_act_recg_sett *sett, struct bmi2_dev *dev);
/**
* \ingroup bmi270_contex
* \defgroup bmi270_contextApiactOut Activity Output
* @brief Activity output operations of the sensor
*/
/*!
* \ingroup bmi270_contextApiactOut
* \page bmi270_context_api_bmi270_context_get_act_recog_output bmi270_context_get_act_recog_output
* \code
* int8_t bmi270_context_get_act_recog_output(struct bmi2_act_recog_output *act_recog,
* uint16_t *act_frm_len,
* struct bmi2_fifo_frame *fifo,
* const struct bmi2_dev *dev);
*
* \endcode
* @details This internal API is used to parse the activity output from the
* FIFO in header mode.
*
* @param[out] act_recog : Pointer to buffer where the parsed activity data
* bytes are stored.
* @param[in] act_frm_len : Number of activity frames parsed.
* @param[in] fifo : Structure instance of bmi2_fifo_frame.
* @param[in] dev : Structure instance of bmi2_dev.
*
* @verbatim
* ----------------------------------------------------------------------------
* bmi2_act_rec_output |
* Structure parameters | Description
*--------------------------|--------------------------------------------------
* time_stamp | time-stamp (expressed in 50Hz ticks)
* -------------------------|---------------------------------------------------
* type | Type of activity
* -------------------------|---------------------------------------------------
* stat | Activity status
* -------------------------|---------------------------------------------------
* @endverbatim
*
*@verbatim
* type | Activities
*----------|---------------------
* 0 | UNKNOWN
* 1 | STILL
* 2 | WALK
* 3 | RUN
* 4 | BIKE
* 5 | VEHICLE
* 6 | TILTED
*@endverbatim
*
*
*@verbatim
* stat | Activity status
*----------|---------------------
* 1 | START
* 2 | END
*@endverbatim
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_context_get_act_recog_output(struct bmi2_act_recog_output *act_recog,
uint16_t *act_frm_len,
struct bmi2_fifo_frame *fifo,
const struct bmi2_dev *dev);
/*!
* \ingroup bmi270_contextApiInt
* \page bmi270_context_api_bmi270_context_map_feat_int bmi270_context_map_feat_int
* \code
* int8_t bmi270_context_map_feat_int(const struct bmi2_sens_int_config *sens_int, uint8_t n_sens, struct bmi2_dev *dev)
* \endcode
* @details This API maps/unmaps feature interrupts to that of interrupt pins.
*
* @param[in] sens_int : Structure instance of bmi2_sens_int_config.
* @param[in] n_sens : Number of interrupts to be mapped.
* @param[in] dev : Structure instance of bmi2_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_context_map_feat_int(const struct bmi2_sens_int_config *sens_int, uint8_t n_sens, struct bmi2_dev *dev);
/******************************************************************************/
/*! @name C++ Guard Macros */
/******************************************************************************/
#ifdef __cplusplus
}
#endif /* End of CPP guard */
#endif /* BMI270_CONTEXT_H_ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,411 @@
/**
* Copyright (c) 2025 Bosch Sensortec GmbH. All rights reserved.
*
* BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @file bmi270_dsd.h
* @date 2025-04-22
* @version v2.113.0
*
*/
/**
* \ingroup bmi2xy
* \defgroup bmi270_dsd BMI270_DSD
* @brief Sensor driver for BMI270_DSD sensor
*/
#ifndef BMI270_DSD_H_
#define BMI270_DSD_H_
/*! CPP guard */
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************/
/*! Header files
****************************************************************************/
#include "bmi2.h"
/***************************************************************************/
/*! Macro definitions
****************************************************************************/
/*! @name BMI270_DSD chip identifier */
#define BMI270_DSD_CHIP_ID UINT8_C(0x24)
/*! @name BMI270_DSD feature input start addresses */
#define BMI270_DSD_CONFIG_ID_STRT_ADDR UINT8_C(0x00)
#define BMI270_DSD_MAX_BURST_LEN_STRT_ADDR UINT8_C(0x02)
#define BMI270_DSD_CRT_GYRO_SELF_TEST_STRT_ADDR UINT8_C(0x03)
#define BMI270_DSD_ABORT_STRT_ADDR UINT8_C(0x03)
#define BMI270_DSD_GYRO_SELF_OFF_STRT_ADDR UINT8_C(0x05)
#define BMI270_DSD_NVM_PROG_PREP_STRT_ADDR UINT8_C(0x05)
#define BMI270_DSD_GYRO_GAIN_UPDATE_STRT_ADDR UINT8_C(0x06)
#define BMI270_DSD_DOOR_STATUS_DET_STRT_ADDR UINT8_C(0x00)
#define BMI270_DSD_DOOR_STATUS_DET_2_STRT_ADDR UINT8_C(0x00)
#define BMI270_DSD_ANY_MOT_STRT_ADDR UINT8_C(0x08)
#define BMI270_DSD_NO_MOT_STRT_ADDR UINT8_C(0x04)
/*! @name BMI270_DSD feature output start addresses */
#define BMI270_DSD_DOOR_EVENT_OUT_STRT_ADDR UINT8_C(0x06)
#define BMI270_DSD_HEADING_OUT_STRT_ADDR UINT8_C(0x08)
#define BMI270_DSD_GYR_USER_GAIN_OUT_STRT_ADDR UINT8_C(0x0A)
#define BMI270_DSD_GYRO_CROSS_SENSE_STRT_ADDR UINT8_C(0x0C)
#define BMI270_DSD_NVM_VFRM_OUT_STRT_ADDR UINT8_C(0x0E)
/*! @name Defines maximum number of pages */
#define BMI270_DSD_MAX_PAGE_NUM UINT8_C(8)
/*! @name Defines maximum number of feature input configurations */
#define BMI270_DSD_MAX_FEAT_IN UINT8_C(11)
/*! @name Defines maximum number of feature outputs */
#define BMI270_DSD_MAX_FEAT_OUT UINT8_C(6)
/*! @name Mask definitions for feature interrupt mapping bits */
#define BMI270_DSD_INT_DOOR_STATE_DETECTOR_MASK UINT8_C(0x08)
#define BMI270_DSD_INT_NO_MOT_MASK UINT8_C(0x20)
#define BMI270_DSD_INT_ANY_MOT_MASK UINT8_C(0x40)
/*! @name Defines maximum number of feature interrupts */
#define BMI270_DSD_MAX_INT_MAP UINT8_C(3)
/*! @name BMI270 door state detector output type */
#define BMI270_DSD_DOOR_EVENT_OUTPUT UINT8_C(1)
#define BMI270_DSD_HEADING_OUTPUT UINT8_C(2)
/*! @name Mask definitions for BMI2 door state detector feature configuration */
#define BMI270_DSD_ENABLE_MASK UINT8_C(0x01)
#define BMI270_DSD_REMAP_FLAG_MASK UINT8_C(0x60) /* 0x 1100000 */
#define BMI270_DSD_Z_SIGN_MASK UINT8_C(0x80) /* 0x10000000 */
#define BMI270_DSD_Z_AXIS_MASK UINT16_C(0x300)
#define BMI270_DSD_GYRO_CALIB_APPLY_MASK UINT16_C(0x400)
#define BMI270_DSD_INIT_CALIB_THR_MASK UINT8_C(0xFF)
#define BMI270_DSD_RESET_ENABLE_FLAG_MASK UINT16_C(0x100)
#define BMI270_DSD_BIAS_X_LOW_WORD_MASK UINT16_C(0xFFFF)
#define BMI270_DSD_BIAS_X_HIGH_WORD_MASK UINT16_C(0xFFFF)
#define BMI270_DSD_BIAS_Y_LOW_WORD_MASK UINT16_C(0xFFFF)
#define BMI270_DSD_BIAS_Y_HIGH_WORD_MASK UINT16_C(0xFFFF)
#define BMI270_DSD_BIAS_Z_LOW_WORD_MASK UINT16_C(0xFFFF)
#define BMI270_DSD_BIAS_Z_HIGH_WORD_MASK UINT16_C(0xFFFF)
#define BMI270_DSD_DOOR_CLOSED_THR_MASK UINT16_C(0x3FF)
#define BMI270_DSD_INT_MASK UINT8_C(0x08)
/*! @name Bit position definitions for BMI2 door state detector feature configuration */
#define BMI270_DSD_REMAP_FLAG_POS UINT8_C(0x5) /* 0x 100000 */
#define BMI270_DSD_Z_SIGN_POS UINT8_C(0x7) /* 0x10000000 */
#define BMI270_DSD_Z_AXIS_POS UINT16_C(0x8)
#define BMI270_DSD_GYRO_CALIB_APPLY_POS UINT16_C(0xA)
#define BMI270_DSD_RESET_ENABLE_FLAG_POS UINT16_C(0x8)
/*! @name Defines GPIO0 output MASK */
#define BMI270_DSD_DSD_OUT_MASK UINT8_C(0x03)
#define BMI270_DSD_CALIB_FLAG_MASK UINT8_C(0x04)
/*! @name Defines GPIO0 output POS */
#define BMI270_DSD_CALIB_FLAG_POS UINT8_C(0x02)
/*! @name Mask definitions for feature interrupt status bits */
#define BMI270_DSD_STATUS_MASK UINT8_C(0x08)
#define BMI270_DSD_NO_MOT_STATUS_MASK UINT8_C(0x20)
#define BMI270_DSD_ANY_MOT_STATUS_MASK UINT8_C(0x40)
/***************************************************************************/
/*! BMI270_DSD User Interface function prototypes
****************************************************************************/
/**
* \ingroup bmi270_dsd
* \defgroup bmi270_dsdApiInit Initialization
* @brief Initialize the sensor and device structure
*/
/*!
* \ingroup bmi270_dsdApiInit
* \page bmi270_dsd_api_bmi270_dsd_init bmi270_dsd_init
* \code
* int8_t bmi270_dsd_init(struct bmi2_dev *dev);
* \endcode
* @details This API:
* 1) updates the device structure with address of the configuration file.
* 2) Initializes BMI270_DSD sensor.
* 3) Writes the configuration file.
* 4) Updates the feature offset parameters in the device structure.
* 5) Updates the maximum number of pages, in the device structure.
*
* @param[in, out] dev : Structure instance of bmi2_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_dsd_init(struct bmi2_dev *dev);
/**
* \ingroup bmi270_dsd
* \defgroup bmi270_dsdApiSensor Feature Set
* @brief Enable / Disable features of the sensor
*/
/*!
* \ingroup bmi270_dsdApiSensor
* \page bmi270_dsd_api_bmi270_dsd_sensor_enable bmi270_dsd_sensor_enable
* \code
* int8_t bmi270_dsd_sensor_enable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev);
* \endcode
* @details This API selects the sensors/features to be enabled.
*
* @param[in] sens_list : Pointer to select the sensor/feature.
* @param[in] n_sens : Number of sensors selected.
* @param[in, out] dev : Structure instance of bmi2_dev.
*
* @note Sensors/features that can be enabled.
*
*@verbatim
* sens_list | Values
* ----------------------------|-----------
* BMI2_ACCEL | 0
* BMI2_GYRO | 1
* BMI2_AUX | 2
* BMI2_GYRO_GAIN_UPDATE | 9
* BMI2_DOOR_STATE_DETECTOR | 57
* BMI2_TEMP | 31
*@endverbatim
*
* @note :
* example uint8_t sens_list[2] = {BMI2_ACCEL, BMI2_GYRO};
* uint8_t n_sens = 2;
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_dsd_sensor_enable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev);
/*!
* \ingroup bmi270_dsdApiSensor
* \page bmi270_dsd_api_bmi270_dsd_sensor_disable bmi270_dsd_sensor_disable
* \code
* int8_t bmi270_dsd_sensor_disable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev);
* \endcode
* @details This API selects the sensors/features to be disabled.
*
* @param[in] sens_list : Pointer to select the sensor/feature.
* @param[in] n_sens : Number of sensors selected.
* @param[in, out] dev : Structure instance of bmi2_dev.
*
* @note Sensors/features that can be disabled.
*
*@verbatim
* sens_list | Values
* ----------------------------|-----------
* BMI2_ACCEL | 0
* BMI2_GYRO | 1
* BMI2_AUX | 2
* BMI2_GYRO_GAIN_UPDATE | 9
* BMI2_DOOR_STATE_DETECTOR | 57
* BMI2_TEMP | 31
*@endverbatim
*
* @note :
* example uint8_t sens_list[2] = {BMI2_ACCEL, BMI2_GYRO};
* uint8_t n_sens = 2;
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_dsd_sensor_disable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev);
/**
* \ingroup bmi270_dsd
* \defgroup bmi270_dsdApiSensorC Sensor Configuration
* @brief Enable / Disable feature configuration of the sensor
*/
/*!
* \ingroup bmi270_dsdApiSensorC
* \page bmi270_dsd_api_bmi270_dsd_set_sensor_config bmi270_dsd_set_sensor_config
* \code
* int8_t bmi270_dsd_set_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev);
* \endcode
* @details This API sets the sensor/feature configuration.
*
* @param[in] sens_cfg : Structure instance of bmi2_sens_config.
* @param[in] n_sens : Number of sensors selected.
* @param[in, out] dev : Structure instance of bmi2_dev.
*
* @note Sensors/features that can be configured
*
*@verbatim
* sens_list | Values
* ----------------------------|-----------
* BMI2_DOOR_STATE_DETECTOR | 57
*@endverbatim
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_dsd_set_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev);
/*!
* \ingroup bmi270_dsdApiSensorC
* \page bmi270_dsd_api_bmi270_dsd_get_sensor_config bmi270_dsd_get_sensor_config
* \code
* int8_t bmi270_dsd_get_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev);
* \endcode
* @details This API gets the sensor/feature configuration.
*
* @param[in] sens_cfg : Structure instance of bmi2_sens_config.
* @param[in] n_sens : Number of sensors selected.
* @param[in, out] dev : Structure instance of bmi2_dev.
*
* @note Sensors/features whose configurations can be read.
*
*@verbatim
* sens_list | Values
* ----------------------------|-----------
* BMI2_DOOR_STATE_DETECTOR | 57
*@endverbatim
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_dsd_get_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev);
/**
* \ingroup bmi270_dsd
* \defgroup bmi270_dsdApiSensorD Feature Sensor Data
* @brief Get feature sensor data
*/
/*!
* \ingroup bmi270_dsdApiSensorD
* \page bmi270_dsd_api_bmi270_dsd_get_feature_data bmi270_dsd_get_feature_data
* \code
* int8_t bmi270_dsd_get_feature_data(struct bmi2_feat_sensor_data *feature_data, uint8_t n_sens, struct bmi2_dev *dev);
* \endcode
* @details This API gets the feature data for accelerometer, gyroscope,
* auxiliary sensor, step counter, high-g, gyroscope user-gain update,
* orientation, gyroscope cross sensitivity and error status for NVM and VFRM.
*
* @param[out] feature_data : Structure instance of bmi2_feat_sensor_data.
* @param[in] n_sens : Number of sensors selected.
* @param[in] dev : Structure instance of bmi2_dev.
*
* @note Sensors/features whose data can be read
*
*@verbatim
* sens_list | Values
* -----------------------------|-----------
* BMI2_DOOR_STATE_DETECTOR | 57
* BMI2_NVM_STATUS | 38
* BMI2_VFRM_STATUS | 39
*@endverbatim
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_dsd_get_feature_data(struct bmi2_feat_sensor_data *feature_data, uint8_t n_sens, struct bmi2_dev *dev);
/**
* \ingroup bmi270_dsd
* \defgroup bmi270_dsdApiGyroUG Gyro User Gain
* @brief Set / Get Gyro User Gain of the sensor
*/
/*!
* \ingroup bmi270_dsdApiGyroUG
* \page bmi270_dsd_api_bmi270_dsd_update_gyro_user_gain bmi270_dsd_update_gyro_user_gain
* \code
* int8_t bmi270_dsd_update_gyro_user_gain(const struct bmi2_gyro_user_gain_config *user_gain, struct bmi2_dev *dev);
* \endcode
* @details This API updates the gyroscope user-gain.
*
* @param[in] user_gain : Structure that stores user-gain configurations.
* @param[in] dev : Structure instance of bmi2_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_dsd_update_gyro_user_gain(const struct bmi2_gyro_user_gain_config *user_gain, struct bmi2_dev *dev);
/*!
* \ingroup bmi270_dsdApiGyroUG
* \page bmi270_dsd_api_bmi270_dsd_read_gyro_user_gain bmi270_dsd_read_gyro_user_gain
* \code
* int8_t bmi270_dsd_read_gyro_user_gain(struct bmi2_gyro_user_gain_data *gyr_usr_gain, const struct bmi2_dev *dev);
* \endcode
* @details This API reads the compensated gyroscope user-gain values.
*
* @param[out] gyr_usr_gain : Structure that stores gain values.
* @param[in] dev : Structure instance of bmi2_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_dsd_read_gyro_user_gain(struct bmi2_gyro_user_gain_data *gyr_usr_gain, struct bmi2_dev *dev);
/*!
* \ingroup bmi270_dsdApiInt
* \page bmi270_dsd_api_bmi270_dsd_map_feat_int bmi270_dsd_map_feat_int
* \code
* int8_t bmi270_dsd_map_feat_int(const struct bmi2_sens_int_config *sens_int, uint8_t n_sens, struct bmi2_dev *dev)
* \endcode
* @details This API maps/unmaps feature interrupts to that of interrupt pins.
*
* @param[in] sens_int : Structure instance of bmi2_sens_int_config.
* @param[in] n_sens : Number of interrupts to be mapped.
* @param[in] dev : Structure instance of bmi2_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_dsd_map_feat_int(const struct bmi2_sens_int_config *sens_int, uint8_t n_sens, struct bmi2_dev *dev);
/******************************************************************************/
/*! @name C++ Guard Macros */
/******************************************************************************/
#ifdef __cplusplus
}
#endif /* End of CPP guard */
#endif /* BMI270_DSD_H_ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,460 @@
/**
* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved.
*
* BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @file bmi270_legacy.h
* @date 2023-05-03
* @version v2.86.1
*
*/
/* BMI270_legacy offers same low-power features as in BMI160 */
/**
* \ingroup bmi2xy
* \defgroup bmi270_legacy BMI270_LEGACY
* @brief Sensor driver for BMI270_LEGACY sensor
*/
#ifndef BMI270_LEGACY_H_
#define BMI270_LEGACY_H_
/*! CPP guard */
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************/
/*! Header files
****************************************************************************/
#include "bmi2.h"
/***************************************************************************/
/*! Macro definitions
****************************************************************************/
/*! @name BMI270_LEGACY chip identifier */
#define BMI270_LEGACY_CHIP_ID UINT8_C(0x24)
/*! @name BMI270_LEGACY feature input start addresses */
#define BMI270_LEGACY_CONFIG_ID_STRT_ADDR UINT8_C(0x00)
#define BMI270_LEGACY_MAX_BURST_LEN_STRT_ADDR UINT8_C(0x02)
#define BMI270_LEGACY_CRT_GYRO_SELF_TEST_STRT_ADDR UINT8_C(0x03)
#define BMI270_LEGACY_ABORT_STRT_ADDR UINT8_C(0x03)
#define BMI270_LEGACY_AXIS_MAP_STRT_ADDR UINT8_C(0x04)
#define BMI270_LEGACY_GYRO_SELF_OFF_STRT_ADDR UINT8_C(0x05)
#define BMI270_LEGACY_NVM_PROG_PREP_STRT_ADDR UINT8_C(0x05)
#define BMI270_LEGACY_ANY_MOT_STRT_ADDR UINT8_C(0x06)
#define BMI270_LEGACY_NO_MOT_STRT_ADDR UINT8_C(0x0A)
#define BMI270_LEGACY_ORIENT_STRT_ADDR UINT8_C(0x00)
#define BMI270_LEGACY_HIGH_G_STRT_ADDR UINT8_C(0x04)
#define BMI270_LEGACY_LOW_G_STRT_ADDR UINT8_C(0x0A)
#define BMI270_LEGACY_FLAT_STRT_ADDR UINT8_C(0x00)
#define BMI270_LEGACY_SIG_MOT_STRT_ADDR UINT8_C(0x04)
#define BMI270_LEGACY_STEP_COUNT_STRT_ADDR UINT8_C(0x00)
#define BMI270_LEGACY_GYRO_USERGAIN_UPDATE_STRT_ADDR UINT8_C(0x04)
#define BMI270_LEGACY_TAP_DETECT_1_STRT_ADDR UINT8_C(0x00)
#define BMI270_LEGACY_TAP_DETECT_2_STRT_ADDR UINT8_C(0x00)
/*! @name BMI270_LEGACY feature output start addresses */
#define BMI270_LEGACY_STEP_CNT_OUT_STRT_ADDR UINT8_C(0x00)
#define BMI270_LEGACY_STEP_ACT_OUT_STRT_ADDR UINT8_C(0x04)
#define BMI270_LEGACY_ORIENT_HIGH_G_OUT_STRT_ADDR UINT8_C(0x06)
#define BMI270_LEGACY_GYR_USER_GAIN_OUT_STRT_ADDR UINT8_C(0x08)
#define BMI270_LEGACY_GYRO_CROSS_SENSE_STRT_ADDR UINT8_C(0x0C)
#define BMI270_LEGACY_NVM_VFRM_OUT_STRT_ADDR UINT8_C(0x0E)
/*! @name Defines maximum number of pages */
#define BMI270_LEGACY_MAX_PAGE_NUM UINT8_C(8)
/*! @name Defines maximum number of feature input configurations */
#define BMI270_LEGACY_MAX_FEAT_IN UINT8_C(23)
/*! @name Defines maximum number of feature outputs */
#define BMI270_LEGACY_MAX_FEAT_OUT UINT8_C(8)
/*! @name Mask definitions for feature interrupt status bits */
#define BMI270_LEGACY_SIG_MOT_STATUS_MASK UINT8_C(0x01)
#define BMI270_LEGACY_STEP_CNT_STATUS_MASK UINT8_C(0x02)
#define BMI270_LEGACY_HIGH_G_STATUS_MASK UINT8_C(0x04)
#define BMI270_LEGACY_LOW_G_STATUS_MASK UINT8_C(0x04)
#define BMI270_LEGACY_TAP_STATUS_MASK UINT8_C(0x08)
#define BMI270_LEGACY_FLAT_STATUS_MASK UINT8_C(0x10)
#define BMI270_LEGACY_NO_MOT_STATUS_MASK UINT8_C(0x20)
#define BMI270_LEGACY_ANY_MOT_STATUS_MASK UINT8_C(0x40)
#define BMI270_LEGACY_ORIENT_STATUS_MASK UINT8_C(0x80)
#define BMI270_LEGACY_SINGLE_TAP_MASK UINT8_C(0x20)
#define BMI270_LEGACY_DOUBLE_TAP_MASK UINT8_C(0x40)
#define BMI270_LEGACY_TRIPLE_TAP_MASK UINT8_C(0x80)
/*! @name Status register for tap */
#define BMI270_LEGACY_TAP_STATUS_REG UINT8_C(0x20)
/*! @name Macros for high-g interrupt axis/sign */
#define BMI270_LEGACY_HIGH_G_DETECT_X UINT8_C(0x08)
#define BMI270_LEGACY_HIGH_G_DETECT_Y UINT8_C(0x10)
#define BMI270_LEGACY_HIGH_G_DETECT_Z UINT8_C(0x20)
#define BMI270_LEGACY_HIGH_G_DETECT_SIGN UINT8_C(0x40)
/*! @name Mask definitions for feature interrupt mapping bits */
#define BMI270_LEGACY_INT_SIG_MOT_MASK UINT8_C(0x01)
#define BMI270_LEGACY_INT_STEP_COUNTER_MASK UINT8_C(0x02)
#define BMI270_LEGACY_INT_STEP_DETECTOR_MASK UINT8_C(0x02)
#define BMI270_LEGACY_INT_STEP_ACTIVITY_MASK UINT8_C(0x02)
#define BMI270_LEGACY_INT_HIGH_G_MASK UINT8_C(0x04)
#define BMI270_LEGACY_INT_LOW_G_MASK UINT8_C(0x04)
#define BMI270_LEGACY_INT_TAP_MASK UINT8_C(0x08)
#define BMI270_LEGACY_INT_FLAT_MASK UINT8_C(0x10)
#define BMI270_LEGACY_INT_NO_MOT_MASK UINT8_C(0x20)
#define BMI270_LEGACY_INT_ANY_MOT_MASK UINT8_C(0x40)
#define BMI270_LEGACY_INT_ORIENT_MASK UINT8_C(0x80)
#define BMI270_LEGACY_INT_SINGLE_TAP_MASK UINT8_C(0x20)
#define BMI270_LEGACY_INT_DOUBLE_TAP_MASK UINT8_C(0x40)
#define BMI270_LEGACY_INT_TRIPLE_TAP_MASK UINT8_C(0x80)
/*! @name Defines maximum number of feature interrupts */
#define BMI270_LEGACY_MAX_INT_MAP UINT8_C(14)
/***************************************************************************/
/*! BMI270_LEGACY User Interface function prototypes
****************************************************************************/
/**
* \ingroup bmi270_legacy
* \defgroup bmi270_legacyApiInit Initialization
* @brief Initialize the sensor and device structure
*/
/*!
* \ingroup bmi270_legacyApiInit
* \page bmi270_legacy_api_bmi270_legacy_init bmi270_legacy_init
* \code
* int8_t bmi270_legacy_init(struct bmi2_dev *dev);
* \endcode
* @details This API:
* 1) updates the device structure with address of the configuration file.
* 2) Initializes BMI270_LEGACY sensor.
* 3) Writes the configuration file.
* 4) Updates the feature offset parameters in the device structure.
* 5) Updates the maximum number of pages, in the device structure.
*
* @param[in, out] dev : Structure instance of bmi2_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_legacy_init(struct bmi2_dev *dev);
/**
* \ingroup bmi270_legacy
* \defgroup bmi270_legacyApiSensor Feature Set
* @brief Enable / Disable features of the sensor
*/
/*!
* \ingroup bmi270_legacyApiSensor
* \page bmi270_legacy_api_bmi270_legacy_sensor_enable bmi270_legacy_sensor_enable
* \code
* int8_t bmi270_legacy_sensor_enable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev);
* \endcode
* @details This API selects the sensors/features to be enabled.
*
* @param[in] sens_list : Pointer to select the sensor/feature.
* @param[in] n_sens : Number of sensors selected.
* @param[in, out] dev : Structure instance of bmi2_dev.
*
* @note Sensors/features that can be enabled.
*
*@verbatim
* sens_list | Values
* ----------------------------|-----------
* BMI2_ACCEL | 0
* BMI2_GYRO | 1
* BMI2_AUX | 2
* BMI2_SIG_MOTION | 3
* BMI2_ANY_MOTION | 4
* BMI2_NO_MOTION | 5
* BMI2_STEP_DETECTOR | 6
* BMI2_STEP_COUNTER | 7
* BMI2_STEP_ACTIVITY | 8
* BMI2_GYRO_GAIN_UPDATE | 9
* BMI2_ORIENTATION | 14
* BMI2_HIGH_G | 15
* BMI2_LOW_G | 16
* BMI2_FLAT | 17
* BMI2_SINGLE_TAP | 25
* BMI2_DOUBLE_TAP | 26
* BMI2_TRIPLE_TAP | 27
* BMI2_TEMP | 31
*@endverbatim
*
* @note :
* example uint8_t sens_list[2] = {BMI2_ACCEL, BMI2_GYRO};
* uint8_t n_sens = 2;
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_legacy_sensor_enable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev);
/*!
* \ingroup bmi270_legacyApiSensor
* \page bmi270_legacy_api_bmi270_legacy_sensor_disable bmi270_legacy_sensor_disable
* \code
* int8_t bmi270_legacy_sensor_disable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev);
* \endcode
* @details This API selects the sensors/features to be disabled.
*
* @param[in] sens_list : Pointer to select the sensor/feature.
* @param[in] n_sens : Number of sensors selected.
* @param[in, out] dev : Structure instance of bmi2_dev.
*
* @note Sensors/features that can be disabled.
*
*@verbatim
* sens_list | Values
* ----------------------------|-----------
* BMI2_ACCEL | 0
* BMI2_GYRO | 1
* BMI2_AUX | 2
* BMI2_SIG_MOTION | 3
* BMI2_ANY_MOTION | 4
* BMI2_NO_MOTION | 5
* BMI2_STEP_DETECTOR | 6
* BMI2_STEP_COUNTER | 7
* BMI2_STEP_ACTIVITY | 8
* BMI2_GYRO_GAIN_UPDATE | 9
* BMI2_ORIENTATION | 14
* BMI2_HIGH_G | 15
* BMI2_LOW_G | 16
* BMI2_FLAT | 17
* BMI2_SINGLE_TAP | 25
* BMI2_DOUBLE_TAP | 26
* BMI2_TRIPLE_TAP | 27
* BMI2_TEMP | 31
*@endverbatim
*
* @note :
* example uint8_t sens_list[2] = {BMI2_ACCEL, BMI2_GYRO};
* uint8_t n_sens = 2;
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_legacy_sensor_disable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev);
/**
* \ingroup bmi270_legacy
* \defgroup bmi270_legacyApiSensorC Sensor Configuration
* @brief Enable / Disable feature configuration of the sensor
*/
/*!
* \ingroup bmi270_legacyApiSensorC
* \page bmi270_legacy_api_bmi270_legacy_set_sensor_config bmi270_legacy_set_sensor_config
* \code
* int8_t bmi270_legacy_set_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev);
* \endcode
* @details This API sets the sensor/feature configuration.
*
* @param[in] sens_cfg : Structure instance of bmi2_sens_config.
* @param[in] n_sens : Number of sensors selected.
* @param[in, out] dev : Structure instance of bmi2_dev.
*
* @note Sensors/features that can be configured
*
*@verbatim
* sens_list | Values
* ----------------------------|-----------
* BMI2_SIG_MOTION | 3
* BMI2_ANY_MOTION | 4
* BMI2_NO_MOTION | 5
* BMI2_STEP_DETECTOR | 6
* BMI2_STEP_COUNTER | 7
* BMI2_STEP_ACTIVITY | 8
* BMI2_ORIENTATION | 14
* BMI2_HIGH_G | 15
* BMI2_LOW_G | 16
* BMI2_FLAT | 17
* BMI2_TAP | 28
*@endverbatim
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_legacy_set_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev);
/*!
* \ingroup bmi270_legacyApiSensorC
* \page bmi270_legacy_api_bmi270_legacy_get_sensor_config bmi270_legacy_get_sensor_config
* \code
* int8_t bmi270_legacy_get_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev);
* \endcode
* @details This API gets the sensor/feature configuration.
*
* @param[in] sens_cfg : Structure instance of bmi2_sens_config.
* @param[in] n_sens : Number of sensors selected.
* @param[in, out] dev : Structure instance of bmi2_dev.
*
* @note Sensors/features whose configurations can be read.
*
*@verbatim
* sens_list | Values
* ----------------------------|-----------
* BMI2_SIG_MOTION | 3
* BMI2_ANY_MOTION | 4
* BMI2_NO_MOTION | 5
* BMI2_STEP_DETECTOR | 6
* BMI2_STEP_COUNTER | 7
* BMI2_STEP_ACTIVITY | 8
* BMI2_ORIENTATION | 14
* BMI2_HIGH_G | 15
* BMI2_LOW_G | 16
* BMI2_FLAT | 17
* BMI2_TAP | 28
*@endverbatim
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_legacy_get_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev);
/**
* \ingroup bmi270_legacy
* \defgroup bmi270_legacyApiSensorD Feature Sensor Data
* @brief Get feature sensor data
*/
/*!
* \ingroup bmi270_legacyApiSensorD
* \page bmi270_legacy_api_bmi270_legacy_get_feature_data bmi270_legacy_get_feature_data
* \code
* int8_t bmi270_legacy_get_feature_data(struct bmi2_feat_sensor_data *feature_data, uint8_t n_sens, struct bmi2_dev *dev);
* \endcode
* @details This API gets the feature data.
*
* @param[out] feature_data : Structure instance of bmi2_feat_sensor_data.
* @param[in] n_sens : Number of sensors selected.
* @param[in] dev : Structure instance of bmi2_dev.
*
* @note Sensors/features whose data can be read
*
*@verbatim
* sens_list | Values
* ---------------------|-----------
* BMI2_STEP_COUNTER | 7
* BMI2_STEP_ACTIVITY | 8
* BMI2_ORIENTATION | 14
* BMI2_HIGH_G | 15
* BMI2_NVM_STATUS | 38
* BMI2_VFRM_STATUS | 39
*@endverbatim
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_legacy_get_feature_data(struct bmi2_feat_sensor_data *feature_data, uint8_t n_sens, struct bmi2_dev *dev);
/**
* \ingroup bmi270_legacy
* \defgroup bmi270_legacyApiGyroUG Gyro User Gain
* @brief Set / Get Gyro User Gain of the sensor
*/
/*!
* \ingroup bmi270_legacyApiGyroUG
* \page bmi270_legacy_api_bmi270_legacy_update_gyro_user_gain bmi270_legacy_update_gyro_user_gain
* \code
* int8_t bmi270_legacy_update_gyro_user_gain(const struct bmi2_gyro_user_gain_config *user_gain, struct bmi2_dev *dev);
* \endcode
* @details This API updates the gyroscope user-gain.
*
* @param[in] user_gain : Structure that stores user-gain configurations.
* @param[in] dev : Structure instance of bmi2_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_legacy_update_gyro_user_gain(const struct bmi2_gyro_user_gain_config *user_gain, struct bmi2_dev *dev);
/*!
* \ingroup bmi270_legacyApiGyroUG
* \page bmi270_legacy_api_bmi270_legacy_read_gyro_user_gain bmi270_legacy_read_gyro_user_gain
* \code
* int8_t bmi270_legacy_read_gyro_user_gain(struct bmi2_gyro_user_gain_data *gyr_usr_gain, const struct bmi2_dev *dev);
* \endcode
* @details This API reads the compensated gyroscope user-gain values.
*
* @param[out] gyr_usr_gain : Structure that stores gain values.
* @param[in] dev : Structure instance of bmi2_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_legacy_read_gyro_user_gain(struct bmi2_gyro_user_gain_data *gyr_usr_gain, struct bmi2_dev *dev);
/*!
* \ingroup bmi270_legacyApiInt
* \page bmi270_legacy_api_bmi270_legacy_map_feat_int bmi270_legacy_map_feat_int
* \code
* int8_t bmi270_legacy_map_feat_int(const struct bmi2_sens_int_config *sens_int, uint8_t n_sens, struct bmi2_dev *dev)
* \endcode
* @details This API maps/unmaps feature interrupts to that of interrupt pins.
*
* @param[in] sens_int : Structure instance of bmi2_sens_int_config.
* @param[in] n_sens : Number of interrupts to be mapped.
* @param[in] dev : Structure instance of bmi2_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_legacy_map_feat_int(const struct bmi2_sens_int_config *sens_int, uint8_t n_sens, struct bmi2_dev *dev);
/******************************************************************************/
/*! @name C++ Guard Macros */
/******************************************************************************/
#ifdef __cplusplus
}
#endif /* End of CPP guard */
#endif /* _BMI270_LEGACY_H_ */
@@ -0,0 +1,208 @@
/**
* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved.
*
* BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @file bmi270_maximum_fifo.c
* @date 2023-05-03
* @version v2.86.1
*
*/
/***************************************************************************/
/*! Header files
****************************************************************************/
#include "bmi270_maximum_fifo.h"
/***************************************************************************/
/*! Global Variable
****************************************************************************/
/*! @name Global array that stores the configuration file of BMI270 */
const uint8_t bmi270_maximum_fifo_config_file[] = {
0xc8, 0x2e, 0x00, 0x2e, 0x80, 0x2e, 0x1a, 0x00, 0xc8, 0x2e, 0x00, 0x2e, 0xc8, 0x2e, 0x00, 0x2e, 0xc8, 0x2e, 0x00,
0x2e, 0xc8, 0x2e, 0x00, 0x2e, 0xc8, 0x2e, 0x00, 0x2e, 0xc8, 0x2e, 0x00, 0x2e, 0x90, 0x32, 0x21, 0x2e, 0x59, 0xf5,
0x10, 0x30, 0x21, 0x2e, 0x6a, 0xf5, 0x1a, 0x24, 0x22, 0x00, 0x80, 0x2e, 0x3b, 0x00, 0xc8, 0x2e, 0x44, 0x47, 0x22,
0x00, 0x37, 0x00, 0xa4, 0x00, 0xff, 0x0f, 0xd1, 0x00, 0x07, 0xad, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1,
0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00,
0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x11, 0x24, 0xfc, 0xf5, 0x80, 0x30, 0x40, 0x42, 0x50, 0x50, 0x00, 0x30, 0x12, 0x24, 0xeb,
0x00, 0x03, 0x30, 0x00, 0x2e, 0xc1, 0x86, 0x5a, 0x0e, 0xfb, 0x2f, 0x21, 0x2e, 0xfc, 0xf5, 0x13, 0x24, 0x63, 0xf5,
0xe0, 0x3c, 0x48, 0x00, 0x22, 0x30, 0xf7, 0x80, 0xc2, 0x42, 0xe1, 0x7f, 0x3a, 0x25, 0xfc, 0x86, 0xf0, 0x7f, 0x41,
0x33, 0x98, 0x2e, 0xc2, 0xc4, 0xd6, 0x6f, 0xf1, 0x30, 0xf1, 0x08, 0xc4, 0x6f, 0x11, 0x24, 0xff, 0x03, 0x12, 0x24,
0x00, 0xfc, 0x61, 0x09, 0xa2, 0x08, 0x36, 0xbe, 0x2a, 0xb9, 0x13, 0x24, 0x38, 0x00, 0x64, 0xbb, 0xd1, 0xbe, 0x94,
0x0a, 0x71, 0x08, 0xd5, 0x42, 0x21, 0xbd, 0x91, 0xbc, 0xd2, 0x42, 0xc1, 0x42, 0x00, 0xb2, 0xfe, 0x82, 0x05, 0x2f,
0x50, 0x30, 0x21, 0x2e, 0x21, 0xf2, 0x00, 0x2e, 0x00, 0x2e, 0xd0, 0x2e, 0xf0, 0x6f, 0x02, 0x30, 0x02, 0x42, 0x20,
0x26, 0xe0, 0x6f, 0x02, 0x31, 0x03, 0x40, 0x9a, 0x0a, 0x02, 0x42, 0xf0, 0x37, 0x05, 0x2e, 0x5e, 0xf7, 0x10, 0x08,
0x12, 0x24, 0x1e, 0xf2, 0x80, 0x42, 0x83, 0x84, 0xf1, 0x7f, 0x0a, 0x25, 0x13, 0x30, 0x83, 0x42, 0x3b, 0x82, 0xf0,
0x6f, 0x00, 0x2e, 0x00, 0x2e, 0xd0, 0x2e, 0x12, 0x40, 0x52, 0x42, 0x00, 0x2e, 0x12, 0x40, 0x52, 0x42, 0x3e, 0x84,
0x00, 0x40, 0x40, 0x42, 0x7e, 0x82, 0xe1, 0x7f, 0xf2, 0x7f, 0x98, 0x2e, 0x6a, 0xd6, 0x21, 0x30, 0x23, 0x2e, 0x61,
0xf5, 0xeb, 0x2c, 0xe1, 0x6f
};
/*! @name Global array that stores the feature input configuration of BMI270 */
const struct bmi2_feature_config bmi270_maximum_fifo_feat_in[BMI270_MAXIMUM_FIFO_MAX_FEAT_IN] = {
};
/*! @name Global array that stores the feature output configuration */
const struct bmi2_feature_config bmi270_maximum_fifo_feat_out[BMI270_MAXIMUM_FIFO_MAX_FEAT_OUT] = {
};
/******************************************************************************/
/*! Local Function Prototypes
******************************************************************************/
/*!
* @brief This internal API is used to validate the device pointer for
* null conditions.
*
* @param[in] dev : Structure instance of bmi2_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
static int8_t null_ptr_check(const struct bmi2_dev *dev);
/***************************************************************************/
/*! User Interface Definitions
****************************************************************************/
/*!
* @brief This API:
* 1) updates the device structure with address of the configuration file.
* 2) Initializes BMI270 sensor.
* 3) Writes the configuration file.
* 4) Updates the feature offset parameters in the device structure.
* 5) Updates the maximum number of pages, in the device structure.
*/
int8_t bmi270_maximum_fifo_init(struct bmi2_dev *dev)
{
/* Variable to define result */
int8_t rslt;
/* Null-pointer check */
rslt = null_ptr_check(dev);
if (rslt == BMI2_OK)
{
/* Assign chip id of BMI270 */
dev->chip_id = BMI270_MAXIMUM_FIFO_CHIP_ID;
dev->config_size = sizeof(bmi270_maximum_fifo_config_file);
/* Enable the variant specific features if any */
dev->variant_feature = BMI2_GYRO_CROSS_SENS_ENABLE | BMI2_MAXIMUM_FIFO_VARIANT;
/* An extra dummy byte is read during SPI read */
if (dev->intf == BMI2_SPI_INTF)
{
dev->dummy_byte = 1;
}
else
{
dev->dummy_byte = 0;
}
/* If configuration file pointer is not assigned any address */
if (!dev->config_file_ptr)
{
/* Give the address of the configuration file array to
* the device pointer
*/
dev->config_file_ptr = bmi270_maximum_fifo_config_file;
}
/* Initialize BMI2 sensor */
rslt = bmi2_sec_init(dev);
if (rslt == BMI2_OK)
{
/* Assign the offsets of the feature input
* configuration to the device structure
*/
dev->feat_config = bmi270_maximum_fifo_feat_in;
/* Assign the offsets of the feature output to
* the device structure
*/
dev->feat_output = bmi270_maximum_fifo_feat_out;
/* Assign the maximum number of pages to the
* device structure
*/
dev->page_max = BMI270_MAXIMUM_FIFO_MAX_PAGE_NUM;
/* Assign maximum number of input sensors/
* features to device structure
*/
dev->input_sens = BMI270_MAXIMUM_FIFO_MAX_FEAT_IN;
/* Assign maximum number of output sensors/
* features to device structure
*/
dev->out_sens = BMI270_MAXIMUM_FIFO_MAX_FEAT_OUT;
/* Get the gyroscope cross axis sensitivity */
rslt = bmi2_get_gyro_cross_sense(dev);
}
}
return rslt;
}
/***************************************************************************/
/*! Local Function Definitions
****************************************************************************/
/*!
* @brief This internal API is used to validate the device structure pointer for
* null conditions.
*/
static int8_t null_ptr_check(const struct bmi2_dev *dev)
{
/* Variable to define result */
int8_t rslt = BMI2_OK;
if ((dev == NULL) || (dev->read == NULL) || (dev->write == NULL) || (dev->delay_us == NULL))
{
/* Device structure pointer is not valid */
rslt = BMI2_E_NULL_PTR;
}
return rslt;
}
@@ -0,0 +1,117 @@
/**
* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved.
*
* BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @file bmi270_maximum_fifo.h
* @date 2023-05-03
* @version v2.86.1
*
*/
/**
* \ingroup bmi2xy
* \defgroup bmi270_maximum_fifo BMI270_MAXIMUM_FIFO
* @brief Sensor driver for BMI270_MAXIMUM_FIFO sensor
*/
#ifndef BMI270_MAXIMUM_FIFO_H_
#define BMI270_MAXIMUM_FIFO_H_
/*! CPP guard */
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************/
/*! Header files
****************************************************************************/
#include "bmi2.h"
/***************************************************************************/
/*! Macro definitions
****************************************************************************/
/*! @name BMI270 Chip identifier */
#define BMI270_MAXIMUM_FIFO_CHIP_ID UINT8_C(0x24)
/*! @name Defines maximum number of pages */
#define BMI270_MAXIMUM_FIFO_MAX_PAGE_NUM UINT8_C(0)
/*! @name Defines maximum number of feature input configurations */
#define BMI270_MAXIMUM_FIFO_MAX_FEAT_IN UINT8_C(0)
/*! @name Defines maximum number of feature outputs */
#define BMI270_MAXIMUM_FIFO_MAX_FEAT_OUT UINT8_C(0)
/*! @name Mask definitions for feature interrupt status bits */
/***************************************************************************/
/*! BMI270 User Interface function prototypes
****************************************************************************/
/**
* \ingroup bmi270_maximum_fifo
* \defgroup bmi270_maximum_fifoApiInit Initialization
* @brief Initialize the sensor and device structure
*/
/*!
* \ingroup bmi270_maximum_fifoApiInit
* \page bmi270_maximum_fifo_api_bmi270_maximum_fifo_init bmi270_maximum_fifo_init
* \code
* int8_t bmi270_maximum_fifo_init(struct bmi2_dev *dev);
* \endcode
* @details This API:
* 1) updates the device structure with address of the configuration file.
* 2) Initializes BMI270 sensor.
* 3) Writes the configuration file.
* 4) Updates the feature offset parameters in the device structure.
* 5) Updates the maximum number of pages, in the device structure.
*
* @param[in, out] dev : Structure instance of bmi2_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi270_maximum_fifo_init(struct bmi2_dev *dev);
/******************************************************************************/
/*! @name C++ Guard Macros */
/******************************************************************************/
#ifdef __cplusplus
}
#endif /* End of CPP guard */
#endif /* BMI270_MAXIMUM_FIFO_H_ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,417 @@
/**
* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved.
*
* BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @file bmi2_ois.c
* @date 2023-05-03
* @version v2.86.1
*
*/
/******************************************************************************/
/*! @name Header Files */
/******************************************************************************/
#include "bmi2_ois.h"
/******************************************************************************/
/*! Local Function Prototypes
******************************************************************************/
/*!
* @brief This internal API gets the OIS accelerometer and the gyroscope data.
*
* @param[out] ois_data : Structure instance of bmi2_sens_axes_data.
* @param[in] reg_addr : Register address where data is stored.
* @param[in] ois_dev : Structure instance of bmi2_ois_dev.
* @param[in] ois_gyr_cross_sens_zx :"gyroscope cross sensitivity value which was calculated during
* bmi2xy_init(), refer the example ois_accel_gyro.c for more info"
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
static int8_t get_ois_acc_gyr_data(struct bmi2_ois_sens_axes_data *ois_data,
uint8_t reg_addr,
struct bmi2_ois_dev *ois_dev,
int16_t ois_gyr_cross_sens_zx);
/*!
* @brief This internal API is used to validate the OIS device pointer for null
* conditions.
*
* @param[in] ois_dev : Structure instance of bmi2_ois_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
static int8_t null_ptr_check(const struct bmi2_ois_dev *ois_dev);
/*!
* @brief This internal API corrects the gyroscope cross-axis sensitivity
* between the z and the x axis.
*
* @param[in] ois_dev : Structure instance of bmi2_ois_dev.
* @param[in] ois_gyr_cross_sens_zx : "gyroscope cross sensitivity value which was calculated during bmi2xy_init(),
* refer the example ois_accel_gyro.c for more info"
*
*/
static void comp_gyro_cross_axis_sensitivity(struct bmi2_ois_sens_axes_data *ois_data, int16_t ois_gyr_cross_sens_zx);
/******************************************************************************/
/*! @name User Interface Definitions */
/******************************************************************************/
/*!
* @brief This API reads the data from the given OIS register address of bmi2
* sensor.
*/
int8_t bmi2_ois_get_regs(uint8_t ois_reg_addr, uint8_t *ois_reg_data, uint16_t data_len, struct bmi2_ois_dev *ois_dev)
{
/* Variable to define error */
int8_t rslt;
/* Variable to define dummy byte for SPI read */
uint8_t dummy_byte = 1;
/* Variable to define temporary length */
uint16_t temp_len = data_len + dummy_byte;
/* Variable to define temporary buffer */
uint8_t temp_buf[temp_len];
/* Variable to index bytes read */
uint16_t index = 0;
/* Null-pointer check */
rslt = null_ptr_check(ois_dev);
if ((rslt == BMI2_OIS_OK) && (ois_reg_data != NULL))
{
/* Configuring reg_addr for SPI Interface */
ois_reg_addr = (ois_reg_addr | BMI2_OIS_SPI_RD_MASK);
/* Read from OIS register through OIS interface */
ois_dev->intf_rslt = ois_dev->ois_read(ois_reg_addr, temp_buf, temp_len, ois_dev->intf_ptr);
if (ois_dev->intf_rslt == BMI2_INTF_RET_SUCCESS)
{
/* Read the data from the position next to dummy byte */
while (index < data_len)
{
ois_reg_data[index] = temp_buf[index + dummy_byte];
index++;
}
}
else
{
rslt = BMI2_OIS_E_COM_FAIL;
}
}
else
{
rslt = BMI2_OIS_E_NULL_PTR;
}
return rslt;
}
/*!
* @brief This API writes data to the given OIS register address of bmi2 sensor.
*/
int8_t bmi2_ois_set_regs(uint8_t ois_reg_addr,
const uint8_t *ois_reg_data,
uint16_t data_len,
struct bmi2_ois_dev *ois_dev)
{
/* Variable to define error */
int8_t rslt;
/* Null-pointer check */
rslt = null_ptr_check(ois_dev);
if ((rslt == BMI2_OIS_OK) && (ois_reg_data != NULL))
{
/* Configuring reg_addr for SPI Interface */
ois_reg_addr = (ois_reg_addr & BMI2_OIS_SPI_WR_MASK);
/* Burst write to OIS register through OIS interface */
ois_dev->intf_rslt = ois_dev->ois_write(ois_reg_addr, ois_reg_data, data_len, ois_dev->intf_ptr);
if (ois_dev->intf_rslt != BMI2_INTF_RET_SUCCESS)
{
rslt = BMI2_OIS_E_COM_FAIL;
}
}
else
{
rslt = BMI2_OIS_E_NULL_PTR;
}
return rslt;
}
/*!
* @brief This API enables/disables accelerometer/gyroscope data read through
* OIS interface.
*/
int8_t bmi2_ois_set_config(struct bmi2_ois_dev *ois_dev)
{
/* Variable to define error */
int8_t rslt;
/* Variable to store data */
uint8_t reg_data = 0;
/* Null-pointer check */
rslt = null_ptr_check(ois_dev);
if (rslt == BMI2_OIS_OK)
{
rslt = bmi2_ois_get_regs(BMI2_OIS_CONFIG_ADDR, &reg_data, 1, ois_dev);
if (rslt == BMI2_OIS_OK)
{
/* Enable/Disable Low pass filter */
reg_data = BMI2_SET_BIT_POS0(reg_data, BMI2_OIS_LP_FILTER_EN, ois_dev->lp_filter_en);
/* Configures Low pass filter cut-off frequency */
reg_data = BMI2_OIS_SET_BITS(reg_data, BMI2_OIS_LP_FILTER_CONFIG, ois_dev->lp_filter_config);
/* Low pass filter - mute on secondary interface */
reg_data = BMI2_OIS_SET_BITS(reg_data, BMI2_OIS_LP_FILTER_MUTE, ois_dev->lp_filter_mute);
/* Enable/Disable ois on accelerometer */
reg_data = BMI2_OIS_SET_BITS(reg_data, BMI2_OIS_ACC_EN, ois_dev->acc_en);
/* Enable/Disable ois on gyroscope */
reg_data = BMI2_OIS_SET_BITS(reg_data, BMI2_OIS_GYR_EN, ois_dev->gyr_en);
/* Set the OIS configurations */
rslt = bmi2_ois_set_regs(BMI2_OIS_CONFIG_ADDR, &reg_data, 1, ois_dev);
}
}
return rslt;
}
/*!
* @brief This API gets the status of accelerometer/gyroscope enable for data
* read through OIS interface.
*/
int8_t bmi2_ois_get_config(struct bmi2_ois_dev *ois_dev)
{
/* Variable to define error */
int8_t rslt;
/* Variable to store data */
uint8_t reg_data = 0;
/* Null-pointer check */
rslt = null_ptr_check(ois_dev);
if (rslt == BMI2_OIS_OK)
{
rslt = bmi2_ois_get_regs(BMI2_OIS_CONFIG_ADDR, &reg_data, 1, ois_dev);
if (rslt == BMI2_OIS_OK)
{
/* Get the status of Low pass filter enable */
ois_dev->lp_filter_en = BMI2_GET_BIT_POS0(reg_data, BMI2_OIS_LP_FILTER_EN);
/* Get the status of Low pass filter cut-off frequency */
ois_dev->lp_filter_config = BMI2_OIS_GET_BITS(reg_data, BMI2_OIS_LP_FILTER_CONFIG);
/* Get the status of Low pass filter mute */
ois_dev->lp_filter_mute = BMI2_OIS_GET_BITS(reg_data, BMI2_OIS_LP_FILTER_MUTE);
/* Get the status of accelerometer enable */
ois_dev->acc_en = BMI2_OIS_GET_BITS(reg_data, BMI2_OIS_ACC_EN);
/* Get the status of gyroscope enable */
ois_dev->gyr_en = BMI2_OIS_GET_BITS(reg_data, BMI2_OIS_GYR_EN);
}
}
return rslt;
}
/*!
* @brief This API reads accelerometer/gyroscope data through OIS interface.
*/
int8_t bmi2_ois_read_data(const uint8_t *sens_sel,
uint8_t n_sens,
struct bmi2_ois_dev *ois_dev,
int16_t gyr_cross_sens_zx)
{
/* Variable to define error */
int8_t rslt;
/* Variable to define loop */
uint8_t loop = 0;
/* Variable to update register address */
uint8_t reg_addr = 0;
/* Null-pointer check */
rslt = null_ptr_check(ois_dev);
if ((rslt == BMI2_OIS_OK) && (sens_sel != NULL))
{
for (loop = 0; loop < n_sens; loop++)
{
switch (sens_sel[loop])
{
case BMI2_OIS_ACCEL:
/* Update OIS accelerometer address */
reg_addr = BMI2_OIS_ACC_X_LSB_ADDR;
/* Get OIS accelerometer data */
rslt = get_ois_acc_gyr_data(&ois_dev->acc_data, reg_addr, ois_dev, 0);
break;
case BMI2_OIS_GYRO:
/* Update OIS gyroscope address */
reg_addr = BMI2_OIS_GYR_X_LSB_ADDR;
/* Get OIS gyroscope data */
rslt = get_ois_acc_gyr_data(&ois_dev->gyr_data, reg_addr, ois_dev, gyr_cross_sens_zx);
break;
default:
rslt = BMI2_OIS_E_INVALID_SENSOR;
break;
}
/* Return error if any of the get sensor data fails */
if (rslt != BMI2_OIS_OK)
{
break;
}
}
}
else
{
rslt = BMI2_OIS_E_NULL_PTR;
}
return rslt;
}
/***************************************************************************/
/*! Local Function Definitions
****************************************************************************/
/*! @cond DOXYGEN_SUPRESS */
/* Suppressing doxygen warnings triggered for same static function names present across various sensor variant
* directories */
/*!
* @brief This internal API gets the accelerometer and the gyroscope data.
*/
static int8_t get_ois_acc_gyr_data(struct bmi2_ois_sens_axes_data *ois_data,
uint8_t reg_addr,
struct bmi2_ois_dev *ois_dev,
int16_t ois_gyr_cross_sens_zx)
{
/* Variable to define error */
int8_t rslt;
/* Variables to store MSB value */
uint8_t msb;
/* Variables to store LSB value */
uint8_t lsb;
/* Variables to store both MSB and LSB value */
uint16_t msb_lsb;
/* Variables to define index */
uint8_t index = 0;
/* Array to define data stored in register */
uint8_t reg_data[BMI2_OIS_ACC_GYR_NUM_BYTES] = { 0 };
/* Read the sensor data */
rslt = bmi2_ois_get_regs(reg_addr, reg_data, BMI2_OIS_ACC_GYR_NUM_BYTES, ois_dev);
if (rslt == BMI2_OIS_OK)
{
/* Read x-axis data */
lsb = reg_data[index++];
msb = reg_data[index++];
msb_lsb = ((uint16_t)msb << 8) | (uint16_t)lsb;
ois_data->x = (int16_t)msb_lsb;
/* Read y-axis data */
lsb = reg_data[index++];
msb = reg_data[index++];
msb_lsb = ((uint16_t)msb << 8) | (uint16_t)lsb;
ois_data->y = (int16_t)msb_lsb;
/* Read z-axis data */
lsb = reg_data[index++];
msb = reg_data[index++];
msb_lsb = ((uint16_t)msb << 8) | (uint16_t)lsb;
ois_data->z = (int16_t)msb_lsb;
comp_gyro_cross_axis_sensitivity(ois_data, ois_gyr_cross_sens_zx);
}
return rslt;
}
/*!
* @brief This internal API is used to validate the device structure pointer for
* null conditions.
*/
static int8_t null_ptr_check(const struct bmi2_ois_dev *ois_dev)
{
/* Variable to define error */
int8_t rslt = BMI2_OIS_OK;
if ((ois_dev == NULL) || (ois_dev->ois_read == NULL) || (ois_dev->ois_write == NULL) ||
(ois_dev->ois_delay_us == NULL))
{
/* Device structure pointer is NULL */
rslt = BMI2_OIS_E_NULL_PTR;
}
return rslt;
}
/*!
* @brief This internal API corrects the gyroscope cross-axis sensitivity
* between the z and the x axis.
*/
static void comp_gyro_cross_axis_sensitivity(struct bmi2_ois_sens_axes_data *ois_data, int16_t ois_gyr_cross_sens_zx)
{
/* Get the compensated gyroscope x-axis */
ois_data->x = ois_data->x - (int16_t)(((int32_t)ois_gyr_cross_sens_zx * (int32_t)ois_data->z) / 512);
}
/*! @endcond */
@@ -0,0 +1,380 @@
/**
* Copyright (c) 2023 Bosch Sensortec GmbH. All rights reserved.
*
* BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @file bmi2_ois.h
* @date 2023-05-03
* @version v2.86.1
*
*/
/**
* \ingroup bmi2xy
* \defgroup bmi2_ois BMI2_OIS
* @brief Sensor driver for BMI2_OIS sensor
*/
#ifndef _BMI2_OIS_H
#define _BMI2_OIS_H
/*! CPP guard */
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************/
/*! Header files
****************************************************************************/
#ifdef __KERNEL__
#include <linux/types.h>
#include <linux/kernel.h>
#else
#include <stdint.h>
#include <stddef.h>
#endif
#include "bmi2_defs.h"
/******************************************************************************/
/*! @name Macros */
/******************************************************************************/
#ifndef BMI2_INTF_RETURN_TYPE
#define BMI2_INTF_RETURN_TYPE int8_t
#endif
/*! @name Utility macros */
#define BMI2_OIS_SET_BITS(reg_data, bitname, data) \
((reg_data & ~(bitname##_MASK)) | \
((data << bitname##_POS) & bitname##_MASK))
#define BMI2_OIS_GET_BITS(reg_data, bitname) \
((reg_data & (bitname##_MASK)) >> \
(bitname##_POS))
/*! @name For enable and disable */
#define BMI2_OIS_ENABLE UINT8_C(1)
#define BMI2_OIS_DISABLE UINT8_C(0)
/*! @name To define success code */
#define BMI2_OIS_OK UINT8_C(0)
/*! @name To define error codes */
#define BMI2_OIS_E_NULL_PTR INT8_C(-1)
#define BMI2_OIS_E_COM_FAIL INT8_C(-2)
#define BMI2_OIS_E_INVALID_SENSOR INT8_C(-8)
/*! @name Mask definitions for SPI read/write address for OIS */
#define BMI2_OIS_SPI_RD_MASK UINT8_C(0x80)
#define BMI2_OIS_SPI_WR_MASK UINT8_C(0x7F)
/*! @name BMI2 OIS data bytes */
#define BMI2_OIS_ACC_GYR_NUM_BYTES UINT8_C(6)
/*! @name Macros to select sensor for OIS data read */
#define BMI2_OIS_ACCEL UINT8_C(0x01)
#define BMI2_OIS_GYRO UINT8_C(0x02)
/*! @name Macros to define OIS register addresses */
#define BMI2_OIS_CONFIG_ADDR UINT8_C(0x40)
#define BMI2_OIS_ACC_X_LSB_ADDR UINT8_C(0x0C)
#define BMI2_OIS_GYR_X_LSB_ADDR UINT8_C(0x12)
/*! @name Mask definitions for OIS configurations */
#define BMI2_OIS_GYR_EN_MASK UINT8_C(0x40)
#define BMI2_OIS_ACC_EN_MASK UINT8_C(0x80)
/*! @name Bit Positions for OIS configurations */
#define BMI2_OIS_GYR_EN_POS UINT8_C(0x06)
#define BMI2_OIS_ACC_EN_POS UINT8_C(0x07)
/*! Low pass filter configuration position and mask */
#define BMI2_OIS_LP_FILTER_EN_POS UINT8_C(0x00)
#define BMI2_OIS_LP_FILTER_EN_MASK UINT8_C(0x01)
#define BMI2_OIS_LP_FILTER_CONFIG_POS UINT8_C(0x01)
#define BMI2_OIS_LP_FILTER_CONFIG_MASK UINT8_C(0x06)
#define BMI2_OIS_LP_FILTER_MUTE_POS UINT8_C(0x05)
#define BMI2_OIS_LP_FILTER_MUTE_MASK UINT8_C(0x20)
/******************************************************************************/
/*! @name Function Pointers */
/******************************************************************************/
/*!
* @brief Bus communication function pointer which should be mapped to
* the platform specific read functions of the user
*
* @param[in] reg_addr : Register address from which data is read.
* @param[out] reg_data : Pointer to data buffer where read data is stored.
* @param[in] len : Number of bytes of data to be read.
* @param[in, out] intf_ptr : Void pointer that can enable the linking of descriptors
* for interface related call backs.
*
* retval = BMI2_INTF_RET_SUCCESS -> Success
* retval != BMI2_INTF_RET_SUCCESS -> Failure
*
*/
typedef BMI2_INTF_RETURN_TYPE (*bmi2_ois_read_fptr_t)(uint8_t reg_addr, uint8_t *data, uint32_t len, void *intf_ptr);
/*!
* @brief Bus communication function pointer which should be mapped to
* the platform specific write functions of the user
*
* @param[in] reg_addr : Register address to which the data is written.
* @param[in] reg_data : Pointer to data buffer in which data to be written
* is stored.
* @param[in] len : Number of bytes of data to be written.
* @param[in, out] intf_ptr : Void pointer that can enable the linking of descriptors
* for interface related call backs
*
* retval = BMI2_INTF_RET_SUCCESS -> Success
* retval != BMI2_INTF_RET_SUCCESS -> Failure
*
*/
typedef BMI2_INTF_RETURN_TYPE (*bmi2_ois_write_fptr_t)(uint8_t reg_addr, const uint8_t *data, uint32_t len,
void *intf_ptr);
/*!
* @brief Delay function pointer which should be mapped to
* delay function of the user
*
* @param[in] period : Delay in microseconds.
* @param[in, out] intf_ptr : Void pointer that can enable the linking of descriptors
* for interface related call backs
*
*/
typedef void (*bmi2_ois_delay_fptr_t)(uint32_t period, void *intf_ptr);
/******************************************************************************/
/*! @name Structure Declarations */
/******************************************************************************/
/*! @name Structure to define accelerometer and gyroscope sensor axes for OIS */
struct bmi2_ois_sens_axes_data
{
/*! Data in x-axis */
int16_t x;
/*! Data in y-axis */
int16_t y;
/*! Data in z-axis */
int16_t z;
};
/*! @name Structure to define bmi2 OIS sensor configurations */
struct bmi2_ois_dev
{
/*! Read function pointer */
bmi2_ois_read_fptr_t ois_read;
/*! Write function pointer */
bmi2_ois_write_fptr_t ois_write;
/*! Delay function pointer */
bmi2_ois_delay_fptr_t ois_delay_us;
/*! Low pass filter en/dis */
uint8_t lp_filter_en;
/*! Void interface pointer */
void *intf_ptr;
/*! To store interface pointer error */
int8_t intf_rslt;
/*! Low pass filter cut-off frequency */
uint8_t lp_filter_config;
/*! Low pass filter mute */
uint8_t lp_filter_mute;
/*! Accelerometer enable for OIS */
uint8_t acc_en;
/*! Gyroscope enable for OIS */
uint8_t gyr_en;
/*! Accelerometer data axes */
struct bmi2_ois_sens_axes_data acc_data;
/*! Gyroscope data axes */
struct bmi2_ois_sens_axes_data gyr_data;
};
/***************************************************************************/
/*! BMI2 OIS User Interface function prototypes
****************************************************************************/
/**
* \ingroup bmi2_ois
* \defgroup bmi2_oisApiRegs Registers
* @brief Read data from the given OIS register address of bmi2
*/
/*!
* \ingroup bmi2_oisApiRegs
* \page bmi2_ois_api_bmi2_ois_get_regs bmi2_ois_get_regs
* \code
* int8_t bmi2_ois_get_regs(uint8_t ois_reg_addr,
* uint8_t *ois_reg_data,
* uint16_t data_len,
* const struct bmi2_ois_dev *ois_dev);
* \endcode
* @details This API reads the data from the given OIS register address of bmi2
* sensor.
*
* @param[in] ois_reg_addr : OIS register address from which data is read.
* @param[out] ois_reg_data : Pointer to data buffer where read data is stored.
* @param[in] data_len : No. of bytes of data to be read.
* @param[in] ois_dev : Structure instance of bmi2_ois_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi2_ois_get_regs(uint8_t ois_reg_addr, uint8_t *ois_reg_data, uint16_t data_len, struct bmi2_ois_dev *ois_dev);
/*!
* \ingroup bmi2_oisApiRegs
* \page bmi2_ois_api_bmi2_ois_set_regs bmi2_ois_set_regs
* \code
* int8_t bmi2_ois_set_regs(uint8_t ois_reg_addr,
* uint8_t *ois_reg_data,
* uint16_t data_len,
* const struct bmi2_ois_dev *ois_dev);
* \endcode
* @details This API writes data to the given OIS register address of bmi2 sensor.
*
* @param[in] ois_reg_addr : OIS register address to which the data is written.
* @param[in] ois_reg_data : Pointer to data buffer in which data to be written
* is stored.
* @param[in] data_len : No. of bytes of data to be written.
* @param[in] ois_dev : Structure instance of bmi2_ois_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi2_ois_set_regs(uint8_t ois_reg_addr,
const uint8_t *ois_reg_data,
uint16_t data_len,
struct bmi2_ois_dev *ois_dev);
/**
* \ingroup bmi2_ois
* \defgroup bmi2_oisApiConfig Status update
* @brief Get / Set the status of Enable / Disable accelerometer / gyroscope data read through OIS interface
*/
/*!
* \ingroup bmi2_oisApiConfig
* \page bmi2_ois_api_bmi2_ois_set_config bmi2_ois_set_config
* \code
* int8_t bmi2_ois_set_config(const struct bmi2_ois_dev *ois_dev);
* \endcode
* @details This API sets the status of enable/disable accelerometer/gyroscope data read through
* OIS interface.
*
* @param[in] ois_dev : Structure instance of bmi2_ois_dev.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi2_ois_set_config(struct bmi2_ois_dev *ois_dev);
/*!
* \ingroup bmi2_oisApiConfig
* \page bmi2_ois_api_bmi2_ois_get_config bmi2_ois_get_config
* \code
* int8_t bmi2_ois_get_config(struct bmi2_ois_dev *ois_dev);
* \endcode
* @details This API gets the status of accelerometer/gyroscope enable for data
* read through OIS interface.
*
* @param[in, out] ois_dev : Structure instance of bmi2_ois_dev.
*
* @note Enabling and disabling is done during OIS structure initialization.
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi2_ois_get_config(struct bmi2_ois_dev *ois_dev);
/**
* \ingroup bmi2_ois
* \defgroup bmi2_oisApiRead Data read
* @brief Read accelerometer / gyroscope data through OIS interface
*/
/*!
* \ingroup bmi2_oisApiRead
* \page bmi2_ois_api_bmi2_ois_read_data bmi2_ois_read_data
* \code
* int8_t bmi2_ois_read_data(const uint8_t *sens_sel,
* uint8_t n_sens,
* struct bmi2_ois_dev *ois_dev,
* int16_t gyr_cross_sens_zx);
* \endcode
* @details This API reads accelerometer/gyroscope data through OIS interface.
*
* @param[in] sens_sel : Select sensor whose data is to be read.
* @param[in] n_sens : Number of sensors selected.
* @param[in, out] ois_dev : Structure instance of bmi2_ois_dev.
* @param[in] gyr_cross_sens_zx : Store the gyroscope cross sensitivity values taken from the bmi2xy
* (refer bmi2_ois example).
*
*@verbatim
* sens_sel | Value
* ---------------|---------------
* BMI2_OIS_ACCEL | 0x01
* BMI2_OIS_GYRO | 0x02
*@endverbatim
*
* @return Result of API execution status
* @retval 0 -> Success
* @retval < 0 -> Fail
*/
int8_t bmi2_ois_read_data(const uint8_t *sens_sel,
uint8_t n_sens,
struct bmi2_ois_dev *ois_dev,
int16_t gyr_cross_sens_zx);
#ifdef __cplusplus
}
#endif /* End of CPP guard */
#endif /* End of _BMI2_OIS_H */
+190
View File
@@ -0,0 +1,190 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "bmi270.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <cmath>
#include <cstring>
static const char* TAG = "BMI270";
BMI270::BMI270(i2c_master_bus_handle_t i2c_bus_handle, uint8_t addr) : _addr(addr), _initialized(false)
{
i2c_device_config_t dev_cfg = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = _addr,
.scl_speed_hz = 400000,
};
ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c_bus_handle, &dev_cfg, &_i2c_dev));
_bmi.intf = BMI2_I2C_INTF;
_bmi.read = bmi2_i2c_read;
_bmi.write = bmi2_i2c_write;
_bmi.delay_us = bmi2_delay_us;
_bmi.read_write_len = 32; // Max read/write length
_bmi.config_file_ptr = NULL; // Use default config
_bmi.intf_ptr = &_i2c_dev; // Pass the device handle as interface pointer
}
BMI270::~BMI270()
{
if (_i2c_dev) {
i2c_master_bus_rm_device(_i2c_dev);
}
}
BMI2_INTF_RETURN_TYPE BMI270::bmi2_i2c_read(uint8_t reg_addr, uint8_t* reg_data, uint32_t len, void* intf_ptr)
{
i2c_master_dev_handle_t dev = *(i2c_master_dev_handle_t*)intf_ptr;
esp_err_t err = i2c_master_transmit_receive(dev, &reg_addr, 1, reg_data, len, 1000);
return (err == ESP_OK) ? BMI2_OK : BMI2_E_COM_FAIL;
}
BMI2_INTF_RETURN_TYPE BMI270::bmi2_i2c_write(uint8_t reg_addr, const uint8_t* reg_data, uint32_t len, void* intf_ptr)
{
i2c_master_dev_handle_t dev = *(i2c_master_dev_handle_t*)intf_ptr;
uint8_t* buf = (uint8_t*)malloc(len + 1);
if (!buf) return BMI2_E_COM_FAIL;
buf[0] = reg_addr;
memcpy(buf + 1, reg_data, len);
esp_err_t err = i2c_master_transmit(dev, buf, len + 1, 1000);
free(buf);
return (err == ESP_OK) ? BMI2_OK : BMI2_E_COM_FAIL;
}
#define NOP() asm volatile("nop")
void BMI270::bmi2_delay_us(uint32_t period, void* intf_ptr)
{
uint64_t m = (uint64_t)esp_timer_get_time();
if (period) {
uint64_t e = (m + period);
if (m > e) { // overflow
while ((uint64_t)esp_timer_get_time() > e) {
NOP();
}
}
while ((uint64_t)esp_timer_get_time() < e) {
NOP();
}
}
}
bool BMI270::begin()
{
int8_t rslt;
// Initialize bmi270
rslt = bmi270_init(&_bmi);
if (rslt != BMI2_OK) {
ESP_LOGE(TAG, "bmi270_init failed: %d", rslt);
return false;
}
// Configure Accel
struct bmi2_sens_config config;
config.type = BMI2_ACCEL;
rslt = bmi2_get_sensor_config(&config, 1, &_bmi);
if (rslt == BMI2_OK) {
config.cfg.acc.odr = BMI2_ACC_ODR_100HZ;
config.cfg.acc.range = BMI2_ACC_RANGE_2G;
config.cfg.acc.bwp = BMI2_ACC_NORMAL_AVG4;
config.cfg.acc.filter_perf = BMI2_PERF_OPT_MODE;
rslt = bmi2_set_sensor_config(&config, 1, &_bmi);
}
if (rslt != BMI2_OK) {
ESP_LOGE(TAG, "Accel config failed: %d", rslt);
return false;
}
// Configure Gyro
config.type = BMI2_GYRO;
rslt = bmi2_get_sensor_config(&config, 1, &_bmi);
if (rslt == BMI2_OK) {
config.cfg.gyr.odr = BMI2_GYR_ODR_100HZ;
config.cfg.gyr.range = BMI2_GYR_RANGE_2000;
config.cfg.gyr.bwp = BMI2_GYR_NORMAL_MODE;
config.cfg.gyr.filter_perf = BMI2_PERF_OPT_MODE;
config.cfg.gyr.noise_perf = BMI2_PERF_OPT_MODE;
rslt = bmi2_set_sensor_config(&config, 1, &_bmi);
}
if (rslt != BMI2_OK) {
ESP_LOGE(TAG, "Gyro config failed: %d", rslt);
return false;
}
// Enable sensors
uint8_t sensor_list[2] = {BMI2_ACCEL, BMI2_GYRO};
rslt = bmi2_sensor_enable(sensor_list, 2, &_bmi);
if (rslt != BMI2_OK) {
ESP_LOGE(TAG, "Sensor enable failed: %d", rslt);
return false;
}
_initialized = true;
return true;
}
bool BMI270::update()
{
if (!_initialized) return false;
struct bmi2_sens_data sens_data = {{0}};
int8_t rslt = bmi2_get_sensor_data(&sens_data, &_bmi);
if (rslt == BMI2_OK) {
// Convert Accel
// Assuming 2G range and 16-bit resolution as configured
_data.accel_x = lsb_to_mps2(sens_data.acc.x, 2.0f, 16);
_data.accel_y = lsb_to_mps2(sens_data.acc.y, 2.0f, 16);
_data.accel_z = lsb_to_mps2(sens_data.acc.z, 2.0f, 16);
// Convert Gyro
// Assuming 2000dps range and 16-bit resolution
_data.gyro_x = lsb_to_dps(sens_data.gyr.x, 2000.0f, 16);
_data.gyro_y = lsb_to_dps(sens_data.gyr.y, 2000.0f, 16);
_data.gyro_z = lsb_to_dps(sens_data.gyr.z, 2000.0f, 16);
return true;
}
return false;
}
void BMI270::getAccelerometer(float& x, float& y, float& z)
{
x = _data.accel_x;
y = _data.accel_y;
z = _data.accel_z;
}
void BMI270::getGyroscope(float& x, float& y, float& z)
{
x = _data.gyro_x;
y = _data.gyro_y;
z = _data.gyro_z;
}
const BMI270_Data& BMI270::getData()
{
return _data;
}
float BMI270::lsb_to_mps2(int16_t val, float g_range, uint8_t bit_width)
{
float half_scale = (float)(1 << (bit_width - 1));
return (9.80665f * val * g_range) / half_scale;
}
float BMI270::lsb_to_dps(int16_t val, float dps, uint8_t bit_width)
{
float half_scale = (float)(1 << (bit_width - 1));
return (dps * val) / half_scale;
}
+63
View File
@@ -0,0 +1,63 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <cstdint>
#include "driver/i2c_master.h"
#include "esp_err.h"
#include "BMI270_SensorAPI/bmi270.h"
struct BMI270_Data {
float accel_x;
float accel_y;
float accel_z;
float gyro_x;
float gyro_y;
float gyro_z;
};
class BMI270 {
public:
static constexpr uint8_t DEFAULT_ADDRESS = BMI2_I2C_PRIM_ADDR; // 0x68
BMI270(i2c_master_bus_handle_t i2c_bus_handle, uint8_t addr = DEFAULT_ADDRESS);
~BMI270();
/**
* @brief Initialize the device
*
* @return true if successful
* @return false if failed
*/
bool begin();
/**
* @brief Read sensor data
*
* @return true if successful
* @return false if failed
*/
bool update();
void getAccelerometer(float& x, float& y, float& z);
void getGyroscope(float& x, float& y, float& z);
const BMI270_Data& getData();
private:
i2c_master_dev_handle_t _i2c_dev;
struct bmi2_dev _bmi;
uint8_t _addr;
bool _initialized;
BMI270_Data _data;
static BMI2_INTF_RETURN_TYPE bmi2_i2c_read(uint8_t reg_addr, uint8_t* reg_data, uint32_t len, void* intf_ptr);
static BMI2_INTF_RETURN_TYPE bmi2_i2c_write(uint8_t reg_addr, const uint8_t* reg_data, uint32_t len,
void* intf_ptr);
static void bmi2_delay_us(uint32_t period, void* intf_ptr);
float lsb_to_mps2(int16_t val, float g_range, uint8_t bit_width);
float lsb_to_dps(int16_t val, float dps, uint8_t bit_width);
};
+219
View File
@@ -0,0 +1,219 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "hal.h"
#include <memory>
#include <mooncake_log.h>
#include <nvs_flash.h>
static std::unique_ptr<Hal> _hal_instance;
static const std::string _tag = "HAL";
Hal& GetHAL()
{
if (!_hal_instance) {
mclog::tagInfo(_tag, "creating hal instance");
_hal_instance = std::make_unique<Hal>();
}
return *_hal_instance.get();
}
void Hal::init()
{
mclog::tagInfo(_tag, "init");
// Initialize NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
// ble_init();
xiaozhi_board_init();
xiaozhi_mcp_init();
head_touch_init();
io_expander_init();
imu_init();
servo_init();
lvgl_init();
reminder_init();
// startWebSocketAvatar();
}
/* -------------------------------------------------------------------------- */
/* System */
/* -------------------------------------------------------------------------- */
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <esp_system.h>
#include <esp_timer.h>
#include <esp_mac.h>
void Hal::delay(std::uint32_t ms)
{
vTaskDelay(pdMS_TO_TICKS(ms));
}
std::uint32_t Hal::millis()
{
return esp_timer_get_time() / 1000;
}
void Hal::feedTheDog()
{
vTaskDelay(1);
}
std::array<uint8_t, 6> Hal::getFactoryMac()
{
std::array<uint8_t, 6> mac;
esp_efuse_mac_get_default(mac.data());
return mac;
}
std::string Hal::getFactoryMacString(std::string divider)
{
auto mac = getFactoryMac();
return fmt::format("{:02X}{}{:02X}{}{:02X}{}{:02X}{}{:02X}{}{:02X}", mac[0], divider, mac[1], divider, mac[2],
divider, mac[3], divider, mac[4], divider, mac[5]);
}
void Hal::reboot()
{
esp_restart();
}
/* -------------------------------------------------------------------------- */
/* Xiaozhi */
/* -------------------------------------------------------------------------- */
#include "board/hal_bridge.h"
void Hal::xiaozhi_board_init()
{
mclog::tagInfo(_tag, "xiaozhi board init");
hal_bridge::xiaozhi_board_init();
}
void Hal::startXiaozhi()
{
mclog::tagInfo(_tag, "start xiaozhi");
hal_bridge::start_xiaozhi_app();
}
/* -------------------------------------------------------------------------- */
/* Display */
/* -------------------------------------------------------------------------- */
#include "board/hal_bridge.h"
void Hal::lvglLock()
{
hal_bridge::disply_lvgl_lock();
}
void Hal::lvglUnlock()
{
hal_bridge::disply_lvgl_unlock();
}
/* -------------------------------------------------------------------------- */
/* Lvgl */
/* -------------------------------------------------------------------------- */
#include "board/hal_bridge.h"
#include <stackchan/stackchan.h>
static void lvgl_read_cb(lv_indev_t* indev, lv_indev_data_t* data)
{
hal_bridge::lock();
auto bridge_data = hal_bridge::get_data();
if (bridge_data.isXiaozhiMode) {
hal_bridge::unlock();
data->state = LV_INDEV_STATE_RELEASED;
return;
}
// mclog::tagInfo(_tag, "touchpoint: {}, x: {}, y: {}", bridge_data.touchPoint.num, bridge_data.touchPoint.x,
// bridge_data.touchPoint.y);
if (bridge_data.touchPoint.num == 0) {
data->state = LV_INDEV_STATE_RELEASED;
} else {
data->state = LV_INDEV_STATE_PRESSED;
data->point.x = bridge_data.touchPoint.x;
data->point.y = bridge_data.touchPoint.y;
}
hal_bridge::unlock();
}
void Hal::lvgl_init()
{
mclog::tagInfo(_tag, "lvgl init");
hal_bridge::disply_lvgl_lock();
mclog::tagInfo(_tag, "create lvgl touchpad indev");
lvTouchpad = lv_indev_create();
lv_indev_set_type(lvTouchpad, LV_INDEV_TYPE_POINTER);
lv_indev_set_read_cb(lvTouchpad, lvgl_read_cb);
lv_indev_set_group(lvTouchpad, lv_group_get_default());
lv_indev_set_display(lvTouchpad, hal_bridge::display_get_lvgl_display());
hal_bridge::disply_lvgl_unlock();
}
lv_timer_t* _timer_stackchan_update = NULL;
void Hal::startStackChanAutoUpdate(int fps)
{
mclog::tagInfo(_tag, "start stack chan auto update with fps: {}", fps);
if (_timer_stackchan_update) {
mclog::tagWarn(_tag, "stack chan auto update already started");
return;
}
_timer_stackchan_update = lv_timer_create([](lv_timer_t* timer) { GetStackChan().update(); }, 1000 / fps, NULL);
}
void Hal::stopStackChanAutoUpdate()
{
mclog::tagInfo(_tag, "stop stack chan auto update");
if (!_timer_stackchan_update) {
mclog::tagWarn(_tag, "stack chan auto update already stopped");
return;
}
lv_timer_delete(_timer_stackchan_update);
_timer_stackchan_update = NULL;
}
/* -------------------------------------------------------------------------- */
/* Reminder */
/* -------------------------------------------------------------------------- */
#include "hal/utils/reminder/reminder.h"
int Hal::createReminder(int duration_s, const std::string& message)
{
return ReminderManager::GetInstance().CreateReminder(duration_s, message);
}
void Hal::stopReminder(int id)
{
ReminderManager::GetInstance().StopReminder(id);
}
void Hal::reminder_init()
{
mclog::tagInfo(_tag, "reminder init");
ReminderManager::GetInstance().Start();
}
+170
View File
@@ -0,0 +1,170 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <memory>
#include <cstdint>
#include <string>
#include <lvgl.h>
#include <smooth_ui_toolkit.hpp>
#include <uitk/short_namespace.hpp>
#include <array>
#include <lvgl_image.h>
#include <string_view>
/**
* @brief
*
*/
enum class HeadPetGesture { None, Press, Release, SwipeForward, SwipeBackward };
/**
* @brief
*
*/
enum class WsSignalSource {
Local = 0,
Remote,
};
/**
* @brief
*
*/
struct WsTextMessage_t {
std::string name;
std::string content;
};
/**
* @brief
*
*/
enum class ImuMotionEvent {
None = 0,
Shake,
PickUp,
};
/**
* @brief
*
*/
enum class AppConfigEvent {
None = 0,
AppConnected,
AppDisconnected,
TryWifiConnect,
WifiConnectFailed,
WifiConnected,
};
/**
* @brief
*
*/
class Hal {
public:
void init();
/* --------------------------------- System --------------------------------- */
void delay(std::uint32_t ms);
std::uint32_t millis();
void feedTheDog();
std::array<uint8_t, 6> getFactoryMac();
std::string getFactoryMacString(std::string divider = "");
void reboot();
/* --------------------------------- Display -------------------------------- */
lv_indev_t* lvTouchpad = nullptr;
void lvglLock();
void lvglUnlock();
/* --------------------------------- Xiaozhi -------------------------------- */
void startXiaozhi();
/* ----------------------------------- BLE ---------------------------------- */
uitk::Signal<const char*> onBleMotionData;
uitk::Signal<const char*> onBleAvatarData;
uitk::Signal<const char*> onBleConfigData;
uitk::Signal<const char*> onBleAnimationData;
uitk::Signal<AppConfigEvent> onAppConfigEvent;
void startBleServer();
bool isBleConnected();
void startAppConfigServer();
bool isAppConfiged();
/* --------------------------------- HeadPet -------------------------------- */
uitk::Signal<HeadPetGesture> onHeadPetGesture;
/* -------------------------------- StackChan ------------------------------- */
void startStackChanAutoUpdate(int fps); // Start the auto update with lvgl timer
void stopStackChanAutoUpdate();
/* ----------------------------------- RGB ---------------------------------- */
void setRgbColor(uint8_t index, uint8_t r, uint8_t g, uint8_t b);
void showRgbColor(uint8_t r, uint8_t g, uint8_t b);
void refreshRgb();
/* ---------------------------------- Power --------------------------------- */
void setServoPowerEnabled(bool enabled);
/* -------------------------------- Websocket ------------------------------- */
uitk::Signal<std::string_view> onWsMotionData;
uitk::Signal<std::string_view> onWsAvatarData;
uitk::Signal<std::string> onWsCallRequest;
uitk::Signal<bool> onWsCallResponse;
uitk::Signal<WsSignalSource> onWsCallEnd;
uitk::Signal<const WsTextMessage_t&> onWsTextMessage;
uitk::Signal<bool> onWsVideoModeChange;
uitk::Signal<std::shared_ptr<LvglImage>> onWsVideoFrame;
uitk::Signal<std::string_view> onWsDanceData;
void startWebSocketAvatar();
/* -------------------------------- Reminder -------------------------------- */
uitk::Signal<int, std::string> onReminderTriggered;
int createReminder(int duration_s, const std::string& message);
void stopReminder(int id);
/* ----------------------------------- IMU ---------------------------------- */
uitk::Signal<ImuMotionEvent> onImuMotionEvent;
/* --------------------------------- EspNow --------------------------------- */
uitk::Signal<const std::vector<uint8_t>&> onEspNowData;
void startEspNow(int channel);
bool espNowSend(const std::vector<uint8_t>& data, const uint8_t* destAddr = nullptr);
void setLaserEnabled(bool enabled);
private:
void xiaozhi_board_init();
void lvgl_init();
void xiaozhi_mcp_init();
void ble_init();
void servo_init();
void head_touch_init();
void io_expander_init();
void reminder_init();
void imu_init();
};
Hal& GetHAL();
/**
* @brief
*
*/
class LvglLockGuard {
public:
LvglLockGuard()
{
GetHAL().lvglLock();
}
~LvglLockGuard()
{
GetHAL().lvglUnlock();
}
};
+235
View File
@@ -0,0 +1,235 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "hal.h"
#include "utils/bleprph/bleprph.h"
#include <ArduinoJson.hpp>
#include <mooncake_log.h>
#include <esp_mac.h>
#include <settings.h>
static const std::string _tag = "HAL-BLE";
static int _handle_ble_motion_write(const char* json_data, uint16_t len, uint16_t conn_handle)
{
// mclog::tagInfo(_tag, "on motion:\n{}", json_data);
GetHAL().onBleMotionData.emit(json_data);
return 0;
}
static int _handle_ble_avatar_write(const char* json_data, uint16_t len, uint16_t conn_handle)
{
// mclog::tagInfo(_tag, "on avatar:\n{}", json_data);
GetHAL().onBleAvatarData.emit(json_data);
return 0;
}
static int _handle_ble_config_write(const char* json_data, uint16_t len, uint16_t conn_handle)
{
mclog::tagInfo(_tag, "on config:\n{}", json_data);
GetHAL().onBleConfigData.emit(json_data);
return 0;
}
static int _handle_ble_animation_write(const char* json_data, uint16_t len, uint16_t conn_handle)
{
mclog::tagInfo(_tag, "on animation:\n{}", json_data);
GetHAL().onBleAnimationData.emit(json_data);
return 0;
}
static uint8_t _handle_ble_battery_read(void)
{
mclog::tagInfo(_tag, "on bat read");
return 96;
}
void Hal::ble_init()
{
mclog::tagInfo(_tag, "init");
static stackchan_ble_callbacks_t ble_callbacks = {
.motion_cb = _handle_ble_motion_write,
.avatar_cb = _handle_ble_avatar_write,
.config_cb = _handle_ble_config_write,
.animation_cb = _handle_ble_animation_write,
.battery_read_cb = _handle_ble_battery_read,
};
stackchan_ble_register_callbacks(&ble_callbacks);
ble_prph_init();
uint8_t mac[6];
esp_read_mac(mac, ESP_MAC_EFUSE_FACTORY);
mclog::tagInfo(_tag, "init done, factory mac: {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", mac[0], mac[1], mac[2],
mac[3], mac[4], mac[5]);
}
void Hal::startBleServer()
{
mclog::tagInfo(_tag, "start ble server");
ble_init();
}
bool Hal::isBleConnected()
{
return stackchan_ble_is_connected();
}
/* -------------------------------------------------------------------------- */
/* App config server */
/* -------------------------------------------------------------------------- */
#include "utils/wifi_connect/wifi_station.h"
#include <string_view>
#include <queue>
#include <mutex>
class WifiConfigServer {
public:
void init()
{
GetHAL().onBleConfigData.connect([this](const char* data) { on_config_data(data); });
_was_connected = stackchan_ble_is_connected();
// Setup WifiStation callbacks
auto& wifi = StackChanWifiStation::GetInstance();
wifi.OnConnect([this](const std::string& ssid) {
mclog::tagInfo(_tag, "Wifi Connecting to {}", ssid);
notify_state(0, "wifiConnecting");
});
wifi.OnConnected([this](const std::string& ssid) {
mclog::tagInfo(_tag, "Wifi Connected to {}", ssid);
notify_state(1, "wifiConnected");
GetHAL().onAppConfigEvent.emit(AppConfigEvent::WifiConnected);
Settings settings("app_config", true);
settings.SetBool("is_configed", true);
});
wifi.OnConnectFailed([this](const std::string& ssid) {
mclog::tagInfo(_tag, "Wifi Connect Failed to {}", ssid);
notify_state(2, "wifiConnectFailed");
GetHAL().onAppConfigEvent.emit(AppConfigEvent::WifiConnectFailed);
});
wifi.Start();
}
void update()
{
bool is_connected = stackchan_ble_is_connected();
if (is_connected != _was_connected) {
_was_connected = is_connected;
if (is_connected) {
mclog::tagInfo("WifiConfigServer", "app Connected");
GetHAL().onAppConfigEvent.emit(AppConfigEvent::AppConnected);
} else {
mclog::tagInfo("WifiConfigServer", "app Disconnected");
GetHAL().onAppConfigEvent.emit(AppConfigEvent::AppDisconnected);
}
}
std::string data;
bool has_data = false;
{
std::lock_guard<std::mutex> lock(_mutex);
if (!_msg_queue.empty()) {
data = _msg_queue.front();
_msg_queue.pop();
has_data = true;
}
}
if (has_data) {
process_config_data(data.c_str());
}
}
private:
static constexpr std::string_view _tag = "WifiConfigServer";
std::queue<std::string> _msg_queue;
std::mutex _mutex;
bool _was_connected = false;
void on_config_data(const char* json_data)
{
std::lock_guard<std::mutex> lock(_mutex);
_msg_queue.push(json_data);
}
void process_config_data(const char* json_data)
{
ArduinoJson::JsonDocument doc;
auto error = ArduinoJson::deserializeJson(doc, json_data);
if (error) {
mclog::tagError(_tag, "deserializeJson() failed: {}", error.c_str());
return;
}
if (doc["cmd"] == "setWifi") {
handle_set_wifi(doc["data"]);
}
}
void handle_set_wifi(ArduinoJson::JsonObject data)
{
const char* ssid = data["ssid"];
const char* password = data["password"];
mclog::tagInfo("WifiConfigServer", "get wifi config: {} / {}", ssid, password);
// Notify state: connecting
notify_state(0, "wifiConnecting");
GetHAL().onAppConfigEvent.emit(AppConfigEvent::TryWifiConnect);
connect_wifi(ssid, password);
}
void connect_wifi(const char* ssid, const char* password)
{
auto& wifi = StackChanWifiStation::GetInstance();
// Save to NVS (compatible with Xiaozhi) and connect
wifi.AddAuth(ssid, password);
}
void notify_state(int type, const char* state)
{
ArduinoJson::JsonDocument doc;
doc["cmd"] = "notifyState";
doc["data"]["type"] = type;
doc["data"]["state"] = state;
std::string json_str;
ArduinoJson::serializeJson(doc, json_str);
stackchan_ble_notify_config(json_str.c_str(), json_str.length());
}
};
static void _app_config_server_task(void* param)
{
auto server = std::make_unique<WifiConfigServer>();
server->init();
while (1) {
server->update();
vTaskDelay(pdMS_TO_TICKS(50));
}
}
void Hal::startAppConfigServer()
{
mclog::tagInfo(_tag, "start app config server");
ble_init();
xTaskCreate(_app_config_server_task, "appconfig", 6000, NULL, 10, NULL);
}
bool Hal::isAppConfiged()
{
Settings settings("app_config", false);
return settings.GetBool("is_configed", false);
}
+184
View File
@@ -0,0 +1,184 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "hal.h"
#include <algorithm>
#include <mooncake_log.h>
#include <esp_wifi.h>
#include <esp_netif.h>
#include <esp_err.h>
#include <esp_system.h>
#include <esp_event.h>
#include <lwip/err.h>
#include <lwip/sys.h>
#include <time.h>
#include <sys/time.h>
#include <esp_sntp.h>
#include <esp_log.h>
#include <esp_mac.h>
#include <espnow.h>
#include <espnow_storage.h>
#include <espnow_utils.h>
#include <esp_check.h>
static const std::string _tag = "HAL-EspNow";
static EventGroupHandle_t s_wifi_event_group = NULL;
static const int WIFI_CONNECTED_BIT = BIT0;
static const int WIFI_DISCONNECTED_BIT = BIT1;
static const int WIFI_FAIL_BIT = BIT2;
static const int WIFI_STARTED_BIT = BIT3;
static void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
{
const char* TAG = "WiFi";
// Wifi started
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
xEventGroupSetBits(s_wifi_event_group, WIFI_STARTED_BIT);
}
// Disconnected
else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
xEventGroupSetBits(s_wifi_event_group, WIFI_DISCONNECTED_BIT);
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
// Connected
else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t* event = (ip_event_got_ip_t*)event_data;
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}
static void _wifi_init(int channel = 1)
{
mclog::tagInfo(_tag, "wifi init");
// ESP_ERROR_CHECK(nvs_flash_init());
// ESP_ERROR_CHECK(esp_netif_init());
// ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_t* sta_netif = esp_netif_create_default_wifi_sta();
assert(sta_netif);
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
if (!s_wifi_event_group) {
s_wifi_event_group = xEventGroupCreate();
}
ESP_ERROR_CHECK(
esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, nullptr, nullptr));
ESP_ERROR_CHECK(
esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, nullptr, nullptr));
ESP_ERROR_CHECK(esp_wifi_start());
channel = std::clamp(channel, 1, 13);
mclog::tagInfo(_tag, "wifi channel set to {}", channel);
// 建议先开启混杂模式再设信道,确保射频频率被强制锁定
ESP_ERROR_CHECK(esp_wifi_set_promiscuous(true));
ESP_ERROR_CHECK(esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE));
ESP_ERROR_CHECK(esp_wifi_set_promiscuous(false));
}
static esp_err_t _handle_espnow_received(uint8_t* src_addr, void* data, size_t size, wifi_pkt_rx_ctrl_t* rx_ctrl)
{
const char* TAG = "EspNow";
ESP_PARAM_CHECK(src_addr);
ESP_PARAM_CHECK(data);
ESP_PARAM_CHECK(size);
ESP_PARAM_CHECK(rx_ctrl);
static uint32_t count = 0;
ESP_LOGI(TAG, "espnow_recv, <%" PRIu32 "> [" MACSTR "][%d][%d][%u]: %.*s", count++, MAC2STR(src_addr),
rx_ctrl->channel, rx_ctrl->rssi, size, size, "~");
std::vector<uint8_t> received_data((uint8_t*)data, (uint8_t*)data + size);
GetHAL().onEspNowData.emit(received_data);
return ESP_OK;
}
void Hal::startEspNow(int channel)
{
mclog::tagInfo(_tag, "start EspNow on channel {}", channel);
_wifi_init(channel);
espnow_config_t espnow_config = ESPNOW_INIT_CONFIG_DEFAULT();
// 2. 修改关键参数以兼容 Arduino
espnow_config.forward_enable = false; // 关闭转发(多跳),Arduino 无法解析带转发头的包
espnow_config.forward_switch_channel = false; // 关闭自动切信道
espnow_config.send_retry_num = 5; // 失败重试次数(可按需调,建议5-10)
// 3. 修改接收使能开关
espnow_config.receive_enable.forward = false; // 关闭转发包接收
espnow_config.receive_enable.data = true; // 必须开启这个,才能接收 Arduino 发来的普通数据包
espnow_init(&espnow_config);
espnow_set_config_for_data_type(ESPNOW_DATA_TYPE_DATA, true, _handle_espnow_received);
mclog::tagInfo(_tag, "factory mac: {}", getFactoryMacString());
}
bool Hal::espNowSend(const std::vector<uint8_t>& data, const uint8_t* destAddr)
{
mclog::tagInfo(_tag, "send data with size: {}", data.size());
espnow_frame_head_t frame_head = ESPNOW_FRAME_CONFIG_DEFAULT();
esp_err_t ret = ESP_FAIL;
if (destAddr == nullptr) {
ret = espnow_send(ESPNOW_DATA_TYPE_DATA, ESPNOW_ADDR_BROADCAST, data.data(), data.size(), &frame_head,
portMAX_DELAY);
} else {
ret = espnow_send(ESPNOW_DATA_TYPE_DATA, destAddr, data.data(), data.size(), &frame_head, portMAX_DELAY);
}
if (ret != ESP_OK) {
mclog::tagError(_tag, "send failed: {}", esp_err_to_name(ret));
return false;
}
return true;
}
#include <driver/gpio.h>
void Hal::setLaserEnabled(bool enabled)
{
static bool laser_enabled = false;
static bool is_inited = false;
if (laser_enabled == enabled) {
return;
}
const gpio_num_t laser_pin = GPIO_NUM_9;
if (!is_inited) {
gpio_reset_pin(laser_pin);
gpio_set_direction(laser_pin, GPIO_MODE_OUTPUT);
gpio_set_pull_mode(laser_pin, GPIO_PULLUP_ONLY);
is_inited = true;
}
mclog::tagInfo(_tag, "set laser {}", enabled ? "enabled" : "disabled");
if (enabled) {
gpio_set_level(laser_pin, 1);
} else {
gpio_set_level(laser_pin, 0);
}
laser_enabled = enabled;
}
+162
View File
@@ -0,0 +1,162 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "hal.h"
#include "drivers/Si12T/Si12T.h"
#include "board/hal_bridge.h"
#include <mooncake_log.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
static const std::string _tag = "HAL-HeadTouch";
// 触摸状态
enum class TouchState { IDLE, TOUCHED, SWIPING };
// 配置参数
struct TouchConfig {
uint8_t touch_threshold = 1;
int16_t swipe_threshold = 40; // 使用百分比,范围-100到100
};
// 触摸数据
struct TouchData {
uint8_t intensity[3];
uint32_t timestamp;
// 计算位置(返回-100到100的整数)
int16_t get_position() const
{
uint16_t total = intensity[0] + intensity[1] + intensity[2];
if (total == 0) return 0;
int32_t weighted = intensity[0] * (-100) + intensity[1] * 0 + intensity[2] * 100;
return static_cast<int16_t>(weighted / total);
}
uint8_t get_max_intensity() const
{
uint8_t max_val = intensity[0];
if (intensity[1] > max_val) max_val = intensity[1];
if (intensity[2] > max_val) max_val = intensity[2];
return max_val;
}
bool is_touched() const
{
return get_max_intensity() >= 1;
}
};
// 手势识别器类
class GestureRecognizer {
public:
GestureRecognizer() : current_state(TouchState::IDLE), initial_position(0)
{
}
// 更新状态机,返回识别到的手势
HeadPetGesture update(const TouchData& data)
{
HeadPetGesture gesture = HeadPetGesture::None;
switch (current_state) {
case TouchState::IDLE:
if (data.is_touched()) {
current_state = TouchState::TOUCHED;
initial_position = data.get_position();
gesture = HeadPetGesture::Press;
// mclog::tagDebug(_tag, "Touch detected at position: {}", initial_position);
}
break;
case TouchState::TOUCHED:
if (!data.is_touched()) {
current_state = TouchState::IDLE;
gesture = HeadPetGesture::Release;
} else {
// Check for swipe
int16_t current_pos = data.get_position();
int16_t delta = current_pos - initial_position;
if (delta > config.swipe_threshold) {
current_state = TouchState::SWIPING;
gesture = HeadPetGesture::SwipeForward;
// mclog::tagDebug(_tag, "Swipe forward detected, delta: {}", delta);
} else if (delta < -config.swipe_threshold) {
current_state = TouchState::SWIPING;
gesture = HeadPetGesture::SwipeBackward;
// mclog::tagDebug(_tag, "Swipe backward detected, delta: {}", delta);
}
}
break;
case TouchState::SWIPING:
if (!data.is_touched()) {
current_state = TouchState::IDLE;
gesture = HeadPetGesture::Release;
}
break;
}
return gesture;
}
void set_config(const TouchConfig& cfg)
{
config = cfg;
}
private:
TouchConfig config;
TouchState current_state;
int16_t initial_position;
};
static void _head_touch_update_task(void* param)
{
mclog::tagInfo(_tag, "start update task");
si12t_handle_t si12t = (si12t_handle_t)param;
uint8_t touch_result = 0;
TouchData data;
GestureRecognizer recognizer;
HeadPetGesture gesture;
vTaskDelay(pdMS_TO_TICKS(200));
while (1) {
// Read data
si12t_read_touch_result(si12t, &touch_result);
si12t_parse_touch_result_to(touch_result, data.intensity);
data.timestamp = xTaskGetTickCount();
// Update and fire event
gesture = recognizer.update(data);
if (gesture != HeadPetGesture::None) {
GetHAL().onHeadPetGesture.emit(gesture);
}
vTaskDelay(pdMS_TO_TICKS(50));
}
}
void Hal::head_touch_init()
{
mclog::tagInfo(_tag, "init");
auto i2c_bus = hal_bridge::board_get_i2c_bus();
si12t_config_t si12t_cfg = {
.i2c_bus = i2c_bus,
.dev_addr = SI12T_GND_ADDRESS,
};
static si12t_handle_t si12t;
si12t_init(&si12t_cfg, &si12t);
si12t_setup(si12t, SI12T_TYPE_LOW, SI12T_SENSITIVITY_LEVEL_3);
xTaskCreate(_head_touch_update_task, "headtouch", 4096, si12t, 5, NULL);
}
+56
View File
@@ -0,0 +1,56 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "hal.h"
#include "board/hal_bridge.h"
#include "drivers/bmi270/bmi270.h"
#include "utils/motion_detector/motion_detector.h"
#include <mooncake_log.h>
#include <memory>
static const std::string _tag = "HAL-IMU";
static std::unique_ptr<BMI270> _bmi270;
static void _imu_task(void* param)
{
auto motion_detector = std::make_unique<MotionDetector>();
while (1) {
if (_bmi270 && _bmi270->update()) {
auto& data = _bmi270->getData();
// mclog::debug("IMU Accel: {:.2f}\t{:.2f}\t{:.2f}", data.accel_x, data.accel_y, data.accel_z);
motion_detector->update(data.accel_x, data.accel_y, data.accel_z);
if (motion_detector->isShakeDetected()) {
mclog::tagInfo(_tag, "Shake Detected!");
GetHAL().onImuMotionEvent.emit(ImuMotionEvent::Shake);
}
if (motion_detector->isPickUpDetected()) {
mclog::tagInfo(_tag, "Pick Up Detected!");
GetHAL().onImuMotionEvent.emit(ImuMotionEvent::PickUp);
}
}
vTaskDelay(pdMS_TO_TICKS(100));
}
}
void Hal::imu_init()
{
mclog::tagInfo(_tag, "init");
auto i2c_bus = hal_bridge::board_get_i2c_bus();
_bmi270 = std::make_unique<BMI270>(i2c_bus, 0x69);
if (!_bmi270->begin()) {
_bmi270.reset();
mclog::tagError(_tag, "BMI270 init failed");
return;
}
mclog::tagInfo(_tag, "BMI270 init ok");
// xTaskCreate(_imu_task, "imu", 4096, NULL, 5, NULL);
}
+91
View File
@@ -0,0 +1,91 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "hal.h"
#include "board/hal_bridge.h"
#include "drivers/PY32IOExpander_Class/PY32IOExpander_Class.hpp"
#include <mooncake_log.h>
#include <memory>
static const std::string _tag = "HAL-IOE";
static std::unique_ptr<m5::PY32IOExpander_Class> _io_expander;
void Hal::io_expander_init()
{
mclog::tagInfo(_tag, "init");
auto i2c_bus = hal_bridge::board_get_i2c_bus();
_io_expander = std::make_unique<m5::PY32IOExpander_Class>(i2c_bus);
uint32_t start_tick = GetHAL().millis();
// PY32 IO Expander may boot slowly, wait for it
while (1) {
vTaskDelay(pdMS_TO_TICKS(200));
if (GetHAL().millis() - start_tick > 1200) {
mclog::tagError(_tag, "init timeout");
_io_expander.reset();
break;
}
if (_io_expander->begin()) {
break;
}
mclog::tagInfo(_tag, "init failed, retrying...");
}
if (_io_expander) {
// VM EN
_io_expander->setDirection(0, true); // Output
_io_expander->setPullMode(0, true); // Pull-up
GetHAL().setServoPowerEnabled(true);
vTaskDelay(pdMS_TO_TICKS(200));
// RGB
_io_expander->setDirection(13, true); // Output
_io_expander->setPullMode(13, true); // Pull-up
_io_expander->setDriveMode(13, false); // Push-pull
_io_expander->setLedCount(12);
vTaskDelay(pdMS_TO_TICKS(200));
GetHAL().showRgbColor(0, 0, 0);
vTaskDelay(pdMS_TO_TICKS(50));
GetHAL().showRgbColor(0, 0, 0);
mclog::tagInfo(_tag, "init done");
}
}
void Hal::setServoPowerEnabled(bool enabled)
{
if (!_io_expander) {
return;
}
_io_expander->digitalWrite(0, enabled ? true : false);
}
void Hal::setRgbColor(uint8_t index, uint8_t r, uint8_t g, uint8_t b)
{
if (!_io_expander) {
return;
}
_io_expander->setLedColor(index, r, g, b);
}
void Hal::refreshRgb()
{
if (!_io_expander) {
return;
}
_io_expander->refreshLeds();
}
void Hal::showRgbColor(uint8_t r, uint8_t g, uint8_t b)
{
for (int i = 0; i < 12; i++) {
setRgbColor(i, r, g, b);
}
refreshRgb();
}
+62
View File
@@ -0,0 +1,62 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "hal.h"
#include <mooncake_log.h>
#include <mcp_server.h>
#include <stackchan/stackchan.h>
using namespace stackchan;
static const std::string _tag = "HAL-MCP";
void Hal::xiaozhi_mcp_init()
{
mclog::tagInfo(_tag, "init");
// https://github.com/78/xiaozhi-esp32/blob/main/docs/mcp-usage.md
auto& mcp_server = McpServer::GetInstance();
mclog::tagInfo(_tag, "add motion.set_angles tool");
mcp_server.AddTool(
"self.motion.set_angles",
"Set the angles of the robot's servos (head movement). Yaw controls left/right (-1280 to "
"1280), Pitch controls up/down (0 to 900). Note: 10 units equals 1 degree. For natural movement, prefer angles "
"within +/- 300 (30 degrees) unless instructed otherwise. Speed controls the movement speed (100-1000).",
PropertyList({Property("yaw", kPropertyTypeInteger, 0, -1280, 1280),
Property("pitch", kPropertyTypeInteger, 0, 0, 900),
Property("speed", kPropertyTypeInteger, 150, 100, 1000)}),
[this](const PropertyList& properties) -> ReturnValue {
int pitch = properties["pitch"].value<int>();
int yaw = properties["yaw"].value<int>();
int speed = properties["speed"].value<int>();
mclog::tagInfo(_tag, "motion set angles: pitch: {}, yaw: {}, speed: {}", pitch, yaw, speed);
auto& motion = GetStackChan().motion();
motion.pitchServo().moveWithSpeed(pitch, speed);
motion.yawServo().moveWithSpeed(yaw, speed);
return true;
});
mclog::tagInfo(_tag, "add led.set_color tool");
mcp_server.AddTool("self.led.set_color",
"Set the color of the RGB LED strip. Each channel (red, green, blue) ranges from 0 to 255. "
"Note: For power saving and eye protection, it is recommended to keep each channel value below "
"126.",
PropertyList({Property("red", kPropertyTypeInteger, 0, 0, 168),
Property("green", kPropertyTypeInteger, 0, 0, 168),
Property("blue", kPropertyTypeInteger, 0, 0, 168)}),
[this](const PropertyList& properties) -> ReturnValue {
int r = properties["red"].value<int>();
int g = properties["green"].value<int>();
int b = properties["blue"].value<int>();
mclog::tagInfo(_tag, "led set color: r: {}, g: {}, b: {}", r, g, b);
GetHAL().showRgbColor(r, g, b);
return true;
});
}
+137
View File
@@ -0,0 +1,137 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "hal.h"
#include "drivers/SCServo_lib/src/SCSCL.h"
#include <stackchan/stackchan.h>
#include <smooth_ui_toolkit.hpp>
#include <mooncake_log.h>
#include <settings.h>
using namespace smooth_ui_toolkit;
using namespace stackchan::motion;
static SCSCL _scs_bus;
class ScsServo : public Servo {
public:
static inline const std::string _tag = "ScsServo";
ScsServo(int id, Vector2i angleLimit, const std::string& settingNs, const std::string& zeroPosKey,
bool enablePwmMode = false)
: _id(id), _setting_ns(settingNs), _zero_pos_key(zeroPosKey), _enable_pwm_mode(enablePwmMode)
{
set_angle_limit(angleLimit);
Settings settings(_setting_ns, false);
_zero_pos = settings.GetInt(_zero_pos_key, 0);
mclog::tagInfo(_tag, "id: {} get zero pos: {} from settings", _id, _zero_pos);
}
void set_angle_impl(int angle) override
{
int mapped_angle = _zero_pos + angle * 16 / 5 / 10; // 一步对应 0.3125度, 0.3125 = 5/16
if (mapped_angle < 0) {
mapped_angle = 0;
}
// mclog::tagInfo(_tag, "id: {} mapped angle: {}", _id, mapped_angle);
check_mode(Mode::Position);
_scs_bus.WritePos(_id, mapped_angle, 20, 0);
}
int getCurrentAngle() override
{
int current_pos = _scs_bus.ReadPos(_id);
int angle = (current_pos - _zero_pos) * 5 * 10 / 16;
angle = uitk::clamp(angle, getAngleLimit().x, getAngleLimit().y);
// mclog::tagInfo(_tag, "id: {} current pos: {} angle: {}", _id, current_pos, angle);
return angle;
}
bool isMoving() override
{
int moving = _scs_bus.ReadMove(_id);
// mclog::tagInfo(_tag, "id: {} moving: {}", _id, moving);
return moving != 0;
}
void setTorqueEnabled(bool enabled) override
{
Servo::setTorqueEnabled(enabled);
_scs_bus.EnableTorque(_id, enabled ? 1 : 0);
// mclog::tagInfo(_tag, "id: {} set torque: {}", _id, enabled);
}
bool getTorqueEnabled() override
{
int torque_enable = _scs_bus.ReadToqueEnable(_id);
// mclog::tagInfo(_tag, "id: {} torque enable: {}", _id, torque_enable);
return torque_enable > 0;
}
void setCurrentAngleAsZero() override
{
_zero_pos = _scs_bus.ReadPos(_id);
Settings settings(_setting_ns, true);
settings.SetInt(_zero_pos_key, _zero_pos);
mclog::tagInfo(_tag, "id: {} set zero pos: {} to settings", _id, _zero_pos);
}
void rotate(int velocity) override
{
velocity = uitk::clamp(velocity, -1000, 1000);
if (!_enable_pwm_mode) {
return;
}
int mapped_velocity = map_range(velocity, 0, 1000, 0, 1023);
check_mode(Mode::PWM);
_scs_bus.WritePWM(_id, mapped_velocity);
}
private:
enum class Mode { Position = 0, PWM = 1 };
int _id = -1;
int _zero_pos = 0;
std::string _setting_ns;
std::string _zero_pos_key;
Mode _current_mode = Mode::Position;
bool _enable_pwm_mode;
uint32_t _last_true_move_ms = 0;
const uint32_t STOP_DEBOUNCE_MS = 250;
void check_mode(Mode targetMode)
{
if (targetMode == _current_mode) {
return;
}
_scs_bus.SwitchMode(_id, static_cast<uint8_t>(targetMode));
_current_mode = targetMode;
}
};
void Hal::servo_init()
{
mclog::tagInfo("HAL-Servo", "init");
_scs_bus.begin(UART_NUM_1, 1000000, 6, 7);
auto motion =
std::make_unique<Motion>(std::make_unique<ScsServo>(1, Vector2i(-1280, 1280), "servo", "zero_pos_1", true),
std::make_unique<ScsServo>(2, Vector2i(0, 900), "servo", "zero_pos_2"));
motion->init();
GetStackChan().attachMotion(std::move(motion));
}

Some files were not shown because too many files have changed in this diff Show More