forked from espressif/esp-idf
Compare commits
378 Commits
v3.2.2
...
v3.3-beta1
Author | SHA1 | Date | |
---|---|---|---|
|
646d36c728 | ||
|
6c868c4bee | ||
|
8b885fb935 | ||
|
def2a13297 | ||
|
423d7b9a65 | ||
|
893cb83343 | ||
|
4e77efc36b | ||
|
b1630084d1 | ||
|
d4cb14bc65 | ||
|
8b7b5821c7 | ||
|
aae955d1ae | ||
|
560e92b101 | ||
|
e224b8a43a | ||
|
3c8a2a099a | ||
|
812a49bd0d | ||
|
61beb16225 | ||
|
357f2264e6 | ||
|
57c54f96f1 | ||
|
3150920cb4 | ||
|
94f2dd27d4 | ||
|
271a2e8e97 | ||
|
a36d714d1a | ||
|
cbaa4ade42 | ||
|
b21ffc8a0c | ||
|
8c7a6be627 | ||
|
54532c6189 | ||
|
8ab2f20c3a | ||
|
8e9359b4fd | ||
|
062c64fca0 | ||
|
ef4a4105f4 | ||
|
ff71ea9202 | ||
|
34109c4171 | ||
|
97a3617a27 | ||
|
f1b4c18c2a | ||
|
d3b3f1e4a3 | ||
|
9f8587360c | ||
|
b56ed1a99e | ||
|
4749b118bc | ||
|
eb27686416 | ||
|
e92e028679 | ||
|
37975c186d | ||
|
e04fd42176 | ||
|
d50af8bd53 | ||
|
36be9b36dd | ||
|
f9522a0eb6 | ||
|
8a7b46aa90 | ||
|
b11238df4d | ||
|
0d5660fbde | ||
|
794155f975 | ||
|
a2d0fbb9ab | ||
|
441e2d5011 | ||
|
deaecf164d | ||
|
d411175e47 | ||
|
50d7067391 | ||
|
b12c58224d | ||
|
dc043109d7 | ||
|
d6ee27e313 | ||
|
2b557523ba | ||
|
2946b5f384 | ||
|
ac1d1aa3c8 | ||
|
b45b0f2348 | ||
|
7f32995a4c | ||
|
89826e8f47 | ||
|
a9429ee5da | ||
|
3b9cb25fe1 | ||
|
588ecaae09 | ||
|
a7a1c32a8e | ||
|
3bc970c5f4 | ||
|
674f0b1ebd | ||
|
80e6def4b8 | ||
|
554cf77963 | ||
|
fffa98647b | ||
|
7fa98593bc | ||
|
340e7f3b2f | ||
|
6bd497f9ed | ||
|
e07c5a22f2 | ||
|
1cffc90e58 | ||
|
f0e8c068d2 | ||
|
0f3eb977cd | ||
|
f7281c75c7 | ||
|
98bc172f58 | ||
|
a3b581bd8c | ||
|
59761b0fcb | ||
|
e621e0af8b | ||
|
7458c1c1e2 | ||
|
ed21457afc | ||
|
a34a27010b | ||
|
c22512d27f | ||
|
ba844caa8a | ||
|
46a948dafa | ||
|
f845af840f | ||
|
4027a7f2c2 | ||
|
afe4c76b6b | ||
|
9163e454f1 | ||
|
924daf7b84 | ||
|
e55f9c1e98 | ||
|
34c1d25c7f | ||
|
2b165f99c4 | ||
|
98f9a3c316 | ||
|
8dc66d3f0f | ||
|
a3a1cc080e | ||
|
29b1f86f16 | ||
|
499fdbd33d | ||
|
edff003e72 | ||
|
a26580d0e8 | ||
|
bbeb62547e | ||
|
907b1a9032 | ||
|
147447b13e | ||
|
a3785792eb | ||
|
56e4c6e5a3 | ||
|
ba6058ba58 | ||
|
add7c49a26 | ||
|
da1f3ea12a | ||
|
a2f63c09bf | ||
|
f6375952bb | ||
|
62cc522f36 | ||
|
44fdca94e9 | ||
|
073dbe6d1d | ||
|
759185b16c | ||
|
d4a5682e7d | ||
|
21b3919369 | ||
|
1d2673eda5 | ||
|
71f57931bd | ||
|
738c56e84a | ||
|
2c7fc07aae | ||
|
98884b4f6c | ||
|
7312294648 | ||
|
a134141320 | ||
|
b926764385 | ||
|
cc5673435b | ||
|
5e08698039 | ||
|
bceec35d0e | ||
|
8ca6904d55 | ||
|
88c81c67b7 | ||
|
06eebfe15f | ||
|
da223fad4e | ||
|
87e8757569 | ||
|
9dde91ce2b | ||
|
ade39f823f | ||
|
4c83f456ab | ||
|
a9c784339d | ||
|
22b4c95d1e | ||
|
19910c8729 | ||
|
8eb40bea51 | ||
|
70554e8caa | ||
|
6f8e2b018f | ||
|
11faab2c5d | ||
|
fac12d0dae | ||
|
f7811671ae | ||
|
983cdcb7f4 | ||
|
1692896e5e | ||
|
a9c1124763 | ||
|
957cf0ab84 | ||
|
7e7cc99241 | ||
|
f1f0bd4b1c | ||
|
bec3bb3ba4 | ||
|
b35c745c4f | ||
|
cedc0b6643 | ||
|
90f5432f2a | ||
|
0908fba1a3 | ||
|
37d30c7a6e | ||
|
81231fcc4b | ||
|
c75c28faf5 | ||
|
f3bfdeaeec | ||
|
b7f56e86ba | ||
|
1b464d23a9 | ||
|
9273de8b43 | ||
|
90a6c9aada | ||
|
9890feaa37 | ||
|
bf0f02112d | ||
|
1c65f18422 | ||
|
03c59658cb | ||
|
c765035b3a | ||
|
cfba157fdd | ||
|
435adaa22a | ||
|
7202aed31e | ||
|
ca7fa6f01a | ||
|
ef9eaddd88 | ||
|
5b3d09d5c8 | ||
|
644571f78b | ||
|
0ad226b375 | ||
|
fa59b1b1c9 | ||
|
5aa7abb216 | ||
|
a0468b2bd6 | ||
|
608fc23278 | ||
|
1751607adf | ||
|
ad22d280c6 | ||
|
64d038c0d5 | ||
|
765bf674d0 | ||
|
dd3d89db49 | ||
|
3a02a12aa4 | ||
|
552f17e260 | ||
|
783ff9c455 | ||
|
f874b52f0a | ||
|
a081e5d25e | ||
|
83f6ee9912 | ||
|
269e94f387 | ||
|
33138a3dec | ||
|
1600c3144c | ||
|
8eeddd287c | ||
|
8e70582cad | ||
|
e199587a11 | ||
|
684f0b0a32 | ||
|
7e142f9d22 | ||
|
09a01f68ba | ||
|
8deb885ce3 | ||
|
6252292d9c | ||
|
56ed588d4f | ||
|
507328d4db | ||
|
e9ee9384fc | ||
|
86fedc3cbb | ||
|
6c3b5ae5a1 | ||
|
0c72b08872 | ||
|
582c547191 | ||
|
c44f15441f | ||
|
9db1987892 | ||
|
0d7f2d77c2 | ||
|
2a55e957fd | ||
|
bd3806193d | ||
|
e7f9e3f6f6 | ||
|
69c9e050b0 | ||
|
3970ea60de | ||
|
c0298a5712 | ||
|
92f32f0060 | ||
|
ffda37dd16 | ||
|
b422a42697 | ||
|
4f4edcf676 | ||
|
61ee1bd31f | ||
|
46e28d7553 | ||
|
8cddfa35b8 | ||
|
3139b2d533 | ||
|
3eaba1c8ce | ||
|
775c6e5ab7 | ||
|
4c881708dc | ||
|
99dd08943c | ||
|
8027adaf81 | ||
|
62efef0444 | ||
|
00a13bd8d3 | ||
|
a46b884a14 | ||
|
3c7819eaf2 | ||
|
6709d26863 | ||
|
57273d48d4 | ||
|
6cdfea4251 | ||
|
e1774cb6f9 | ||
|
26a6969873 | ||
|
8915f48208 | ||
|
964f5a91f7 | ||
|
a5adfd0169 | ||
|
a98674d78b | ||
|
6091021e83 | ||
|
d4ef2135f0 | ||
|
aa692b3483 | ||
|
5fb3d59a92 | ||
|
c9a873c034 | ||
|
b1189e9645 | ||
|
8b6436eb2a | ||
|
7d888ff6eb | ||
|
1d3f4074de | ||
|
9a9d18e466 | ||
|
639502ed5d | ||
|
aa6066a197 | ||
|
4dd0fa61e9 | ||
|
a10fc02dd9 | ||
|
5b4e3da759 | ||
|
26bcb7f2cf | ||
|
7ef74ee863 | ||
|
e3956787f6 | ||
|
960c240578 | ||
|
8c9407f22f | ||
|
364f98b67e | ||
|
96f152341a | ||
|
0db8c2e618 | ||
|
a55d350f43 | ||
|
ad2cdeb476 | ||
|
8be8ea2488 | ||
|
6fa2f388ef | ||
|
43936ab48a | ||
|
6309643c1d | ||
|
d16762a036 | ||
|
f2de7602e3 | ||
|
6fbc3c4361 | ||
|
63411fc556 | ||
|
b00be955ee | ||
|
ac5a3443a4 | ||
|
b6d7c70238 | ||
|
9c9aa4ea4c | ||
|
7b86247428 | ||
|
09e4321e97 | ||
|
fb56ce7d5c | ||
|
78a7a152d1 | ||
|
b152c1020c | ||
|
76e02cadcc | ||
|
181a40ae30 | ||
|
30e766ee6b | ||
|
a55cc99f50 | ||
|
8b5f61eb35 | ||
|
bbdcff1f45 | ||
|
e677bdf5c9 | ||
|
79043882d9 | ||
|
8e1c91ac7d | ||
|
fe5b2c56a4 | ||
|
f1949a59b6 | ||
|
eec6de57ff | ||
|
bd34ae0409 | ||
|
26626dfbf2 | ||
|
a52ab8ca87 | ||
|
356fe47ce1 | ||
|
08ef71b386 | ||
|
5fccb73f86 | ||
|
beada90b06 | ||
|
ef4a87d62e | ||
|
df8feaa5c2 | ||
|
7efb3926c5 | ||
|
c7fb749b84 | ||
|
ccb3841a9e | ||
|
933dc75294 | ||
|
1e99e61c33 | ||
|
521fb5d906 | ||
|
be0123e10e | ||
|
3685d325d8 | ||
|
a96deceb27 | ||
|
ccfa134533 | ||
|
e2ca285fae | ||
|
4fe3673f35 | ||
|
a0ab2a15d2 | ||
|
9859428606 | ||
|
baf57b9702 | ||
|
fb3aa88565 | ||
|
90a4e37acd | ||
|
f4cfca4353 | ||
|
f85f64b481 | ||
|
0c9f7271a9 | ||
|
b5c58557fc | ||
|
3ed0f7697d | ||
|
049c9f7bea | ||
|
b358581ab8 | ||
|
288d9b75e9 | ||
|
17177e352b | ||
|
1b7a4758e3 | ||
|
71f1a34540 | ||
|
c15e7b18f8 | ||
|
71b9720309 | ||
|
df9d1cc5d4 | ||
|
5fd76d7490 | ||
|
05838641ff | ||
|
2d34a93dc4 | ||
|
b5d7541c09 | ||
|
2c353edbc4 | ||
|
621e316725 | ||
|
1f6622b2d1 | ||
|
17c70a4a32 | ||
|
888406231c | ||
|
77668b3912 | ||
|
2e139c7885 | ||
|
85d63871ab | ||
|
28f1e1597b | ||
|
35d1c7b173 | ||
|
ddfd62ee66 | ||
|
ded53bd0ff | ||
|
b6d7675e60 | ||
|
364f033a49 | ||
|
fb334baa7c | ||
|
ea963c480c | ||
|
0716e65955 | ||
|
22dd3103bd | ||
|
ae08bdcc31 | ||
|
b7841ec313 | ||
|
b33cdfc1f5 | ||
|
7bb83b0056 | ||
|
ff346f92af | ||
|
20a666fe03 | ||
|
9b5d0f3322 | ||
|
55dfb79e91 | ||
|
901e2af793 | ||
|
9459526e50 | ||
|
b47aca1175 | ||
|
6e6f07ba59 | ||
|
4e81705ca2 |
237
.flake8
Normal file
237
.flake8
Normal file
@@ -0,0 +1,237 @@
|
||||
[flake8]
|
||||
|
||||
select =
|
||||
# Full lists are given in order to suppress all errors from other plugins
|
||||
# Full list of pyflakes error codes:
|
||||
F401, # module imported but unused
|
||||
F402, # import module from line N shadowed by loop variable
|
||||
F403, # 'from module import *' used; unable to detect undefined names
|
||||
F404, # future import(s) name after other statements
|
||||
F405, # name may be undefined, or defined from star imports: module
|
||||
F406, # 'from module import *' only allowed at module level
|
||||
F407, # an undefined __future__ feature name was imported
|
||||
F601, # dictionary key name repeated with different values
|
||||
F602, # dictionary key variable name repeated with different values
|
||||
F621, # too many expressions in an assignment with star-unpacking
|
||||
F622, # two or more starred expressions in an assignment (a, *b, *c = d)
|
||||
F631, # assertion test is a tuple, which are always True
|
||||
F701, # a break statement outside of a while or for loop
|
||||
F702, # a continue statement outside of a while or for loop
|
||||
F703, # a continue statement in a finally block in a loop
|
||||
F704, # a yield or yield from statement outside of a function
|
||||
F705, # a return statement with arguments inside a generator
|
||||
F706, # a return statement outside of a function/method
|
||||
F707, # an except: block as not the last exception handler
|
||||
F721, F722, # doctest syntax error syntax error in forward type annotation
|
||||
F811, # redefinition of unused name from line N
|
||||
F812, # list comprehension redefines name from line N
|
||||
F821, # undefined name name
|
||||
F822, # undefined name name in __all__
|
||||
F823, # local variable name referenced before assignment
|
||||
F831, # duplicate argument name in function definition
|
||||
F841, # local variable name is assigned to but never used
|
||||
F901, # raise NotImplemented should be raise NotImplementedError
|
||||
|
||||
# Full list of pycodestyle violations:
|
||||
E101, # indentation contains mixed spaces and tabs
|
||||
E111, # indentation is not a multiple of four
|
||||
E112, # expected an indented block
|
||||
E113, # unexpected indentation
|
||||
E114, # indentation is not a multiple of four (comment)
|
||||
E115, # expected an indented block (comment)
|
||||
E116, # unexpected indentation (comment)
|
||||
E121, # continuation line under-indented for hanging indent
|
||||
E122, # continuation line missing indentation or outdented
|
||||
E123, # closing bracket does not match indentation of opening bracket's line
|
||||
E124, # closing bracket does not match visual indentation
|
||||
E125, # continuation line with same indent as next logical line
|
||||
E126, # continuation line over-indented for hanging indent
|
||||
E127, # continuation line over-indented for visual indent
|
||||
E128, # continuation line under-indented for visual indent
|
||||
E129, # visually indented line with same indent as next logical line
|
||||
E131, # continuation line unaligned for hanging indent
|
||||
E133, # closing bracket is missing indentation
|
||||
E201, # whitespace after '('
|
||||
E202, # whitespace before ')'
|
||||
E203, # whitespace before ':'
|
||||
E211, # whitespace before '('
|
||||
E221, # multiple spaces before operator
|
||||
E222, # multiple spaces after operator
|
||||
E223, # tab before operator
|
||||
E224, # tab after operator
|
||||
E225, # missing whitespace around operator
|
||||
E226, # missing whitespace around arithmetic operator
|
||||
E227, # missing whitespace around bitwise or shift operator
|
||||
E228, # missing whitespace around modulo operator
|
||||
E231, # missing whitespace after ',', ';', or ':'
|
||||
E241, # multiple spaces after ','
|
||||
E242, # tab after ','
|
||||
E251, # unexpected spaces around keyword / parameter equals
|
||||
E261, # at least two spaces before inline comment
|
||||
E262, # inline comment should start with '# '
|
||||
E265, # block comment should start with '# '
|
||||
E266, # too many leading '#' for block comment
|
||||
E271, # multiple spaces after keyword
|
||||
E272, # multiple spaces before keyword
|
||||
E273, # tab after keyword
|
||||
E274, # tab before keyword
|
||||
E275, # missing whitespace after keyword
|
||||
E301, # expected 1 blank line, found 0
|
||||
E302, # expected 2 blank lines, found 0
|
||||
E303, # too many blank lines
|
||||
E304, # blank lines found after function decorator
|
||||
E305, # expected 2 blank lines after end of function or class
|
||||
E306, # expected 1 blank line before a nested definition
|
||||
E401, # multiple imports on one line
|
||||
E402, # module level import not at top of file
|
||||
E501, # line too long (82 > 79 characters)
|
||||
E502, # the backslash is redundant between brackets
|
||||
E701, # multiple statements on one line (colon)
|
||||
E702, # multiple statements on one line (semicolon)
|
||||
E703, # statement ends with a semicolon
|
||||
E704, # multiple statements on one line (def)
|
||||
E711, # comparison to None should be 'if cond is None:'
|
||||
E712, # comparison to True should be 'if cond is True:' or 'if cond:'
|
||||
E713, # test for membership should be 'not in'
|
||||
E714, # test for object identity should be 'is not'
|
||||
E721, # do not compare types, use 'isinstance()'
|
||||
E722, # do not use bare except, specify exception instead
|
||||
E731, # do not assign a lambda expression, use a def
|
||||
E741, # do not use variables named 'l', 'O', or 'I'
|
||||
E742, # do not define classes named 'l', 'O', or 'I'
|
||||
E743, # do not define functions named 'l', 'O', or 'I'
|
||||
E901, # SyntaxError or IndentationError
|
||||
E902, # IOError
|
||||
W191, # indentation contains tabs
|
||||
W291, # trailing whitespace
|
||||
W292, # no newline at end of file
|
||||
W293, # blank line contains whitespace
|
||||
W391, # blank line at end of file
|
||||
W503, # line break before binary operator
|
||||
W504, # line break after binary operator
|
||||
W505, # doc line too long (82 > 79 characters)
|
||||
W601, # .has_key() is deprecated, use 'in'
|
||||
W602, # deprecated form of raising exception
|
||||
W603, # '<>' is deprecated, use '!='
|
||||
W604, # backticks are deprecated, use 'repr()'
|
||||
W605, # invalid escape sequence 'x'
|
||||
W606, # 'async' and 'await' are reserved keywords starting with Python 3.7
|
||||
|
||||
# Full list of flake8 violations
|
||||
E999, # failed to compile a file into an Abstract Syntax Tree for the plugins that require it
|
||||
|
||||
# Full list of mccabe violations
|
||||
C901 # complexity value provided by the user
|
||||
|
||||
ignore =
|
||||
E221, # multiple spaces before operator
|
||||
E231, # missing whitespace after ',', ';', or ':'
|
||||
E241, # multiple spaces after ','
|
||||
W503, # line break before binary operator
|
||||
W504 # line break after binary operator
|
||||
|
||||
max-line-length = 160
|
||||
|
||||
show_source = True
|
||||
|
||||
statistics = True
|
||||
|
||||
exclude =
|
||||
.git,
|
||||
__pycache__,
|
||||
# submodules
|
||||
components/esptool_py/esptool,
|
||||
components/micro-ecc/micro-ecc,
|
||||
components/nghttp/nghttp2,
|
||||
components/libsodium/libsodium,
|
||||
components/json/cJSON,
|
||||
components/mbedtls/mbedtls,
|
||||
components/expat/expat,
|
||||
components/unity/unity,
|
||||
examples/build_system/cmake/import_lib/main/lib/tinyxml2
|
||||
# autogenerated scripts
|
||||
examples/provisioning/custom_config/components/custom_provisioning/python/custom_config_pb2.py,
|
||||
# temporary list (should be empty)
|
||||
components/app_update/dump_otadata.py,
|
||||
components/app_update/gen_empty_partition.py,
|
||||
components/espcoredump/espcoredump.py,
|
||||
components/espcoredump/test/test_espcoredump.py,
|
||||
components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py,
|
||||
components/partition_table/gen_esp32part.py,
|
||||
components/partition_table/test_gen_esp32part_host/gen_esp32part_tests.py,
|
||||
components/protocomm/python/constants_pb2.py,
|
||||
components/protocomm/python/sec0_pb2.py,
|
||||
components/protocomm/python/sec1_pb2.py,
|
||||
components/protocomm/python/session_pb2.py,
|
||||
components/ulp/esp32ulp_mapgen.py,
|
||||
components/wifi_provisioning/python/wifi_config_pb2.py,
|
||||
components/wifi_provisioning/python/wifi_constants_pb2.py,
|
||||
examples/provisioning/ble_prov/ble_prov_test.py,
|
||||
examples/provisioning/softap_prov/softap_prov_test.py,
|
||||
examples/provisioning/softap_prov/utils/wifi_tools.py,
|
||||
tools/ci/apply_bot_filter.py,
|
||||
tools/cmake/convert_to_cmake.py,
|
||||
tools/esp_app_trace/apptrace_proc.py,
|
||||
tools/esp_app_trace/logtrace_proc.py,
|
||||
tools/esp_app_trace/pylibelf/__init__.py,
|
||||
tools/esp_app_trace/pylibelf/constants/__init__.py,
|
||||
tools/esp_app_trace/pylibelf/iterators/__init__.py,
|
||||
tools/esp_app_trace/pylibelf/macros/__init__.py,
|
||||
tools/esp_app_trace/pylibelf/types/__init__.py,
|
||||
tools/esp_app_trace/pylibelf/util/__init__.py,
|
||||
tools/esp_app_trace/pylibelf/util/syms/__init__.py,
|
||||
tools/esp_prov/esp_prov.py,
|
||||
tools/esp_prov/proto/__init__.py,
|
||||
tools/esp_prov/prov/__init__.py,
|
||||
tools/esp_prov/prov/custom_prov.py,
|
||||
tools/esp_prov/prov/wifi_prov.py,
|
||||
tools/esp_prov/security/__init__.py,
|
||||
tools/esp_prov/security/security.py,
|
||||
tools/esp_prov/security/security0.py,
|
||||
tools/esp_prov/security/security1.py,
|
||||
tools/esp_prov/transport/__init__.py,
|
||||
tools/esp_prov/transport/ble_cli.py,
|
||||
tools/esp_prov/transport/transport.py,
|
||||
tools/esp_prov/transport/transport_ble.py,
|
||||
tools/esp_prov/transport/transport_console.py,
|
||||
tools/esp_prov/transport/transport_softap.py,
|
||||
tools/esp_prov/utils/__init__.py,
|
||||
tools/esp_prov/utils/convenience.py,
|
||||
tools/gen_esp_err_to_name.py,
|
||||
tools/idf.py,
|
||||
tools/idf_size.py,
|
||||
tools/kconfig_new/confgen.py,
|
||||
tools/kconfig_new/confserver.py,
|
||||
tools/kconfig_new/gen_kconfig_doc.py,
|
||||
tools/kconfig_new/kconfiglib.py,
|
||||
tools/kconfig_new/test/test_confserver.py,
|
||||
tools/ldgen/fragments.py,
|
||||
tools/ldgen/generation.py,
|
||||
tools/ldgen/ldgen.py,
|
||||
tools/ldgen/pyparsing.py,
|
||||
tools/ldgen/sdkconfig.py,
|
||||
tools/ldgen/test/test_fragments.py,
|
||||
tools/ldgen/test/test_generation.py,
|
||||
tools/mass_mfg/mfg_gen.py,
|
||||
tools/test_idf_monitor/run_test_idf_monitor.py,
|
||||
tools/test_idf_size/test_idf_size.py,
|
||||
tools/tiny-test-fw/CIAssignExampleTest.py,
|
||||
tools/tiny-test-fw/CIAssignUnitTest.py,
|
||||
tools/tiny-test-fw/DUT.py,
|
||||
tools/tiny-test-fw/EnvConfig.py,
|
||||
tools/tiny-test-fw/IDF/IDFApp.py,
|
||||
tools/tiny-test-fw/IDF/IDFDUT.py,
|
||||
tools/tiny-test-fw/Runner.py,
|
||||
tools/tiny-test-fw/TinyFW.py,
|
||||
tools/tiny-test-fw/Utility/CaseConfig.py,
|
||||
tools/tiny-test-fw/Utility/LineChart.py,
|
||||
tools/tiny-test-fw/Utility/PowerControl.py,
|
||||
tools/tiny-test-fw/Utility/SearchCases.py,
|
||||
tools/tiny-test-fw/Utility/__init__.py,
|
||||
tools/tiny-test-fw/docs/conf.py,
|
||||
tools/tiny-test-fw/example.py,
|
||||
tools/unit-test-app/idf_ext.py,
|
||||
tools/unit-test-app/tools/CreateSectionTable.py,
|
||||
tools/unit-test-app/tools/UnitTestParser.py,
|
||||
tools/unit-test-app/unit_test.py,
|
||||
tools/windows/eclipse_make.py,
|
6
.gitignore
vendored
6
.gitignore
vendored
@@ -68,3 +68,9 @@ test_multi_heap_host
|
||||
|
||||
# VS Code Settings
|
||||
.vscode/
|
||||
|
||||
# Results for the checking of the Python coding style
|
||||
flake8_output.txt
|
||||
|
||||
# ESP-IDF library
|
||||
build
|
||||
|
236
.gitlab-ci.yml
236
.gitlab-ci.yml
@@ -2,8 +2,7 @@ stages:
|
||||
- build
|
||||
- assign_test
|
||||
- host_test
|
||||
- unit_test
|
||||
- integration_test
|
||||
- target_test
|
||||
- check
|
||||
- deploy
|
||||
- post_check
|
||||
@@ -121,12 +120,15 @@ build_template_app:
|
||||
- $BOT_LABEL_BUILD
|
||||
- $BOT_LABEL_REGULAR_TEST
|
||||
script:
|
||||
- git clone https://github.com/espressif/esp-idf-template.git
|
||||
# Set the variable for 'esp-idf-template' testing
|
||||
- ESP_IDF_TEMPLATE_GIT=${ESP_IDF_TEMPLATE_GIT:-"https://github.com/espressif/esp-idf-template.git"}
|
||||
- git clone ${ESP_IDF_TEMPLATE_GIT}
|
||||
- cd esp-idf-template
|
||||
# Try to use the same branch name for esp-idf-template that we're
|
||||
# using on esp-idf. If it doesn't exist then just stick to the default
|
||||
# branch
|
||||
- python $CHECKOUT_REF_SCRIPT esp-idf-template
|
||||
- make defconfig
|
||||
# Test debug build (default)
|
||||
- make all V=1
|
||||
# Now test release build
|
||||
@@ -180,13 +182,13 @@ build_ssc_02:
|
||||
|
||||
# If you want to add new build ssc jobs, please add it into dependencies of `assign_test` and `.test_template`
|
||||
|
||||
build_esp_idf_tests:
|
||||
|
||||
.build_esp_idf_unit_test_template: &build_esp_idf_unit_test_template
|
||||
<<: *build_template
|
||||
artifacts:
|
||||
paths:
|
||||
- tools/unit-test-app/output
|
||||
- components/idf_test/unit_test/TestCaseAll.yml
|
||||
- components/idf_test/unit_test/CIConfigs/*.yml
|
||||
expire_in: 2 days
|
||||
only:
|
||||
variables:
|
||||
@@ -194,11 +196,30 @@ build_esp_idf_tests:
|
||||
- $BOT_LABEL_BUILD
|
||||
- $BOT_LABEL_UNIT_TEST
|
||||
- $BOT_LABEL_REGULAR_TEST
|
||||
|
||||
build_esp_idf_tests_make:
|
||||
<<: *build_esp_idf_unit_test_template
|
||||
script:
|
||||
- export PATH="$IDF_PATH/tools:$PATH"
|
||||
- cd $CI_PROJECT_DIR/tools/unit-test-app
|
||||
- export EXTRA_CFLAGS="-Werror -Werror=deprecated-declarations"
|
||||
- export EXTRA_CXXFLAGS=${EXTRA_CFLAGS}
|
||||
- cd $CI_PROJECT_DIR/tools/unit-test-app
|
||||
- MAKEFLAGS= make help # make sure kconfig tools are built in single process
|
||||
- make ut-clean-all-configs
|
||||
- make ut-build-all-configs
|
||||
- python tools/UnitTestParser.py
|
||||
- if [ "$UNIT_TEST_BUILD_SYSTEM" == "make" ]; then exit 0; fi
|
||||
# If Make, delete the CMake built artifacts
|
||||
- rm -rf builds output sdkconfig
|
||||
- rm -rf components/idf_test/unit_test/TestCaseAll.yml
|
||||
- rm -rf components/idf_test/unit_test/CIConfigs/*.yml
|
||||
|
||||
build_esp_idf_tests_cmake:
|
||||
<<: *build_esp_idf_unit_test_template
|
||||
script:
|
||||
- export PATH="$IDF_PATH/tools:$PATH"
|
||||
- export EXTRA_CFLAGS="-Werror -Werror=deprecated-declarations"
|
||||
- export EXTRA_CXXFLAGS=${EXTRA_CFLAGS}
|
||||
- cd $CI_PROJECT_DIR/tools/unit-test-app
|
||||
# Build with CMake first
|
||||
- idf.py ut-clean-all-configs
|
||||
- idf.py ut-build-all-configs
|
||||
@@ -209,12 +230,6 @@ build_esp_idf_tests:
|
||||
- rm -rf builds output sdkconfig
|
||||
- rm -rf components/idf_test/unit_test/TestCaseAll.yml
|
||||
- rm -rf components/idf_test/unit_test/CIConfigs/*.yml
|
||||
# Then build with Make
|
||||
- cd $CI_PROJECT_DIR/tools/unit-test-app
|
||||
- MAKEFLAGS= make help # make sure kconfig tools are built in single process
|
||||
- make ut-clean-all-configs
|
||||
- make ut-build-all-configs
|
||||
- python tools/UnitTestParser.py
|
||||
|
||||
.build_examples_make_template: &build_examples_make_template
|
||||
<<: *build_template
|
||||
@@ -370,9 +385,17 @@ build_docs:
|
||||
- make html
|
||||
- ../check_doc_warnings.sh
|
||||
|
||||
verify_cmake_style:
|
||||
stage: build
|
||||
.check_job_template: &check_job_template
|
||||
stage: check
|
||||
image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG
|
||||
tags:
|
||||
- host_test
|
||||
dependencies: []
|
||||
before_script: *do_nothing_before_no_filter
|
||||
|
||||
verify_cmake_style:
|
||||
<<: *check_job_template
|
||||
stage: build
|
||||
only:
|
||||
variables:
|
||||
- $BOT_TRIGGER_WITH_LABEL == null
|
||||
@@ -438,6 +461,13 @@ test_fatfs_on_host:
|
||||
- cd components/fatfs/test_fatfs_host/
|
||||
- make test
|
||||
|
||||
test_ldgen_on_host:
|
||||
<<: *host_test_template
|
||||
script:
|
||||
- cd tools/ldgen/test
|
||||
- ./test_fragments.py
|
||||
- ./test_generation.py
|
||||
|
||||
.host_fuzzer_test_template: &host_fuzzer_test_template
|
||||
stage: host_test
|
||||
image: $CI_DOCKER_REGISTRY/afl-fuzzer-test
|
||||
@@ -537,7 +567,7 @@ test_idf_monitor:
|
||||
expire_in: 1 week
|
||||
script:
|
||||
- cd ${IDF_PATH}/tools/test_idf_monitor
|
||||
- ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./run_test_idf_monitor.py
|
||||
- ./run_test_idf_monitor.py
|
||||
|
||||
test_idf_size:
|
||||
<<: *host_test_template
|
||||
@@ -561,9 +591,9 @@ test_esp_err_to_name_on_host:
|
||||
script:
|
||||
- cd ${IDF_PATH}/tools/
|
||||
- ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh -p 2.7.15 ./gen_esp_err_to_name.py
|
||||
- git diff --exit-code -- ../components/esp32/esp_err_to_name.c || (echo 'Differences found. Please run gen_esp_err_to_name.py and commit the changes.'; exit 1)
|
||||
- git diff --exit-code -- ../components/esp32/esp_err_to_name.c || { echo 'Differences found. Please run gen_esp_err_to_name.py and commit the changes.'; exit 1; }
|
||||
- ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh -p 3.4.8 ./gen_esp_err_to_name.py
|
||||
- git diff --exit-code -- ../components/esp32/esp_err_to_name.c || (echo 'Differences found between running under Python 2 and 3.'; exit 1)
|
||||
- git diff --exit-code -- ../components/esp32/esp_err_to_name.c || { echo 'Differences found between running under Python 2 and 3.'; exit 1; }
|
||||
|
||||
test_espcoredump:
|
||||
<<: *host_test_template
|
||||
@@ -663,14 +693,6 @@ check_doc_links:
|
||||
- cd docs
|
||||
- make linkcheck
|
||||
|
||||
.check_job_template: &check_job_template
|
||||
stage: check
|
||||
image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG
|
||||
tags:
|
||||
- build
|
||||
dependencies: []
|
||||
before_script: *do_nothing_before_no_filter
|
||||
|
||||
check_line_endings:
|
||||
<<: *check_job_template
|
||||
script:
|
||||
@@ -699,6 +721,18 @@ check_examples_cmake_make:
|
||||
script:
|
||||
- tools/ci/check_examples_cmake_make.sh
|
||||
|
||||
check_python_style:
|
||||
<<: *check_job_template
|
||||
artifacts:
|
||||
when: on_failure
|
||||
paths:
|
||||
- flake8_output.txt
|
||||
expire_in: 1 week
|
||||
before_script: *do_nothing_before
|
||||
script:
|
||||
# run it only under Python 3 (it is very slow under Python 2)
|
||||
- ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh -p 3.4.8 python -m flake8 --config=$IDF_PATH/.flake8 --output-file=flake8_output.txt --tee --benchmark $IDF_PATH
|
||||
|
||||
check_ut_cmake_make:
|
||||
stage: check
|
||||
image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG
|
||||
@@ -749,7 +783,8 @@ assign_test:
|
||||
- build_ssc_00
|
||||
- build_ssc_01
|
||||
- build_ssc_02
|
||||
- build_esp_idf_tests
|
||||
- build_esp_idf_tests_make
|
||||
- build_esp_idf_tests_cmake
|
||||
variables:
|
||||
TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw"
|
||||
EXAMPLE_CONFIG_OUTPUT_PATH: "$CI_PROJECT_DIR/examples/test_configs"
|
||||
@@ -779,7 +814,7 @@ assign_test:
|
||||
- python CIAssignTestCases.py -t $IDF_PATH/components/idf_test/integration_test -c $IDF_PATH/.gitlab-ci.yml -b $IDF_PATH/SSC/ssc_bin
|
||||
|
||||
.example_test_template: &example_test_template
|
||||
stage: integration_test
|
||||
stage: target_test
|
||||
when: on_success
|
||||
only:
|
||||
refs:
|
||||
@@ -814,6 +849,8 @@ assign_test:
|
||||
paths:
|
||||
- $LOG_PATH
|
||||
expire_in: 1 week
|
||||
reports:
|
||||
junit: $LOG_PATH/*/XUNIT_RESULT.xml
|
||||
variables:
|
||||
TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw"
|
||||
TEST_CASE_PATH: "$CI_PROJECT_DIR/examples"
|
||||
@@ -833,10 +870,11 @@ assign_test:
|
||||
|
||||
.unit_test_template: &unit_test_template
|
||||
<<: *example_test_template
|
||||
stage: unit_test
|
||||
stage: target_test
|
||||
dependencies:
|
||||
- assign_test
|
||||
- build_esp_idf_tests
|
||||
- build_esp_idf_tests_make
|
||||
- build_esp_idf_tests_cmake
|
||||
only:
|
||||
refs:
|
||||
- master
|
||||
@@ -855,7 +893,7 @@ assign_test:
|
||||
ENV_FILE: "$CI_PROJECT_DIR/ci-test-runner-configs/$CI_RUNNER_DESCRIPTION/EnvConfig.yml"
|
||||
|
||||
.test_template: &test_template
|
||||
stage: integration_test
|
||||
stage: target_test
|
||||
when: on_success
|
||||
only:
|
||||
refs:
|
||||
@@ -970,6 +1008,12 @@ example_test_006_01:
|
||||
- ESP32
|
||||
- Example_ShieldBox
|
||||
|
||||
example_test_007_01:
|
||||
<<: *example_test_template
|
||||
tags:
|
||||
- ESP32
|
||||
- Example_I2C_CCS811_SENSOR
|
||||
|
||||
UT_001_01:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
@@ -1210,6 +1254,18 @@ UT_001_40:
|
||||
- ESP32_IDF
|
||||
- UT_T1_1
|
||||
|
||||
UT_001_41:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_1
|
||||
|
||||
UT_001_42:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_1
|
||||
|
||||
UT_002_01:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
@@ -1314,7 +1370,7 @@ UT_004_10:
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_1
|
||||
- psram
|
||||
- psram
|
||||
|
||||
UT_004_11:
|
||||
<<: *unit_test_template
|
||||
@@ -1336,7 +1392,28 @@ UT_004_13:
|
||||
- ESP32_IDF
|
||||
- UT_T1_1
|
||||
- psram
|
||||
|
||||
|
||||
UT_004_14:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_1
|
||||
- psram
|
||||
|
||||
UT_004_15:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_1
|
||||
- psram
|
||||
|
||||
UT_004_14:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_1
|
||||
- psram
|
||||
|
||||
UT_005_01:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
@@ -1432,7 +1509,7 @@ UT_008_04:
|
||||
- ESP32_IDF
|
||||
- UT_T1_LEDC
|
||||
- psram
|
||||
|
||||
|
||||
UT_009_01:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
@@ -1444,7 +1521,7 @@ UT_009_02:
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T2_RS485
|
||||
|
||||
|
||||
UT_009_03:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
@@ -1522,6 +1599,95 @@ UT_012_03:
|
||||
- UT_T1_1
|
||||
- 8Mpsram
|
||||
|
||||
UT_012_04:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_1
|
||||
- 8Mpsram
|
||||
|
||||
UT_012_05:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_1
|
||||
- 8Mpsram
|
||||
|
||||
UT_014_01:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T2_I2C
|
||||
|
||||
UT_014_02:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T2_I2C
|
||||
|
||||
UT_014_03:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T2_I2C
|
||||
|
||||
UT_014_04:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T2_I2C
|
||||
- psram
|
||||
|
||||
UT_015_01:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_MCPWM
|
||||
|
||||
UT_015_02:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_MCPWM
|
||||
|
||||
UT_015_03:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_MCPWM
|
||||
|
||||
UT_015_04:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_MCPWM
|
||||
- psram
|
||||
|
||||
UT_016_01:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_I2S
|
||||
|
||||
UT_016_02:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_I2S
|
||||
|
||||
UT_016_03:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_I2S
|
||||
|
||||
UT_016_04:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_I2S
|
||||
- psram
|
||||
|
||||
UT_601_01:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
|
8
.gitmodules
vendored
8
.gitmodules
vendored
@@ -61,3 +61,11 @@
|
||||
[submodule "components/protobuf-c/protobuf-c"]
|
||||
path = components/protobuf-c/protobuf-c
|
||||
url = https://github.com/protobuf-c/protobuf-c
|
||||
|
||||
[submodule "components/unity/unity"]
|
||||
path = components/unity/unity
|
||||
url = https://github.com/ThrowTheSwitch/Unity
|
||||
|
||||
[submodule "examples/build_system/cmake/import_lib/main/lib/tinyxml2"]
|
||||
path = examples/build_system/cmake/import_lib/main/lib/tinyxml2
|
||||
url = https://github.com/leethomason/tinyxml2
|
||||
|
7
.travis.yml
Normal file
7
.travis.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
language: python
|
||||
sudo: false
|
||||
python:
|
||||
- "3.4"
|
||||
script:
|
||||
- pip install flake8
|
||||
- travis_wait 20 python -m flake8 --config=.flake8 .
|
153
CMakeLists.txt
Normal file
153
CMakeLists.txt
Normal file
@@ -0,0 +1,153 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(esp-idf C CXX ASM)
|
||||
|
||||
if(NOT IDF_PATH)
|
||||
set(IDF_PATH ${CMAKE_CURRENT_LIST_DIR})
|
||||
endif()
|
||||
|
||||
include(tools/cmake/idf_functions.cmake)
|
||||
|
||||
#
|
||||
# Set variables that control the build configuration and the build itself
|
||||
#
|
||||
idf_set_variables()
|
||||
|
||||
kconfig_set_variables()
|
||||
|
||||
#
|
||||
# Generate a component dependencies file, enumerating components to be included in the build
|
||||
# as well as their dependencies.
|
||||
#
|
||||
execute_process(COMMAND "${CMAKE_COMMAND}"
|
||||
-D "COMPONENTS=${IDF_COMPONENTS}"
|
||||
-D "COMPONENT_REQUIRES_COMMON=${IDF_COMPONENT_REQUIRES_COMMON}"
|
||||
-D "EXCLUDE_COMPONENTS=${IDF_EXCLUDE_COMPONENTS}"
|
||||
-D "TEST_COMPONENTS=${IDF_TEST_COMPONENTS}"
|
||||
-D "TEST_EXCLUDE_COMPONENTS=${IDF_TEST_EXCLUDE_COMPONENTS}"
|
||||
-D "BUILD_TESTS=${IDF_BUILD_TESTS}"
|
||||
-D "DEPENDENCIES_FILE=${CMAKE_BINARY_DIR}/component_depends.cmake"
|
||||
-D "COMPONENT_DIRS=${IDF_COMPONENT_DIRS}"
|
||||
-D "BOOTLOADER_BUILD=${BOOTLOADER_BUILD}"
|
||||
-D "IDF_TARGET=${IDF_TARGET}"
|
||||
-D "IDF_PATH=${IDF_PATH}"
|
||||
-D "DEBUG=${DEBUG}"
|
||||
-P "${IDF_PATH}/tools/cmake/scripts/expand_requirements.cmake"
|
||||
WORKING_DIRECTORY "${PROJECT_PATH}")
|
||||
include("${CMAKE_BINARY_DIR}/component_depends.cmake")
|
||||
|
||||
#
|
||||
# We now have the following component-related variables:
|
||||
#
|
||||
# IDF_COMPONENTS is the list of initial components set by the user
|
||||
# (or empty to include all components in the build).
|
||||
# BUILD_COMPONENTS is the list of components to include in the build.
|
||||
# BUILD_COMPONENT_PATHS is the paths to all of these components, obtained from the component dependencies file.
|
||||
#
|
||||
# Print the list of found components and test components
|
||||
#
|
||||
string(REPLACE ";" " " BUILD_COMPONENTS_SPACES "${BUILD_COMPONENTS}")
|
||||
message(STATUS "Component names: ${BUILD_COMPONENTS_SPACES}")
|
||||
unset(BUILD_COMPONENTS_SPACES)
|
||||
message(STATUS "Component paths: ${BUILD_COMPONENT_PATHS}")
|
||||
|
||||
# Print list of test components
|
||||
if(TESTS_ALL EQUAL 1 OR TEST_COMPONENTS)
|
||||
string(REPLACE ";" " " BUILD_TEST_COMPONENTS_SPACES "${BUILD_TEST_COMPONENTS}")
|
||||
message(STATUS "Test component names: ${BUILD_TEST_COMPONENTS_SPACES}")
|
||||
unset(BUILD_TEST_COMPONENTS_SPACES)
|
||||
message(STATUS "Test component paths: ${BUILD_TEST_COMPONENT_PATHS}")
|
||||
endif()
|
||||
|
||||
# Generate project configuration
|
||||
kconfig_process_config()
|
||||
|
||||
# Include sdkconfig.cmake so rest of the build knows the configuration
|
||||
include(${SDKCONFIG_CMAKE})
|
||||
|
||||
# Verify the environment is configured correctly
|
||||
idf_verify_environment()
|
||||
|
||||
# Check git revision (may trigger reruns of cmake)
|
||||
## sets IDF_VER to IDF git revision
|
||||
idf_get_git_revision()
|
||||
|
||||
# Check that the targets set in cache, sdkconfig, and in environment all match
|
||||
idf_check_config_target()
|
||||
|
||||
## get PROJECT_VER
|
||||
app_get_revision("${CMAKE_SOURCE_DIR}")
|
||||
|
||||
# Add some idf-wide definitions
|
||||
idf_set_global_compile_options()
|
||||
|
||||
# generate compile_commands.json (needs to come after project)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
|
||||
|
||||
#
|
||||
# Setup variables for linker script generation
|
||||
#
|
||||
ldgen_set_variables()
|
||||
|
||||
# Include any top-level project_include.cmake files from components
|
||||
foreach(component ${BUILD_COMPONENT_PATHS})
|
||||
set(COMPONENT_PATH "${component}")
|
||||
include_if_exists("${component}/project_include.cmake")
|
||||
unset(COMPONENT_PATH)
|
||||
endforeach()
|
||||
|
||||
#
|
||||
# Add each component to the build as a library
|
||||
#
|
||||
foreach(COMPONENT_PATH ${BUILD_COMPONENT_PATHS})
|
||||
get_filename_component(COMPONENT_NAME ${COMPONENT_PATH} NAME)
|
||||
|
||||
list(FIND BUILD_TEST_COMPONENT_PATHS ${COMPONENT_PATH} idx)
|
||||
|
||||
if(NOT idx EQUAL -1)
|
||||
list(GET BUILD_TEST_COMPONENTS ${idx} test_component)
|
||||
set(COMPONENT_NAME ${test_component})
|
||||
endif()
|
||||
|
||||
component_get_target(COMPONENT_TARGET ${COMPONENT_NAME})
|
||||
|
||||
add_subdirectory(${COMPONENT_PATH} ${COMPONENT_NAME})
|
||||
endforeach()
|
||||
unset(COMPONENT_NAME)
|
||||
unset(COMPONENT_PATH)
|
||||
|
||||
# each component should see the include directories of its requirements
|
||||
#
|
||||
# (we can't do this until all components are registered and targets exist in cmake, as we have
|
||||
# a circular requirements graph...)
|
||||
foreach(component ${BUILD_COMPONENTS})
|
||||
component_get_target(component_target ${component})
|
||||
if(TARGET ${component_target})
|
||||
get_component_requirements(${component} deps priv_deps)
|
||||
|
||||
list(APPEND priv_deps ${IDF_COMPONENT_REQUIRES_COMMON})
|
||||
|
||||
foreach(dep ${deps})
|
||||
component_get_target(dep_target ${dep})
|
||||
add_component_dependencies(${component_target} ${dep_target} PUBLIC)
|
||||
endforeach()
|
||||
|
||||
foreach(dep ${priv_deps})
|
||||
component_get_target(dep_target ${dep})
|
||||
add_component_dependencies(${component_target} ${dep_target} PRIVATE)
|
||||
endforeach()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(IDF_BUILD_ARTIFACTS)
|
||||
# Write project description JSON file
|
||||
make_json_list("${BUILD_COMPONENTS}" build_components_json)
|
||||
make_json_list("${BUILD_COMPONENT_PATHS}" build_component_paths_json)
|
||||
configure_file("${IDF_PATH}/tools/cmake/project_description.json.in"
|
||||
"${IDF_BUILD_ARTIFACTS_DIR}/project_description.json")
|
||||
unset(build_components_json)
|
||||
unset(build_component_paths_json)
|
||||
endif()
|
||||
|
||||
set(BUILD_COMPONENTS ${BUILD_COMPONENTS} PARENT_SCOPE)
|
||||
|
||||
ldgen_add_dependencies()
|
16
Kconfig
16
Kconfig
@@ -8,6 +8,22 @@ config IDF_CMAKE
|
||||
bool
|
||||
option env="IDF_CMAKE"
|
||||
|
||||
|
||||
# A proxy to get environment variable $IDF_TARGET
|
||||
config IDF_TARGET_ENV
|
||||
string
|
||||
option env="IDF_TARGET"
|
||||
|
||||
# This option records the IDF target when sdkconfig is generated the first time.
|
||||
# It is not updated if environment variable $IDF_TARGET changes later, and
|
||||
# the build system is responsible for detecting the mismatch between
|
||||
# CONFIG_IDF_TARGET and $IDF_TARGET.
|
||||
config IDF_TARGET
|
||||
string
|
||||
default "IDF_TARGET_NOT_SET" if IDF_TARGET_ENV=""
|
||||
default IDF_TARGET_ENV
|
||||
|
||||
|
||||
menu "SDK tool configuration"
|
||||
config TOOLPREFIX
|
||||
string "Compiler toolchain path/prefix"
|
||||
|
@@ -9,6 +9,7 @@
|
||||
if [ -z ${IDF_PATH} ]; then
|
||||
echo "IDF_PATH must be set before including this script."
|
||||
else
|
||||
IDF_ADD_PATHS_EXTRAS=
|
||||
IDF_ADD_PATHS_EXTRAS="${IDF_ADD_PATHS_EXTRAS}:${IDF_PATH}/components/esptool_py/esptool"
|
||||
IDF_ADD_PATHS_EXTRAS="${IDF_ADD_PATHS_EXTRAS}:${IDF_PATH}/components/espcoredump"
|
||||
IDF_ADD_PATHS_EXTRAS="${IDF_ADD_PATHS_EXTRAS}:${IDF_PATH}/components/partition_table/"
|
||||
|
@@ -18,6 +18,7 @@ endif()
|
||||
|
||||
set(COMPONENT_REQUIRES)
|
||||
set(COMPONENT_PRIV_REQUIRES xtensa-debug-module)
|
||||
set(COMPONENT_ADD_LDFRAGMENTS linker.lf)
|
||||
|
||||
register_component()
|
||||
|
||||
@@ -25,4 +26,4 @@ register_component()
|
||||
# for gcov
|
||||
component_compile_options("-fno-profile-arcs" "-fno-test-coverage")
|
||||
|
||||
target_link_libraries(app_trace gcov)
|
||||
target_link_libraries(${COMPONENT_TARGET} gcov)
|
||||
|
@@ -172,7 +172,6 @@
|
||||
|
||||
#define ESP_APPTRACE_PRINT_LOCK 0
|
||||
|
||||
#define LOG_LOCAL_LEVEL CONFIG_LOG_DEFAULT_LEVEL
|
||||
#include "esp_log.h"
|
||||
const static char *TAG = "esp_apptrace";
|
||||
|
||||
|
@@ -27,3 +27,5 @@ COMPONENT_SRCDIRS += \
|
||||
else
|
||||
COMPONENT_SRCDIRS += gcov
|
||||
endif
|
||||
|
||||
COMPONENT_ADD_LDFRAGMENTS += linker.lf
|
||||
|
12
components/app_trace/linker.lf
Normal file
12
components/app_trace/linker.lf
Normal file
@@ -0,0 +1,12 @@
|
||||
[mapping]
|
||||
archive: libapp_trace.a
|
||||
entries:
|
||||
* (noflash)
|
||||
|
||||
[mapping]
|
||||
archive: libdriver.a
|
||||
entries:
|
||||
: SYSVIEW_TS_SOURCE_TIMER_00 = y || SYSVIEW_TS_SOURCE_TIMER_01 = y
|
||||
|| SYSVIEW_TS_SOURCE_TIMER_10 = y || SYSVIEW_TS_SOURCE_TIMER_11 = y
|
||||
timer (noflash)
|
||||
|
@@ -166,10 +166,11 @@ Revision: $Rev: 5927 $
|
||||
#define SEGGER_SYSVIEW_GET_INTERRUPT_ID() SEGGER_SYSVIEW_X_GetInterruptId() // Get the currently active interrupt Id from the user-provided function.
|
||||
#endif
|
||||
|
||||
void SEGGER_SYSVIEW_X_SysView_Lock();
|
||||
void SEGGER_SYSVIEW_X_SysView_Unlock();
|
||||
#define SEGGER_SYSVIEW_LOCK() SEGGER_SYSVIEW_X_SysView_Lock()
|
||||
#define SEGGER_SYSVIEW_UNLOCK() SEGGER_SYSVIEW_X_SysView_Unlock()
|
||||
unsigned SEGGER_SYSVIEW_X_SysView_Lock();
|
||||
void SEGGER_SYSVIEW_X_SysView_Unlock(unsigned int_state);
|
||||
// to be recursive save IRQ status on the stack of the caller
|
||||
#define SEGGER_SYSVIEW_LOCK() unsigned _SYSVIEW_int_state = SEGGER_SYSVIEW_X_SysView_Lock()
|
||||
#define SEGGER_SYSVIEW_UNLOCK() SEGGER_SYSVIEW_X_SysView_Unlock(_SYSVIEW_int_state)
|
||||
|
||||
#endif // SEGGER_SYSVIEW_CONF_H
|
||||
|
||||
|
@@ -2368,7 +2368,7 @@ void SEGGER_SYSVIEW_RegisterModule(SEGGER_SYSVIEW_MODULE* pModule) {
|
||||
_pFirstModule = pModule;
|
||||
_NumModules++;
|
||||
}
|
||||
SEGGER_SYSVIEW_SendModule(0);
|
||||
SEGGER_SYSVIEW_SendModule(_NumModules-1);
|
||||
if (pModule->pfSendModuleDesc) {
|
||||
pModule->pfSendModuleDesc();
|
||||
}
|
||||
|
@@ -337,15 +337,18 @@ void SEGGER_SYSVIEW_X_RTT_Unlock()
|
||||
{
|
||||
}
|
||||
|
||||
void SEGGER_SYSVIEW_X_SysView_Lock()
|
||||
unsigned SEGGER_SYSVIEW_X_SysView_Lock()
|
||||
{
|
||||
esp_apptrace_tmo_t tmo;
|
||||
esp_apptrace_tmo_init(&tmo, SEGGER_LOCK_WAIT_TMO);
|
||||
esp_apptrace_lock_take(&s_sys_view_lock, &tmo);
|
||||
// to be recursive save IRQ status on the stack of the caller to keep it from overwriting
|
||||
return s_sys_view_lock.int_state;
|
||||
}
|
||||
|
||||
void SEGGER_SYSVIEW_X_SysView_Unlock()
|
||||
void SEGGER_SYSVIEW_X_SysView_Unlock(unsigned int_state)
|
||||
{
|
||||
s_sys_view_lock.int_state = int_state;
|
||||
esp_apptrace_lock_give(&s_sys_view_lock);
|
||||
}
|
||||
|
||||
|
@@ -1,17 +1,36 @@
|
||||
set(COMPONENT_SRCS "esp_ota_ops.c")
|
||||
set(COMPONENT_SRCS "esp_ota_ops.c"
|
||||
"esp_app_desc.c")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "include")
|
||||
|
||||
set(COMPONENT_REQUIRES spi_flash partition_table)
|
||||
set(COMPONENT_PRIV_REQUIRES bootloader_support)
|
||||
set(COMPONENT_REQUIRES spi_flash partition_table bootloader_support)
|
||||
|
||||
register_component()
|
||||
|
||||
# Add custom target for generating empty otadata partition for flashing
|
||||
if(${OTADATA_PARTITION_OFFSET})
|
||||
add_custom_command(OUTPUT "${PROJECT_BINARY_DIR}/${BLANK_OTADATA_FILE}"
|
||||
COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/gen_empty_partition.py
|
||||
--size ${OTADATA_PARTITION_SIZE} "${PROJECT_BINARY_DIR}/${BLANK_OTADATA_FILE}")
|
||||
# esp_app_desc structure is added as an undefined symbol because otherwise the
|
||||
# linker will ignore this structure as it has no other files depending on it.
|
||||
target_link_libraries(${COMPONENT_TARGET} "-u esp_app_desc")
|
||||
|
||||
add_custom_target(blank_ota_data ALL DEPENDS "${PROJECT_BINARY_DIR}/${BLANK_OTADATA_FILE}")
|
||||
set_source_files_properties(
|
||||
SOURCE "esp_app_desc.c"
|
||||
PROPERTIES COMPILE_DEFINITIONS
|
||||
PROJECT_VER=\"${PROJECT_VER}\")
|
||||
|
||||
# Add custom target for generating empty otadata partition for flashing
|
||||
if(OTADATA_PARTITION_OFFSET AND OTADATA_PARTITION_SIZE)
|
||||
add_custom_command(OUTPUT "${IDF_BUILD_ARTIFACTS_DIR}/${BLANK_OTADATA_FILE}"
|
||||
COMMAND ${PYTHON} ${IDF_PATH}/components/partition_table/parttool.py
|
||||
--partition-type data --partition-subtype ota -q
|
||||
--partition-table-file ${PARTITION_CSV_PATH} generate_blank_partition_file
|
||||
--output "${IDF_BUILD_ARTIFACTS_DIR}/${BLANK_OTADATA_FILE}")
|
||||
|
||||
add_custom_target(blank_ota_data ALL DEPENDS "${IDF_BUILD_ARTIFACTS_DIR}/${BLANK_OTADATA_FILE}")
|
||||
add_dependencies(flash blank_ota_data)
|
||||
endif()
|
||||
|
||||
set(otatool_py ${PYTHON} ${COMPONENT_PATH}/otatool.py)
|
||||
|
||||
add_custom_target(read_otadata DEPENDS "${PARTITION_CSV_PATH}"
|
||||
COMMAND ${otatool_py} --partition-table-file ${PARTITION_CSV_PATH} read_otadata)
|
||||
|
||||
add_custom_target(erase_otadata DEPENDS "${PARTITION_CSV_PATH}"
|
||||
COMMAND ${otatool_py} --partition-table-file ${PARTITION_CSV_PATH} erase_otadata)
|
||||
|
12
components/app_update/Kconfig.projbuild
Normal file
12
components/app_update/Kconfig.projbuild
Normal file
@@ -0,0 +1,12 @@
|
||||
menu "Application manager"
|
||||
|
||||
config APP_COMPILE_TIME_DATE
|
||||
bool "Use time/date stamp for app"
|
||||
default y
|
||||
help
|
||||
If set, then the app will be built with the current time/date stamp. It is stored in the app description structure.
|
||||
If not set, time/date stamp will be excluded from app image.
|
||||
This can be useful for getting the same binary image files made from the same source,
|
||||
but at different times.
|
||||
|
||||
endmenu # "Application manager"
|
@@ -1,60 +1,42 @@
|
||||
# Generate partition binary
|
||||
#
|
||||
.PHONY: dump_otadata erase_ota blank_ota_data
|
||||
.PHONY: blank_ota_data erase_otadata read_otadata
|
||||
|
||||
GEN_EMPTY_PART := $(PYTHON) $(COMPONENT_PATH)/gen_empty_partition.py
|
||||
OTATOOL_PY := $(PYTHON) $(COMPONENT_PATH)/otatool.py
|
||||
PARTTOOL_PY := $(PYTHON) $(IDF_PATH)/components/partition_table/parttool.py
|
||||
|
||||
# Generate blank partition file
|
||||
BLANK_OTA_DATA_FILE = $(BUILD_DIR_BASE)/ota_data_initial.bin
|
||||
|
||||
PARTITION_TABLE_LEN := 0xC00
|
||||
OTADATA_LEN := 0x2000
|
||||
$(BLANK_OTA_DATA_FILE): partition_table_get_info $(PARTITION_TABLE_BIN) | check_python_dependencies
|
||||
$(shell if [ "$(OTA_DATA_OFFSET)" != "" ] && [ "$(OTA_DATA_SIZE)" != "" ]; then \
|
||||
$(PARTTOOL_PY) --partition-type data --partition-subtype ota --partition-table-file $(PARTITION_TABLE_BIN) \
|
||||
-q generate_blank_partition_file --output $(BLANK_OTA_DATA_FILE); \
|
||||
fi; )
|
||||
$(eval BLANK_OTA_DATA_FILE = $(shell if [ "$(OTA_DATA_OFFSET)" != "" ] && [ "$(OTA_DATA_SIZE)" != "" ]; then \
|
||||
echo $(BLANK_OTA_DATA_FILE); else echo " "; fi) )
|
||||
|
||||
PARTITION_TABLE_ONCHIP_BIN_PATH := $(call dequote,$(abspath $(BUILD_DIR_BASE)))
|
||||
PARTITION_TABLE_ONCHIP_BIN_NAME := "onchip_partition.bin"
|
||||
OTADATA_ONCHIP_BIN_NAME := "onchip_otadata.bin"
|
||||
|
||||
PARTITION_TABLE_ONCHIP_BIN := $(PARTITION_TABLE_ONCHIP_BIN_PATH)/$(call dequote,$(PARTITION_TABLE_ONCHIP_BIN_NAME))
|
||||
OTADATA_ONCHIP_BIN := $(PARTITION_TABLE_ONCHIP_BIN_PATH)/$(call dequote,$(OTADATA_ONCHIP_BIN_NAME))
|
||||
|
||||
PARTITION_TABLE_GET_BIN_CMD = $(ESPTOOLPY_SERIAL) read_flash $(PARTITION_TABLE_OFFSET) $(PARTITION_TABLE_LEN) $(PARTITION_TABLE_ONCHIP_BIN)
|
||||
OTADATA_GET_BIN_CMD = $(ESPTOOLPY_SERIAL) read_flash $(OTADATA_OFFSET) $(OTADATA_LEN) $(OTADATA_ONCHIP_BIN)
|
||||
|
||||
GEN_OTADATA = $(IDF_PATH)/components/app_update/dump_otadata.py
|
||||
ERASE_OTADATA_CMD = $(ESPTOOLPY_SERIAL) erase_region $(OTADATA_OFFSET) $(OTADATA_LEN)
|
||||
blank_ota_data: $(BLANK_OTA_DATA_FILE)
|
||||
|
||||
# If there is no otadata partition, both OTA_DATA_OFFSET and BLANK_OTA_DATA_FILE
|
||||
# expand to empty values.
|
||||
ESPTOOL_ALL_FLASH_ARGS += $(OTA_DATA_OFFSET) $(BLANK_OTA_DATA_FILE)
|
||||
|
||||
$(PARTITION_TABLE_ONCHIP_BIN):
|
||||
$(PARTITION_TABLE_GET_BIN_CMD)
|
||||
erase_otadata: $(PARTITION_TABLE_BIN) partition_table_get_info | check_python_dependencies
|
||||
$(OTATOOL_PY) --partition-table-file $(PARTITION_TABLE_BIN) erase_otadata
|
||||
|
||||
onchip_otadata_get_info: $(PARTITION_TABLE_ONCHIP_BIN)
|
||||
$(eval OTADATA_OFFSET:=$(shell $(GET_PART_INFO) --type data --subtype ota --offset $(PARTITION_TABLE_ONCHIP_BIN)))
|
||||
@echo $(if $(OTADATA_OFFSET), $(shell export OTADATA_OFFSET), $(shell rm -f $(PARTITION_TABLE_ONCHIP_BIN));$(error "ERROR: ESP32 does not have otadata partition."))
|
||||
read_otadata: $(PARTITION_TABLE_BIN) partition_table_get_info | check_python_dependencies
|
||||
$(OTATOOL_PY) --partition-table-file $(PARTITION_TABLE_BIN) read_otadata
|
||||
|
||||
$(OTADATA_ONCHIP_BIN):
|
||||
$(OTADATA_GET_BIN_CMD)
|
||||
|
||||
dump_otadata: onchip_otadata_get_info $(OTADATA_ONCHIP_BIN) $(PARTITION_TABLE_ONCHIP_BIN)
|
||||
@echo "otadata retrieved. Contents:"
|
||||
@echo $(SEPARATOR)
|
||||
$(GEN_OTADATA) $(OTADATA_ONCHIP_BIN)
|
||||
@echo $(SEPARATOR)
|
||||
rm -f $(PARTITION_TABLE_ONCHIP_BIN)
|
||||
rm -f $(OTADATA_ONCHIP_BIN)
|
||||
|
||||
$(BLANK_OTA_DATA_FILE): partition_table_get_info
|
||||
$(GEN_EMPTY_PART) --size $(OTA_DATA_SIZE) $(BLANK_OTA_DATA_FILE)
|
||||
$(eval BLANK_OTA_DATA_FILE = $(shell if [ $(OTA_DATA_SIZE) != 0 ]; then echo $(BLANK_OTA_DATA_FILE); else echo " "; fi) )
|
||||
|
||||
blank_ota_data: $(BLANK_OTA_DATA_FILE)
|
||||
|
||||
erase_ota: partition_table_get_info | check_python_dependencies
|
||||
@echo $(if $(OTA_DATA_OFFSET), "Erase ota_data [addr=$(OTA_DATA_OFFSET) size=$(OTA_DATA_SIZE)] ...", $(error "ERROR: Partition table does not have ota_data partition."))
|
||||
$(ESPTOOLPY_SERIAL) erase_region $(OTA_DATA_OFFSET) $(OTA_DATA_SIZE)
|
||||
erase_ota: erase_otadata
|
||||
@echo "WARNING: erase_ota is deprecated. Use erase_otadata instead."
|
||||
|
||||
all: blank_ota_data
|
||||
flash: blank_ota_data
|
||||
|
||||
TMP_DEFINES := $(BUILD_DIR_BASE)/app_update/tmp_cppflags.txt
|
||||
export TMP_DEFINES
|
||||
|
||||
clean:
|
||||
rm -f $(BLANK_OTA_DATA_FILE)
|
||||
rm -f $(TMP_DEFINES)
|
||||
|
@@ -3,3 +3,47 @@
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
|
||||
# esp_app_desc structure is added as an undefined symbol because otherwise the
|
||||
# linker will ignore this structure as it has no other files depending on it.
|
||||
COMPONENT_ADD_LDFLAGS += -u esp_app_desc
|
||||
|
||||
ifndef IS_BOOTLOADER_BUILD
|
||||
GET_PROJECT_VER ?=
|
||||
ifeq ("${PROJECT_VER}", "")
|
||||
ifeq ("$(wildcard ${PROJECT_PATH}/version.txt)","")
|
||||
GET_PROJECT_VER := $(shell cd ${PROJECT_PATH} && git describe --always --tags --dirty || echo "Not found git repo")
|
||||
ifeq ("${GET_PROJECT_VER}", "Not found git repo")
|
||||
$(info Project do not have git repo, it needs to get PROJECT_VER from `git describe` command.)
|
||||
GET_PROJECT_VER := ""
|
||||
endif
|
||||
else
|
||||
# read from version.txt
|
||||
GET_PROJECT_VER := $(shell cat ${PROJECT_PATH}/version.txt)
|
||||
endif
|
||||
endif
|
||||
# If ``PROJECT_VER`` variable set in project Makefile file, its value will be used.
|
||||
# Else, if the ``$PROJECT_PATH/version.txt`` exists, its contents will be used as ``PROJECT_VER``.
|
||||
# Else, if the project is located inside a Git repository, the output of git describe will be used.
|
||||
# Otherwise, ``PROJECT_VER`` will be empty.
|
||||
|
||||
ifeq ("${PROJECT_VER}", "")
|
||||
PROJECT_VER:= $(GET_PROJECT_VER)
|
||||
else
|
||||
PROJECT_VER:= $(PROJECT_VER)
|
||||
endif
|
||||
$(info App "$(PROJECT_NAME)" version: $(PROJECT_VER))
|
||||
|
||||
NEW_DEFINES:= $(PROJECT_VER) $(PROJECT_NAME) $(IDF_VER)
|
||||
ifeq ("$(wildcard ${TMP_DEFINES})","")
|
||||
OLD_DEFINES:=
|
||||
else
|
||||
OLD_DEFINES:= $(shell cat $(TMP_DEFINES))
|
||||
endif
|
||||
|
||||
# If NEW_DEFINES (PROJECT_VER, PROJECT_NAME) were changed then rebuild only esp_app_desc.
|
||||
ifneq ("${NEW_DEFINES}", "${OLD_DEFINES}")
|
||||
$(shell echo $(NEW_DEFINES) > $(TMP_DEFINES); rm -f esp_app_desc.o;)
|
||||
endif
|
||||
|
||||
esp_app_desc.o: CPPFLAGS += -D PROJECT_VER=\"$(PROJECT_VER)\" -D PROJECT_NAME=\"$(PROJECT_NAME)\"
|
||||
endif
|
||||
|
@@ -1,88 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# gen_otadata prints info about the otadata partition.
|
||||
#
|
||||
# Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http:#www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from __future__ import print_function, division
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import struct
|
||||
import sys
|
||||
import hashlib
|
||||
import binascii
|
||||
|
||||
__version__ = '1.0'
|
||||
|
||||
quiet = False
|
||||
|
||||
def status(msg):
|
||||
""" Print status message to stderr """
|
||||
if not quiet:
|
||||
critical(msg)
|
||||
|
||||
def critical(msg):
|
||||
""" Print critical message to stderr """
|
||||
if not quiet:
|
||||
sys.stderr.write(msg)
|
||||
sys.stderr.write('\n')
|
||||
|
||||
def little_endian(buff, offset):
|
||||
data = buff[offset:offset+4]
|
||||
data.reverse()
|
||||
data = ''.join(data)
|
||||
return data
|
||||
|
||||
def main():
|
||||
global quiet
|
||||
parser = argparse.ArgumentParser(description='Prints otadata partition in human readable form.')
|
||||
|
||||
parser.add_argument('--quiet', '-q', help="Don't print status messages to stderr", action='store_true')
|
||||
|
||||
search_type = parser.add_mutually_exclusive_group()
|
||||
|
||||
parser.add_argument('input', help='Path to binary file containing otadata partition to parse.',
|
||||
type=argparse.FileType('rb'))
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
quiet = args.quiet
|
||||
|
||||
input = args.input.read()
|
||||
|
||||
hex_input_0 = binascii.hexlify(input)
|
||||
hex_input_0 = map(''.join, zip(*[iter(hex_input_0)]*2))
|
||||
hex_input_1 = binascii.hexlify(input[4096:])
|
||||
hex_input_1 = map(''.join, zip(*[iter(hex_input_1)]*2))
|
||||
|
||||
print("\t%11s\t%8s |\t%8s\t%8s" %("OTA_SEQ", "CRC", "OTA_SEQ", "CRC"))
|
||||
print("Firmware: 0x%s \t 0x%s |\t0x%s \t 0x%s" % (little_endian(hex_input_0, 0), little_endian(hex_input_0, 28), \
|
||||
little_endian(hex_input_1, 0), little_endian(hex_input_1, 28)))
|
||||
class InputError(RuntimeError):
|
||||
def __init__(self, e):
|
||||
super(InputError, self).__init__(e)
|
||||
|
||||
class ValidationError(InputError):
|
||||
def __init__(self, partition, message):
|
||||
super(ValidationError, self).__init__(
|
||||
"Partition %s invalid: %s" % (partition.name, message))
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
r = main()
|
||||
sys.exit(r)
|
||||
except InputError as e:
|
||||
print(e, file=sys.stderr)
|
||||
sys.exit(2)
|
49
components/app_update/esp_app_desc.c
Normal file
49
components/app_update/esp_app_desc.c
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <assert.h>
|
||||
#include "esp_ota_ops.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
// Application version info
|
||||
const __attribute__((section(".rodata_desc"))) esp_app_desc_t esp_app_desc = {
|
||||
.magic_word = ESP_APP_DESC_MAGIC_WORD,
|
||||
.version = PROJECT_VER,
|
||||
.project_name = PROJECT_NAME,
|
||||
.idf_ver = IDF_VER,
|
||||
|
||||
#ifdef CONFIG_APP_SECURE_VERSION
|
||||
.secure_version = CONFIG_APP_SECURE_VERSION,
|
||||
#else
|
||||
.secure_version = 0,
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_APP_COMPILE_TIME_DATE
|
||||
.time = __TIME__,
|
||||
.date = __DATE__,
|
||||
#else
|
||||
.time = "",
|
||||
.date = "",
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
_Static_assert(sizeof(PROJECT_VER) <= sizeof(esp_app_desc.version), "PROJECT_VER is longer than version field in structure");
|
||||
_Static_assert(sizeof(IDF_VER) <= sizeof(esp_app_desc.idf_ver), "IDF_VER is longer than idf_ver field in structure");
|
||||
_Static_assert(sizeof(PROJECT_NAME) <= sizeof(esp_app_desc.project_name), "PROJECT_NAME is longer than project_name field in structure");
|
||||
|
||||
const esp_app_desc_t *esp_ota_get_app_description(void)
|
||||
{
|
||||
return &esp_app_desc;
|
||||
}
|
@@ -36,10 +36,10 @@
|
||||
#include "rom/crc.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_flash_data_types.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "sys/param.h"
|
||||
|
||||
|
||||
#define OTA_MAX(a,b) ((a) >= (b) ? (a) : (b))
|
||||
#define OTA_MIN(a,b) ((a) <= (b) ? (a) : (b))
|
||||
#define SUB_TYPE_ID(i) (i & 0x0F)
|
||||
|
||||
typedef struct ota_ops_entry_ {
|
||||
@@ -52,19 +52,10 @@ typedef struct ota_ops_entry_ {
|
||||
LIST_ENTRY(ota_ops_entry_) entries;
|
||||
} ota_ops_entry_t;
|
||||
|
||||
/* OTA selection structure (two copies in the OTA data partition.)
|
||||
Size of 32 bytes is friendly to flash encryption */
|
||||
typedef struct {
|
||||
uint32_t ota_seq;
|
||||
uint8_t seq_label[24];
|
||||
uint32_t crc; /* CRC32 of ota_seq field only */
|
||||
} ota_select;
|
||||
|
||||
static LIST_HEAD(ota_ops_entries_head, ota_ops_entry_) s_ota_ops_entries_head =
|
||||
LIST_HEAD_INITIALIZER(s_ota_ops_entries_head);
|
||||
|
||||
static uint32_t s_ota_ops_last_handle = 0;
|
||||
static ota_select s_ota_select[2];
|
||||
|
||||
const static char *TAG = "esp_ota_ops";
|
||||
|
||||
@@ -77,6 +68,53 @@ static bool is_ota_partition(const esp_partition_t *p)
|
||||
&& p->subtype < ESP_PARTITION_SUBTYPE_APP_OTA_MAX);
|
||||
}
|
||||
|
||||
// Read otadata partition and fill array from two otadata structures.
|
||||
// Also return pointer to otadata info partition.
|
||||
static const esp_partition_t *read_otadata(esp_ota_select_entry_t *two_otadata)
|
||||
{
|
||||
const esp_partition_t *otadata_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
|
||||
|
||||
if (otadata_partition == NULL) {
|
||||
ESP_LOGE(TAG, "not found otadata");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
spi_flash_mmap_handle_t ota_data_map;
|
||||
const void *result = NULL;
|
||||
esp_err_t err = esp_partition_mmap(otadata_partition, 0, otadata_partition->size, SPI_FLASH_MMAP_DATA, &result, &ota_data_map);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "mmap otadata filed. Err=0x%8x", err);
|
||||
return NULL;
|
||||
} else {
|
||||
memcpy(&two_otadata[0], result, sizeof(esp_ota_select_entry_t));
|
||||
memcpy(&two_otadata[1], result + SPI_FLASH_SEC_SIZE, sizeof(esp_ota_select_entry_t));
|
||||
spi_flash_munmap(ota_data_map);
|
||||
}
|
||||
return otadata_partition;
|
||||
}
|
||||
|
||||
static esp_err_t image_validate(const esp_partition_t *partition, esp_image_load_mode_t load_mode)
|
||||
{
|
||||
esp_image_metadata_t data;
|
||||
const esp_partition_pos_t part_pos = {
|
||||
.offset = partition->address,
|
||||
.size = partition->size,
|
||||
};
|
||||
|
||||
if (esp_image_verify(load_mode, &part_pos, &data) != ESP_OK) {
|
||||
return ESP_ERR_OTA_VALIDATE_FAILED;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SECURE_SIGNED_ON_UPDATE
|
||||
esp_err_t ret = esp_secure_boot_verify_signature(partition->address, data.image_len);
|
||||
if (ret != ESP_OK) {
|
||||
return ESP_ERR_OTA_VALIDATE_FAILED;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp_ota_handle_t *out_handle)
|
||||
{
|
||||
ota_ops_entry_t *new_entry;
|
||||
@@ -157,7 +195,7 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size)
|
||||
|
||||
/* check if we have partially written data from earlier */
|
||||
if (it->partial_bytes != 0) {
|
||||
copy_len = OTA_MIN(16 - it->partial_bytes, size);
|
||||
copy_len = MIN(16 - it->partial_bytes, size);
|
||||
memcpy(it->partial_data + it->partial_bytes, data_bytes, copy_len);
|
||||
it->partial_bytes += copy_len;
|
||||
if (it->partial_bytes != 16) {
|
||||
@@ -247,32 +285,20 @@ esp_err_t esp_ota_end(esp_ota_handle_t handle)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t ota_select_crc(const ota_select *s)
|
||||
static esp_err_t rewrite_ota_seq(esp_ota_select_entry_t *two_otadata, uint32_t seq, uint8_t sec_id, const esp_partition_t *ota_data_partition)
|
||||
{
|
||||
return crc32_le(UINT32_MAX, (uint8_t *)&s->ota_seq, 4);
|
||||
}
|
||||
|
||||
static bool ota_select_valid(const ota_select *s)
|
||||
{
|
||||
return s->ota_seq != UINT32_MAX && s->crc == ota_select_crc(s);
|
||||
}
|
||||
|
||||
static esp_err_t rewrite_ota_seq(uint32_t seq, uint8_t sec_id, const esp_partition_t *ota_data_partition)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
if (sec_id == 0 || sec_id == 1) {
|
||||
s_ota_select[sec_id].ota_seq = seq;
|
||||
s_ota_select[sec_id].crc = ota_select_crc(&s_ota_select[sec_id]);
|
||||
ret = esp_partition_erase_range(ota_data_partition, sec_id * SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
} else {
|
||||
return esp_partition_write(ota_data_partition, SPI_FLASH_SEC_SIZE * sec_id, &s_ota_select[sec_id].ota_seq, sizeof(ota_select));
|
||||
}
|
||||
} else {
|
||||
if (two_otadata == NULL || sec_id > 1) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
two_otadata[sec_id].ota_seq = seq;
|
||||
two_otadata[sec_id].crc = bootloader_common_ota_select_crc(&two_otadata[sec_id]);
|
||||
esp_err_t ret = esp_partition_erase_range(ota_data_partition, sec_id * SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
} else {
|
||||
return esp_partition_write(ota_data_partition, SPI_FLASH_SEC_SIZE * sec_id, &two_otadata[sec_id], sizeof(esp_ota_select_entry_t));
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t get_ota_partition_count(void)
|
||||
@@ -287,119 +313,70 @@ static uint8_t get_ota_partition_count(void)
|
||||
|
||||
static esp_err_t esp_rewrite_ota_data(esp_partition_subtype_t subtype)
|
||||
{
|
||||
esp_err_t ret;
|
||||
const esp_partition_t *find_partition = NULL;
|
||||
uint16_t ota_app_count = 0;
|
||||
uint32_t i = 0;
|
||||
uint32_t seq;
|
||||
spi_flash_mmap_handle_t ota_data_map;
|
||||
const void *result = NULL;
|
||||
|
||||
find_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
|
||||
if (find_partition != NULL) {
|
||||
ota_app_count = get_ota_partition_count();
|
||||
//esp32_idf use two sector for store information about which partition is running
|
||||
//it defined the two sector as ota data partition,two structure ota_select is saved in the two sector
|
||||
//named data in first sector as s_ota_select[0], second sector data as s_ota_select[1]
|
||||
//e.g.
|
||||
//if s_ota_select[0].ota_seq == s_ota_select[1].ota_seq == 0xFFFFFFFF,means ota info partition is in init status
|
||||
//so it will boot factory application(if there is),if there's no factory application,it will boot ota[0] application
|
||||
//if s_ota_select[0].ota_seq != 0 and s_ota_select[1].ota_seq != 0,it will choose a max seq ,and get value of max_seq%max_ota_app_number
|
||||
//and boot a subtype (mask 0x0F) value is (max_seq - 1)%max_ota_app_number,so if want switch to run ota[x],can use next formulas.
|
||||
//for example, if s_ota_select[0].ota_seq = 4, s_ota_select[1].ota_seq = 5, and there are 8 ota application,
|
||||
//current running is (5-1)%8 = 4,running ota[4],so if we want to switch to run ota[7],
|
||||
//we should add s_ota_select[0].ota_seq (is 4) to 4 ,(8-1)%8=7,then it will boot ota[7]
|
||||
//if A=(B - C)%D
|
||||
//then B=(A + C)%D + D*n ,n= (0,1,2...)
|
||||
//so current ota app sub type id is x , dest bin subtype is y,total ota app count is n
|
||||
//seq will add (x + n*1 + 1 - seq)%n
|
||||
if (SUB_TYPE_ID(subtype) >= ota_app_count) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
ret = esp_partition_mmap(find_partition, 0, find_partition->size, SPI_FLASH_MMAP_DATA, &result, &ota_data_map);
|
||||
if (ret != ESP_OK) {
|
||||
result = NULL;
|
||||
return ret;
|
||||
} else {
|
||||
memcpy(&s_ota_select[0], result, sizeof(ota_select));
|
||||
memcpy(&s_ota_select[1], result + SPI_FLASH_SEC_SIZE, sizeof(ota_select));
|
||||
spi_flash_munmap(ota_data_map);
|
||||
}
|
||||
|
||||
if (ota_select_valid(&s_ota_select[0]) && ota_select_valid(&s_ota_select[1])) {
|
||||
seq = OTA_MAX(s_ota_select[0].ota_seq, s_ota_select[1].ota_seq);
|
||||
while (seq > (SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count) {
|
||||
i++;
|
||||
}
|
||||
|
||||
if (s_ota_select[0].ota_seq >= s_ota_select[1].ota_seq) {
|
||||
return rewrite_ota_seq((SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count, 1, find_partition);
|
||||
} else {
|
||||
return rewrite_ota_seq((SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count, 0, find_partition);
|
||||
}
|
||||
|
||||
} else if (ota_select_valid(&s_ota_select[0])) {
|
||||
while (s_ota_select[0].ota_seq > (SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count) {
|
||||
i++;
|
||||
}
|
||||
return rewrite_ota_seq((SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count, 1, find_partition);
|
||||
|
||||
} else if (ota_select_valid(&s_ota_select[1])) {
|
||||
while (s_ota_select[1].ota_seq > (SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count) {
|
||||
i++;
|
||||
}
|
||||
return rewrite_ota_seq((SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count, 0, find_partition);
|
||||
|
||||
} else {
|
||||
/* Both OTA slots are invalid, probably because unformatted... */
|
||||
return rewrite_ota_seq(SUB_TYPE_ID(subtype) + 1, 0, find_partition);
|
||||
}
|
||||
|
||||
} else {
|
||||
esp_ota_select_entry_t otadata[2];
|
||||
const esp_partition_t *otadata_partition = read_otadata(otadata);
|
||||
if (otadata_partition == NULL) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
int ota_app_count = get_ota_partition_count();
|
||||
if (SUB_TYPE_ID(subtype) >= ota_app_count) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
//esp32_idf use two sector for store information about which partition is running
|
||||
//it defined the two sector as ota data partition,two structure esp_ota_select_entry_t is saved in the two sector
|
||||
//named data in first sector as otadata[0], second sector data as otadata[1]
|
||||
//e.g.
|
||||
//if otadata[0].ota_seq == otadata[1].ota_seq == 0xFFFFFFFF,means ota info partition is in init status
|
||||
//so it will boot factory application(if there is),if there's no factory application,it will boot ota[0] application
|
||||
//if otadata[0].ota_seq != 0 and otadata[1].ota_seq != 0,it will choose a max seq ,and get value of max_seq%max_ota_app_number
|
||||
//and boot a subtype (mask 0x0F) value is (max_seq - 1)%max_ota_app_number,so if want switch to run ota[x],can use next formulas.
|
||||
//for example, if otadata[0].ota_seq = 4, otadata[1].ota_seq = 5, and there are 8 ota application,
|
||||
//current running is (5-1)%8 = 4,running ota[4],so if we want to switch to run ota[7],
|
||||
//we should add otadata[0].ota_seq (is 4) to 4 ,(8-1)%8=7,then it will boot ota[7]
|
||||
//if A=(B - C)%D
|
||||
//then B=(A + C)%D + D*n ,n= (0,1,2...)
|
||||
//so current ota app sub type id is x , dest bin subtype is y,total ota app count is n
|
||||
//seq will add (x + n*1 + 1 - seq)%n
|
||||
|
||||
int active_otadata = bootloader_common_get_active_otadata(otadata);
|
||||
if (active_otadata != -1) {
|
||||
uint32_t seq = otadata[active_otadata].ota_seq;
|
||||
uint32_t i = 0;
|
||||
while (seq > (SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count) {
|
||||
i++;
|
||||
}
|
||||
int next_otadata = (~active_otadata)&1; // if 0 -> will be next 1. and if 1 -> will be next 0.
|
||||
return rewrite_ota_seq(otadata, (SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count, next_otadata, otadata_partition);
|
||||
} else {
|
||||
/* Both OTA slots are invalid, probably because unformatted... */
|
||||
int next_otadata = 0;
|
||||
return rewrite_ota_seq(otadata, SUB_TYPE_ID(subtype) + 1, next_otadata, otadata_partition);
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t esp_ota_set_boot_partition(const esp_partition_t *partition)
|
||||
{
|
||||
const esp_partition_t *find_partition = NULL;
|
||||
if (partition == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_image_metadata_t data;
|
||||
const esp_partition_pos_t part_pos = {
|
||||
.offset = partition->address,
|
||||
.size = partition->size,
|
||||
};
|
||||
if (esp_image_verify(ESP_IMAGE_VERIFY, &part_pos, &data) != ESP_OK) {
|
||||
if (image_validate(partition, ESP_IMAGE_VERIFY) != ESP_OK) {
|
||||
return ESP_ERR_OTA_VALIDATE_FAILED;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SECURE_SIGNED_ON_UPDATE
|
||||
esp_err_t ret = esp_secure_boot_verify_signature(partition->address, data.image_len);
|
||||
if (ret != ESP_OK) {
|
||||
return ESP_ERR_OTA_VALIDATE_FAILED;
|
||||
}
|
||||
#endif
|
||||
// if set boot partition to factory bin ,just format ota info partition
|
||||
if (partition->type == ESP_PARTITION_TYPE_APP) {
|
||||
if (partition->subtype == ESP_PARTITION_SUBTYPE_APP_FACTORY) {
|
||||
find_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
|
||||
const esp_partition_t *find_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
|
||||
if (find_partition != NULL) {
|
||||
return esp_partition_erase_range(find_partition, 0, find_partition->size);
|
||||
} else {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
} else {
|
||||
// try to find this partition in flash,if not find it ,return error
|
||||
find_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
|
||||
if (find_partition != NULL) {
|
||||
return esp_rewrite_ota_data(partition->subtype);
|
||||
} else {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
return esp_rewrite_ota_data(partition->subtype);
|
||||
}
|
||||
} else {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
@@ -436,58 +413,30 @@ static const esp_partition_t *find_default_boot_partition(void)
|
||||
|
||||
const esp_partition_t *esp_ota_get_boot_partition(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
const esp_partition_t *find_partition = NULL;
|
||||
spi_flash_mmap_handle_t ota_data_map;
|
||||
const void *result = NULL;
|
||||
uint16_t ota_app_count = 0;
|
||||
find_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
|
||||
|
||||
if (find_partition == NULL) {
|
||||
ESP_LOGE(TAG, "not found ota data");
|
||||
esp_ota_select_entry_t otadata[2];
|
||||
const esp_partition_t *otadata_partition = read_otadata(otadata);
|
||||
if (otadata_partition == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = esp_partition_mmap(find_partition, 0, find_partition->size, SPI_FLASH_MMAP_DATA, &result, &ota_data_map);
|
||||
if (ret != ESP_OK) {
|
||||
spi_flash_munmap(ota_data_map);
|
||||
ESP_LOGE(TAG, "mmap ota data filed");
|
||||
return NULL;
|
||||
} else {
|
||||
memcpy(&s_ota_select[0], result, sizeof(ota_select));
|
||||
memcpy(&s_ota_select[1], result + 0x1000, sizeof(ota_select));
|
||||
spi_flash_munmap(ota_data_map);
|
||||
}
|
||||
ota_app_count = get_ota_partition_count();
|
||||
|
||||
int ota_app_count = get_ota_partition_count();
|
||||
ESP_LOGD(TAG, "found ota app max = %d", ota_app_count);
|
||||
|
||||
if (s_ota_select[0].ota_seq == 0xFFFFFFFF && s_ota_select[1].ota_seq == 0xFFFFFFFF) {
|
||||
ESP_LOGD(TAG, "finding factory app......");
|
||||
if ((bootloader_common_ota_select_invalid(&otadata[0]) &&
|
||||
bootloader_common_ota_select_invalid(&otadata[1])) ||
|
||||
ota_app_count == 0) {
|
||||
ESP_LOGD(TAG, "finding factory app...");
|
||||
return find_default_boot_partition();
|
||||
} else if (ota_select_valid(&s_ota_select[0]) && ota_select_valid(&s_ota_select[1])) {
|
||||
ESP_LOGD(TAG, "finding ota_%d app......", \
|
||||
ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ((OTA_MAX(s_ota_select[0].ota_seq, s_ota_select[1].ota_seq) - 1) % ota_app_count));
|
||||
|
||||
return esp_partition_find_first(ESP_PARTITION_TYPE_APP, \
|
||||
ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ((OTA_MAX(s_ota_select[0].ota_seq, s_ota_select[1].ota_seq) - 1) % ota_app_count), NULL);
|
||||
} else if (ota_select_valid(&s_ota_select[0])) {
|
||||
ESP_LOGD(TAG, "finding ota_%d app......", \
|
||||
ESP_PARTITION_SUBTYPE_APP_OTA_MIN + (s_ota_select[0].ota_seq - 1) % ota_app_count);
|
||||
|
||||
return esp_partition_find_first(ESP_PARTITION_TYPE_APP, \
|
||||
ESP_PARTITION_SUBTYPE_APP_OTA_MIN + (s_ota_select[0].ota_seq - 1) % ota_app_count, NULL);
|
||||
|
||||
} else if (ota_select_valid(&s_ota_select[1])) {
|
||||
ESP_LOGD(TAG, "finding ota_%d app......", \
|
||||
ESP_PARTITION_SUBTYPE_APP_OTA_MIN + (s_ota_select[1].ota_seq - 1) % ota_app_count);
|
||||
|
||||
return esp_partition_find_first(ESP_PARTITION_TYPE_APP, \
|
||||
ESP_PARTITION_SUBTYPE_APP_OTA_MIN + (s_ota_select[1].ota_seq - 1) % ota_app_count, NULL);
|
||||
|
||||
} else {
|
||||
ESP_LOGE(TAG, "ota data invalid, no current app. Assuming factory");
|
||||
return find_default_boot_partition();
|
||||
int active_otadata = bootloader_common_get_active_otadata(otadata);
|
||||
if (active_otadata != -1) {
|
||||
int ota_slot = (otadata[active_otadata].ota_seq - 1) % ota_app_count; // Actual OTA partition selection
|
||||
ESP_LOGD(TAG, "finding ota_%d app...", ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ota_slot);
|
||||
return esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ota_slot, NULL);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "ota data invalid, no current app. Assuming factory");
|
||||
return find_default_boot_partition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -576,3 +525,25 @@ const esp_partition_t* esp_ota_get_next_update_partition(const esp_partition_t *
|
||||
return default_ota;
|
||||
|
||||
}
|
||||
|
||||
esp_err_t esp_ota_get_partition_description(const esp_partition_t *partition, esp_app_desc_t *app_desc)
|
||||
{
|
||||
if (partition == NULL || app_desc == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if(partition->type != ESP_PARTITION_TYPE_APP) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
esp_err_t err = esp_partition_read(partition, sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t), app_desc, sizeof(esp_app_desc_t));
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (app_desc->magic_word != ESP_APP_DESC_MAGIC_WORD) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@@ -1,82 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# generates an empty binary file
|
||||
#
|
||||
# This tool generates an empty binary file of the required size.
|
||||
#
|
||||
# Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http:#www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from __future__ import print_function, division
|
||||
from __future__ import unicode_literals
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import struct
|
||||
import sys
|
||||
import hashlib
|
||||
import binascii
|
||||
|
||||
__version__ = '1.0'
|
||||
|
||||
quiet = False
|
||||
|
||||
def status(msg):
|
||||
""" Print status message to stderr """
|
||||
if not quiet:
|
||||
critical(msg)
|
||||
|
||||
def critical(msg):
|
||||
""" Print critical message to stderr """
|
||||
if not quiet:
|
||||
sys.stderr.write(msg)
|
||||
sys.stderr.write('\n')
|
||||
|
||||
def generate_blanked_file(size, output_path):
|
||||
output = b"\xFF" * size
|
||||
try:
|
||||
stdout_binary = sys.stdout.buffer # Python 3
|
||||
except AttributeError:
|
||||
stdout_binary = sys.stdout
|
||||
with stdout_binary if output_path == '-' else open(output_path, 'wb') as f:
|
||||
f.write(output)
|
||||
|
||||
def main():
|
||||
global quiet
|
||||
parser = argparse.ArgumentParser(description='Generates an empty binary file of the required size.')
|
||||
|
||||
parser.add_argument('--quiet', '-q', help="Don't print status messages to stderr", action='store_true')
|
||||
|
||||
parser.add_argument('--size', help='Size of generated the file', type=str, required=True)
|
||||
|
||||
parser.add_argument('output', help='Path for binary file.', nargs='?', default='-')
|
||||
args = parser.parse_args()
|
||||
|
||||
quiet = args.quiet
|
||||
|
||||
size = int(args.size, 0)
|
||||
if size > 0 :
|
||||
generate_blanked_file(size, args.output)
|
||||
return 0
|
||||
|
||||
class InputError(RuntimeError):
|
||||
def __init__(self, e):
|
||||
super(InputError, self).__init__(e)
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
r = main()
|
||||
sys.exit(r)
|
||||
except InputError as e:
|
||||
print(e, file=sys.stderr)
|
||||
sys.exit(2)
|
@@ -20,6 +20,7 @@
|
||||
#include <stddef.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_partition.h"
|
||||
#include "esp_image_format.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
@@ -41,6 +42,14 @@ extern "C"
|
||||
*/
|
||||
typedef uint32_t esp_ota_handle_t;
|
||||
|
||||
/**
|
||||
* @brief Return esp_app_desc structure. This structure includes app version.
|
||||
*
|
||||
* Return description for running app.
|
||||
* @return Pointer to esp_app_desc structure.
|
||||
*/
|
||||
const esp_app_desc_t *esp_ota_get_app_description(void);
|
||||
|
||||
/**
|
||||
* @brief Commence an OTA update writing to the specified partition.
|
||||
|
||||
@@ -170,6 +179,22 @@ const esp_partition_t* esp_ota_get_running_partition(void);
|
||||
*/
|
||||
const esp_partition_t* esp_ota_get_next_update_partition(const esp_partition_t *start_from);
|
||||
|
||||
/**
|
||||
* @brief Returns esp_app_desc structure for app partition. This structure includes app version.
|
||||
*
|
||||
* Returns a description for the requested app partition.
|
||||
* @param[in] partition Pointer to app partition. (only app partition)
|
||||
* @param[out] app_desc Structure of info about app.
|
||||
* @return
|
||||
* - ESP_OK Successful.
|
||||
* - ESP_ERR_NOT_FOUND app_desc structure is not found. Magic word is incorrect.
|
||||
* - ESP_ERR_NOT_SUPPORTED Partition is not application.
|
||||
* - ESP_ERR_INVALID_ARG Arguments is NULL or if partition's offset exceeds partition size.
|
||||
* - ESP_ERR_INVALID_SIZE Read would go out of bounds of the partition.
|
||||
* - or one of error codes from lower-level flash driver.
|
||||
*/
|
||||
esp_err_t esp_ota_get_partition_description(const esp_partition_t *partition, esp_app_desc_t *app_desc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
327
components/app_update/otatool.py
Executable file
327
components/app_update/otatool.py
Executable file
@@ -0,0 +1,327 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# otatool is used to perform ota-level operations - flashing ota partition
|
||||
# erasing ota partition and switching ota partition
|
||||
#
|
||||
# Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http:#www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from __future__ import print_function, division
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import binascii
|
||||
import subprocess
|
||||
import tempfile
|
||||
import collections
|
||||
import struct
|
||||
|
||||
__version__ = '1.0'
|
||||
|
||||
IDF_COMPONENTS_PATH = os.path.expandvars(os.path.join("$IDF_PATH", "components"))
|
||||
|
||||
PARTTOOL_PY = os.path.join(IDF_COMPONENTS_PATH, "partition_table", "parttool.py")
|
||||
|
||||
SPI_FLASH_SEC_SIZE = 0x2000
|
||||
|
||||
quiet = False
|
||||
|
||||
|
||||
def status(msg):
|
||||
if not quiet:
|
||||
print(msg)
|
||||
|
||||
|
||||
def _invoke_parttool(parttool_args, args, output=False, partition=None):
|
||||
invoke_args = []
|
||||
|
||||
if partition:
|
||||
invoke_args += [sys.executable, PARTTOOL_PY] + partition
|
||||
else:
|
||||
invoke_args += [sys.executable, PARTTOOL_PY, "--partition-type", "data", "--partition-subtype", "ota"]
|
||||
|
||||
if quiet:
|
||||
invoke_args += ["-q"]
|
||||
|
||||
if args.port != "":
|
||||
invoke_args += ["--port", args.port]
|
||||
|
||||
if args.partition_table_file:
|
||||
invoke_args += ["--partition-table-file", args.partition_table_file]
|
||||
|
||||
if args.partition_table_offset:
|
||||
invoke_args += ["--partition-table-offset", args.partition_table_offset]
|
||||
|
||||
invoke_args += parttool_args
|
||||
|
||||
if output:
|
||||
return subprocess.check_output(invoke_args)
|
||||
else:
|
||||
return subprocess.check_call(invoke_args)
|
||||
|
||||
|
||||
def _get_otadata_contents(args, check=True):
|
||||
global quiet
|
||||
|
||||
if check:
|
||||
check_args = ["get_partition_info", "--info", "offset", "size"]
|
||||
|
||||
quiet = True
|
||||
output = _invoke_parttool(check_args, args, True).split(b" ")
|
||||
quiet = args.quiet
|
||||
|
||||
if not output:
|
||||
raise RuntimeError("No ota_data partition found")
|
||||
|
||||
with tempfile.NamedTemporaryFile() as otadata_file:
|
||||
invoke_args = ["read_partition", "--output", otadata_file.name]
|
||||
_invoke_parttool(invoke_args, args)
|
||||
return otadata_file.read()
|
||||
|
||||
|
||||
def _get_otadata_status(otadata_contents):
|
||||
status = []
|
||||
|
||||
otadata_status = collections.namedtuple("otadata_status", "seq crc")
|
||||
|
||||
for i in range(2):
|
||||
start = i * (SPI_FLASH_SEC_SIZE >> 1)
|
||||
|
||||
seq = bytearray(otadata_contents[start:start + 4])
|
||||
crc = bytearray(otadata_contents[start + 28:start + 32])
|
||||
|
||||
seq = struct.unpack('>I', seq)
|
||||
crc = struct.unpack('>I', crc)
|
||||
|
||||
status.append(otadata_status(seq[0], crc[0]))
|
||||
|
||||
return status
|
||||
|
||||
|
||||
def read_otadata(args):
|
||||
status("Reading ota_data partition contents...")
|
||||
otadata_info = _get_otadata_contents(args)
|
||||
otadata_info = _get_otadata_status(otadata_info)
|
||||
|
||||
print(otadata_info)
|
||||
|
||||
print("\t\t{:11}\t{:8s}|\t{:8s}\t{:8s}".format("OTA_SEQ", "CRC", "OTA_SEQ", "CRC"))
|
||||
print("Firmware: 0x{:8x} \t 0x{:8x} |\t0x{:8x} \t 0x{:8x}".format(otadata_info[0].seq, otadata_info[0].crc,
|
||||
otadata_info[1].seq, otadata_info[1].crc))
|
||||
|
||||
|
||||
def erase_otadata(args):
|
||||
status("Erasing ota_data partition contents...")
|
||||
_invoke_parttool(["erase_partition"], args)
|
||||
status("Erased ota_data partition contents")
|
||||
|
||||
|
||||
def switch_otadata(args):
|
||||
sys.path.append(os.path.join(IDF_COMPONENTS_PATH, "partition_table"))
|
||||
import gen_esp32part as gen
|
||||
|
||||
def is_otadata_status_valid(status):
|
||||
seq = status.seq % (1 << 32)
|
||||
crc = hex(binascii.crc32(struct.pack("I", seq), 0xFFFFFFFF) % (1 << 32))
|
||||
return seq < (int('0xFFFFFFFF', 16) % (1 << 32)) and status.crc == crc
|
||||
|
||||
status("Looking for ota app partitions...")
|
||||
|
||||
# In order to get the number of ota app partitions, we need the partition table
|
||||
partition_table = None
|
||||
|
||||
with tempfile.NamedTemporaryFile() as partition_table_file:
|
||||
invoke_args = ["get_partition_info", "--table", partition_table_file.name]
|
||||
|
||||
_invoke_parttool(invoke_args, args)
|
||||
|
||||
partition_table = partition_table_file.read()
|
||||
partition_table = gen.PartitionTable.from_binary(partition_table)
|
||||
|
||||
ota_partitions = list()
|
||||
|
||||
for i in range(gen.NUM_PARTITION_SUBTYPE_APP_OTA):
|
||||
ota_partition = filter(lambda p: p.subtype == (gen.MIN_PARTITION_SUBTYPE_APP_OTA + i), partition_table)
|
||||
|
||||
try:
|
||||
ota_partitions.append(list(ota_partition)[0])
|
||||
except IndexError:
|
||||
break
|
||||
|
||||
ota_partitions = sorted(ota_partitions, key=lambda p: p.subtype)
|
||||
|
||||
if not ota_partitions:
|
||||
raise RuntimeError("No ota app partitions found")
|
||||
|
||||
status("Verifying partition to switch to exists...")
|
||||
|
||||
# Look for the app partition to switch to
|
||||
ota_partition_next = None
|
||||
|
||||
try:
|
||||
if args.name:
|
||||
ota_partition_next = filter(lambda p: p.name == args.name, ota_partitions)
|
||||
else:
|
||||
ota_partition_next = filter(lambda p: p.subtype - gen.MIN_PARTITION_SUBTYPE_APP_OTA == args.slot, ota_partitions)
|
||||
|
||||
ota_partition_next = list(ota_partition_next)[0]
|
||||
except IndexError:
|
||||
raise RuntimeError("Partition to switch to not found")
|
||||
|
||||
otadata_contents = _get_otadata_contents(args)
|
||||
otadata_status = _get_otadata_status(otadata_contents)
|
||||
|
||||
# Find the copy to base the computation for ota sequence number on
|
||||
otadata_compute_base = -1
|
||||
|
||||
# Both are valid, take the max as computation base
|
||||
if is_otadata_status_valid(otadata_status[0]) and is_otadata_status_valid(otadata_status[1]):
|
||||
if otadata_status[0].seq >= otadata_status[1].seq:
|
||||
otadata_compute_base = 0
|
||||
else:
|
||||
otadata_compute_base = 1
|
||||
# Only one copy is valid, use that
|
||||
elif is_otadata_status_valid(otadata_status[0]):
|
||||
otadata_compute_base = 0
|
||||
elif is_otadata_status_valid(otadata_status[1]):
|
||||
otadata_compute_base = 1
|
||||
# Both are invalid (could be initial state - all 0xFF's)
|
||||
else:
|
||||
pass
|
||||
|
||||
ota_seq_next = 0
|
||||
ota_partitions_num = len(ota_partitions)
|
||||
|
||||
target_seq = (ota_partition_next.subtype & 0x0F) + 1
|
||||
|
||||
# Find the next ota sequence number
|
||||
if otadata_compute_base == 0 or otadata_compute_base == 1:
|
||||
base_seq = otadata_status[otadata_compute_base].seq % (1 << 32)
|
||||
|
||||
i = 0
|
||||
while base_seq > target_seq % ota_partitions_num + i * ota_partitions_num:
|
||||
i += 1
|
||||
|
||||
ota_seq_next = target_seq % ota_partitions_num + i * ota_partitions_num
|
||||
else:
|
||||
ota_seq_next = target_seq
|
||||
|
||||
# Create binary data from computed values
|
||||
ota_seq_next = struct.pack("I", ota_seq_next)
|
||||
ota_seq_crc_next = binascii.crc32(ota_seq_next, 0xFFFFFFFF) % (1 << 32)
|
||||
ota_seq_crc_next = struct.pack("I", ota_seq_crc_next)
|
||||
|
||||
with tempfile.NamedTemporaryFile() as otadata_next_file:
|
||||
start = (1 if otadata_compute_base == 0 else 0) * (SPI_FLASH_SEC_SIZE >> 1)
|
||||
|
||||
otadata_next_file.write(otadata_contents)
|
||||
|
||||
otadata_next_file.seek(start)
|
||||
otadata_next_file.write(ota_seq_next)
|
||||
|
||||
otadata_next_file.seek(start + 28)
|
||||
otadata_next_file.write(ota_seq_crc_next)
|
||||
|
||||
otadata_next_file.flush()
|
||||
|
||||
_invoke_parttool(["write_partition", "--input", otadata_next_file.name], args)
|
||||
status("Updated ota_data partition")
|
||||
|
||||
|
||||
def _get_partition_specifier(args):
|
||||
if args.name:
|
||||
return ["--partition-name", args.name]
|
||||
else:
|
||||
return ["--partition-type", "app", "--partition-subtype", "ota_" + str(args.slot)]
|
||||
|
||||
|
||||
def read_ota_partition(args):
|
||||
invoke_args = ["read_partition", "--output", args.output]
|
||||
_invoke_parttool(invoke_args, args, partition=_get_partition_specifier(args))
|
||||
status("Read ota partition contents to file {}".format(args.output))
|
||||
|
||||
|
||||
def write_ota_partition(args):
|
||||
invoke_args = ["write_partition", "--input", args.input]
|
||||
_invoke_parttool(invoke_args, args, partition=_get_partition_specifier(args))
|
||||
status("Written contents of file {} to ota partition".format(args.input))
|
||||
|
||||
|
||||
def erase_ota_partition(args):
|
||||
invoke_args = ["erase_partition"]
|
||||
_invoke_parttool(invoke_args, args, partition=_get_partition_specifier(args))
|
||||
status("Erased contents of ota partition")
|
||||
|
||||
|
||||
def main():
|
||||
global quiet
|
||||
|
||||
parser = argparse.ArgumentParser("ESP-IDF OTA Partitions Tool")
|
||||
|
||||
parser.add_argument("--quiet", "-q", help="suppress stderr messages", action="store_true")
|
||||
|
||||
# There are two possible sources for the partition table: a device attached to the host
|
||||
# or a partition table CSV/binary file. These sources are mutually exclusive.
|
||||
partition_table_info_source_args = parser.add_mutually_exclusive_group()
|
||||
|
||||
partition_table_info_source_args.add_argument("--port", "-p", help="port where the device to read the partition table from is attached", default="")
|
||||
partition_table_info_source_args.add_argument("--partition-table-file", "-f", help="file (CSV/binary) to read the partition table from", default="")
|
||||
|
||||
parser.add_argument("--partition-table-offset", "-o", help="offset to read the partition table from", default="0x8000")
|
||||
|
||||
subparsers = parser.add_subparsers(dest="operation", help="run otatool -h for additional help")
|
||||
|
||||
# Specify the supported operations
|
||||
subparsers.add_parser("read_otadata", help="read otadata partition")
|
||||
subparsers.add_parser("erase_otadata", help="erase otadata partition")
|
||||
|
||||
slot_or_name_parser = argparse.ArgumentParser(add_help=False)
|
||||
slot_or_name_parser_args = slot_or_name_parser.add_mutually_exclusive_group()
|
||||
slot_or_name_parser_args.add_argument("--slot", help="slot number of the ota partition", type=int)
|
||||
slot_or_name_parser_args.add_argument("--name", help="name of the ota partition")
|
||||
|
||||
subparsers.add_parser("switch_otadata", help="switch otadata partition", parents=[slot_or_name_parser])
|
||||
|
||||
read_ota_partition_subparser = subparsers.add_parser("read_ota_partition", help="read contents of an ota partition", parents=[slot_or_name_parser])
|
||||
read_ota_partition_subparser.add_argument("--output", help="file to write the contents of the ota partition to")
|
||||
|
||||
write_ota_partition_subparser = subparsers.add_parser("write_ota_partition", help="write contents to an ota partition", parents=[slot_or_name_parser])
|
||||
write_ota_partition_subparser.add_argument("--input", help="file whose contents to write to the ota partition")
|
||||
|
||||
subparsers.add_parser("erase_ota_partition", help="erase contents of an ota partition", parents=[slot_or_name_parser])
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
quiet = args.quiet
|
||||
|
||||
# No operation specified, display help and exit
|
||||
if args.operation is None:
|
||||
if not quiet:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
# Else execute the operation
|
||||
operation_func = globals()[args.operation]
|
||||
|
||||
if quiet:
|
||||
# If exceptions occur, suppress and exit quietly
|
||||
try:
|
||||
operation_func(args)
|
||||
except Exception:
|
||||
sys.exit(2)
|
||||
else:
|
||||
operation_func(args)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
@@ -3,6 +3,7 @@
|
||||
# partition table
|
||||
# (NB: because of component dependency, we know partition_table
|
||||
# project_include.cmake has already been included.)
|
||||
if(${OTADATA_PARTITION_OFFSET})
|
||||
|
||||
if(OTADATA_PARTITION_OFFSET AND OTADATA_PARTITION_SIZE AND IDF_BUILD_ARTIFACTS)
|
||||
set(BLANK_OTADATA_FILE "ota_data_initial.bin")
|
||||
endif()
|
||||
|
@@ -1,6 +1,6 @@
|
||||
set(COMPONENT_SRCDIRS ".")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
set(COMPONENT_REQUIRES unity app_update bootloader_support nvs_flash)
|
||||
set(COMPONENT_REQUIRES unity test_utils app_update bootloader_support nvs_flash)
|
||||
|
||||
register_component()
|
@@ -8,7 +8,7 @@
|
||||
#include <unity.h>
|
||||
#include <test_utils.h>
|
||||
#include <esp_ota_ops.h>
|
||||
|
||||
#include "bootloader_common.h"
|
||||
|
||||
/* These OTA tests currently don't assume an OTA partition exists
|
||||
on the device, so they're a bit limited
|
||||
@@ -84,3 +84,26 @@ TEST_CASE("esp_ota_get_next_update_partition logic", "[ota]")
|
||||
TEST_ASSERT_EQUAL_PTR(ota_0, p);
|
||||
}
|
||||
|
||||
TEST_CASE("esp_ota_get_partition_description ", "[ota]")
|
||||
{
|
||||
const esp_partition_t *running = esp_ota_get_running_partition();
|
||||
TEST_ASSERT_NOT_NULL(running);
|
||||
esp_app_desc_t app_desc1, app_desc2;
|
||||
TEST_ESP_OK(esp_ota_get_partition_description(running, &app_desc1));
|
||||
const esp_partition_pos_t running_pos = {
|
||||
.offset = running->address,
|
||||
.size = running->size
|
||||
};
|
||||
TEST_ESP_OK(bootloader_common_get_partition_description(&running_pos, &app_desc2));
|
||||
|
||||
TEST_ASSERT_EQUAL_MEMORY_MESSAGE((uint8_t *)&app_desc1, (uint8_t *)&app_desc2, sizeof(app_desc1), "must be the same");
|
||||
|
||||
const esp_partition_t *not_app = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
|
||||
TEST_ASSERT_NOT_NULL(not_app);
|
||||
TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, esp_ota_get_partition_description(not_app, &app_desc1));
|
||||
const esp_partition_pos_t not_app_pos = {
|
||||
.offset = not_app->address,
|
||||
.size = not_app->size
|
||||
};
|
||||
TEST_ESP_ERR(ESP_ERR_NOT_FOUND, bootloader_common_get_partition_description(¬_app_pos, &app_desc1));
|
||||
}
|
||||
|
@@ -236,6 +236,7 @@ IoT_Error_t iot_tls_connect(Network *pNetwork, TLSConnectParams *params) {
|
||||
|
||||
mbedtls_ssl_conf_read_timeout(&(tlsDataParams->conf), pNetwork->tlsConnectParams.timeout_ms);
|
||||
|
||||
#ifdef CONFIG_MBEDTLS_SSL_ALPN
|
||||
/* Use the AWS IoT ALPN extension for MQTT, if port 443 is requested */
|
||||
if (pNetwork->tlsConnectParams.DestinationPort == 443) {
|
||||
const char *alpnProtocols[] = { "x-amzn-mqtt-ca", NULL };
|
||||
@@ -244,6 +245,7 @@ IoT_Error_t iot_tls_connect(Network *pNetwork, TLSConnectParams *params) {
|
||||
return SSL_CONNECTION_ERROR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if((ret = mbedtls_ssl_setup(&(tlsDataParams->ssl), &(tlsDataParams->conf))) != 0) {
|
||||
ESP_LOGE(TAG, "failed! mbedtls_ssl_setup returned -0x%x", -ret);
|
||||
|
@@ -1,28 +1,66 @@
|
||||
# This is for tracking the top level project path
|
||||
if(BOOTLOADER_BUILD)
|
||||
return() # don't keep recursing!
|
||||
set(main_project_path "${CMAKE_BINARY_DIR}/../..")
|
||||
else()
|
||||
set(main_project_path "${IDF_PROJECT_PATH}")
|
||||
endif()
|
||||
|
||||
get_filename_component(secure_boot_signing_key
|
||||
"${CONFIG_SECURE_BOOT_SIGNING_KEY}"
|
||||
ABSOLUTE BASE_DIR "${main_project_path}")
|
||||
if(NOT EXISTS ${secure_boot_signing_key})
|
||||
# If the signing key is not found, create a phony gen_secure_boot_signing_key target that
|
||||
# fails the build. fail_at_build_time also touches CMakeCache.txt to cause a cmake run next time
|
||||
# (to pick up a new signing key if one exists, etc.)
|
||||
fail_at_build_time(gen_secure_boot_signing_key
|
||||
"Secure Boot Signing Key ${CONFIG_SECURE_BOOT_SIGNING_KEY} does not exist. Generate using:"
|
||||
"\tespsecure.py generate_signing_key ${CONFIG_SECURE_BOOT_SIGNING_KEY}")
|
||||
else()
|
||||
add_custom_target(gen_secure_boot_signing_key)
|
||||
endif()
|
||||
|
||||
if(BOOTLOADER_BUILD OR NOT IDF_BUILD_ARTIFACTS)
|
||||
return() # don't keep recursing, generate on project builds
|
||||
endif()
|
||||
|
||||
# Glue to build the bootloader subproject binary as an external
|
||||
# cmake project under this one
|
||||
#
|
||||
#
|
||||
set(bootloader_build_dir "${CMAKE_BINARY_DIR}/bootloader")
|
||||
set(bootloader_build_dir "${IDF_BUILD_ARTIFACTS_DIR}/bootloader")
|
||||
set(bootloader_binary_files
|
||||
"${bootloader_build_dir}/bootloader.elf"
|
||||
"${bootloader_build_dir}/bootloader.bin"
|
||||
"${bootloader_build_dir}/bootloader.map"
|
||||
)
|
||||
|
||||
externalproject_add(bootloader
|
||||
# TODO: support overriding the bootloader in COMPONENT_PATHS
|
||||
SOURCE_DIR "${IDF_PATH}/components/bootloader/subproject"
|
||||
BINARY_DIR "${bootloader_build_dir}"
|
||||
CMAKE_ARGS -DSDKCONFIG=${SDKCONFIG} -DIDF_PATH=${IDF_PATH} -DEXTRA_COMPONENT_DIRS=${COMPONENT_DIRS}
|
||||
-DTESTS_ALL=0 -DTEST_COMPONENTS=""
|
||||
INSTALL_COMMAND ""
|
||||
BUILD_ALWAYS 1 # no easy way around this...
|
||||
BUILD_BYPRODUCTS ${bootloader_binary_files}
|
||||
)
|
||||
# These additional files may get generated
|
||||
if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE)
|
||||
set(bootloader_binary_files
|
||||
${bootloader_binary_files}
|
||||
"${bootloader_build_dir}/bootloader-reflash-digest.bin"
|
||||
"${bootloader_build_dir}/secure-bootloader-key-192.bin"
|
||||
"${bootloader_build_dir}/secure-bootloader-key-256.bin"
|
||||
)
|
||||
endif()
|
||||
|
||||
if((NOT CONFIG_SECURE_BOOT_ENABLED) OR
|
||||
CONFIG_SECURE_BOOTLOADER_REFLASHABLE OR
|
||||
CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH)
|
||||
externalproject_add(bootloader
|
||||
# TODO: support overriding the bootloader in COMPONENT_PATHS
|
||||
SOURCE_DIR "${IDF_PATH}/components/bootloader/subproject"
|
||||
BINARY_DIR "${bootloader_build_dir}"
|
||||
CMAKE_ARGS -DSDKCONFIG=${SDKCONFIG} -DIDF_PATH=${IDF_PATH}
|
||||
-DSECURE_BOOT_SIGNING_KEY=${secure_boot_signing_key}
|
||||
INSTALL_COMMAND ""
|
||||
BUILD_ALWAYS 1 # no easy way around this...
|
||||
BUILD_BYPRODUCTS ${bootloader_binary_files}
|
||||
DEPENDS gen_secure_boot_signing_key
|
||||
)
|
||||
else()
|
||||
fail_at_build_time(bootloader "Invalid bootloader target: bad sdkconfig?")
|
||||
endif()
|
||||
|
||||
# this is a hack due to an (annoying) shortcoming in cmake, it can't
|
||||
# extend the 'clean' target to the external project
|
||||
|
@@ -21,8 +21,117 @@ project(bootloader)
|
||||
|
||||
target_linker_script(bootloader.elf
|
||||
"main/esp32.bootloader.ld"
|
||||
"main/esp32.bootloader.rom.ld")
|
||||
# Imported from esp32 component
|
||||
"main/esp32.bootloader.rom.ld"
|
||||
)
|
||||
|
||||
# as cmake won't attach linker args to a header-only library, attach
|
||||
# linker args directly to the bootloader.elf
|
||||
set(ESP32_BOOTLOADER_LINKER_SCRIPTS
|
||||
"../../esp32/ld/esp32.rom.ld"
|
||||
"../../esp32/ld/esp32.rom.spiram_incompatible_fns.ld"
|
||||
"../../esp32/ld/esp32.peripherals.ld")
|
||||
|
||||
target_linker_script(bootloader.elf ${ESP32_BOOTLOADER_LINKER_SCRIPTS})
|
||||
|
||||
target_link_libraries(bootloader.elf gcc)
|
||||
|
||||
set(secure_boot_signing_key ${SECURE_BOOT_SIGNING_KEY})
|
||||
|
||||
string(REPLACE ";" " " espsecurepy "${ESPSECUREPY}")
|
||||
string(REPLACE ";" " " espefusepy "${ESPEFUSEPY}")
|
||||
set(esptoolpy_write_flash "${ESPTOOLPY_WRITE_FLASH_STR}")
|
||||
|
||||
if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE)
|
||||
if(CONFIG_SECURE_BOOTLOADER_KEY_ENCODING_192BIT)
|
||||
set(key_digest_len 192)
|
||||
else()
|
||||
set(key_digest_len 256)
|
||||
endif()
|
||||
|
||||
get_filename_component(bootloader_digest_bin
|
||||
"bootloader-reflash-digest.bin"
|
||||
ABSOLUTE BASE_DIR "${CMAKE_BINARY_DIR}")
|
||||
|
||||
get_filename_component(secure_bootloader_key
|
||||
"secure-bootloader-key-${key_digest_len}.bin"
|
||||
ABSOLUTE BASE_DIR "${CMAKE_BINARY_DIR}")
|
||||
|
||||
add_custom_command(OUTPUT "${secure_bootloader_key}"
|
||||
COMMAND ${ESPSECUREPY} digest_private_key
|
||||
--keylen "${key_digest_len}"
|
||||
--keyfile "${secure_boot_signing_key}"
|
||||
"${secure_bootloader_key}"
|
||||
VERBATIM)
|
||||
|
||||
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
|
||||
add_custom_target(gen_secure_bootloader_key ALL DEPENDS "${secure_bootloader_key}")
|
||||
else()
|
||||
if(NOT EXISTS "${secure_bootloader_key}")
|
||||
message(FATAL_ERROR
|
||||
"No pre-generated key for a reflashable secure bootloader is available, "
|
||||
"due to signing configuration."
|
||||
"\nTo generate one, you can use this command:"
|
||||
"\n\t${espsecurepy} generate_flash_encryption_key ${secure_bootloader_key}"
|
||||
"\nIf a signing key is present, then instead use:"
|
||||
"\n\t${ESPSECUREPY} digest_private_key "
|
||||
"--keylen (192/256) --keyfile KEYFILE "
|
||||
"${secure_bootloader_key}")
|
||||
endif()
|
||||
add_custom_target(gen_secure_bootloader_key)
|
||||
endif()
|
||||
|
||||
add_custom_command(OUTPUT "${bootloader_digest_bin}"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "DIGEST ${bootloader_digest_bin}"
|
||||
COMMAND ${ESPSECUREPY} digest_secure_bootloader --keyfile "${secure_bootloader_key}"
|
||||
-o "${bootloader_digest_bin}" "${CMAKE_BINARY_DIR}/bootloader.bin"
|
||||
DEPENDS gen_secure_bootloader_key "${CMAKE_BINARY_DIR}/bootloader.bin"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_target (gen_bootloader_digest_bin ALL DEPENDS "${bootloader_digest_bin}")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH)
|
||||
add_custom_command(TARGET bootloader POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"=============================================================================="
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"Bootloader built. Secure boot enabled, so bootloader not flashed automatically."
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"One-time flash command is:"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"\t${esptoolpy_write_flash} ${BOOTLOADER_OFFSET} ${CMAKE_BINARY_DIR}/bootloader.bin"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"* IMPORTANT: After first boot, BOOTLOADER CANNOT BE RE-FLASHED on same device"
|
||||
VERBATIM)
|
||||
|
||||
elseif(CONFIG_SECURE_BOOTLOADER_REFLASHABLE)
|
||||
add_custom_command(TARGET bootloader POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"=============================================================================="
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"Bootloader built and secure digest generated."
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"Secure boot enabled, so bootloader not flashed automatically."
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"Burn secure boot key to efuse using:"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"\t${espefusepy} burn_key secure_boot ${secure_bootloader_key}"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"First time flash command is:"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"\t${esptoolpy_write_flash} ${BOOTLOADER_OFFSET} ${CMAKE_BINARY_DIR}/bootloader.bin"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"=============================================================================="
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"To reflash the bootloader after initial flash:"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"\t${esptoolpy_write_flash} 0x0 ${bootloader_digest_bin}"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"=============================================================================="
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"* After first boot, only re-flashes of this kind (with same key) will be accepted."
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"* Not recommended to re-use the same secure boot keyfile on multiple production devices."
|
||||
DEPENDS gen_secure_bootloader_key gen_bootloader_digest_bin
|
||||
VERBATIM)
|
||||
endif()
|
||||
|
@@ -17,6 +17,40 @@ if(${BOOTLOADER_BUILD})
|
||||
set(COMPONENT_REQUIRES)
|
||||
set(COMPONENT_PRIV_REQUIRES spi_flash micro-ecc)
|
||||
list(APPEND COMPONENT_SRCS "src/bootloader_init.c")
|
||||
|
||||
if(CONFIG_SECURE_SIGNED_APPS)
|
||||
get_filename_component(secure_boot_verification_key
|
||||
"signature_verification_key.bin"
|
||||
ABSOLUTE BASE_DIR "${CMAKE_BINARY_DIR}")
|
||||
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
|
||||
add_custom_command(OUTPUT "${secure_boot_verification_key}"
|
||||
COMMAND ${ESPSECUREPY}
|
||||
extract_public_key --keyfile "${secure_boot_signing_key}"
|
||||
"${secure_boot_verification_key}"
|
||||
DEPENDS gen_secure_boot_signing_key
|
||||
VERBATIM)
|
||||
else()
|
||||
get_filename_component(orig_secure_boot_verification_key
|
||||
"${CONFIG_SECURE_BOOT_VERIFICATION_KEY}"
|
||||
ABSOLUTE BASE_DIR "${main_project_path}")
|
||||
if(NOT EXISTS ${orig_secure_boot_verification_key})
|
||||
message(FATAL_ERROR
|
||||
"Secure Boot Verification Public Key ${CONFIG_SECURE_BOOT_VERIFICATION_KEY} does not exist."
|
||||
"\nThis can be extracted from the private signing key."
|
||||
"\nSee docs/security/secure-boot.rst for details.")
|
||||
endif()
|
||||
|
||||
add_custom_command(OUTPUT "${secure_boot_verification_key}"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy "${orig_secure_boot_verification_key}"
|
||||
"${secure_boot_verification_key}"
|
||||
DEPENDS "${orig_secure_boot_verification_key}"
|
||||
VERBATIM)
|
||||
endif()
|
||||
set(COMPONENT_EMBED_FILES "${secure_boot_verification_key}")
|
||||
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
|
||||
"${secure_boot_verification_key}")
|
||||
endif()
|
||||
else()
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "include")
|
||||
set(COMPONENT_PRIV_INCLUDEDIRS "include_bootloader")
|
||||
|
@@ -14,6 +14,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "esp_flash_data_types.h"
|
||||
#include "esp_image_format.h"
|
||||
|
||||
/// Type of hold a GPIO in low state
|
||||
typedef enum {
|
||||
@@ -23,21 +24,29 @@ typedef enum {
|
||||
} esp_comm_gpio_hold_t;
|
||||
|
||||
/**
|
||||
* @brief Calculate crc for the OTA data partition.
|
||||
* @brief Calculate crc for the OTA data select.
|
||||
*
|
||||
* @param[in] ota_data The OTA data partition.
|
||||
* @param[in] s The OTA data select.
|
||||
* @return Returns crc value.
|
||||
*/
|
||||
uint32_t bootloader_common_ota_select_crc(const esp_ota_select_entry_t *s);
|
||||
|
||||
/**
|
||||
* @brief Verifies the validity of the OTA data partition
|
||||
* @brief Verifies the validity of the OTA data select
|
||||
*
|
||||
* @param[in] ota_data The OTA data partition.
|
||||
* @param[in] s The OTA data select.
|
||||
* @return Returns true on valid, false otherwise.
|
||||
*/
|
||||
bool bootloader_common_ota_select_valid(const esp_ota_select_entry_t *s);
|
||||
|
||||
/**
|
||||
* @brief Returns true if OTADATA is not marked as bootable partition.
|
||||
*
|
||||
* @param[in] s The OTA data select.
|
||||
* @return Returns true if OTADATA invalid, false otherwise.
|
||||
*/
|
||||
bool bootloader_common_ota_select_invalid(const esp_ota_select_entry_t *s);
|
||||
|
||||
/**
|
||||
* @brief Check if the GPIO input is a long hold or a short hold.
|
||||
*
|
||||
@@ -91,3 +100,27 @@ bool bootloader_common_label_search(const char *list, char *label);
|
||||
* - ESP_FAIL: An allocation error occurred.
|
||||
*/
|
||||
esp_err_t bootloader_common_get_sha256_of_partition(uint32_t address, uint32_t size, int type, uint8_t *out_sha_256);
|
||||
|
||||
/**
|
||||
* @brief Returns the number of active otadata.
|
||||
*
|
||||
* @param[in] two_otadata Pointer on array from two otadata structures.
|
||||
*
|
||||
* @return The number of active otadata (0 or 1).
|
||||
* - -1: If it does not have active otadata.
|
||||
*/
|
||||
int bootloader_common_get_active_otadata(esp_ota_select_entry_t *two_otadata);
|
||||
|
||||
/**
|
||||
* @brief Returns esp_app_desc structure for app partition. This structure includes app version.
|
||||
*
|
||||
* Returns a description for the requested app partition.
|
||||
* @param[in] partition App partition description.
|
||||
* @param[out] app_desc Structure of info about app.
|
||||
* @return
|
||||
* - ESP_OK: Successful.
|
||||
* - ESP_ERR_INVALID_ARG: The arguments passed are not valid.
|
||||
* - ESP_ERR_NOT_FOUND: app_desc structure is not found. Magic word is incorrect.
|
||||
* - ESP_FAIL: mapping is fail.
|
||||
*/
|
||||
esp_err_t bootloader_common_get_partition_description(const esp_partition_pos_t *partition, esp_app_desc_t *app_desc);
|
||||
|
@@ -89,6 +89,25 @@ typedef struct {
|
||||
uint32_t data_len;
|
||||
} esp_image_segment_header_t;
|
||||
|
||||
#define ESP_APP_DESC_MAGIC_WORD 0xABCD5432 /*!< The magic word for the esp_app_desc structure that is in DROM. */
|
||||
|
||||
/**
|
||||
* @brief Description about application.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t magic_word; /*!< Magic word ESP_APP_DESC_MAGIC_WORD */
|
||||
uint32_t secure_version; /*!< Secure version */
|
||||
uint32_t reserv1[2]; /*!< --- */
|
||||
char version[32]; /*!< Application version */
|
||||
char project_name[32]; /*!< Project name */
|
||||
char time[16]; /*!< Compile time */
|
||||
char date[16]; /*!< Compile date*/
|
||||
char idf_ver[32]; /*!< Version IDF */
|
||||
uint8_t app_elf_sha256[32]; /*!< sha256 of elf file */
|
||||
uint32_t reserv2[20]; /*!< --- */
|
||||
} esp_app_desc_t;
|
||||
_Static_assert(sizeof(esp_app_desc_t) == 256, "esp_app_desc_t should be 256 bytes");
|
||||
|
||||
#define ESP_IMAGE_MAX_SEGMENTS 16
|
||||
|
||||
/* Structure to hold on-flash image metadata */
|
||||
|
@@ -29,6 +29,7 @@
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "sys/param.h"
|
||||
|
||||
#define ESP_PARTITION_HASH_LEN 32 /* SHA-256 digest length */
|
||||
|
||||
@@ -39,9 +40,14 @@ uint32_t bootloader_common_ota_select_crc(const esp_ota_select_entry_t *s)
|
||||
return crc32_le(UINT32_MAX, (uint8_t*)&s->ota_seq, 4);
|
||||
}
|
||||
|
||||
bool bootloader_common_ota_select_invalid(const esp_ota_select_entry_t *s)
|
||||
{
|
||||
return s->ota_seq == UINT32_MAX;
|
||||
}
|
||||
|
||||
bool bootloader_common_ota_select_valid(const esp_ota_select_entry_t *s)
|
||||
{
|
||||
return s->ota_seq != UINT32_MAX && s->crc == bootloader_common_ota_select_crc(s);
|
||||
return bootloader_common_ota_select_invalid(s) == false && s->crc == bootloader_common_ota_select_crc(s);
|
||||
}
|
||||
|
||||
esp_comm_gpio_hold_t bootloader_common_check_long_hold_gpio(uint32_t num_pin, uint32_t delay_sec)
|
||||
@@ -192,3 +198,51 @@ esp_err_t bootloader_common_get_sha256_of_partition (uint32_t address, uint32_t
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int bootloader_common_get_active_otadata(esp_ota_select_entry_t *two_otadata)
|
||||
{
|
||||
int active_otadata = -1;
|
||||
|
||||
bool valid_otadata[2];
|
||||
valid_otadata[0] = bootloader_common_ota_select_valid(&two_otadata[0]);
|
||||
valid_otadata[1] = bootloader_common_ota_select_valid(&two_otadata[1]);
|
||||
if (valid_otadata[0] && valid_otadata[1]) {
|
||||
if (MAX(two_otadata[0].ota_seq, two_otadata[1].ota_seq) == two_otadata[0].ota_seq) {
|
||||
active_otadata = 0;
|
||||
} else {
|
||||
active_otadata = 1;
|
||||
}
|
||||
ESP_LOGD(TAG, "Both OTA copies are valid");
|
||||
} else {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (valid_otadata[i]) {
|
||||
active_otadata = i;
|
||||
ESP_LOGD(TAG, "Only otadata[%d] is valid", i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return active_otadata;
|
||||
}
|
||||
|
||||
esp_err_t bootloader_common_get_partition_description(const esp_partition_pos_t *partition, esp_app_desc_t *app_desc)
|
||||
{
|
||||
if (partition == NULL || app_desc == NULL || partition->offset == 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
const uint8_t *image = bootloader_mmap(partition->offset, partition->size);
|
||||
if (image == NULL) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", partition->offset, partition->size);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
memcpy(app_desc, image + sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t), sizeof(esp_app_desc_t));
|
||||
bootloader_munmap(image);
|
||||
|
||||
if (app_desc->magic_word != ESP_APP_DESC_MAGIC_WORD) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@@ -72,6 +72,7 @@ static void wdt_reset_check(void);
|
||||
esp_err_t bootloader_init()
|
||||
{
|
||||
cpu_configure_region_protection();
|
||||
cpu_init_memctl();
|
||||
|
||||
/* Sanity check that static RAM is after the stack */
|
||||
#ifndef NDEBUG
|
||||
|
@@ -67,6 +67,34 @@ static void set_cache_and_start_app(uint32_t drom_addr,
|
||||
uint32_t irom_size,
|
||||
uint32_t entry_addr);
|
||||
|
||||
// Read ota_info partition and fill array from two otadata structures.
|
||||
static esp_err_t read_otadata(const esp_partition_pos_t *ota_info, esp_ota_select_entry_t *two_otadata)
|
||||
{
|
||||
const esp_ota_select_entry_t *ota_select_map;
|
||||
if (ota_info->offset == 0) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
// partition table has OTA data partition
|
||||
if (ota_info->size < 2 * SPI_SEC_SIZE) {
|
||||
ESP_LOGE(TAG, "ota_info partition size %d is too small (minimum %d bytes)", ota_info->size, sizeof(esp_ota_select_entry_t));
|
||||
return ESP_FAIL; // can't proceed
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "OTA data offset 0x%x", ota_info->offset);
|
||||
ota_select_map = bootloader_mmap(ota_info->offset, ota_info->size);
|
||||
if (!ota_select_map) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", ota_info->offset, ota_info->size);
|
||||
return ESP_FAIL; // can't proceed
|
||||
}
|
||||
|
||||
memcpy(&two_otadata[0], ota_select_map, sizeof(esp_ota_select_entry_t));
|
||||
memcpy(&two_otadata[1], (uint8_t *)ota_select_map + SPI_SEC_SIZE, sizeof(esp_ota_select_entry_t));
|
||||
bootloader_munmap(ota_select_map);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
bool bootloader_utility_load_partition_table(bootloader_state_t* bs)
|
||||
{
|
||||
const esp_partition_info_t *partitions;
|
||||
@@ -194,71 +222,48 @@ static void log_invalid_app_partition(int index)
|
||||
|
||||
int bootloader_utility_get_selected_boot_partition(const bootloader_state_t *bs)
|
||||
{
|
||||
esp_ota_select_entry_t sa,sb;
|
||||
const esp_ota_select_entry_t *ota_select_map;
|
||||
esp_ota_select_entry_t otadata[2];
|
||||
int boot_index = FACTORY_INDEX;
|
||||
|
||||
if (bs->ota_info.offset != 0) {
|
||||
// partition table has OTA data partition
|
||||
if (bs->ota_info.size < 2 * SPI_SEC_SIZE) {
|
||||
ESP_LOGE(TAG, "ota_info partition size %d is too small (minimum %d bytes)", bs->ota_info.size, sizeof(esp_ota_select_entry_t));
|
||||
return INVALID_INDEX; // can't proceed
|
||||
if (bs->ota_info.offset == 0) {
|
||||
return FACTORY_INDEX;
|
||||
}
|
||||
|
||||
if (read_otadata(&bs->ota_info, otadata) != ESP_OK) {
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "otadata[0]: sequence values 0x%08x", otadata[0].ota_seq);
|
||||
ESP_LOGD(TAG, "otadata[1]: sequence values 0x%08x", otadata[1].ota_seq);
|
||||
|
||||
if ((bootloader_common_ota_select_invalid(&otadata[0]) &&
|
||||
bootloader_common_ota_select_invalid(&otadata[1])) ||
|
||||
bs->app_count == 0) {
|
||||
ESP_LOGD(TAG, "OTA sequence numbers both empty (all-0xFF) or partition table does not have bootable ota_apps (app_count=%d)", bs->app_count);
|
||||
if (bs->factory.offset != 0) {
|
||||
ESP_LOGI(TAG, "Defaulting to factory image");
|
||||
boot_index = FACTORY_INDEX;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "No factory image, trying OTA 0");
|
||||
boot_index = 0;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "OTA data offset 0x%x", bs->ota_info.offset);
|
||||
ota_select_map = bootloader_mmap(bs->ota_info.offset, bs->ota_info.size);
|
||||
if (!ota_select_map) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", bs->ota_info.offset, bs->ota_info.size);
|
||||
return INVALID_INDEX; // can't proceed
|
||||
}
|
||||
memcpy(&sa, ota_select_map, sizeof(esp_ota_select_entry_t));
|
||||
memcpy(&sb, (uint8_t *)ota_select_map + SPI_SEC_SIZE, sizeof(esp_ota_select_entry_t));
|
||||
bootloader_munmap(ota_select_map);
|
||||
|
||||
ESP_LOGD(TAG, "OTA sequence values A 0x%08x B 0x%08x", sa.ota_seq, sb.ota_seq);
|
||||
if ((sa.ota_seq == UINT32_MAX && sb.ota_seq == UINT32_MAX) || (bs->app_count == 0)) {
|
||||
ESP_LOGD(TAG, "OTA sequence numbers both empty (all-0xFF) or partition table does not have bootable ota_apps (app_count=%d)", bs->app_count);
|
||||
if (bs->factory.offset != 0) {
|
||||
ESP_LOGI(TAG, "Defaulting to factory image");
|
||||
return FACTORY_INDEX;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "No factory image, trying OTA 0");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
bool ota_valid = false;
|
||||
const char *ota_msg;
|
||||
int ota_seq; // Raw OTA sequence number. May be more than # of OTA slots
|
||||
if(bootloader_common_ota_select_valid(&sa) && bootloader_common_ota_select_valid(&sb)) {
|
||||
ota_valid = true;
|
||||
ota_msg = "Both OTA values";
|
||||
ota_seq = MAX(sa.ota_seq, sb.ota_seq) - 1;
|
||||
} else if(bootloader_common_ota_select_valid(&sa)) {
|
||||
ota_valid = true;
|
||||
ota_msg = "Only OTA sequence A is";
|
||||
ota_seq = sa.ota_seq - 1;
|
||||
} else if(bootloader_common_ota_select_valid(&sb)) {
|
||||
ota_valid = true;
|
||||
ota_msg = "Only OTA sequence B is";
|
||||
ota_seq = sb.ota_seq - 1;
|
||||
}
|
||||
|
||||
if (ota_valid) {
|
||||
int ota_slot = ota_seq % bs->app_count; // Actual OTA partition selection
|
||||
ESP_LOGD(TAG, "%s valid. Mapping seq %d -> OTA slot %d", ota_msg, ota_seq, ota_slot);
|
||||
return ota_slot;
|
||||
} else if (bs->factory.offset != 0) {
|
||||
ESP_LOGE(TAG, "ota data partition invalid, falling back to factory");
|
||||
return FACTORY_INDEX;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "ota data partition invalid and no factory, will try all partitions");
|
||||
return FACTORY_INDEX;
|
||||
}
|
||||
} else {
|
||||
int active_otadata = bootloader_common_get_active_otadata(otadata);
|
||||
if (active_otadata != -1) {
|
||||
ESP_LOGD(TAG, "Active OTADATA copy is #%d", active_otadata);
|
||||
uint32_t ota_seq = otadata[active_otadata].ota_seq - 1; // Raw OTA sequence number. May be more than # of OTA slots
|
||||
boot_index = ota_seq % bs->app_count; // Actual OTA partition selection
|
||||
ESP_LOGD(TAG, "Mapping seq %d -> OTA slot %d", ota_seq, boot_index);
|
||||
} else if (bs->factory.offset != 0) {
|
||||
ESP_LOGE(TAG, "ota data partition invalid, falling back to factory");
|
||||
boot_index = FACTORY_INDEX;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "ota data partition invalid and no factory, will try all partitions");
|
||||
boot_index = FACTORY_INDEX;
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise, start from factory app partition and let the search logic
|
||||
// proceed from there
|
||||
return FACTORY_INDEX;
|
||||
return boot_index;
|
||||
}
|
||||
|
||||
/* Return true if a partition has a valid app image that was successfully loaded */
|
||||
|
@@ -281,6 +281,6 @@ if(CONFIG_BT_ENABLED)
|
||||
component_compile_options(-Wno-implicit-fallthrough -Wno-unused-const-variable)
|
||||
endif()
|
||||
|
||||
target_link_libraries(bt "-L${CMAKE_CURRENT_LIST_DIR}/lib")
|
||||
target_link_libraries(bt btdm_app)
|
||||
target_link_libraries(${COMPONENT_TARGET} "-L${CMAKE_CURRENT_LIST_DIR}/lib")
|
||||
target_link_libraries(${COMPONENT_TARGET} btdm_app)
|
||||
endif()
|
||||
|
@@ -124,6 +124,7 @@ config BT_HCI_UART_BAUDRATE
|
||||
default 921600
|
||||
help
|
||||
UART Baudrate for HCI. Please use standard baudrate.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "MODEM SLEEP Options"
|
||||
@@ -238,7 +239,13 @@ config MESH_DUPLICATE_SCAN_CACHE_SIZE
|
||||
Maximum number of adv packets which can be recorded in duplicate scan cache for BLE Mesh.
|
||||
When the maximum amount of device in the filter is reached, the cache will be refreshed.
|
||||
|
||||
|
||||
config BTDM_CONTROLLER_FULL_SCAN_SUPPORTED
|
||||
bool "BLE full scan feature supported"
|
||||
depends on BTDM_CONTROLLER_MODE_BLE_ONLY
|
||||
default n
|
||||
help
|
||||
The full scan function is mainly used to provide BLE scan performance.
|
||||
This is required for scenes with high scan performance requirements, such as BLE Mesh scenes.
|
||||
|
||||
endmenu
|
||||
|
||||
|
@@ -449,6 +449,69 @@ esp_err_t esp_ble_gap_config_scan_rsp_data_raw(uint8_t *raw_data, uint32_t raw_d
|
||||
|
||||
}
|
||||
|
||||
esp_err_t esp_ble_gap_add_duplicate_scan_exceptional_device(esp_ble_duplicate_exceptional_info_type_t type, esp_duplicate_info_t device_info)
|
||||
{
|
||||
btc_msg_t msg;
|
||||
btc_ble_gap_args_t arg;
|
||||
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (!device_info){
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_GAP_BLE;
|
||||
msg.act = BTC_GAP_BLE_UPDATE_DUPLICATE_SCAN_EXCEPTIONAL_LIST;
|
||||
arg.update_duplicate_exceptional_list.subcode = ESP_BLE_DUPLICATE_EXCEPTIONAL_LIST_ADD;
|
||||
arg.update_duplicate_exceptional_list.info_type = type;
|
||||
memcpy(arg.update_duplicate_exceptional_list.device_info, device_info, sizeof(esp_bd_addr_t));
|
||||
|
||||
return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gap_args_t), NULL)
|
||||
== BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
|
||||
esp_err_t esp_ble_gap_remove_duplicate_scan_exceptional_device(esp_ble_duplicate_exceptional_info_type_t type, esp_duplicate_info_t device_info)
|
||||
{
|
||||
btc_msg_t msg;
|
||||
btc_ble_gap_args_t arg;
|
||||
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (!device_info){
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_GAP_BLE;
|
||||
msg.act = BTC_GAP_BLE_UPDATE_DUPLICATE_SCAN_EXCEPTIONAL_LIST;
|
||||
arg.update_duplicate_exceptional_list.subcode = ESP_BLE_DUPLICATE_EXCEPTIONAL_LIST_REMOVE;
|
||||
arg.update_duplicate_exceptional_list.info_type = type;
|
||||
memcpy(arg.update_duplicate_exceptional_list.device_info, device_info, sizeof(esp_bd_addr_t));
|
||||
|
||||
return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gap_args_t), NULL)
|
||||
== BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
|
||||
esp_err_t esp_ble_gap_clean_duplicate_scan_exceptional_list(esp_duplicate_scan_exceptional_list_type_t list_type)
|
||||
{
|
||||
btc_msg_t msg;
|
||||
btc_ble_gap_args_t arg;
|
||||
|
||||
if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_GAP_BLE;
|
||||
msg.act = BTC_GAP_BLE_UPDATE_DUPLICATE_SCAN_EXCEPTIONAL_LIST;
|
||||
arg.update_duplicate_exceptional_list.subcode = ESP_BLE_DUPLICATE_EXCEPTIONAL_LIST_CLEAN;
|
||||
arg.update_duplicate_exceptional_list.info_type = list_type;
|
||||
|
||||
return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gap_args_t), NULL)
|
||||
== BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
|
||||
#if (SMP_INCLUDED == TRUE)
|
||||
esp_err_t esp_ble_gap_set_security_param(esp_ble_sm_param_t param_type,
|
||||
void *value, uint8_t len)
|
||||
@@ -598,6 +661,29 @@ esp_err_t esp_ble_get_bond_device_list(int *dev_num, esp_ble_bond_dev_t *dev_lis
|
||||
|
||||
return (ret == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
|
||||
esp_err_t esp_ble_oob_req_reply(esp_bd_addr_t bd_addr, uint8_t *TK, uint8_t len)
|
||||
{
|
||||
if(len != ESP_BT_OCTET16_LEN) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
btc_ble_gap_args_t arg;
|
||||
|
||||
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_GAP_BLE;
|
||||
msg.act = BTC_GAP_BLE_OOB_REQ_REPLY_EVT;
|
||||
memcpy(arg.oob_req_reply.bd_addr, bd_addr, ESP_BD_ADDR_LEN);
|
||||
arg.oob_req_reply.len = len;
|
||||
arg.oob_req_reply.p_value = TK;
|
||||
|
||||
return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gap_args_t), btc_gap_ble_arg_deep_copy)
|
||||
== BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
|
||||
#endif /* #if (SMP_INCLUDED == TRUE) */
|
||||
|
||||
esp_err_t esp_ble_gap_disconnect(esp_bd_addr_t remote_device)
|
||||
|
@@ -54,6 +54,7 @@ typedef uint8_t esp_ble_key_type_t;
|
||||
#define ESP_LE_AUTH_NO_BOND 0x00 /*!< 0*/ /* relate to BTM_LE_AUTH_NO_BOND in stack/btm_api.h */
|
||||
#define ESP_LE_AUTH_BOND 0x01 /*!< 1 << 0 */ /* relate to BTM_LE_AUTH_BOND in stack/btm_api.h */
|
||||
#define ESP_LE_AUTH_REQ_MITM (1 << 2) /*!< 1 << 2 */ /* relate to BTM_LE_AUTH_REQ_MITM in stack/btm_api.h */
|
||||
#define ESP_LE_AUTH_REQ_BOND_MITM (ESP_LE_AUTH_BOND | ESP_LE_AUTH_REQ_MITM)/*!< 0101*/
|
||||
#define ESP_LE_AUTH_REQ_SC_ONLY (1 << 3) /*!< 1 << 3 */ /* relate to BTM_LE_AUTH_REQ_SC_ONLY in stack/btm_api.h */
|
||||
#define ESP_LE_AUTH_REQ_SC_BOND (ESP_LE_AUTH_BOND | ESP_LE_AUTH_REQ_SC_ONLY) /*!< 1001 */ /* relate to BTM_LE_AUTH_REQ_SC_BOND in stack/btm_api.h */
|
||||
#define ESP_LE_AUTH_REQ_SC_MITM (ESP_LE_AUTH_REQ_MITM | ESP_LE_AUTH_REQ_SC_ONLY) /*!< 1100 */ /* relate to BTM_LE_AUTH_REQ_SC_MITM in stack/btm_api.h */
|
||||
@@ -63,6 +64,9 @@ typedef uint8_t esp_ble_auth_req_t; /*!< combination of the above bit
|
||||
#define ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_DISABLE 0
|
||||
#define ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_ENABLE 1
|
||||
|
||||
#define ESP_BLE_OOB_DISABLE 0
|
||||
#define ESP_BLE_OOB_ENABLE 1
|
||||
|
||||
/* relate to BTM_IO_CAP_xxx in stack/btm_api.h */
|
||||
#define ESP_IO_CAP_OUT 0 /*!< DisplayOnly */ /* relate to BTM_IO_CAP_OUT in stack/btm_api.h */
|
||||
#define ESP_IO_CAP_IO 1 /*!< DisplayYesNo */ /* relate to BTM_IO_CAP_IO in stack/btm_api.h */
|
||||
@@ -161,6 +165,7 @@ typedef enum {
|
||||
ESP_GAP_BLE_GET_BOND_DEV_COMPLETE_EVT, /*!< When get the bond device list complete, the event comes */
|
||||
ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT, /*!< When read the rssi complete, the event comes */
|
||||
ESP_GAP_BLE_UPDATE_WHITELIST_COMPLETE_EVT, /*!< When add or remove whitelist complete, the event comes */
|
||||
ESP_GAP_BLE_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_COMPLETE_EVT, /*!< When update duplicate exceptional list complete, the event comes */
|
||||
ESP_GAP_BLE_EVT_MAX,
|
||||
} esp_gap_ble_cb_event_t;
|
||||
/// This is the old name, just for backwards compatibility
|
||||
@@ -270,6 +275,7 @@ typedef enum {
|
||||
ESP_BLE_SM_SET_STATIC_PASSKEY,
|
||||
ESP_BLE_SM_CLEAR_STATIC_PASSKEY,
|
||||
ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH,
|
||||
ESP_BLE_SM_OOB_SUPPORT,
|
||||
ESP_BLE_SM_MAX_PARAM,
|
||||
} esp_ble_sm_param_t;
|
||||
|
||||
@@ -286,7 +292,7 @@ typedef struct {
|
||||
esp_ble_adv_type_t adv_type; /*!< Advertising type */
|
||||
esp_ble_addr_type_t own_addr_type; /*!< Owner bluetooth device address type */
|
||||
esp_bd_addr_t peer_addr; /*!< Peer device bluetooth device address */
|
||||
esp_ble_addr_type_t peer_addr_type; /*!< Peer device bluetooth device address type */
|
||||
esp_ble_addr_type_t peer_addr_type; /*!< Peer device bluetooth device address type, only support public address type and random address type */
|
||||
esp_ble_adv_channel_t channel_map; /*!< Advertising channel map */
|
||||
esp_ble_adv_filter_t adv_filter_policy; /*!< Advertising filter policy */
|
||||
} esp_ble_adv_params_t;
|
||||
@@ -303,9 +309,9 @@ typedef struct {
|
||||
Value of 0xFFFF indicates no specific minimum.
|
||||
Values not defined above are reserved for future use.*/
|
||||
|
||||
int max_interval; /*!< Advertising data show slave preferred connection max interval.
|
||||
int max_interval; /*!< Advertising data show slave preferred connection max interval.
|
||||
The connection interval in the following manner:
|
||||
connIntervalmax = Conn_Interval_Max * 1.25 ms
|
||||
connIntervalmax = Conn_Interval_Max * 1.25 ms
|
||||
Conn_Interval_Max range: 0x0006 to 0x0C80
|
||||
Conn_Interval_Max shall be equal to or greater than the Conn_Interval_Min.
|
||||
Value of 0xFFFF indicates no specific maximum.
|
||||
@@ -366,8 +372,8 @@ typedef struct {
|
||||
Range: 0x0004 to 0x4000 Default: 0x0010 (10 ms)
|
||||
Time = N * 0.625 msec
|
||||
Time Range: 2.5 msec to 10240 msec */
|
||||
esp_ble_scan_duplicate_t scan_duplicate; /*!< The Scan_Duplicates parameter controls whether the Link Layer should filter out
|
||||
duplicate advertising reports (BLE_SCAN_DUPLICATE_ENABLE) to the Host, or if the Link Layer should generate
|
||||
esp_ble_scan_duplicate_t scan_duplicate; /*!< The Scan_Duplicates parameter controls whether the Link Layer should filter out
|
||||
duplicate advertising reports (BLE_SCAN_DUPLICATE_ENABLE) to the Host, or if the Link Layer should generate
|
||||
advertising reports for each packet received */
|
||||
} esp_ble_scan_params_t;
|
||||
|
||||
@@ -570,6 +576,28 @@ typedef enum{
|
||||
ESP_BLE_WHITELIST_REMOVE = 0X00, /*!< remove mac from whitelist */
|
||||
ESP_BLE_WHITELIST_ADD = 0X01, /*!< add address to whitelist */
|
||||
}esp_ble_wl_opration_t;
|
||||
|
||||
typedef enum {
|
||||
ESP_BLE_DUPLICATE_EXCEPTIONAL_LIST_ADD = 0, /*!< Add device info into duplicate scan exceptional list */
|
||||
ESP_BLE_DUPLICATE_EXCEPTIONAL_LIST_REMOVE, /*!< Remove device info from duplicate scan exceptional list */
|
||||
ESP_BLE_DUPLICATE_EXCEPTIONAL_LIST_CLEAN, /*!< Clean duplicate scan exceptional list */
|
||||
} esp_bt_duplicate_exceptional_subcode_type_t;
|
||||
|
||||
#define BLE_BIT(n) (1UL<<(n))
|
||||
|
||||
typedef enum {
|
||||
ESP_BLE_DUPLICATE_SCAN_EXCEPTIONAL_INFO_ADV_ADDR = 0, /*!< BLE advertising address , device info will be added into ESP_BLE_DUPLICATE_SCAN_EXCEPTIONAL_ADDR_LIST */
|
||||
ESP_BLE_DUPLICATE_SCAN_EXCEPTIONAL_INFO_MESH_LINK_ID, /*!< BLE mesh link ID, it is for BLE mesh, device info will be added into ESP_BLE_DUPLICATE_SCAN_EXCEPTIONAL_MESH_LINK_ID_LIST */
|
||||
} esp_ble_duplicate_exceptional_info_type_t;
|
||||
|
||||
typedef enum {
|
||||
ESP_BLE_DUPLICATE_SCAN_EXCEPTIONAL_ADDR_LIST = BLE_BIT(0), /*!< duplicate scan exceptional addr list */
|
||||
ESP_BLE_DUPLICATE_SCAN_EXCEPTIONAL_MESH_LINK_ID_LIST = BLE_BIT(1), /*!< duplicate scan exceptional mesh link ID list */
|
||||
ESP_BLE_DUPLICATE_SCAN_EXCEPTIONAL_ALL_LIST = (BLE_BIT(0) | BLE_BIT(1)), /*!< duplicate scan exceptional all list */
|
||||
} esp_duplicate_scan_exceptional_list_type_t;
|
||||
|
||||
typedef uint8_t esp_duplicate_info_t[ESP_BD_ADDR_LEN];
|
||||
|
||||
/**
|
||||
* @brief Gap callback parameters union
|
||||
*/
|
||||
@@ -715,6 +743,15 @@ typedef union {
|
||||
esp_bt_status_t status; /*!< Indicate the add or remove whitelist operation success status */
|
||||
esp_ble_wl_opration_t wl_opration; /*!< The value is ESP_BLE_WHITELIST_ADD if add address to whitelist operation success, ESP_BLE_WHITELIST_REMOVE if remove address from the whitelist operation success */
|
||||
} update_whitelist_cmpl; /*!< Event parameter of ESP_GAP_BLE_UPDATE_WHITELIST_COMPLETE_EVT */
|
||||
/**
|
||||
* @brief ESP_GAP_BLE_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_COMPLETE_EVT
|
||||
*/
|
||||
struct ble_update_duplicate_exceptional_list_cmpl_evt_param {
|
||||
esp_bt_status_t status; /*!< Indicate update duplicate scan exceptional list operation success status */
|
||||
uint8_t subcode; /*!< Define in esp_bt_duplicate_exceptional_subcode_type_t */
|
||||
uint16_t length; /*!< The length of device_info */
|
||||
esp_duplicate_info_t device_info; /*!< device information, when subcode is ESP_BLE_DUPLICATE_EXCEPTIONAL_LIST_CLEAN, the value is invalid */
|
||||
} update_duplicate_exceptional_list_cmpl; /*!< Event parameter of ESP_GAP_BLE_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_COMPLETE_EVT */
|
||||
} esp_ble_gap_cb_param_t;
|
||||
|
||||
/**
|
||||
@@ -962,8 +999,7 @@ esp_err_t esp_ble_gap_get_local_used_addr(esp_bd_addr_t local_used_addr, uint8_t
|
||||
* @param[in] type - finding ADV data type
|
||||
* @param[out] length - return the length of ADV data not including type
|
||||
*
|
||||
* @return - ESP_OK : success
|
||||
* - other : failed
|
||||
* @return pointer of ADV data
|
||||
*
|
||||
*/
|
||||
uint8_t *esp_ble_resolve_adv_data(uint8_t *adv_data, uint8_t type, uint8_t *length);
|
||||
@@ -1008,6 +1044,43 @@ esp_err_t esp_ble_gap_config_scan_rsp_data_raw(uint8_t *raw_data, uint32_t raw_d
|
||||
*/
|
||||
esp_err_t esp_ble_gap_read_rssi(esp_bd_addr_t remote_addr);
|
||||
|
||||
/**
|
||||
* @brief This function is called to add a device info into the duplicate scan exceptional list.
|
||||
*
|
||||
*
|
||||
* @param[in] type: device info type, it is defined in esp_ble_duplicate_exceptional_info_type_t
|
||||
* @param[in] device_info: the device information.
|
||||
* @return
|
||||
* - ESP_OK : success
|
||||
* - other : failed
|
||||
*/
|
||||
esp_err_t esp_ble_gap_add_duplicate_scan_exceptional_device(esp_ble_duplicate_exceptional_info_type_t type, esp_duplicate_info_t device_info);
|
||||
|
||||
/**
|
||||
* @brief This function is called to remove a device info from the duplicate scan exceptional list.
|
||||
*
|
||||
*
|
||||
* @param[in] type: device info type, it is defined in esp_ble_duplicate_exceptional_info_type_t
|
||||
* @param[in] device_info: the device information.
|
||||
* @return
|
||||
* - ESP_OK : success
|
||||
* - other : failed
|
||||
*/
|
||||
esp_err_t esp_ble_gap_remove_duplicate_scan_exceptional_device(esp_ble_duplicate_exceptional_info_type_t type, esp_duplicate_info_t device_info);
|
||||
|
||||
/**
|
||||
* @brief This function is called to clean the duplicate scan exceptional list.
|
||||
* This API will delete all device information in the duplicate scan exceptional list.
|
||||
*
|
||||
*
|
||||
* @param[in] list_type: duplicate scan exceptional list type, the value can be one or more of esp_duplicate_scan_exceptional_list_type_t.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : success
|
||||
* - other : failed
|
||||
*/
|
||||
esp_err_t esp_ble_gap_clean_duplicate_scan_exceptional_list(esp_duplicate_scan_exceptional_list_type_t list_type);
|
||||
|
||||
#if (SMP_INCLUDED == TRUE)
|
||||
/**
|
||||
* @brief Set a GAP security parameter value. Overrides the default value.
|
||||
@@ -1116,6 +1189,20 @@ int esp_ble_get_bond_device_num(void);
|
||||
*/
|
||||
esp_err_t esp_ble_get_bond_device_list(int *dev_num, esp_ble_bond_dev_t *dev_list);
|
||||
|
||||
/**
|
||||
* @brief This function is called to provide the OOB data for
|
||||
* SMP in response to ESP_GAP_BLE_OOB_REQ_EVT
|
||||
*
|
||||
* @param[in] bd_addr: BD address of the peer device.
|
||||
* @param[in] TK: TK value, the TK value shall be a 128-bit random number
|
||||
* @param[in] len: length of tk, should always be 128-bit
|
||||
*
|
||||
* @return - ESP_OK : success
|
||||
* - other : failed
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_ble_oob_req_reply(esp_bd_addr_t bd_addr, uint8_t *TK, uint8_t len);
|
||||
|
||||
#endif /* #if (SMP_INCLUDED == TRUE) */
|
||||
|
||||
/**
|
||||
|
@@ -251,9 +251,9 @@ typedef union {
|
||||
} esp_hf_client_cb_param_t;
|
||||
|
||||
/**
|
||||
* @brief HFP client incoming data callback function, the callback is useful in case of
|
||||
* @brief HFP client incoming data callback function, the callback is useful in case of
|
||||
* Voice Over HCI.
|
||||
* @param[in] buf : pointer to incoming data(payload of HCI synchronous data packet), the
|
||||
* @param[in] buf : pointer to incoming data(payload of HCI synchronous data packet), the
|
||||
* buffer is allocated inside bluetooth protocol stack and will be released after
|
||||
* invoke of the callback is finished.
|
||||
* @param[in] len : size(in bytes) in buf
|
||||
@@ -261,13 +261,13 @@ typedef union {
|
||||
typedef void (* esp_hf_client_incoming_data_cb_t)(const uint8_t *buf, uint32_t len);
|
||||
|
||||
/**
|
||||
* @brief HFP client outgoing data callback function, the callback is useful in case of
|
||||
* Voice Over HCI. Once audio connection is set up and the application layer has
|
||||
* prepared data to send, the lower layer will call this function to read data
|
||||
* @brief HFP client outgoing data callback function, the callback is useful in case of
|
||||
* Voice Over HCI. Once audio connection is set up and the application layer has
|
||||
* prepared data to send, the lower layer will call this function to read data
|
||||
* and then send. This callback is supposed to be implemented as non-blocking,
|
||||
* and if data is not enough, return value 0 is supposed.
|
||||
*
|
||||
* @param[in] buf : pointer to incoming data(payload of HCI synchronous data packet), the
|
||||
*
|
||||
* @param[in] buf : pointer to incoming data(payload of HCI synchronous data packet), the
|
||||
* buffer is allocated inside bluetooth protocol stack and will be released after
|
||||
* invoke of the callback is finished.
|
||||
* @param[in] len : size(in bytes) in buf
|
||||
@@ -326,7 +326,7 @@ esp_err_t esp_hf_client_deinit(void);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Connect to remote bluetooth HFP audio gateway(AG) device, must after esp_a2d_hf_client_init()
|
||||
* @brief Connect to remote bluetooth HFP audio gateway(AG) device, must after esp_hf_client_init()
|
||||
*
|
||||
* @param[in] remote_bda: remote bluetooth device address
|
||||
*
|
||||
@@ -606,7 +606,7 @@ void esp_hf_client_outgoing_data_ready(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize the down sampling converter. This is a utility function that can
|
||||
* only be used in the case that Voice Over HCI is enabled.
|
||||
* only be used in the case that Voice Over HCI is enabled.
|
||||
*
|
||||
* @param[in] src_sps: original samples per second(source audio data, i.e. 48000, 32000,
|
||||
* 16000, 44100, 22050, 11025)
|
||||
|
@@ -190,8 +190,7 @@ esp_err_t esp_spp_register_callback(esp_spp_cb_t callback);
|
||||
/**
|
||||
* @brief This function is called to init SPP.
|
||||
*
|
||||
* @param[in] mode: Choose the mode of SPP, ESP_SPP_MODE_CB or ESP_SPP_MODE_CB.
|
||||
* Now only supports ESP_SPP_MODE_CB mode, we will continue to update.
|
||||
* @param[in] mode: Choose the mode of SPP, ESP_SPP_MODE_CB or ESP_SPP_MODE_VFS.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
|
@@ -1150,6 +1150,21 @@ void bta_dm_loc_oob(tBTA_DM_MSG *p_data)
|
||||
BTM_ReadLocalOobData();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_dm_oob_reply
|
||||
**
|
||||
** Description This function is called to provide the OOB data for
|
||||
** SMP in response to BLE OOB request.
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void bta_dm_oob_reply(tBTA_DM_MSG *p_data)
|
||||
{
|
||||
BTM_BleOobDataReply(p_data->oob_reply.bd_addr, BTM_SUCCESS, p_data->oob_reply.len, p_data->oob_reply.value);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_dm_ci_io_req_act
|
||||
@@ -4604,14 +4619,25 @@ void bta_dm_ble_set_scan_params(tBTA_DM_MSG *p_data)
|
||||
*******************************************************************************/
|
||||
void bta_dm_ble_set_scan_fil_params(tBTA_DM_MSG *p_data)
|
||||
{
|
||||
BTM_BleSetScanFilterParams (p_data->ble_set_scan_fil_params.client_if,
|
||||
tBTA_STATUS status = BTA_FAILURE;
|
||||
|
||||
if (BTM_BleSetScanFilterParams (p_data->ble_set_scan_fil_params.client_if,
|
||||
p_data->ble_set_scan_fil_params.scan_int,
|
||||
p_data->ble_set_scan_fil_params.scan_window,
|
||||
p_data->ble_set_scan_fil_params.scan_mode,
|
||||
p_data->ble_set_scan_fil_params.addr_type_own,
|
||||
p_data->ble_set_scan_fil_params.scan_duplicate_filter,
|
||||
p_data->ble_set_scan_fil_params.scan_filter_policy,
|
||||
p_data->ble_set_scan_fil_params.scan_param_setup_cback);
|
||||
p_data->ble_set_scan_fil_params.scan_param_setup_cback) == BTM_SUCCESS) {
|
||||
status = BTA_SUCCESS;
|
||||
|
||||
} else {
|
||||
APPL_TRACE_ERROR("%s(), fail to set scan params.", __func__);
|
||||
}
|
||||
if (p_data->ble_set_scan_fil_params.scan_param_setup_cback != NULL) {
|
||||
p_data->ble_set_scan_fil_params.scan_param_setup_cback(p_data->ble_set_scan_fil_params.client_if, status);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -4854,7 +4880,8 @@ void bta_dm_ble_set_adv_params (tBTA_DM_MSG *p_data)
|
||||
*******************************************************************************/
|
||||
void bta_dm_ble_set_adv_params_all (tBTA_DM_MSG *p_data)
|
||||
{
|
||||
if (BTM_BleSetAdvParamsStartAdv(p_data->ble_set_adv_params_all.adv_int_min,
|
||||
tBTA_STATUS status = BTA_FAILURE;
|
||||
if (BTM_BleSetAdvParamsAll(p_data->ble_set_adv_params_all.adv_int_min,
|
||||
p_data->ble_set_adv_params_all.adv_int_max,
|
||||
p_data->ble_set_adv_params_all.adv_type,
|
||||
p_data->ble_set_adv_params_all.addr_type_own,
|
||||
@@ -4862,10 +4889,36 @@ void bta_dm_ble_set_adv_params_all (tBTA_DM_MSG *p_data)
|
||||
p_data->ble_set_adv_params_all.channel_map,
|
||||
p_data->ble_set_adv_params_all.adv_filter_policy,
|
||||
p_data->ble_set_adv_params_all.p_start_adv_cback) == BTM_SUCCESS) {
|
||||
APPL_TRACE_DEBUG("%s(), success to start ble adv.", __func__);
|
||||
APPL_TRACE_DEBUG("%s(), success to set ble adv params.", __func__);
|
||||
} else {
|
||||
APPL_TRACE_ERROR("%s(), fail to start ble adv.", __func__);
|
||||
APPL_TRACE_ERROR("%s(), fail to set ble adv params.", __func__);
|
||||
if(p_data->ble_set_adv_params_all.p_start_adv_cback) {
|
||||
(*p_data->ble_set_adv_params_all.p_start_adv_cback)(status);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(BTM_BleStartAdv() == BTM_SUCCESS) {
|
||||
status = BTA_SUCCESS;
|
||||
}
|
||||
if(p_data->ble_set_adv_params_all.p_start_adv_cback) {
|
||||
(*p_data->ble_set_adv_params_all.p_start_adv_cback)(status);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_dm_ble_update_duplicate_exceptional_list
|
||||
**
|
||||
** Description This function is to update duplicate scan exceptional list
|
||||
**
|
||||
**
|
||||
*******************************************************************************/
|
||||
void bta_dm_ble_update_duplicate_exceptional_list(tBTA_DM_MSG *p_data)
|
||||
{
|
||||
BTM_UpdateBleDuplicateExceptionalList(p_data->ble_duplicate_exceptional_list.subcode,
|
||||
p_data->ble_duplicate_exceptional_list.type,
|
||||
p_data->ble_duplicate_exceptional_list.device_info,
|
||||
p_data->ble_duplicate_exceptional_list.exceptional_list_cb);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -4891,6 +4944,29 @@ void bta_dm_ble_set_adv_config (tBTA_DM_MSG *p_data)
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_dm_ble_set_long_adv
|
||||
**
|
||||
** Description This function set the long ADV data
|
||||
**
|
||||
** Parameters:
|
||||
**
|
||||
*******************************************************************************/
|
||||
void bta_dm_ble_set_long_adv (tBTA_DM_MSG *p_data)
|
||||
{
|
||||
tBTA_STATUS status = BTA_FAILURE;
|
||||
|
||||
if (BTM_BleWriteLongAdvData(p_data->ble_set_long_adv_data.adv_data,
|
||||
p_data->ble_set_long_adv_data.adv_data_len) == BTM_SUCCESS) {
|
||||
status = BTA_SUCCESS;
|
||||
}
|
||||
|
||||
if (p_data->ble_set_adv_data.p_adv_data_cback) {
|
||||
(*p_data->ble_set_adv_data.p_adv_data_cback)(status);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bta_dm_ble_set_adv_config_raw
|
||||
@@ -5006,16 +5082,17 @@ void bta_dm_ble_set_data_length(tBTA_DM_MSG *p_data)
|
||||
*******************************************************************************/
|
||||
void bta_dm_ble_broadcast (tBTA_DM_MSG *p_data)
|
||||
{
|
||||
tBTM_STATUS status = 0;
|
||||
tBTA_STATUS status = BTA_FAILURE;
|
||||
BOOLEAN start = p_data->ble_observe.start;
|
||||
|
||||
status = BTM_BleBroadcast(start, p_data->ble_observe.p_stop_adv_cback);
|
||||
if (BTM_BleBroadcast(start, p_data->ble_observe.p_stop_adv_cback) == BTM_SUCCESS) {
|
||||
status = BTA_SUCCESS;
|
||||
} else {
|
||||
APPL_TRACE_ERROR("%s failed\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
if (p_data->ble_observe.p_stop_adv_cback){
|
||||
if (status != BTM_SUCCESS){
|
||||
APPL_TRACE_WARNING("%s, %s, status=0x%x\n", __func__,\
|
||||
(start == TRUE) ? "start adv failed" : "stop adv failed", status);
|
||||
}
|
||||
(*p_data->ble_observe.p_stop_adv_cback)(status);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -510,6 +510,36 @@ void BTA_DmLocalOob(void)
|
||||
bta_sys_sendmsg(p_msg);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_DmOobReply
|
||||
**
|
||||
** This function is called to provide the OOB data for
|
||||
** SMP in response to BTM_LE_OOB_REQ_EVT
|
||||
**
|
||||
** Parameters: bd_addr - Address of the peer device
|
||||
** len - length of simple pairing Randomizer C
|
||||
** p_value - simple pairing Randomizer C.
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_DmOobReply(BD_ADDR bd_addr, UINT8 len, UINT8 *p_value)
|
||||
{
|
||||
tBTA_DM_API_OOB_REPLY *p_msg;
|
||||
|
||||
if ((p_msg = (tBTA_DM_API_OOB_REPLY *) osi_malloc(sizeof(tBTA_DM_API_OOB_REPLY))) != NULL) {
|
||||
p_msg->hdr.event = BTA_DM_API_OOB_REPLY_EVT;
|
||||
if(p_value == NULL || len > BT_OCTET16_LEN) {
|
||||
return;
|
||||
}
|
||||
memcpy(p_msg->bd_addr, bd_addr, BD_ADDR_LEN);
|
||||
p_msg->len = len;
|
||||
memcpy(p_msg->value, p_value, len);
|
||||
bta_sys_sendmsg(p_msg);
|
||||
}
|
||||
}
|
||||
#endif /* BTM_OOB_INCLUDED */
|
||||
/*******************************************************************************
|
||||
**
|
||||
@@ -1200,6 +1230,35 @@ void BTA_DmBleSetAdvConfigRaw (UINT8 *p_raw_adv, UINT32 raw_adv_len,
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_DmBleSetLongAdv
|
||||
**
|
||||
** Description This function is called to set long Advertising data
|
||||
**
|
||||
** Parameters adv_data : long advertising data.
|
||||
** adv_data_len : long advertising data length.
|
||||
** p_adv_data_cback : set long adv data complete callback.
|
||||
**
|
||||
** Returns None
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_DmBleSetLongAdv (UINT8 *adv_data, UINT32 adv_data_len,
|
||||
tBTA_SET_ADV_DATA_CMPL_CBACK *p_adv_data_cback)
|
||||
{
|
||||
tBTA_DM_API_SET_LONG_ADV *p_msg;
|
||||
|
||||
if ((p_msg = (tBTA_DM_API_SET_LONG_ADV *)
|
||||
osi_malloc(sizeof(tBTA_DM_API_SET_LONG_ADV))) != NULL) {
|
||||
p_msg->hdr.event = BTA_DM_API_BLE_SET_LONG_ADV_EVT;
|
||||
p_msg->p_adv_data_cback = p_adv_data_cback;
|
||||
p_msg->adv_data = adv_data;
|
||||
p_msg->adv_data_len = adv_data_len;
|
||||
|
||||
bta_sys_sendmsg(p_msg);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_DmBleSetScanRsp
|
||||
@@ -1256,6 +1315,34 @@ void BTA_DmBleSetScanRspRaw (UINT8 *p_raw_scan_rsp, UINT32 raw_scan_rsp_len,
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_DmUpdateDuplicateExceptionalList
|
||||
**
|
||||
** Description This function is called to update duplicate scan exceptional list
|
||||
**
|
||||
** Parameters subcode : add, remove or clean duplicate scan exceptional list.
|
||||
** type : device info type.
|
||||
** device_info: device info
|
||||
** p_update_duplicate_ignore_list_cback : update complete callback.
|
||||
**
|
||||
** Returns None
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_DmUpdateDuplicateExceptionalList(UINT8 subcode, UINT32 type, BD_ADDR device_info, tBTA_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_CMPL_CBACK p_update_duplicate_exceptional_list_cback)
|
||||
{
|
||||
tBTA_DM_API_UPDATE_DUPLICATE_EXCEPTIONAL_LIST *p_msg;
|
||||
if ((p_msg = (tBTA_DM_API_UPDATE_DUPLICATE_EXCEPTIONAL_LIST *)osi_malloc(sizeof(tBTA_DM_API_UPDATE_DUPLICATE_EXCEPTIONAL_LIST))) != NULL) {
|
||||
p_msg->hdr.event = BTA_DM_API_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_EVT;
|
||||
p_msg->subcode = subcode;
|
||||
p_msg->type = type;
|
||||
p_msg->exceptional_list_cb = p_update_duplicate_exceptional_list_cback;
|
||||
memcpy(p_msg->device_info, device_info, sizeof(BD_ADDR));
|
||||
|
||||
bta_sys_sendmsg(p_msg);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_DmBleSetStorageParams
|
||||
|
@@ -35,6 +35,9 @@
|
||||
#define BTM_BLE_ONLY_ACCEPT_SPECIFIED_SEC_AUTH_DISABLE 0
|
||||
#define BTM_BLE_ONLY_ACCEPT_SPECIFIED_SEC_AUTH_ENABLE 1
|
||||
|
||||
#define BTM_BLE_OOB_DISABLE 0
|
||||
#define BTM_BLE_OOB_ENABLE 1
|
||||
|
||||
tBTE_APPL_CFG bte_appl_cfg = {
|
||||
#if SMP_INCLUDED == TRUE
|
||||
BTA_LE_AUTH_REQ_SC_MITM_BOND, // Authentication requirements
|
||||
@@ -45,7 +48,8 @@ tBTE_APPL_CFG bte_appl_cfg = {
|
||||
BTM_BLE_INITIATOR_KEY_SIZE,
|
||||
BTM_BLE_RESPONDER_KEY_SIZE,
|
||||
BTM_BLE_MAX_KEY_SIZE,
|
||||
BTM_BLE_ONLY_ACCEPT_SPECIFIED_SEC_AUTH_DISABLE
|
||||
BTM_BLE_ONLY_ACCEPT_SPECIFIED_SEC_AUTH_DISABLE,
|
||||
BTM_BLE_OOB_DISABLE,
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -338,12 +342,16 @@ void bta_dm_co_ble_io_req(BD_ADDR bd_addr, tBTA_IO_CAP *p_io_cap,
|
||||
* If the answer can not be obtained right away,
|
||||
* set *p_oob_data to BTA_OOB_UNKNOWN and call bta_dm_ci_io_req() when the answer is available */
|
||||
|
||||
*p_oob_data = FALSE;
|
||||
*p_oob_data = bte_appl_cfg.oob_support;
|
||||
|
||||
/* *p_auth_req by default is FALSE for devices with NoInputNoOutput; TRUE for other devices. */
|
||||
|
||||
*p_auth_req = bte_appl_cfg.ble_auth_req | (bte_appl_cfg.ble_auth_req & BTA_LE_AUTH_REQ_MITM) | ((*p_auth_req) & BTA_LE_AUTH_REQ_MITM);
|
||||
|
||||
if (*p_oob_data == BTM_BLE_OOB_ENABLE) {
|
||||
*p_auth_req = (*p_auth_req)&(~BTA_LE_AUTH_REQ_SC_ONLY);
|
||||
}
|
||||
|
||||
if (bte_appl_cfg.ble_io_cap <= 4) {
|
||||
*p_io_cap = bte_appl_cfg.ble_io_cap;
|
||||
}
|
||||
@@ -433,5 +441,16 @@ UINT8 bta_dm_co_ble_get_auth_req(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bta_dm_co_ble_oob_support(UINT8 enable)
|
||||
{
|
||||
#if (SMP_INCLUDED == TRUE)
|
||||
if (enable) {
|
||||
bte_appl_cfg.oob_support = BTM_BLE_OOB_ENABLE;
|
||||
} else {
|
||||
bte_appl_cfg.oob_support = BTM_BLE_OOB_DISABLE;
|
||||
}
|
||||
#endif ///SMP_INCLUDED == TRUE
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -82,6 +82,7 @@ const tBTA_DM_ACTION bta_dm_action[BTA_DM_MAX_EVT] = {
|
||||
#endif ///SMP_INCLUDED == TRUE
|
||||
#if (BTM_OOB_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
|
||||
bta_dm_loc_oob, /* BTA_DM_API_LOC_OOB_EVT */
|
||||
bta_dm_oob_reply, /* BTA_DM_API_OOB_REPLY_EVT */
|
||||
bta_dm_ci_io_req_act, /* BTA_DM_CI_IO_REQ_EVT */
|
||||
bta_dm_ci_rmt_oob_act, /* BTA_DM_CI_RMT_OOB_EVT */
|
||||
#endif /* BTM_OOB_INCLUDED */
|
||||
@@ -130,6 +131,7 @@ const tBTA_DM_ACTION bta_dm_action[BTA_DM_MAX_EVT] = {
|
||||
bta_dm_ble_set_scan_rsp_raw, /* BTA_DM_API_BLE_SET_SCAN_RSP_RAW_EVT */
|
||||
bta_dm_ble_broadcast, /* BTA_DM_API_BLE_BROADCAST_EVT */
|
||||
bta_dm_ble_set_data_length, /* BTA_DM_API_SET_DATA_LENGTH_EVT */
|
||||
bta_dm_ble_set_long_adv, /* BTA_DM_API_BLE_SET_LONG_ADV_EVT */
|
||||
#if BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE
|
||||
bta_dm_cfg_filter_cond, /* BTA_DM_API_CFG_FILTER_COND_EVT */
|
||||
bta_dm_scan_filter_param_setup, /* BTA_DM_API_SCAN_FILTER_SETUP_EVT */
|
||||
@@ -157,6 +159,7 @@ const tBTA_DM_ACTION bta_dm_action[BTA_DM_MAX_EVT] = {
|
||||
bta_dm_update_white_list, /* BTA_DM_API_UPDATE_WHITE_LIST_EVT */
|
||||
bta_dm_ble_read_adv_tx_power, /* BTA_DM_API_BLE_READ_ADV_TX_POWER_EVT */
|
||||
bta_dm_ble_read_rssi, /* BTA_DM_API_BLE_READ_RSSI_EVT */
|
||||
bta_dm_ble_update_duplicate_exceptional_list,/* BTA_DM_API_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_EVT */
|
||||
};
|
||||
|
||||
|
||||
|
@@ -79,6 +79,7 @@ enum {
|
||||
#endif ///SMP_INCLUDED == TRUE
|
||||
#if (BTM_OOB_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
|
||||
BTA_DM_API_LOC_OOB_EVT,
|
||||
BTA_DM_API_OOB_REPLY_EVT,
|
||||
BTA_DM_CI_IO_REQ_EVT,
|
||||
BTA_DM_CI_RMT_OOB_EVT,
|
||||
#endif /* BTM_OOB_INCLUDED */
|
||||
@@ -127,7 +128,7 @@ enum {
|
||||
BTA_DM_API_BLE_SET_SCAN_RSP_RAW_EVT,
|
||||
BTA_DM_API_BLE_BROADCAST_EVT,
|
||||
BTA_DM_API_SET_DATA_LENGTH_EVT,
|
||||
|
||||
BTA_DM_API_BLE_SET_LONG_ADV_EVT,
|
||||
#if BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE
|
||||
BTA_DM_API_CFG_FILTER_COND_EVT,
|
||||
BTA_DM_API_SCAN_FILTER_SETUP_EVT,
|
||||
@@ -155,6 +156,7 @@ enum {
|
||||
BTA_DM_API_UPDATE_WHITE_LIST_EVT,
|
||||
BTA_DM_API_BLE_READ_ADV_TX_POWER_EVT,
|
||||
BTA_DM_API_BLE_READ_RSSI_EVT,
|
||||
BTA_DM_API_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_EVT,
|
||||
BTA_DM_MAX_EVT
|
||||
};
|
||||
|
||||
@@ -193,6 +195,14 @@ typedef struct {
|
||||
tBTA_ADD_WHITELIST_CBACK *add_wl_cb;
|
||||
}tBTA_DM_API_UPDATE_WHITE_LIST;
|
||||
|
||||
typedef struct {
|
||||
BT_HDR hdr;
|
||||
UINT8 subcode;
|
||||
UINT32 type;
|
||||
BD_ADDR device_info;
|
||||
tBTA_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_CMPL_CBACK *exceptional_list_cb;
|
||||
}tBTA_DM_API_UPDATE_DUPLICATE_EXCEPTIONAL_LIST;
|
||||
|
||||
typedef struct {
|
||||
BT_HDR hdr;
|
||||
tBTA_CMPL_CB *read_tx_power_cb;
|
||||
@@ -298,6 +308,14 @@ typedef struct {
|
||||
BT_HDR hdr;
|
||||
} tBTA_DM_API_LOC_OOB;
|
||||
|
||||
/* data type for BTA_DM_API_OOB_REPLY_EVT */
|
||||
typedef struct {
|
||||
BT_HDR hdr;
|
||||
BD_ADDR bd_addr;
|
||||
UINT8 len;
|
||||
UINT8 value[BT_OCTET16_LEN];
|
||||
} tBTA_DM_API_OOB_REPLY;
|
||||
|
||||
/* data type for BTA_DM_API_CONFIRM_EVT */
|
||||
typedef struct {
|
||||
BT_HDR hdr;
|
||||
@@ -647,6 +665,13 @@ typedef struct {
|
||||
tBTA_SET_ADV_DATA_CMPL_CBACK *p_adv_data_cback;
|
||||
} tBTA_DM_API_SET_ADV_CONFIG_RAW;
|
||||
|
||||
typedef struct {
|
||||
BT_HDR hdr;
|
||||
UINT8 *adv_data;
|
||||
UINT8 adv_data_len;
|
||||
tBTA_SET_ADV_DATA_CMPL_CBACK *p_adv_data_cback;
|
||||
} tBTA_DM_API_SET_LONG_ADV;
|
||||
|
||||
typedef struct {
|
||||
BT_HDR hdr;
|
||||
UINT8 batch_scan_full_max;
|
||||
@@ -779,6 +804,7 @@ typedef union {
|
||||
tBTA_DM_API_PIN_REPLY pin_reply;
|
||||
|
||||
tBTA_DM_API_LOC_OOB loc_oob;
|
||||
tBTA_DM_API_OOB_REPLY oob_reply;
|
||||
tBTA_DM_API_CONFIRM confirm;
|
||||
tBTA_DM_API_KEY_REQ key_req;
|
||||
tBTA_DM_CI_IO_REQ ci_io_req;
|
||||
@@ -826,6 +852,7 @@ typedef union {
|
||||
tBTA_DM_API_BLE_ADV_PARAMS_ALL ble_set_adv_params_all;
|
||||
tBTA_DM_API_SET_ADV_CONFIG ble_set_adv_data;
|
||||
tBTA_DM_API_SET_ADV_CONFIG_RAW ble_set_adv_data_raw;
|
||||
tBTA_DM_API_SET_LONG_ADV ble_set_long_adv_data;
|
||||
#if BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE
|
||||
tBTA_DM_API_SCAN_FILTER_PARAM_SETUP ble_scan_filt_param_setup;
|
||||
tBTA_DM_API_CFG_FILTER_COND ble_cfg_filter_cond;
|
||||
@@ -847,6 +874,7 @@ typedef union {
|
||||
tBTA_DM_API_TRACK_ADVERTISER ble_track_advert;
|
||||
tBTA_DM_API_ENERGY_INFO ble_energy_info;
|
||||
tBTA_DM_API_BLE_DISCONNECT ble_disconnect;
|
||||
tBTA_DM_API_UPDATE_DUPLICATE_EXCEPTIONAL_LIST ble_duplicate_exceptional_list;
|
||||
#endif
|
||||
|
||||
tBTA_DM_API_REMOVE_ACL remove_acl;
|
||||
@@ -1237,12 +1265,13 @@ extern void bta_dm_ble_config_local_icon (tBTA_DM_MSG *p_data);
|
||||
extern void bta_dm_ble_set_adv_params (tBTA_DM_MSG *p_data);
|
||||
extern void bta_dm_ble_set_adv_params_all(tBTA_DM_MSG *p_data);
|
||||
extern void bta_dm_ble_set_adv_config (tBTA_DM_MSG *p_data);
|
||||
extern void bta_dm_ble_set_long_adv (tBTA_DM_MSG *p_data);
|
||||
extern void bta_dm_ble_set_adv_config_raw (tBTA_DM_MSG *p_data);
|
||||
extern void bta_dm_ble_set_scan_rsp (tBTA_DM_MSG *p_data);
|
||||
extern void bta_dm_ble_set_scan_rsp_raw (tBTA_DM_MSG *p_data);
|
||||
extern void bta_dm_ble_broadcast (tBTA_DM_MSG *p_data);
|
||||
extern void bta_dm_ble_set_data_length(tBTA_DM_MSG *p_data);
|
||||
|
||||
extern void bta_dm_ble_update_duplicate_exceptional_list(tBTA_DM_MSG *p_data);
|
||||
#if BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE
|
||||
extern void bta_dm_cfg_filter_cond (tBTA_DM_MSG *p_data);
|
||||
extern void bta_dm_scan_filter_param_setup (tBTA_DM_MSG *p_data);
|
||||
@@ -1266,6 +1295,7 @@ extern void bta_dm_confirm(tBTA_DM_MSG *p_data);
|
||||
extern void bta_dm_key_req(tBTA_DM_MSG *p_data);
|
||||
#if (BTM_OOB_INCLUDED == TRUE)
|
||||
extern void bta_dm_loc_oob(tBTA_DM_MSG *p_data);
|
||||
extern void bta_dm_oob_reply(tBTA_DM_MSG *p_data);
|
||||
extern void bta_dm_ci_io_req_act(tBTA_DM_MSG *p_data);
|
||||
extern void bta_dm_ci_rmt_oob_act(tBTA_DM_MSG *p_data);
|
||||
#endif /* BTM_OOB_INCLUDED */
|
||||
|
@@ -691,16 +691,25 @@ void bta_gatts_indicate_handle (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg)
|
||||
p_rcb && p_cb->rcb[p_srvc_cb->rcb_idx].p_cback) {
|
||||
cb_data.req_data.status = status;
|
||||
cb_data.req_data.conn_id = p_msg->api_indicate.hdr.layer_specific;
|
||||
cb_data.req_data.value = NULL;
|
||||
cb_data.req_data.data_len = 0;
|
||||
cb_data.req_data.handle = p_msg->api_indicate.attr_id;
|
||||
|
||||
cb_data.req_data.value = (uint8_t *)osi_malloc(p_msg->api_indicate.len);
|
||||
if (cb_data.req_data.value != NULL){
|
||||
memset(cb_data.req_data.value, 0, p_msg->api_indicate.len);
|
||||
cb_data.req_data.data_len = p_msg->api_indicate.len;
|
||||
memcpy(cb_data.req_data.value, p_msg->api_indicate.value, p_msg->api_indicate.len);
|
||||
}else{
|
||||
cb_data.req_data.data_len = 0;
|
||||
APPL_TRACE_ERROR("%s, malloc failed", __func__);
|
||||
if (p_msg->api_indicate.value && (p_msg->api_indicate.len > 0)) {
|
||||
cb_data.req_data.value = (uint8_t *) osi_malloc(p_msg->api_indicate.len);
|
||||
if (cb_data.req_data.value != NULL) {
|
||||
memset(cb_data.req_data.value, 0, p_msg->api_indicate.len);
|
||||
cb_data.req_data.data_len = p_msg->api_indicate.len;
|
||||
memcpy(cb_data.req_data.value, p_msg->api_indicate.value, p_msg->api_indicate.len);
|
||||
} else {
|
||||
APPL_TRACE_ERROR("%s, malloc failed", __func__);
|
||||
}
|
||||
} else {
|
||||
if (p_msg->api_indicate.value) {
|
||||
APPL_TRACE_ERROR("%s, incorrect length", __func__);
|
||||
} else {
|
||||
APPL_TRACE_WARNING("%s, NULL value", __func__);
|
||||
}
|
||||
}
|
||||
(*p_rcb->p_cback)(BTA_GATTS_CONF_EVT, &cb_data);
|
||||
if (cb_data.req_data.value != NULL) {
|
||||
|
@@ -399,6 +399,8 @@ typedef struct {
|
||||
UINT8 tx_power;
|
||||
} tBTA_BLE_ADV_DATA;
|
||||
|
||||
typedef void (tBTA_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_CMPL_CBACK) (tBTA_STATUS status, uint8_t subcode, uint32_t length, uint8_t *device_info);
|
||||
|
||||
typedef void (tBTA_SET_ADV_DATA_CMPL_CBACK) (tBTA_STATUS status);
|
||||
|
||||
typedef tBTM_START_ADV_CMPL_CBACK tBTA_START_ADV_CMPL_CBACK;
|
||||
@@ -1616,6 +1618,22 @@ extern void BTA_DmPinReply(BD_ADDR bd_addr, BOOLEAN accept, UINT8 pin_len,
|
||||
**
|
||||
*******************************************************************************/
|
||||
extern void BTA_DmLocalOob(void);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_DmOobReply
|
||||
**
|
||||
** This function is called to provide the OOB data for
|
||||
** SMP in response to BTM_LE_OOB_REQ_EVT
|
||||
**
|
||||
** Parameters: bd_addr - Address of the peer device
|
||||
** len - length of simple pairing Randomizer C
|
||||
** p_value - simple pairing Randomizer C.
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
extern void BTA_DmOobReply(BD_ADDR bd_addr, UINT8 len, UINT8 *p_value);
|
||||
#endif /* BTM_OOB_INCLUDED */
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -2205,6 +2223,22 @@ extern void BTA_DmBleSetAdvConfig (tBTA_BLE_AD_MASK data_mask,
|
||||
extern void BTA_DmBleSetAdvConfigRaw (UINT8 *p_raw_adv, UINT32 raw_adv_len,
|
||||
tBTA_SET_ADV_DATA_CMPL_CBACK *p_adv_data_cback);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_DmBleSetLongAdv
|
||||
**
|
||||
** Description This function is called to set long Advertising data
|
||||
**
|
||||
** Parameters adv_data : long advertising data.
|
||||
** adv_data_len : long advertising data length.
|
||||
** p_adv_data_cback : set long adv data complete callback.
|
||||
**
|
||||
** Returns None
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_DmBleSetLongAdv (UINT8 *adv_data, UINT32 adv_data_len,
|
||||
tBTA_SET_ADV_DATA_CMPL_CBACK *p_adv_data_cback);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_DmBleSetScanRsp
|
||||
@@ -2236,6 +2270,24 @@ extern void BTA_DmBleSetScanRsp (tBTA_BLE_AD_MASK data_mask,
|
||||
extern void BTA_DmBleSetScanRspRaw (UINT8 *p_raw_scan_rsp, UINT32 raw_scan_rsp_len,
|
||||
tBTA_SET_ADV_DATA_CMPL_CBACK *p_scan_rsp_data_cback);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_DmUpdateDuplicateExceptionalList
|
||||
**
|
||||
** Description This function is called to update duplicate scan exceptional list
|
||||
**
|
||||
** Parameters subcode : add, remove or clean duplicate scan exceptional list.
|
||||
** type : device info type.
|
||||
** device_info: device info
|
||||
** p_update_duplicate_ignore_list_cback : update complete callback.
|
||||
**
|
||||
** Returns None
|
||||
**
|
||||
*******************************************************************************/
|
||||
extern void BTA_DmUpdateDuplicateExceptionalList(UINT8 subcode, UINT32 type,
|
||||
BD_ADDR device_info,
|
||||
tBTA_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_CMPL_CBACK p_update_duplicate_exceptional_list_cback);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_DmBleBroadcast
|
||||
|
@@ -210,4 +210,6 @@ extern void bta_dm_co_ble_set_accept_auth_enable(UINT8 enable);
|
||||
extern UINT8 bta_dm_co_ble_get_accept_auth_enable(void);
|
||||
|
||||
extern UINT8 bta_dm_co_ble_get_auth_req(void);
|
||||
|
||||
extern void bta_dm_co_ble_oob_support(UINT8 enable);
|
||||
#endif
|
||||
|
@@ -64,7 +64,7 @@ static void btc_init_bluetooth(void)
|
||||
bte_main_boot_entry(btc_init_callback);
|
||||
#if (SMP_INCLUDED)
|
||||
btc_config_init();
|
||||
//load the ble local key whitch has been store in the flash
|
||||
//load the ble local key which has been stored in the flash
|
||||
btc_dm_load_ble_local_keys();
|
||||
#endif /* #if (SMP_INCLUDED) */
|
||||
}
|
||||
|
@@ -143,9 +143,21 @@ static inline void btc_a2d_data_cb_to_app(const uint8_t *data, uint32_t len)
|
||||
}
|
||||
}
|
||||
|
||||
OI_CODEC_SBC_DECODER_CONTEXT context;
|
||||
OI_UINT32 contextData[CODEC_DATA_WORDS(2, SBC_CODEC_FAST_FILTER_BUFFERS)];
|
||||
OI_INT16 pcmData[15 * SBC_MAX_SAMPLES_PER_FRAME * SBC_MAX_CHANNELS];
|
||||
#define BTC_SBC_DEC_CONTEXT_DATA_LEN (CODEC_DATA_WORDS(2, SBC_CODEC_FAST_FILTER_BUFFERS))
|
||||
#define BTC_SBC_DEC_PCM_DATA_LEN (15 * SBC_MAX_SAMPLES_PER_FRAME * SBC_MAX_CHANNELS)
|
||||
|
||||
#if BTC_SBC_DEC_DYNAMIC_MEMORY == FALSE
|
||||
static OI_CODEC_SBC_DECODER_CONTEXT btc_sbc_decoder_context;
|
||||
static OI_UINT32 btc_sbc_decoder_context_data[BTC_SBC_DEC_CONTEXT_DATA_LEN];
|
||||
static OI_INT16 btc_sbc_pcm_data[BTC_SBC_DEC_PCM_DATA_LEN];
|
||||
#else
|
||||
static OI_CODEC_SBC_DECODER_CONTEXT *btc_sbc_decoder_context_ptr;
|
||||
static OI_UINT32 *btc_sbc_decoder_context_data;
|
||||
static OI_INT16 *btc_sbc_pcm_data;
|
||||
#define btc_sbc_decoder_context (*btc_sbc_decoder_context_ptr)
|
||||
#endif /* BTC_SBC_DEC_DYNAMIC_MEMORY == FALSE */
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
** Misc helper functions
|
||||
@@ -235,6 +247,16 @@ bool btc_a2dp_sink_startup(void)
|
||||
|
||||
APPL_TRACE_EVENT("## A2DP SINK START MEDIA THREAD ##");
|
||||
|
||||
#if (BTC_SBC_DEC_DYNAMIC_MEMORY == TRUE)
|
||||
btc_sbc_decoder_context_ptr = osi_calloc(sizeof(OI_CODEC_SBC_DECODER_CONTEXT));
|
||||
btc_sbc_decoder_context_data = osi_calloc(BTC_SBC_DEC_CONTEXT_DATA_LEN * sizeof(OI_UINT32));
|
||||
btc_sbc_pcm_data = osi_calloc(BTC_SBC_DEC_PCM_DATA_LEN * sizeof(OI_INT16));
|
||||
if (!btc_sbc_decoder_context_ptr || !btc_sbc_decoder_context_data || !btc_sbc_pcm_data) {
|
||||
APPL_TRACE_ERROR("failed to allocate SBC decoder");
|
||||
goto error_exit;
|
||||
}
|
||||
#endif /* BTC_SBC_DEC_DYNAMIC_MEMORY == TRUE */
|
||||
|
||||
btc_aa_snk_queue_set = xQueueCreateSet(BTC_A2DP_SINK_TASK_QUEUE_SET_LEN);
|
||||
configASSERT(btc_aa_snk_queue_set);
|
||||
btc_aa_snk_data_queue = xQueueCreate(BTC_A2DP_SINK_DATA_QUEUE_LEN, sizeof(int32_t));
|
||||
@@ -280,6 +302,21 @@ error_exit:;
|
||||
vQueueDelete(btc_aa_snk_queue_set);
|
||||
btc_aa_snk_queue_set = NULL;
|
||||
}
|
||||
#if (BTC_SBC_DEC_DYNAMIC_MEMORY == TRUE)
|
||||
if (btc_sbc_decoder_context_ptr) {
|
||||
osi_free(btc_sbc_decoder_context_ptr);
|
||||
btc_sbc_decoder_context_ptr = NULL;
|
||||
}
|
||||
if (btc_sbc_decoder_context_data) {
|
||||
osi_free(btc_sbc_decoder_context_data);
|
||||
btc_sbc_decoder_context_data = NULL;
|
||||
}
|
||||
if (btc_sbc_pcm_data) {
|
||||
osi_free(btc_sbc_pcm_data);
|
||||
btc_sbc_pcm_data = NULL;
|
||||
}
|
||||
#endif /* BTC_SBC_DEC_DYNAMIC_MEMORY == TRUE */
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -306,6 +343,17 @@ void btc_a2dp_sink_shutdown(void)
|
||||
|
||||
vQueueDelete(btc_aa_snk_queue_set);
|
||||
btc_aa_snk_queue_set = NULL;
|
||||
|
||||
#if (BTC_SBC_DEC_DYNAMIC_MEMORY == TRUE)
|
||||
osi_free(btc_sbc_decoder_context_ptr);
|
||||
btc_sbc_decoder_context_ptr = NULL;
|
||||
|
||||
osi_free(btc_sbc_decoder_context_data);
|
||||
btc_sbc_decoder_context_data = NULL;
|
||||
|
||||
osi_free(btc_sbc_pcm_data);
|
||||
btc_sbc_pcm_data = NULL;
|
||||
#endif /* BTC_SBC_DEC_DYNAMIC_MEMORY == TRUE */
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
@@ -467,7 +515,8 @@ static void btc_a2dp_sink_handle_decoder_reset(tBTC_MEDIA_SINK_CFG_UPDATE *p_msg
|
||||
|
||||
btc_aa_snk_cb.rx_flush = FALSE;
|
||||
APPL_TRACE_EVENT("Reset to sink role");
|
||||
status = OI_CODEC_SBC_DecoderReset(&context, contextData, sizeof(contextData), 2, 2, FALSE);
|
||||
status = OI_CODEC_SBC_DecoderReset(&btc_sbc_decoder_context, btc_sbc_decoder_context_data,
|
||||
BTC_SBC_DEC_CONTEXT_DATA_LEN * sizeof(OI_UINT32), 2, 2, FALSE);
|
||||
if (!OI_SUCCESS(status)) {
|
||||
APPL_TRACE_ERROR("OI_CODEC_SBC_DecoderReset failed with error code %d\n", status);
|
||||
}
|
||||
@@ -582,11 +631,11 @@ static void btc_a2dp_sink_handle_inc_media(tBT_SBC_HDR *p_msg)
|
||||
UINT8 *sbc_start_frame = ((UINT8 *)(p_msg + 1) + p_msg->offset + 1);
|
||||
int count;
|
||||
UINT32 pcmBytes, availPcmBytes;
|
||||
OI_INT16 *pcmDataPointer = pcmData; /*Will be overwritten on next packet receipt*/
|
||||
OI_INT16 *pcmDataPointer = btc_sbc_pcm_data; /*Will be overwritten on next packet receipt*/
|
||||
OI_STATUS status;
|
||||
int num_sbc_frames = p_msg->num_frames_to_be_processed;
|
||||
UINT32 sbc_frame_len = p_msg->len - 1;
|
||||
availPcmBytes = sizeof(pcmData);
|
||||
availPcmBytes = BTC_SBC_DEC_PCM_DATA_LEN * sizeof(OI_INT16);
|
||||
|
||||
/* XXX: Check if the below check is correct, we are checking for peer to be sink when we are sink */
|
||||
if (btc_av_get_peer_sep() == AVDT_TSEP_SNK || (btc_aa_snk_cb.rx_flush)) {
|
||||
@@ -603,7 +652,7 @@ static void btc_a2dp_sink_handle_inc_media(tBT_SBC_HDR *p_msg)
|
||||
|
||||
for (count = 0; count < num_sbc_frames && sbc_frame_len != 0; count ++) {
|
||||
pcmBytes = availPcmBytes;
|
||||
status = OI_CODEC_SBC_DecodeFrame(&context, (const OI_BYTE **)&sbc_start_frame,
|
||||
status = OI_CODEC_SBC_DecodeFrame(&btc_sbc_decoder_context, (const OI_BYTE **)&sbc_start_frame,
|
||||
(OI_UINT32 *)&sbc_frame_len,
|
||||
(OI_INT16 *)pcmDataPointer,
|
||||
(OI_UINT32 *)&pcmBytes);
|
||||
@@ -617,7 +666,7 @@ static void btc_a2dp_sink_handle_inc_media(tBT_SBC_HDR *p_msg)
|
||||
p_msg->len = sbc_frame_len + 1;
|
||||
}
|
||||
|
||||
btc_a2d_data_cb_to_app((uint8_t *)pcmData, (sizeof(pcmData) - availPcmBytes));
|
||||
btc_a2d_data_cb_to_app((uint8_t *)btc_sbc_pcm_data, (BTC_SBC_DEC_PCM_DATA_LEN * sizeof(OI_INT16) - availPcmBytes));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
@@ -156,7 +156,6 @@ typedef struct {
|
||||
tBTC_AV_FEEDING_MODE feeding_mode;
|
||||
tBTC_AV_MEDIA_FEEDINGS_STATE media_feeding_state;
|
||||
tBTC_AV_MEDIA_FEEDINGS media_feeding;
|
||||
SBC_ENC_PARAMS encoder;
|
||||
osi_alarm_t *media_alarm;
|
||||
} tBTC_A2DP_SOURCE_CB;
|
||||
|
||||
@@ -187,6 +186,13 @@ static QueueSetHandle_t btc_aa_src_queue_set;
|
||||
static esp_a2d_source_data_cb_t btc_aa_src_data_cb = NULL;
|
||||
static UINT64 last_frame_us = 0;
|
||||
|
||||
#if BTC_SBC_ENC_DYNAMIC_MEMORY == FALSE
|
||||
static SBC_ENC_PARAMS btc_sbc_encoder;
|
||||
#else
|
||||
static SBC_ENC_PARAMS *btc_sbc_encoder_ptr;
|
||||
#define btc_sbc_encoder (*btc_sbc_encoder_ptr)
|
||||
#endif /* BTC_SBC_ENC_DYNAMIC_MEMORY == FALSE */
|
||||
|
||||
void btc_a2dp_src_reg_data_cb(esp_a2d_source_data_cb_t callback)
|
||||
{
|
||||
// todo: critical section protection
|
||||
@@ -310,6 +316,14 @@ bool btc_a2dp_source_startup(void)
|
||||
|
||||
APPL_TRACE_EVENT("## A2DP SOURCE START MEDIA THREAD ##");
|
||||
|
||||
#if BTC_SBC_ENC_DYNAMIC_MEMORY == TRUE
|
||||
btc_sbc_encoder_ptr = osi_calloc(sizeof(SBC_ENC_PARAMS));
|
||||
if (!btc_sbc_encoder_ptr) {
|
||||
APPL_TRACE_ERROR("failed to allocate SBC encoder");
|
||||
goto error_exit;
|
||||
}
|
||||
#endif /* #if BTC_SBC_ENC_DYNAMIC_MEMORY == TRUE */
|
||||
|
||||
btc_aa_src_queue_set = xQueueCreateSet(BTC_A2DP_SOURCE_TASK_QUEUE_SET_LEN);
|
||||
configASSERT(btc_aa_src_queue_set);
|
||||
btc_aa_src_data_queue = xQueueCreate(BTC_A2DP_SOURCE_DATA_QUEUE_LEN, sizeof(void *));
|
||||
@@ -355,6 +369,12 @@ error_exit:;
|
||||
vQueueDelete(btc_aa_src_queue_set);
|
||||
btc_aa_src_queue_set = NULL;
|
||||
}
|
||||
#if (BTC_SBC_ENC_DYNAMIC_MEMORY == TRUE)
|
||||
if (btc_sbc_encoder_ptr) {
|
||||
osi_free(btc_sbc_encoder_ptr);
|
||||
btc_sbc_encoder_ptr = NULL;
|
||||
}
|
||||
#endif /* #if BTC_SBC_ENC_DYNAMIC_MEMORY == TRUE */
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -381,6 +401,11 @@ void btc_a2dp_source_shutdown(void)
|
||||
|
||||
vQueueDelete(btc_aa_src_queue_set);
|
||||
btc_aa_src_queue_set = NULL;
|
||||
|
||||
#if (BTC_SBC_ENC_DYNAMIC_MEMORY == TRUE)
|
||||
osi_free(btc_sbc_encoder_ptr);
|
||||
btc_sbc_encoder_ptr = NULL;
|
||||
#endif /* #if BTC_SBC_ENC_DYNAMIC_MEMORY == TRUE */
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
@@ -794,13 +819,14 @@ static void btc_a2dp_source_enc_init(BT_HDR *p_msg)
|
||||
btc_aa_src_cb.timestamp = 0;
|
||||
|
||||
/* SBC encoder config (enforced even if not used) */
|
||||
btc_aa_src_cb.encoder.s16ChannelMode = pInitAudio->ChannelMode;
|
||||
btc_aa_src_cb.encoder.s16NumOfSubBands = pInitAudio->NumOfSubBands;
|
||||
btc_aa_src_cb.encoder.s16NumOfBlocks = pInitAudio->NumOfBlocks;
|
||||
btc_aa_src_cb.encoder.s16AllocationMethod = pInitAudio->AllocationMethod;
|
||||
btc_aa_src_cb.encoder.s16SamplingFreq = pInitAudio->SamplingFreq;
|
||||
|
||||
btc_aa_src_cb.encoder.u16BitRate = btc_a2dp_source_get_sbc_rate();
|
||||
btc_sbc_encoder.s16ChannelMode = pInitAudio->ChannelMode;
|
||||
btc_sbc_encoder.s16NumOfSubBands = pInitAudio->NumOfSubBands;
|
||||
btc_sbc_encoder.s16NumOfBlocks = pInitAudio->NumOfBlocks;
|
||||
btc_sbc_encoder.s16AllocationMethod = pInitAudio->AllocationMethod;
|
||||
btc_sbc_encoder.s16SamplingFreq = pInitAudio->SamplingFreq;
|
||||
|
||||
btc_sbc_encoder.u16BitRate = btc_a2dp_source_get_sbc_rate();
|
||||
|
||||
/* Default transcoding is PCM to SBC, modified by feeding configuration */
|
||||
btc_aa_src_cb.TxTranscoding = BTC_MEDIA_TRSCD_PCM_2_SBC;
|
||||
@@ -811,14 +837,14 @@ static void btc_a2dp_source_enc_init(BT_HDR *p_msg)
|
||||
APPL_TRACE_EVENT("btc_a2dp_source_enc_init mtu %d, peer mtu %d",
|
||||
btc_aa_src_cb.TxAaMtuSize, pInitAudio->MtuSize);
|
||||
APPL_TRACE_EVENT(" ch mode %d, subnd %d, nb blk %d, alloc %d, rate %d, freq %d",
|
||||
btc_aa_src_cb.encoder.s16ChannelMode, btc_aa_src_cb.encoder.s16NumOfSubBands,
|
||||
btc_aa_src_cb.encoder.s16NumOfBlocks,
|
||||
btc_aa_src_cb.encoder.s16AllocationMethod, btc_aa_src_cb.encoder.u16BitRate,
|
||||
btc_aa_src_cb.encoder.s16SamplingFreq);
|
||||
btc_sbc_encoder.s16ChannelMode, btc_sbc_encoder.s16NumOfSubBands,
|
||||
btc_sbc_encoder.s16NumOfBlocks,
|
||||
btc_sbc_encoder.s16AllocationMethod, btc_sbc_encoder.u16BitRate,
|
||||
btc_sbc_encoder.s16SamplingFreq);
|
||||
|
||||
/* Reset entirely the SBC encoder */
|
||||
SBC_Encoder_Init(&(btc_aa_src_cb.encoder));
|
||||
APPL_TRACE_DEBUG("btc_a2dp_source_enc_init bit pool %d", btc_aa_src_cb.encoder.s16BitPool);
|
||||
SBC_Encoder_Init(&(btc_sbc_encoder));
|
||||
APPL_TRACE_DEBUG("btc_a2dp_source_enc_init bit pool %d", btc_sbc_encoder.s16BitPool);
|
||||
}
|
||||
|
||||
|
||||
@@ -835,7 +861,7 @@ static void btc_a2dp_source_enc_init(BT_HDR *p_msg)
|
||||
static void btc_a2dp_source_enc_update(BT_HDR *p_msg)
|
||||
{
|
||||
tBTC_MEDIA_UPDATE_AUDIO *pUpdateAudio = (tBTC_MEDIA_UPDATE_AUDIO *) p_msg;
|
||||
SBC_ENC_PARAMS *pstrEncParams = &btc_aa_src_cb.encoder;
|
||||
SBC_ENC_PARAMS *pstrEncParams = &btc_sbc_encoder;
|
||||
UINT16 s16SamplingFreq;
|
||||
SINT16 s16BitPool = 0;
|
||||
SINT16 s16BitRate;
|
||||
@@ -928,19 +954,19 @@ static void btc_a2dp_source_enc_update(BT_HDR *p_msg)
|
||||
if (s16BitPool > pUpdateAudio->MaxBitPool) {
|
||||
APPL_TRACE_DEBUG("%s computed bitpool too large (%d)", __FUNCTION__, s16BitPool);
|
||||
/* Decrease bitrate */
|
||||
btc_aa_src_cb.encoder.u16BitRate -= BTC_MEDIA_BITRATE_STEP;
|
||||
btc_sbc_encoder.u16BitRate -= BTC_MEDIA_BITRATE_STEP;
|
||||
/* Record that we have decreased the bitrate */
|
||||
protect |= 1;
|
||||
} else if (s16BitPool < pUpdateAudio->MinBitPool) {
|
||||
APPL_TRACE_WARNING("%s computed bitpool too small (%d)", __FUNCTION__, s16BitPool);
|
||||
|
||||
/* Increase bitrate */
|
||||
UINT16 previous_u16BitRate = btc_aa_src_cb.encoder.u16BitRate;
|
||||
btc_aa_src_cb.encoder.u16BitRate += BTC_MEDIA_BITRATE_STEP;
|
||||
UINT16 previous_u16BitRate = btc_sbc_encoder.u16BitRate;
|
||||
btc_sbc_encoder.u16BitRate += BTC_MEDIA_BITRATE_STEP;
|
||||
/* Record that we have increased the bitrate */
|
||||
protect |= 2;
|
||||
/* Check over-flow */
|
||||
if (btc_aa_src_cb.encoder.u16BitRate < previous_u16BitRate) {
|
||||
if (btc_sbc_encoder.u16BitRate < previous_u16BitRate) {
|
||||
protect |= 3;
|
||||
}
|
||||
} else {
|
||||
@@ -957,10 +983,10 @@ static void btc_a2dp_source_enc_update(BT_HDR *p_msg)
|
||||
pstrEncParams->s16BitPool = s16BitPool;
|
||||
|
||||
APPL_TRACE_DEBUG("%s final bit rate %d, final bit pool %d", __FUNCTION__,
|
||||
btc_aa_src_cb.encoder.u16BitRate, btc_aa_src_cb.encoder.s16BitPool);
|
||||
btc_sbc_encoder.u16BitRate, btc_sbc_encoder.s16BitPool);
|
||||
|
||||
/* make sure we reinitialize encoder with new settings */
|
||||
SBC_Encoder_Init(&(btc_aa_src_cb.encoder));
|
||||
SBC_Encoder_Init(&(btc_sbc_encoder));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -991,10 +1017,10 @@ static void btc_a2dp_source_pcm2sbc_init(tBTC_MEDIA_INIT_AUDIO_FEEDING *p_feedin
|
||||
case 32000:
|
||||
case 48000:
|
||||
/* For these sampling_freq the AV connection must be 48000 */
|
||||
if (btc_aa_src_cb.encoder.s16SamplingFreq != SBC_sf48000) {
|
||||
if (btc_sbc_encoder.s16SamplingFreq != SBC_sf48000) {
|
||||
/* Reconfiguration needed at 48000 */
|
||||
APPL_TRACE_DEBUG("SBC Reconfiguration needed at 48000");
|
||||
btc_aa_src_cb.encoder.s16SamplingFreq = SBC_sf48000;
|
||||
btc_sbc_encoder.s16SamplingFreq = SBC_sf48000;
|
||||
reconfig_needed = TRUE;
|
||||
}
|
||||
break;
|
||||
@@ -1003,10 +1029,10 @@ static void btc_a2dp_source_pcm2sbc_init(tBTC_MEDIA_INIT_AUDIO_FEEDING *p_feedin
|
||||
case 22050:
|
||||
case 44100:
|
||||
/* For these sampling_freq the AV connection must be 44100 */
|
||||
if (btc_aa_src_cb.encoder.s16SamplingFreq != SBC_sf44100) {
|
||||
if (btc_sbc_encoder.s16SamplingFreq != SBC_sf44100) {
|
||||
/* Reconfiguration needed at 44100 */
|
||||
APPL_TRACE_DEBUG("SBC Reconfiguration needed at 44100");
|
||||
btc_aa_src_cb.encoder.s16SamplingFreq = SBC_sf44100;
|
||||
btc_sbc_encoder.s16SamplingFreq = SBC_sf44100;
|
||||
reconfig_needed = TRUE;
|
||||
}
|
||||
break;
|
||||
@@ -1016,21 +1042,21 @@ static void btc_a2dp_source_pcm2sbc_init(tBTC_MEDIA_INIT_AUDIO_FEEDING *p_feedin
|
||||
}
|
||||
|
||||
/* Some AV Headsets do not support Mono => always ask for Stereo */
|
||||
if (btc_aa_src_cb.encoder.s16ChannelMode == SBC_MONO) {
|
||||
if (btc_sbc_encoder.s16ChannelMode == SBC_MONO) {
|
||||
APPL_TRACE_DEBUG("SBC Reconfiguration needed in Stereo");
|
||||
btc_aa_src_cb.encoder.s16ChannelMode = SBC_JOINT_STEREO;
|
||||
btc_sbc_encoder.s16ChannelMode = SBC_JOINT_STEREO;
|
||||
reconfig_needed = TRUE;
|
||||
}
|
||||
|
||||
if (reconfig_needed != FALSE) {
|
||||
APPL_TRACE_DEBUG("%s :: mtu %d", __FUNCTION__, btc_aa_src_cb.TxAaMtuSize);
|
||||
APPL_TRACE_DEBUG("ch mode %d, nbsubd %d, nb %d, alloc %d, rate %d, freq %d",
|
||||
btc_aa_src_cb.encoder.s16ChannelMode,
|
||||
btc_aa_src_cb.encoder.s16NumOfSubBands, btc_aa_src_cb.encoder.s16NumOfBlocks,
|
||||
btc_aa_src_cb.encoder.s16AllocationMethod, btc_aa_src_cb.encoder.u16BitRate,
|
||||
btc_aa_src_cb.encoder.s16SamplingFreq);
|
||||
btc_sbc_encoder.s16ChannelMode,
|
||||
btc_sbc_encoder.s16NumOfSubBands, btc_sbc_encoder.s16NumOfBlocks,
|
||||
btc_sbc_encoder.s16AllocationMethod, btc_sbc_encoder.u16BitRate,
|
||||
btc_sbc_encoder.s16SamplingFreq);
|
||||
|
||||
SBC_Encoder_Init(&(btc_aa_src_cb.encoder));
|
||||
SBC_Encoder_Init(&(btc_sbc_encoder));
|
||||
} else {
|
||||
APPL_TRACE_DEBUG("%s no SBC reconfig needed", __FUNCTION__);
|
||||
}
|
||||
@@ -1105,8 +1131,8 @@ static UINT8 btc_get_num_aa_frame(void)
|
||||
|
||||
switch (btc_aa_src_cb.TxTranscoding) {
|
||||
case BTC_MEDIA_TRSCD_PCM_2_SBC: {
|
||||
UINT32 pcm_bytes_per_frame = btc_aa_src_cb.encoder.s16NumOfSubBands *
|
||||
btc_aa_src_cb.encoder.s16NumOfBlocks *
|
||||
UINT32 pcm_bytes_per_frame = btc_sbc_encoder.s16NumOfSubBands *
|
||||
btc_sbc_encoder.s16NumOfBlocks *
|
||||
btc_aa_src_cb.media_feeding.cfg.pcm.num_channel *
|
||||
btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample / 8;
|
||||
|
||||
@@ -1162,12 +1188,12 @@ static UINT8 btc_get_num_aa_frame(void)
|
||||
|
||||
BOOLEAN btc_media_aa_read_feeding(void)
|
||||
{
|
||||
UINT16 blocm_x_subband = btc_aa_src_cb.encoder.s16NumOfSubBands * \
|
||||
btc_aa_src_cb.encoder.s16NumOfBlocks;
|
||||
UINT16 blocm_x_subband = btc_sbc_encoder.s16NumOfSubBands * \
|
||||
btc_sbc_encoder.s16NumOfBlocks;
|
||||
UINT32 read_size;
|
||||
UINT16 sbc_sampling = 48000;
|
||||
UINT32 src_samples;
|
||||
UINT16 bytes_needed = blocm_x_subband * btc_aa_src_cb.encoder.s16NumOfChannels * \
|
||||
UINT16 bytes_needed = blocm_x_subband * btc_sbc_encoder.s16NumOfChannels * \
|
||||
btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample / 8;
|
||||
static UINT16 up_sampled_buffer[SBC_MAX_NUM_FRAME * SBC_MAX_NUM_OF_BLOCKS
|
||||
* SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS * 2];
|
||||
@@ -1181,7 +1207,7 @@ BOOLEAN btc_media_aa_read_feeding(void)
|
||||
UINT32 nb_byte_read = 0;
|
||||
|
||||
/* Get the SBC sampling rate */
|
||||
switch (btc_aa_src_cb.encoder.s16SamplingFreq) {
|
||||
switch (btc_sbc_encoder.s16SamplingFreq) {
|
||||
case SBC_sf48000:
|
||||
sbc_sampling = 48000;
|
||||
break;
|
||||
@@ -1199,7 +1225,7 @@ BOOLEAN btc_media_aa_read_feeding(void)
|
||||
if (sbc_sampling == btc_aa_src_cb.media_feeding.cfg.pcm.sampling_freq) {
|
||||
read_size = bytes_needed - btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue;
|
||||
nb_byte_read = btc_aa_src_data_read(
|
||||
((uint8_t *)btc_aa_src_cb.encoder.as16PcmBuffer) +
|
||||
((uint8_t *)btc_sbc_encoder.as16PcmBuffer) +
|
||||
btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue,
|
||||
read_size);
|
||||
if (nb_byte_read == read_size) {
|
||||
@@ -1293,7 +1319,7 @@ BOOLEAN btc_media_aa_read_feeding(void)
|
||||
/* only copy the pcm sample when we have up-sampled enough PCM */
|
||||
if (btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue >= bytes_needed) {
|
||||
/* Copy the output pcm samples in SBC encoding buffer */
|
||||
memcpy((UINT8 *)btc_aa_src_cb.encoder.as16PcmBuffer,
|
||||
memcpy((UINT8 *)btc_sbc_encoder.as16PcmBuffer,
|
||||
(UINT8 *)up_sampled_buffer,
|
||||
bytes_needed);
|
||||
/* update the residue */
|
||||
@@ -1322,8 +1348,8 @@ BOOLEAN btc_media_aa_read_feeding(void)
|
||||
static void btc_media_aa_prep_sbc_2_send(UINT8 nb_frame)
|
||||
{
|
||||
BT_HDR *p_buf;
|
||||
UINT16 blocm_x_subband = btc_aa_src_cb.encoder.s16NumOfSubBands *
|
||||
btc_aa_src_cb.encoder.s16NumOfBlocks;
|
||||
UINT16 blocm_x_subband = btc_sbc_encoder.s16NumOfSubBands *
|
||||
btc_sbc_encoder.s16NumOfBlocks;
|
||||
|
||||
while (nb_frame) {
|
||||
if (NULL == (p_buf = osi_malloc(BTC_MEDIA_AA_BUF_SIZE))) {
|
||||
@@ -1339,27 +1365,27 @@ static void btc_media_aa_prep_sbc_2_send(UINT8 nb_frame)
|
||||
|
||||
do {
|
||||
/* Write @ of allocated buffer in encoder.pu8Packet */
|
||||
btc_aa_src_cb.encoder.pu8Packet = (UINT8 *) (p_buf + 1) + p_buf->offset + p_buf->len;
|
||||
btc_sbc_encoder.pu8Packet = (UINT8 *) (p_buf + 1) + p_buf->offset + p_buf->len;
|
||||
/* Fill allocated buffer with 0 */
|
||||
memset(btc_aa_src_cb.encoder.as16PcmBuffer, 0, blocm_x_subband
|
||||
* btc_aa_src_cb.encoder.s16NumOfChannels);
|
||||
memset(btc_sbc_encoder.as16PcmBuffer, 0, blocm_x_subband
|
||||
* btc_sbc_encoder.s16NumOfChannels);
|
||||
|
||||
/* Read PCM data and upsample them if needed */
|
||||
if (btc_media_aa_read_feeding()) {
|
||||
/* SBC encode and descramble frame */
|
||||
SBC_Encoder(&(btc_aa_src_cb.encoder));
|
||||
A2D_SbcChkFrInit(btc_aa_src_cb.encoder.pu8Packet);
|
||||
A2D_SbcDescramble(btc_aa_src_cb.encoder.pu8Packet, btc_aa_src_cb.encoder.u16PacketLength);
|
||||
SBC_Encoder(&(btc_sbc_encoder));
|
||||
A2D_SbcChkFrInit(btc_sbc_encoder.pu8Packet);
|
||||
A2D_SbcDescramble(btc_sbc_encoder.pu8Packet, btc_sbc_encoder.u16PacketLength);
|
||||
/* Update SBC frame length */
|
||||
p_buf->len += btc_aa_src_cb.encoder.u16PacketLength;
|
||||
p_buf->len += btc_sbc_encoder.u16PacketLength;
|
||||
nb_frame--;
|
||||
p_buf->layer_specific++;
|
||||
} else {
|
||||
APPL_TRACE_WARNING("btc_media_aa_prep_sbc_2_send underflow %d, %d",
|
||||
nb_frame, btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue);
|
||||
btc_aa_src_cb.media_feeding_state.pcm.counter += nb_frame *
|
||||
btc_aa_src_cb.encoder.s16NumOfSubBands *
|
||||
btc_aa_src_cb.encoder.s16NumOfBlocks *
|
||||
btc_sbc_encoder.s16NumOfSubBands *
|
||||
btc_sbc_encoder.s16NumOfBlocks *
|
||||
btc_aa_src_cb.media_feeding.cfg.pcm.num_channel *
|
||||
btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample / 8;
|
||||
/* no more pcm to read */
|
||||
@@ -1372,7 +1398,7 @@ static void btc_media_aa_prep_sbc_2_send(UINT8 nb_frame)
|
||||
}
|
||||
}
|
||||
|
||||
} while (((p_buf->len + btc_aa_src_cb.encoder.u16PacketLength) < btc_aa_src_cb.TxAaMtuSize)
|
||||
} while (((p_buf->len + btc_sbc_encoder.u16PacketLength) < btc_aa_src_cb.TxAaMtuSize)
|
||||
&& (p_buf->layer_specific < 0x0F) && nb_frame);
|
||||
|
||||
if (p_buf->len) {
|
||||
|
@@ -426,6 +426,35 @@ static void btc_stop_adv_callback(uint8_t status)
|
||||
}
|
||||
}
|
||||
|
||||
void btc_update_duplicate_exceptional_list_callback(tBTA_STATUS status, uint8_t subcode, uint32_t length, uint8_t *device_info)
|
||||
{
|
||||
esp_ble_gap_cb_param_t param;
|
||||
bt_status_t ret;
|
||||
btc_msg_t msg;
|
||||
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_GAP_BLE;
|
||||
msg.act = ESP_GAP_BLE_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_COMPLETE_EVT;
|
||||
param.update_duplicate_exceptional_list_cmpl.status = status;
|
||||
param.update_duplicate_exceptional_list_cmpl.subcode = subcode;
|
||||
if(length > sizeof(param.update_duplicate_exceptional_list_cmpl.device_info)) {
|
||||
length = sizeof(param.update_duplicate_exceptional_list_cmpl.device_info);
|
||||
}
|
||||
param.update_duplicate_exceptional_list_cmpl.length = length;
|
||||
memcpy(param.update_duplicate_exceptional_list_cmpl.device_info, device_info, length);
|
||||
ret = btc_transfer_context(&msg, ¶m, sizeof(esp_ble_gap_cb_param_t), NULL);
|
||||
|
||||
if (ret != BT_STATUS_SUCCESS) {
|
||||
BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
static void btc_ble_update_duplicate_exceptional_list(uint8_t subcode, uint32_t info_type, BD_ADDR device_info,
|
||||
tBTA_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_CMPL_CBACK p_update_duplicate_ignore_list_cback)
|
||||
{
|
||||
BTA_DmUpdateDuplicateExceptionalList(subcode, info_type, device_info, p_update_duplicate_ignore_list_cback);
|
||||
}
|
||||
|
||||
static void btc_ble_start_advertising (esp_ble_adv_params_t *ble_adv_params, tBTA_START_ADV_CMPL_CBACK start_adv_cback)
|
||||
{
|
||||
tBLE_BD_ADDR peer_addr;
|
||||
@@ -452,6 +481,10 @@ static void btc_ble_start_advertising (esp_ble_adv_params_t *ble_adv_params, tBT
|
||||
status = ESP_BT_STATUS_PARM_INVALID;
|
||||
BTC_TRACE_ERROR("Invalid advertisting channel map parameters.\n");
|
||||
}
|
||||
if (!BLE_ISVALID_PARAM(ble_adv_params->peer_addr_type, BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_RANDOM)) {
|
||||
status = ESP_BT_STATUS_PARM_INVALID;
|
||||
BTC_TRACE_ERROR("Invalid advertisting peer address type parameters.\n");
|
||||
}
|
||||
if(status != ESP_BT_STATUS_SUCCESS) {
|
||||
if(start_adv_cback) {
|
||||
start_adv_cback(status);
|
||||
@@ -831,7 +864,7 @@ static void btc_ble_set_rand_addr (BD_ADDR rand_addr, tBTA_SET_RAND_ADDR_CBACK *
|
||||
BTA_DmSetRandAddress(rand_addr, btc_set_rand_addr_callback);
|
||||
} else {
|
||||
btc_set_rand_addr_callback(BTM_INVALID_STATIC_RAND_ADDR);
|
||||
BTC_TRACE_ERROR("Invalid random address, the high bit should be 0b11, all bits of the random part shall not be to 1 or 0");
|
||||
BTC_TRACE_ERROR("Invalid random address, the high bit should be 0b11, bits of the random part shall not be all 1 or 0");
|
||||
}
|
||||
} else {
|
||||
btc_set_rand_addr_callback(BTM_INVALID_STATIC_RAND_ADDR);
|
||||
@@ -931,6 +964,21 @@ void btc_gap_ble_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BTC_GAP_BLE_OOB_REQ_REPLY_EVT: {
|
||||
btc_ble_gap_args_t *src = (btc_ble_gap_args_t *)p_src;
|
||||
btc_ble_gap_args_t *dst = (btc_ble_gap_args_t *) p_dest;
|
||||
uint8_t length = 0;
|
||||
if (src->oob_req_reply.p_value) {
|
||||
length = dst->oob_req_reply.len;
|
||||
dst->oob_req_reply.p_value = osi_malloc(length);
|
||||
if (dst->oob_req_reply.p_value != NULL) {
|
||||
memcpy(dst->oob_req_reply.p_value, src->oob_req_reply.p_value, length);
|
||||
} else {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BTC_TRACE_ERROR("Unhandled deep copy %d\n", msg->act);
|
||||
break;
|
||||
@@ -986,6 +1034,13 @@ void btc_gap_ble_arg_deep_free(btc_msg_t *msg)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BTC_GAP_BLE_OOB_REQ_REPLY_EVT: {
|
||||
uint8_t *value = ((btc_ble_gap_args_t *)msg->arg)->oob_req_reply.p_value;
|
||||
if (value) {
|
||||
osi_free(value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BTC_TRACE_DEBUG("Unhandled deep free %d\n", msg->act);
|
||||
break;
|
||||
@@ -1082,6 +1137,12 @@ void btc_gap_ble_call_handler(btc_msg_t *msg)
|
||||
arg->cfg_scan_rsp_data_raw.raw_scan_rsp_len,
|
||||
btc_scan_rsp_data_raw_callback);
|
||||
break;
|
||||
case BTC_GAP_BLE_UPDATE_DUPLICATE_SCAN_EXCEPTIONAL_LIST:
|
||||
btc_ble_update_duplicate_exceptional_list(arg->update_duplicate_exceptional_list.subcode,
|
||||
arg->update_duplicate_exceptional_list.info_type,
|
||||
arg->update_duplicate_exceptional_list.device_info,
|
||||
btc_update_duplicate_exceptional_list_callback);
|
||||
break;
|
||||
#if (SMP_INCLUDED == TRUE)
|
||||
case BTC_GAP_BLE_SET_ENCRYPTION_EVT: {
|
||||
BD_ADDR bd_addr;
|
||||
@@ -1144,6 +1205,12 @@ void btc_gap_ble_call_handler(btc_msg_t *msg)
|
||||
bta_dm_co_ble_set_accept_auth_enable(enable);
|
||||
break;
|
||||
}
|
||||
case ESP_BLE_SM_OOB_SUPPORT: {
|
||||
uint8_t enable = 0;
|
||||
STREAM_TO_UINT8(enable, value);
|
||||
bta_dm_co_ble_oob_support(enable);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1174,6 +1241,9 @@ void btc_gap_ble_call_handler(btc_msg_t *msg)
|
||||
BTA_DmRemoveDevice(bd_addr, BT_TRANSPORT_LE);
|
||||
break;
|
||||
}
|
||||
case BTC_GAP_BLE_OOB_REQ_REPLY_EVT:
|
||||
BTA_DmOobReply(arg->oob_req_reply.bd_addr, arg->oob_req_reply.len, arg->oob_req_reply.p_value);
|
||||
break;
|
||||
#endif ///SMP_INCLUDED == TRUE
|
||||
case BTC_GAP_BLE_DISCONNECT_EVT:
|
||||
btc_ble_disconnect(arg->disconnect.remote_device);
|
||||
|
@@ -81,72 +81,105 @@ void btc_gatts_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
|
||||
|
||||
switch (msg->act) {
|
||||
case BTC_GATTS_ACT_SEND_INDICATE: {
|
||||
dst->send_ind.value = (uint8_t *)osi_malloc(src->send_ind.value_len);
|
||||
if (dst->send_ind.value) {
|
||||
memcpy(dst->send_ind.value, src->send_ind.value, src->send_ind.value_len);
|
||||
if (src->send_ind.value && (src->send_ind.value_len > 0)) {
|
||||
dst->send_ind.value = (uint8_t *) osi_malloc(src->send_ind.value_len);
|
||||
if (dst->send_ind.value) {
|
||||
memcpy(dst->send_ind.value, src->send_ind.value, src->send_ind.value_len);
|
||||
} else {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
|
||||
}
|
||||
} else {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
|
||||
dst->send_ind.value = NULL;
|
||||
if (src->send_ind.value) {
|
||||
BTC_TRACE_ERROR("%s %d, invalid length", __func__, msg->act);
|
||||
} else {
|
||||
BTC_TRACE_WARNING("%s %d, NULL value", __func__, msg->act);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BTC_GATTS_ACT_SEND_RESPONSE: {
|
||||
if (src->send_rsp.rsp) {
|
||||
dst->send_rsp.rsp = (esp_gatt_rsp_t *)osi_malloc(sizeof(esp_gatt_rsp_t));
|
||||
dst->send_rsp.rsp = (esp_gatt_rsp_t *) osi_malloc(sizeof(esp_gatt_rsp_t));
|
||||
if (dst->send_rsp.rsp) {
|
||||
memcpy(dst->send_rsp.rsp, src->send_rsp.rsp, sizeof(esp_gatt_rsp_t));
|
||||
} else {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
|
||||
}
|
||||
} else {
|
||||
BTC_TRACE_WARNING("%s %d, NULL response", __func__, msg->act);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
case BTC_GATTS_ACT_ADD_CHAR:{
|
||||
if (src->add_char.char_val.attr_value != NULL){
|
||||
dst->add_char.char_val.attr_value = (uint8_t *)osi_malloc(src->add_char.char_val.attr_len);
|
||||
if(dst->add_char.char_val.attr_value != NULL){
|
||||
case BTC_GATTS_ACT_ADD_CHAR: {
|
||||
if (src->add_char.char_val.attr_value && (src->add_char.char_val.attr_len > 0)) {
|
||||
dst->add_char.char_val.attr_value = (uint8_t *) osi_malloc(src->add_char.char_val.attr_len);
|
||||
if (dst->add_char.char_val.attr_value) {
|
||||
memcpy(dst->add_char.char_val.attr_value, src->add_char.char_val.attr_value,
|
||||
src->add_char.char_val.attr_len);
|
||||
}else{
|
||||
} else {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
|
||||
}
|
||||
} else {
|
||||
dst->add_char.char_val.attr_value = NULL;
|
||||
if (src->add_char.char_val.attr_value) {
|
||||
BTC_TRACE_ERROR("%s %d, invalid length", __func__, msg->act);
|
||||
} else {
|
||||
BTC_TRACE_WARNING("%s %d, NULL value", __func__, msg->act);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BTC_GATTS_ACT_ADD_CHAR_DESCR:{
|
||||
if(src->add_descr.descr_val.attr_value != NULL){
|
||||
dst->add_descr.descr_val.attr_value = (uint8_t *)osi_malloc(src->add_descr.descr_val.attr_len);
|
||||
if(dst->add_descr.descr_val.attr_value != NULL){
|
||||
case BTC_GATTS_ACT_ADD_CHAR_DESCR: {
|
||||
if (src->add_descr.descr_val.attr_value && (src->add_descr.descr_val.attr_len > 0)) {
|
||||
dst->add_descr.descr_val.attr_value = (uint8_t *) osi_malloc(src->add_descr.descr_val.attr_len);
|
||||
if (dst->add_descr.descr_val.attr_value) {
|
||||
memcpy(dst->add_descr.descr_val.attr_value, src->add_descr.descr_val.attr_value,
|
||||
src->add_descr.descr_val.attr_len);
|
||||
}else{
|
||||
} else {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BTC_GATTS_ACT_CREATE_ATTR_TAB:{
|
||||
uint8_t num_attr = src->create_attr_tab.max_nb_attr;
|
||||
if(src->create_attr_tab.gatts_attr_db != NULL){
|
||||
dst->create_attr_tab.gatts_attr_db = (esp_gatts_attr_db_t *)osi_malloc(sizeof(esp_gatts_attr_db_t)*num_attr);
|
||||
if(dst->create_attr_tab.gatts_attr_db != NULL){
|
||||
memcpy(dst->create_attr_tab.gatts_attr_db, src->create_attr_tab.gatts_attr_db,
|
||||
sizeof(esp_gatts_attr_db_t)*num_attr);
|
||||
}else{
|
||||
BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act);
|
||||
} else {
|
||||
dst->add_descr.descr_val.attr_value = NULL;
|
||||
if (src->add_descr.descr_val.attr_value) {
|
||||
BTC_TRACE_ERROR("%s %d, invalid length", __func__, msg->act);
|
||||
} else {
|
||||
BTC_TRACE_WARNING("%s %d, NULL value", __func__, msg->act);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BTC_GATTS_ACT_SET_ATTR_VALUE:{
|
||||
uint16_t len = src->set_attr_val.length;
|
||||
if(src->set_attr_val.value){
|
||||
dst->set_attr_val.value = (uint8_t *)osi_malloc(len);
|
||||
if(dst->set_attr_val.value != NULL){
|
||||
memcpy(dst->set_attr_val.value, src->set_attr_val.value, len);
|
||||
}else{
|
||||
case BTC_GATTS_ACT_CREATE_ATTR_TAB: {
|
||||
uint8_t num_attr = src->create_attr_tab.max_nb_attr;
|
||||
if (src->create_attr_tab.gatts_attr_db && (num_attr > 0)) {
|
||||
dst->create_attr_tab.gatts_attr_db = (esp_gatts_attr_db_t *) osi_malloc(sizeof(esp_gatts_attr_db_t) * num_attr);
|
||||
if (dst->create_attr_tab.gatts_attr_db) {
|
||||
memcpy(dst->create_attr_tab.gatts_attr_db, src->create_attr_tab.gatts_attr_db,
|
||||
sizeof(esp_gatts_attr_db_t) * num_attr);
|
||||
} else {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act);
|
||||
}
|
||||
} else {
|
||||
BTC_TRACE_ERROR("%s %d, NULL data", __func__, msg->act);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BTC_GATTS_ACT_SET_ATTR_VALUE: {
|
||||
if (src->set_attr_val.value && (src->set_attr_val.length > 0)) {
|
||||
dst->set_attr_val.value = (uint8_t *) osi_malloc(src->set_attr_val.length);
|
||||
if (dst->set_attr_val.value) {
|
||||
memcpy(dst->set_attr_val.value, src->set_attr_val.value, src->set_attr_val.length);
|
||||
} else {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n",__func__, msg->act);
|
||||
}
|
||||
} else {
|
||||
dst->set_attr_val.value = NULL;
|
||||
if (src->set_attr_val.value) {
|
||||
BTC_TRACE_ERROR("%s %d, invalid length", __func__, msg->act);
|
||||
} else {
|
||||
BTC_TRACE_WARNING("%s %d, NULL value", __func__, msg->act);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@@ -46,6 +46,8 @@ typedef enum {
|
||||
BTC_GAP_BLE_CONFIRM_REPLY_EVT,
|
||||
BTC_GAP_BLE_DISCONNECT_EVT,
|
||||
BTC_GAP_BLE_REMOVE_BOND_DEV_EVT,
|
||||
BTC_GAP_BLE_OOB_REQ_REPLY_EVT,
|
||||
BTC_GAP_BLE_UPDATE_DUPLICATE_SCAN_EXCEPTIONAL_LIST,
|
||||
} btc_gap_ble_act_t;
|
||||
|
||||
/* btc_ble_gap_args_t */
|
||||
@@ -94,6 +96,12 @@ typedef union {
|
||||
bool add_remove;
|
||||
esp_bd_addr_t remote_bda;
|
||||
}update_white_list;
|
||||
//BTC_GAP_BLE_UPDATE_DUPLICATE_SCAN_EXCEPTIONAL_LIST
|
||||
struct update_duplicate_exceptional_list_args {
|
||||
uint8_t subcode;
|
||||
uint32_t info_type;
|
||||
esp_duplicate_info_t device_info;
|
||||
}update_duplicate_exceptional_list;
|
||||
//BTC_GAP_BLE_ACT_SET_CONN_PARAMS
|
||||
struct set_conn_params_args {
|
||||
esp_bd_addr_t bd_addr;
|
||||
@@ -144,6 +152,12 @@ typedef union {
|
||||
esp_bd_addr_t bd_addr;
|
||||
bool accept;
|
||||
} enc_comfirm_replay;
|
||||
//BTC_GAP_BLE_OOB_DATA_REPLY_EVT
|
||||
struct oob_req_reply_args {
|
||||
esp_bd_addr_t bd_addr;
|
||||
uint8_t len;
|
||||
uint8_t *p_value;
|
||||
} oob_req_reply;
|
||||
//BTC_GAP_BLE_DISCONNECT_EVT
|
||||
struct disconnect_args {
|
||||
esp_bd_addr_t remote_device;
|
||||
|
@@ -32,6 +32,7 @@ typedef struct {
|
||||
UINT8 ble_resp_key;
|
||||
UINT8 ble_max_key_size;
|
||||
UINT8 ble_accept_auth_enable;
|
||||
UINT8 oob_support;
|
||||
#endif
|
||||
|
||||
} tBTE_APPL_CFG;
|
||||
|
@@ -43,7 +43,7 @@
|
||||
//#include "osi/include/log.h"
|
||||
|
||||
#if SMP_INCLUDED == TRUE
|
||||
// The temp variable to pass parameter between functions when in the connected event comeback.
|
||||
// The temp variable to pass parameter between functions when in the connected event callback.
|
||||
static BOOLEAN temp_enhanced = FALSE;
|
||||
extern BOOLEAN aes_cipher_msg_auth_code(BT_OCTET16 key, UINT8 *input, UINT16 length,
|
||||
UINT16 tlen, UINT8 *p_signature);
|
||||
@@ -629,7 +629,7 @@ void BTM_ReadDevInfo (BD_ADDR remote_bda, tBT_DEVICE_TYPE *p_dev_type, tBLE_ADDR
|
||||
|
||||
*p_addr_type = BLE_ADDR_PUBLIC;
|
||||
|
||||
if (!p_dev_rec) {
|
||||
if (!p_dev_rec) {
|
||||
*p_dev_type = BT_DEVICE_TYPE_BREDR;
|
||||
/* Check with the BT manager if details about remote device are known */
|
||||
if (p_inq_info != NULL) {
|
||||
@@ -1471,7 +1471,7 @@ tBTM_STATUS btm_ble_set_encryption (BD_ADDR bd_addr, void *p_ref_data, UINT8 lin
|
||||
if(link_role == BTM_ROLE_SLAVE && (p_rec->ble.key_type & BTM_LE_KEY_PENC)) {
|
||||
p_rec->ble.skip_update_conn_param = true;
|
||||
} else {
|
||||
p_rec->ble.skip_update_conn_param = false;
|
||||
p_rec->ble.skip_update_conn_param = false;
|
||||
}
|
||||
if (SMP_Pair(bd_addr) == SMP_STARTED) {
|
||||
cmd = BTM_CMD_STARTED;
|
||||
@@ -1620,7 +1620,7 @@ void btm_ble_link_encrypted(BD_ADDR bd_addr, UINT8 encr_enable)
|
||||
/* to notify GATT to send data if any request is pending */
|
||||
gatt_notify_enc_cmpl(p_dev_rec->ble.pseudo_addr);
|
||||
}
|
||||
#endif ///SMP_INCLUDED == TRUE
|
||||
#endif ///SMP_INCLUDED == TRUE
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -1946,10 +1946,10 @@ void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len, BOOLEAN enhanced)
|
||||
|
||||
/* It will cause that scanner doesn't send scan request to advertiser
|
||||
* which has sent IRK to us and we have stored the IRK in controller.
|
||||
* It is a design problem of hardware. The temporal solution is not to
|
||||
* send the key to the controller and then resolve the random address in host.
|
||||
* so we need send the real address information to controller to connect.
|
||||
* Once the connection is successful, resolve device address whether it is
|
||||
* It is a hardware limitation. The preliminary solution is not to
|
||||
* send key to the controller, but to resolve the random address in host.
|
||||
* so we need send the real address information to controller to connect.
|
||||
* Once the connection is successful, resolve device address whether it is
|
||||
* slave or master*/
|
||||
|
||||
/* if (!match && role == HCI_ROLE_SLAVE && BTM_BLE_IS_RESOLVE_BDA(bda)) { */
|
||||
|
@@ -44,6 +44,8 @@
|
||||
#include "btm_ble_int.h"
|
||||
//#define LOG_TAG "bt_btm_ble"
|
||||
//#include "osi/include/log.h"
|
||||
#include "osi/osi.h"
|
||||
#include "osi/mutex.h"
|
||||
|
||||
#define BTM_BLE_NAME_SHORT 0x01
|
||||
#define BTM_BLE_NAME_CMPL 0x02
|
||||
@@ -223,6 +225,58 @@ const UINT8 btm_le_state_combo_tbl[BTM_BLE_STATE_MAX][BTM_BLE_STATE_MAX][2] = {
|
||||
/* check LE combo state supported */
|
||||
#define BTM_LE_STATES_SUPPORTED(x, y, z) ((x)[(z)] & (y))
|
||||
|
||||
static osi_mutex_t adv_enable_lock;
|
||||
static osi_mutex_t adv_data_lock;
|
||||
static osi_mutex_t adv_param_lock;
|
||||
static osi_mutex_t scan_enable_lock;
|
||||
static osi_mutex_t scan_param_lock;
|
||||
osi_sem_t adv_enable_sem;
|
||||
osi_sem_t adv_data_sem;
|
||||
osi_sem_t adv_param_sem;
|
||||
osi_sem_t scan_enable_sem;
|
||||
osi_sem_t scan_param_sem;
|
||||
uint8_t adv_enable_status = 0;
|
||||
uint8_t adv_data_status = 0;
|
||||
uint8_t adv_param_status = 0;
|
||||
uint8_t scan_enable_status = 0;
|
||||
uint8_t scan_param_status = 0;
|
||||
|
||||
void btm_lock_init(void)
|
||||
{
|
||||
osi_mutex_new(&adv_enable_lock);
|
||||
osi_mutex_new(&adv_data_lock);
|
||||
osi_mutex_new(&adv_param_lock);
|
||||
osi_mutex_new(&scan_enable_lock);
|
||||
osi_mutex_new(&scan_param_lock);
|
||||
}
|
||||
|
||||
void btm_lock_free(void)
|
||||
{
|
||||
osi_mutex_free(&adv_enable_lock);
|
||||
osi_mutex_free(&adv_data_lock);
|
||||
osi_mutex_free(&adv_param_lock);
|
||||
osi_mutex_free(&scan_enable_lock);
|
||||
osi_mutex_free(&scan_param_lock);
|
||||
}
|
||||
|
||||
void btm_sem_init(void)
|
||||
{
|
||||
osi_sem_new(&adv_enable_sem, 1, 0);
|
||||
osi_sem_new(&adv_data_sem, 1, 0);
|
||||
osi_sem_new(&adv_param_sem, 1, 0);
|
||||
osi_sem_new(&scan_enable_sem, 1, 0);
|
||||
osi_sem_new(&scan_param_sem, 1, 0);
|
||||
}
|
||||
|
||||
void btm_sem_free(void)
|
||||
{
|
||||
osi_sem_free(&adv_enable_sem);
|
||||
osi_sem_free(&adv_data_sem);
|
||||
osi_sem_free(&adv_param_sem);
|
||||
osi_sem_free(&scan_enable_sem);
|
||||
osi_sem_free(&scan_param_sem);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTM_BleRegiseterConnParamCallback
|
||||
@@ -529,13 +583,7 @@ tBTM_STATUS BTM_BleBroadcast(BOOLEAN start, tBTM_START_STOP_ADV_CMPL_CBACK *p_s
|
||||
evt_type = p_cb->scan_rsp ? BTM_BLE_CONNECT_EVT : BTM_BLE_NON_CONNECT_EVT;
|
||||
}
|
||||
#endif
|
||||
// if adv state is BTM_BLE_ADV_PENDING, return immediately
|
||||
if (p_cb->state == BTM_BLE_ADV_PENDING) {
|
||||
if (p_stop_adv_cback) {
|
||||
(*p_stop_adv_cback)(HCI_ERR_ILLEGAL_COMMAND);
|
||||
}
|
||||
return BTM_BUSY;
|
||||
}
|
||||
|
||||
if (start && p_cb->adv_mode == BTM_BLE_ADV_DISABLE) {
|
||||
/* update adv params */
|
||||
if (!btsnd_hcic_ble_write_adv_params ((UINT16)(p_cb->adv_interval_min ? p_cb->adv_interval_min :
|
||||
@@ -569,9 +617,6 @@ tBTM_STATUS BTM_BleBroadcast(BOOLEAN start, tBTM_START_STOP_ADV_CMPL_CBACK *p_s
|
||||
2. stop adv shen adv has already stoped
|
||||
*/
|
||||
status = BTM_SUCCESS;
|
||||
if (p_stop_adv_cback) {
|
||||
(*p_stop_adv_cback)(status);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@@ -708,6 +753,37 @@ extern void BTM_BleReadControllerFeatures(tBTM_BLE_CTRL_FEATURES_CBACK *p_vsc_c
|
||||
return ;
|
||||
}
|
||||
|
||||
void BTM_VendorHciEchoCmdCallback(tBTM_VSC_CMPL *p1)
|
||||
{
|
||||
if (!p1) {
|
||||
return;
|
||||
}
|
||||
uint8_t *p = p1->p_param_buf;
|
||||
uint8_t status, echo;
|
||||
STREAM_TO_UINT8 (status, p);
|
||||
STREAM_TO_UINT8 (echo, p);
|
||||
BTM_TRACE_DEBUG("%s status 0x%x echo 0x%x", __func__, status, echo);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
**
|
||||
** Function BTM_VendorHciEchoCmdTest
|
||||
**
|
||||
** Description vendor common echo hci cmd test, controller will return status and echo
|
||||
**
|
||||
** Parameters: echo : echo value
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTM_VendorHciEchoCmdTest(uint8_t echo)
|
||||
{
|
||||
BTM_VendorSpecificCommand (HCI_VENDOR_COMMON_ECHO_CMD_OPCODE,
|
||||
1,
|
||||
&echo,
|
||||
BTM_VendorHciEchoCmdCallback);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTM_BleEnableMixedPrivacyMode
|
||||
@@ -1197,7 +1273,7 @@ tBTM_STATUS BTM_BleSetAdvParams(UINT16 adv_int_min, UINT16 adv_int_max,
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTM_BleSetAdvParamsStartAdv
|
||||
** Function BTM_BleSetAdvParamsAll
|
||||
**
|
||||
** Description This function is called to set all of the advertising parameters.
|
||||
**
|
||||
@@ -1206,14 +1282,14 @@ tBTM_STATUS BTM_BleSetAdvParams(UINT16 adv_int_min, UINT16 adv_int_max,
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
tBTM_STATUS BTM_BleSetAdvParamsStartAdv(UINT16 adv_int_min, UINT16 adv_int_max, UINT8 adv_type,
|
||||
tBTM_STATUS BTM_BleSetAdvParamsAll(UINT16 adv_int_min, UINT16 adv_int_max, UINT8 adv_type,
|
||||
tBLE_ADDR_TYPE own_bda_type, tBLE_BD_ADDR *p_dir_bda,
|
||||
tBTM_BLE_ADV_CHNL_MAP chnl_map, tBTM_BLE_AFP afp, tBTM_START_ADV_CMPL_CBACK *adv_cb)
|
||||
{
|
||||
tBTM_LE_RANDOM_CB *p_addr_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
|
||||
tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
|
||||
|
||||
BTM_TRACE_EVENT ("BTM_BleSetAdvParamsStartAdv\n");
|
||||
BTM_TRACE_EVENT ("BTM_BleSetAdvParamsAll\n");
|
||||
|
||||
if (!controller_get_interface()->supports_ble()) {
|
||||
return BTM_ILLEGAL_VALUE;
|
||||
@@ -1290,6 +1366,9 @@ tBTM_STATUS BTM_BleSetAdvParamsStartAdv(UINT16 adv_int_min, UINT16 adv_int_max,
|
||||
return BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
btm_ble_stop_adv();
|
||||
|
||||
osi_mutex_lock(&adv_param_lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
if(adv_type == BTM_BLE_CONNECT_DIR_EVT){
|
||||
btm_ble_set_topology_mask(BTM_BLE_STATE_HI_DUTY_DIR_ADV_BIT);
|
||||
}else if(adv_type == BTM_BLE_CONNECT_LO_DUTY_DIR_EVT){
|
||||
@@ -1311,40 +1390,39 @@ tBTM_STATUS BTM_BleSetAdvParamsStartAdv(UINT16 adv_int_min, UINT16 adv_int_max,
|
||||
}
|
||||
|
||||
BTM_TRACE_EVENT ("update params for an active adv\n");
|
||||
// if adv state is BTM_BLE_ADV_PENDING, return immediately
|
||||
if (p_cb->state == BTM_BLE_ADV_PENDING) {
|
||||
if (p_cb->p_adv_cb) {
|
||||
(*p_cb->p_adv_cb)(HCI_ERR_ILLEGAL_COMMAND);
|
||||
}
|
||||
return BTM_BUSY;
|
||||
}
|
||||
/* host will stop adv first and then start adv again if adv has already started
|
||||
it will get callback twice.
|
||||
*/
|
||||
if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE) {
|
||||
p_cb->adv_callback_twice = TRUE;
|
||||
}
|
||||
tBTM_STATUS status = btm_ble_stop_adv();
|
||||
if (status != BTM_SUCCESS) {
|
||||
p_cb->adv_callback_twice = FALSE;
|
||||
}
|
||||
|
||||
|
||||
tBTM_STATUS status = BTM_SUCCESS;
|
||||
/* update adv params */
|
||||
btsnd_hcic_ble_write_adv_params (adv_int_min,
|
||||
adv_int_max,
|
||||
adv_type,
|
||||
own_bda_type,
|
||||
p_dir_bda->type,
|
||||
p_dir_bda->bda,
|
||||
chnl_map,
|
||||
p_cb->afp);
|
||||
|
||||
return btm_ble_start_adv();
|
||||
if (btsnd_hcic_ble_write_adv_params (adv_int_min,
|
||||
adv_int_max,
|
||||
adv_type,
|
||||
own_bda_type,
|
||||
p_dir_bda->type,
|
||||
p_dir_bda->bda,
|
||||
chnl_map,
|
||||
p_cb->afp)) {
|
||||
osi_sem_take(&adv_param_sem, OSI_SEM_MAX_TIMEOUT);
|
||||
status = adv_param_status;
|
||||
} else {
|
||||
status = BTM_NO_RESOURCES;
|
||||
}
|
||||
osi_mutex_unlock(&adv_param_lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
tBTM_STATUS BTM_BleStartAdv(void)
|
||||
{
|
||||
tBTM_STATUS status = BTM_SUCCESS;
|
||||
if (!controller_get_interface()->supports_ble()) {
|
||||
return BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
btm_ble_stop_adv();
|
||||
|
||||
status = btm_ble_start_adv();
|
||||
|
||||
|
||||
return status;
|
||||
}
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTM_BleReadAdvParams
|
||||
@@ -1437,17 +1515,18 @@ void BTM_BleSetScanParams(tGATT_IF client_if, UINT32 scan_interval, UINT32 scan_
|
||||
|
||||
}
|
||||
|
||||
void BTM_BleSetScanFilterParams(tGATT_IF client_if, UINT32 scan_interval, UINT32 scan_window,
|
||||
tBTM_STATUS BTM_BleSetScanFilterParams(tGATT_IF client_if, UINT32 scan_interval, UINT32 scan_window,
|
||||
tBLE_SCAN_MODE scan_mode, UINT8 addr_type_own, UINT8 scan_duplicate_filter, tBTM_BLE_SFP scan_filter_policy,
|
||||
tBLE_SCAN_PARAM_SETUP_CBACK scan_setup_status_cback)
|
||||
{
|
||||
tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
|
||||
UINT32 max_scan_interval;
|
||||
UINT32 max_scan_window;
|
||||
tBTM_STATUS ret = BTM_SUCCESS;
|
||||
|
||||
BTM_TRACE_EVENT ("%s\n", __func__);
|
||||
if (!controller_get_interface()->supports_ble()) {
|
||||
return;
|
||||
return BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
if(addr_type_own == BLE_ADDR_RANDOM) {
|
||||
@@ -1468,11 +1547,8 @@ void BTM_BleSetScanFilterParams(tGATT_IF client_if, UINT32 scan_interval, UINT32
|
||||
memcpy(btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr, btm_cb.ble_ctr_cb.addr_mgnt_cb.resolvale_addr, BD_ADDR_LEN);
|
||||
btsnd_hcic_ble_set_random_addr(btm_cb.ble_ctr_cb.addr_mgnt_cb.resolvale_addr);
|
||||
}else {
|
||||
if (scan_setup_status_cback != NULL) {
|
||||
scan_setup_status_cback(client_if, BTM_ILLEGAL_VALUE);
|
||||
}
|
||||
BTM_TRACE_ERROR ("No random address yet, please set random address and try\n");
|
||||
return;
|
||||
return BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
} else if(addr_type_own == BLE_ADDR_PUBLIC_ID || addr_type_own == BLE_ADDR_RANDOM_ID) {
|
||||
if((btm_cb.ble_ctr_cb.addr_mgnt_cb.exist_addr_bit & BTM_BLE_GAP_ADDR_BIT_RESOLVABLE) == BTM_BLE_GAP_ADDR_BIT_RESOLVABLE) {
|
||||
@@ -1484,10 +1560,7 @@ void BTM_BleSetScanFilterParams(tGATT_IF client_if, UINT32 scan_interval, UINT32
|
||||
#if BLE_PRIVACY_SPT == TRUE
|
||||
if(btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) {
|
||||
BTM_TRACE_ERROR ("Error state\n");
|
||||
if (scan_setup_status_cback != NULL) {
|
||||
scan_setup_status_cback(client_if, BTM_ILLEGAL_VALUE);
|
||||
}
|
||||
return;
|
||||
return BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
#endif
|
||||
if(addr_type_own == BLE_ADDR_PUBLIC_ID) {
|
||||
@@ -1502,10 +1575,7 @@ void BTM_BleSetScanFilterParams(tGATT_IF client_if, UINT32 scan_interval, UINT32
|
||||
btsnd_hcic_ble_set_random_addr(btm_cb.ble_ctr_cb.addr_mgnt_cb.static_rand_addr);
|
||||
} else {
|
||||
BTM_TRACE_ERROR ("No RPA and no random address yet, please set RPA or random address and try\n");
|
||||
if (scan_setup_status_cback != NULL) {
|
||||
scan_setup_status_cback(client_if, BTM_ILLEGAL_VALUE);
|
||||
}
|
||||
return;
|
||||
return BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1523,10 +1593,12 @@ void BTM_BleSetScanFilterParams(tGATT_IF client_if, UINT32 scan_interval, UINT32
|
||||
max_scan_window = BTM_BLE_EXT_SCAN_WIN_MAX;
|
||||
}
|
||||
|
||||
osi_mutex_lock(&scan_param_lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
|
||||
if (BTM_BLE_ISVALID_PARAM(scan_interval, BTM_BLE_SCAN_INT_MIN, max_scan_interval) &&
|
||||
BTM_BLE_ISVALID_PARAM(scan_window, BTM_BLE_SCAN_WIN_MIN, max_scan_window) &&
|
||||
(scan_mode == BTM_BLE_SCAN_MODE_ACTI || scan_mode == BTM_BLE_SCAN_MODE_PASS) &&
|
||||
(scan_duplicate_filter < BTM_BLE_SCAN_DUPLICATE_MAX)) {
|
||||
(scan_duplicate_filter < BTM_BLE_SCAN_DUPLICATE_MAX) && (scan_window <= scan_interval)) {
|
||||
p_cb->scan_type = scan_mode;
|
||||
p_cb->scan_interval = scan_interval;
|
||||
p_cb->scan_window = scan_window;
|
||||
@@ -1535,22 +1607,20 @@ void BTM_BleSetScanFilterParams(tGATT_IF client_if, UINT32 scan_interval, UINT32
|
||||
p_cb->scan_duplicate_filter = scan_duplicate_filter;
|
||||
|
||||
|
||||
btsnd_hcic_ble_set_scan_params(p_cb->scan_type, (UINT16)scan_interval,
|
||||
if (btsnd_hcic_ble_set_scan_params(p_cb->scan_type, (UINT16)scan_interval,
|
||||
(UINT16)scan_window,
|
||||
addr_type_own,
|
||||
scan_filter_policy);
|
||||
|
||||
if (scan_setup_status_cback != NULL) {
|
||||
scan_setup_status_cback(client_if, BTM_SUCCESS);
|
||||
scan_filter_policy)) {
|
||||
osi_sem_take(&scan_param_sem, OSI_SEM_MAX_TIMEOUT);
|
||||
ret = scan_param_status;
|
||||
}
|
||||
} else {
|
||||
if (scan_setup_status_cback != NULL) {
|
||||
scan_setup_status_cback(client_if, BTM_ILLEGAL_VALUE);
|
||||
}
|
||||
|
||||
ret = BTM_ILLEGAL_VALUE;
|
||||
BTM_TRACE_ERROR("Illegal params: scan_interval = %d scan_window = %d\n",
|
||||
scan_interval, scan_window);
|
||||
}
|
||||
osi_mutex_unlock(&scan_param_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -1567,7 +1637,7 @@ void BTM_BleSetScanFilterParams(tGATT_IF client_if, UINT32 scan_interval, UINT32
|
||||
*******************************************************************************/
|
||||
tBTM_STATUS BTM_BleWriteScanRsp(tBTM_BLE_AD_MASK data_mask, tBTM_BLE_ADV_DATA *p_data)
|
||||
{
|
||||
tBTM_STATUS status = BTM_NO_RESOURCES;
|
||||
tBTM_STATUS ret;
|
||||
UINT8 rsp_data[BTM_BLE_AD_DATA_LEN],
|
||||
*p = rsp_data;
|
||||
|
||||
@@ -1577,22 +1647,25 @@ tBTM_STATUS BTM_BleWriteScanRsp(tBTM_BLE_AD_MASK data_mask, tBTM_BLE_ADV_DATA *p
|
||||
return BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
osi_mutex_lock(&adv_data_lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
memset(rsp_data, 0, BTM_BLE_AD_DATA_LEN);
|
||||
btm_ble_build_adv_data(&data_mask, &p, p_data);
|
||||
|
||||
if (btsnd_hcic_ble_set_scan_rsp_data((UINT8)(p - rsp_data), rsp_data)) {
|
||||
status = BTM_SUCCESS;
|
||||
osi_sem_take(&adv_data_sem, OSI_SEM_MAX_TIMEOUT);
|
||||
ret = adv_data_status;
|
||||
|
||||
if (data_mask != 0) {
|
||||
if (adv_data_status == BTM_SUCCESS && data_mask != 0) {
|
||||
btm_cb.ble_ctr_cb.inq_var.scan_rsp = TRUE;
|
||||
} else {
|
||||
btm_cb.ble_ctr_cb.inq_var.scan_rsp = FALSE;
|
||||
}
|
||||
} else {
|
||||
status = BTM_ILLEGAL_VALUE;
|
||||
ret = BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
return status;
|
||||
osi_mutex_unlock(&adv_data_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -1608,11 +1681,64 @@ tBTM_STATUS BTM_BleWriteScanRsp(tBTM_BLE_AD_MASK data_mask, tBTM_BLE_ADV_DATA *p
|
||||
*******************************************************************************/
|
||||
tBTM_STATUS BTM_BleWriteScanRspRaw(UINT8 *p_raw_scan_rsp, UINT32 raw_scan_rsp_len)
|
||||
{
|
||||
tBTM_STATUS ret;
|
||||
|
||||
osi_mutex_lock(&adv_data_lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
if (btsnd_hcic_ble_set_scan_rsp_data((UINT8)raw_scan_rsp_len, p_raw_scan_rsp)) {
|
||||
return BTM_SUCCESS;
|
||||
osi_sem_take(&adv_data_sem, OSI_SEM_MAX_TIMEOUT);
|
||||
ret = adv_data_status;
|
||||
} else {
|
||||
return BTM_NO_RESOURCES;
|
||||
ret = BTM_NO_RESOURCES;
|
||||
}
|
||||
osi_mutex_unlock(&adv_data_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTM_UpdateBleDuplicateExceptionalList
|
||||
**
|
||||
** Description This function is called to update duplicate scan exceptional list.
|
||||
**
|
||||
** Parameters: subcode: add, remove or clean duplicate scan exceptional list.
|
||||
** type: device info type
|
||||
** device_info: device information
|
||||
** update_exceptional_list_cmp_cb: complete callback
|
||||
**
|
||||
** Returns status
|
||||
**
|
||||
*******************************************************************************/
|
||||
tBTM_STATUS BTM_UpdateBleDuplicateExceptionalList(uint8_t subcode, uint32_t type, BD_ADDR device_info,
|
||||
tBTM_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_CMPL_CBACK update_exceptional_list_cmp_cb)
|
||||
{
|
||||
tBTM_BLE_CB *ble_cb = &btm_cb.ble_ctr_cb;
|
||||
ble_cb->update_exceptional_list_cmp_cb = update_exceptional_list_cmp_cb;
|
||||
tBTM_STATUS status = BTM_NO_RESOURCES;
|
||||
if (!controller_get_interface()->supports_ble()) {
|
||||
return BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
if(!device_info) {
|
||||
return BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
// subcoe + type + device info
|
||||
uint8_t device_info_array[1 + 4 + BD_ADDR_LEN] = {0};
|
||||
device_info_array[0] = subcode;
|
||||
device_info_array[1] = type & 0xff;
|
||||
device_info_array[2] = (type >> 8) & 0xff;
|
||||
device_info_array[3] = (type >> 16) & 0xff;
|
||||
device_info_array[4] = (type >> 24) & 0xff;
|
||||
if(type == BTM_DUPLICATE_SCAN_EXCEPTIONAL_INFO_ADV_ADDR) {
|
||||
bt_rcopy(&device_info_array[5], device_info, BD_ADDR_LEN);
|
||||
} else {
|
||||
memcpy(&device_info_array[5], device_info, 4);
|
||||
}
|
||||
status = BTM_VendorSpecificCommand(HCI_VENDOR_BLE_UPDATE_DUPLICATE_EXCEPTIONAL_LIST, 1 + 4 + BD_ADDR_LEN, device_info_array, NULL);
|
||||
if(status == BTM_CMD_STARTED) {
|
||||
status = BTM_SUCCESS;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -1631,13 +1757,14 @@ tBTM_STATUS BTM_BleWriteAdvData(tBTM_BLE_AD_MASK data_mask, tBTM_BLE_ADV_DATA *p
|
||||
tBTM_BLE_LOCAL_ADV_DATA *p_cb_data = &btm_cb.ble_ctr_cb.inq_var.adv_data;
|
||||
UINT8 *p;
|
||||
tBTM_BLE_AD_MASK mask = data_mask;
|
||||
tBTM_STATUS ret;
|
||||
|
||||
BTM_TRACE_EVENT ("BTM_BleWriteAdvData ");
|
||||
|
||||
if (!controller_get_interface()->supports_ble()) {
|
||||
return BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
osi_mutex_lock(&adv_data_lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
memset(p_cb_data, 0, sizeof(tBTM_BLE_LOCAL_ADV_DATA));
|
||||
p = p_cb_data->ad_data;
|
||||
p_cb_data->data_mask = data_mask;
|
||||
@@ -1654,13 +1781,46 @@ tBTM_STATUS BTM_BleWriteAdvData(tBTM_BLE_AD_MASK data_mask, tBTM_BLE_ADV_DATA *p
|
||||
|
||||
if (btsnd_hcic_ble_set_adv_data((UINT8)(p_cb_data->p_pad - p_cb_data->ad_data),
|
||||
p_cb_data->ad_data)) {
|
||||
return BTM_SUCCESS;
|
||||
osi_sem_take(&adv_data_sem, OSI_SEM_MAX_TIMEOUT);
|
||||
ret = adv_data_status;
|
||||
} else {
|
||||
return BTM_NO_RESOURCES;
|
||||
ret = BTM_NO_RESOURCES;
|
||||
}
|
||||
|
||||
osi_mutex_unlock(&adv_data_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTM_BleWriteLongAdvData
|
||||
**
|
||||
** Description This function is called to write long advertising data.
|
||||
**
|
||||
** Parameters: adv_data: long advertising data
|
||||
** adv_data_len: the length of long advertising data
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
tBTM_STATUS BTM_BleWriteLongAdvData(uint8_t *adv_data, uint8_t adv_data_len)
|
||||
{
|
||||
tBTM_STATUS status = BTM_NO_RESOURCES;
|
||||
if (!controller_get_interface()->supports_ble()) {
|
||||
return BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
if(!adv_data || adv_data_len <= 0 || adv_data_len > BTM_BLE_LONG_ADV_MAX_LEN) {
|
||||
return BTM_ILLEGAL_VALUE;
|
||||
}
|
||||
uint8_t long_adv[BTM_BLE_LONG_ADV_MAX_LEN + 1] = {0};
|
||||
long_adv[0] = adv_data_len;
|
||||
memcpy(&long_adv[1], adv_data, adv_data_len);
|
||||
status = BTM_VendorSpecificCommand(HCI_VENDOR_BLE_LONG_ADV_DATA, BTM_BLE_LONG_ADV_MAX_LEN + 1, long_adv, NULL);
|
||||
if(status == BTM_CMD_STARTED) {
|
||||
status = BTM_SUCCESS;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
@@ -1675,11 +1835,17 @@ tBTM_STATUS BTM_BleWriteAdvData(tBTM_BLE_AD_MASK data_mask, tBTM_BLE_ADV_DATA *p
|
||||
*******************************************************************************/
|
||||
tBTM_STATUS BTM_BleWriteAdvDataRaw(UINT8 *p_raw_adv, UINT32 raw_adv_len)
|
||||
{
|
||||
tBTM_STATUS ret;
|
||||
osi_mutex_lock(&adv_data_lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
if (btsnd_hcic_ble_set_adv_data((UINT8)raw_adv_len, p_raw_adv)) {
|
||||
return BTM_SUCCESS;
|
||||
osi_sem_take(&adv_data_sem, OSI_SEM_MAX_TIMEOUT);
|
||||
ret = adv_data_status;
|
||||
} else {
|
||||
return BTM_NO_RESOURCES;
|
||||
ret = BTM_NO_RESOURCES;
|
||||
}
|
||||
osi_mutex_unlock(&adv_data_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -3431,6 +3597,8 @@ tBTM_STATUS btm_ble_start_scan(void)
|
||||
tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var;
|
||||
tBTM_STATUS status = BTM_CMD_STARTED;
|
||||
|
||||
osi_mutex_lock(&scan_enable_lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
|
||||
if(p_inq->scan_duplicate_filter > BTM_BLE_DUPLICATE_MAX) {
|
||||
p_inq->scan_duplicate_filter = BTM_BLE_DUPLICATE_DISABLE;
|
||||
}
|
||||
@@ -3438,6 +3606,10 @@ tBTM_STATUS btm_ble_start_scan(void)
|
||||
if (!btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, p_inq->scan_duplicate_filter)) {
|
||||
status = BTM_NO_RESOURCES;
|
||||
} else {
|
||||
osi_sem_take(&scan_enable_sem, OSI_SEM_MAX_TIMEOUT);
|
||||
if(scan_enable_status != BTM_SUCCESS) {
|
||||
status = BTM_NO_RESOURCES;
|
||||
}
|
||||
btm_cb.ble_ctr_cb.inq_var.state = BTM_BLE_SCANNING;
|
||||
if (p_inq->scan_type == BTM_BLE_SCAN_MODE_ACTI) {
|
||||
btm_ble_set_topology_mask(BTM_BLE_STATE_ACTIVE_SCAN_BIT);
|
||||
@@ -3445,7 +3617,7 @@ tBTM_STATUS btm_ble_start_scan(void)
|
||||
btm_ble_set_topology_mask(BTM_BLE_STATE_PASSIVE_SCAN_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
osi_mutex_unlock(&scan_enable_lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -3553,6 +3725,7 @@ static void btm_ble_stop_discover(void)
|
||||
tBTM_CMPL_CB *p_scan_cb = p_ble_cb->p_scan_cmpl_cb;
|
||||
btu_stop_timer (&p_ble_cb->scan_timer_ent);
|
||||
|
||||
osi_mutex_lock(&scan_enable_lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
p_ble_cb->scan_activity &= ~BTM_LE_DISCOVER_ACTIVE;
|
||||
|
||||
p_ble_cb->p_scan_results_cb = NULL;
|
||||
@@ -3563,12 +3736,15 @@ static void btm_ble_stop_discover(void)
|
||||
btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_NONE;
|
||||
btm_cb.ble_ctr_cb.inq_var.state = BTM_BLE_STOP_SCAN;
|
||||
/* stop discovery now */
|
||||
btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
|
||||
if(btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE)) {
|
||||
osi_sem_take(&scan_enable_sem, OSI_SEM_MAX_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
if (p_scan_cb) {
|
||||
(p_scan_cb)((tBTM_INQUIRY_CMPL *) &btm_cb.btm_inq_vars.inq_cmpl_info);
|
||||
}
|
||||
osi_mutex_unlock(&scan_enable_lock);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -3634,6 +3810,8 @@ tBTM_STATUS btm_ble_start_adv(void)
|
||||
return BTM_WRONG_MODE;
|
||||
}
|
||||
|
||||
osi_mutex_lock(&adv_enable_lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
|
||||
#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
|
||||
/* To relax resolving list, always have resolving list enabled, unless directed adv */
|
||||
if (p_cb->evt_type != BTM_BLE_CONNECT_LO_DUTY_DIR_EVT &&
|
||||
@@ -3653,10 +3831,11 @@ tBTM_STATUS btm_ble_start_adv(void)
|
||||
tBTM_BLE_GAP_STATE temp_state = p_cb->state;
|
||||
UINT8 adv_mode = p_cb->adv_mode;
|
||||
p_cb->adv_mode = BTM_BLE_ADV_ENABLE;
|
||||
p_cb->state = BTM_BLE_ADV_PENDING;
|
||||
p_cb->state = BTM_BLE_ADVERTISING;
|
||||
btm_ble_adv_states_operation(btm_ble_set_topology_mask, p_cb->evt_type);
|
||||
if (btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_ENABLE)) {
|
||||
rt = BTM_SUCCESS;
|
||||
osi_sem_take(&adv_enable_sem, OSI_SEM_MAX_TIMEOUT);
|
||||
rt = adv_enable_status;
|
||||
BTM_TRACE_EVENT ("BTM_SUCCESS\n");
|
||||
} else {
|
||||
p_cb->adv_mode = BTM_BLE_ADV_DISABLE;
|
||||
@@ -3665,6 +3844,11 @@ tBTM_STATUS btm_ble_start_adv(void)
|
||||
btm_ble_adv_states_operation(btm_ble_clear_topology_mask, p_cb->evt_type);
|
||||
btm_cb.ble_ctr_cb.wl_state &= ~BTM_BLE_WL_ADV;
|
||||
}
|
||||
|
||||
if(adv_enable_status != HCI_SUCCESS) {
|
||||
p_cb->adv_mode = adv_mode;
|
||||
}
|
||||
osi_mutex_unlock(&adv_enable_lock);
|
||||
return rt;
|
||||
}
|
||||
|
||||
@@ -3681,8 +3865,8 @@ tBTM_STATUS btm_ble_stop_adv(void)
|
||||
{
|
||||
tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
|
||||
tBTM_STATUS rt = BTM_SUCCESS;
|
||||
|
||||
if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE) {
|
||||
osi_mutex_lock(&adv_enable_lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
UINT8 temp_adv_mode = p_cb->adv_mode;
|
||||
BOOLEAN temp_fast_adv_on = p_cb->fast_adv_on;
|
||||
tBTM_BLE_GAP_STATE temp_state = p_cb->state;
|
||||
@@ -3691,14 +3875,15 @@ tBTM_STATUS btm_ble_stop_adv(void)
|
||||
|
||||
p_cb->fast_adv_on = FALSE;
|
||||
p_cb->adv_mode = BTM_BLE_ADV_DISABLE;
|
||||
p_cb->state = BTM_BLE_ADV_PENDING;
|
||||
p_cb->state = BTM_BLE_STOP_ADV;
|
||||
btm_cb.ble_ctr_cb.wl_state &= ~BTM_BLE_WL_ADV;
|
||||
|
||||
/* clear all adv states */
|
||||
btm_ble_clear_topology_mask (BTM_BLE_STATE_ALL_ADV_MASK);
|
||||
|
||||
if (btsnd_hcic_ble_set_adv_enable (BTM_BLE_ADV_DISABLE)) {
|
||||
|
||||
osi_sem_take(&adv_enable_sem, OSI_SEM_MAX_TIMEOUT);
|
||||
rt = adv_enable_status;
|
||||
} else {
|
||||
// reset state
|
||||
p_cb->fast_adv_on = temp_fast_adv_on;
|
||||
@@ -3709,6 +3894,10 @@ tBTM_STATUS btm_ble_stop_adv(void)
|
||||
|
||||
rt = BTM_NO_RESOURCES;
|
||||
}
|
||||
if(adv_enable_status != HCI_SUCCESS) {
|
||||
p_cb->adv_mode = temp_adv_mode;
|
||||
}
|
||||
osi_mutex_unlock(&adv_enable_lock);
|
||||
}
|
||||
return rt;
|
||||
}
|
||||
@@ -3870,35 +4059,9 @@ void btm_ble_read_remote_features_complete(UINT8 *p)
|
||||
*******************************************************************************/
|
||||
void btm_ble_write_adv_enable_complete(UINT8 *p)
|
||||
{
|
||||
tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
|
||||
UINT8 status = *p;
|
||||
|
||||
// callback to the APP after receive the adv complete from the controller.
|
||||
if (p_cb->p_adv_cb && p_cb->adv_mode == BTM_BLE_ADV_ENABLE) {
|
||||
if (p_cb->adv_callback_twice) {
|
||||
p_cb->adv_callback_twice = FALSE;
|
||||
}else {
|
||||
p_cb->state = BTM_BLE_ADVERTISING;
|
||||
(*p_cb->p_adv_cb)(status);
|
||||
p_cb->p_adv_cb = NULL;
|
||||
}
|
||||
} else if (p_cb->p_stop_adv_cb && p_cb->adv_mode == BTM_BLE_ADV_DISABLE) {
|
||||
p_cb->state = BTM_BLE_STOP_ADV;
|
||||
(*p_cb->p_stop_adv_cb)(status);
|
||||
p_cb->p_stop_adv_cb = NULL;
|
||||
}else {
|
||||
// p_cb->p_adv_cb is NULL or p_cb->p_stop_adv_cb is NULL
|
||||
if (p_cb->adv_mode == BTM_BLE_ADV_ENABLE) {
|
||||
p_cb->state = BTM_BLE_ADVERTISING;
|
||||
}else {
|
||||
p_cb->state = BTM_BLE_STOP_ADV;
|
||||
}
|
||||
p_cb->adv_callback_twice = FALSE;
|
||||
}
|
||||
/* if write adv enable/disbale not succeed */
|
||||
if (*p != HCI_SUCCESS) {
|
||||
/* toggle back the adv mode */
|
||||
p_cb->adv_mode = !p_cb->adv_mode;
|
||||
BTM_TRACE_ERROR("%s failed", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -771,8 +771,8 @@ BOOLEAN btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC *p_dev_rec)
|
||||
}
|
||||
/* It will cause that scanner doesn't send scan request to advertiser
|
||||
* which has sent IRK to us and we have stored the IRK in controller.
|
||||
* It is a design problem of hardware. The temporal solution is not to
|
||||
* send the key to the controller and then resolve the random address in host. */
|
||||
* It is a hardware limitation. The preliminary solution is not to
|
||||
* send key to the controller, but to resolve the random address in host. */
|
||||
/*
|
||||
BTM_TRACE_DEBUG("%s:adding device to controller resolving list\n", __func__);
|
||||
UINT8 *peer_irk = p_dev_rec->ble.keys.irk;
|
||||
|
@@ -689,6 +689,24 @@ tBTM_STATUS BTM_VendorSpecificCommand(UINT16 opcode, UINT8 param_len,
|
||||
void btm_vsc_complete (UINT8 *p, UINT16 opcode, UINT16 evt_len,
|
||||
tBTM_CMPL_CB *p_vsc_cplt_cback)
|
||||
{
|
||||
tBTM_BLE_CB *ble_cb = &btm_cb.ble_ctr_cb;
|
||||
switch(opcode) {
|
||||
case HCI_VENDOR_BLE_LONG_ADV_DATA:
|
||||
BTM_TRACE_EVENT("Set long adv data complete\n");
|
||||
break;
|
||||
case HCI_VENDOR_BLE_UPDATE_DUPLICATE_EXCEPTIONAL_LIST: {
|
||||
uint8_t subcode, status; uint32_t length;
|
||||
STREAM_TO_UINT8(status, p);
|
||||
STREAM_TO_UINT8(subcode, p);
|
||||
STREAM_TO_UINT32(length, p);
|
||||
if(ble_cb && ble_cb->update_exceptional_list_cmp_cb) {
|
||||
(*ble_cb->update_exceptional_list_cmp_cb)(status, subcode, length, p);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
tBTM_VSC_CMPL vcs_cplt_params;
|
||||
|
||||
/* If there was a callback address for vcs complete, call it */
|
||||
|
@@ -75,6 +75,8 @@ void btm_init (void)
|
||||
#endif
|
||||
|
||||
btm_dev_init(); /* Device Manager Structures & HCI_Reset */
|
||||
btm_lock_init();
|
||||
btm_sem_init();
|
||||
}
|
||||
|
||||
|
||||
@@ -94,4 +96,6 @@ void btm_free(void)
|
||||
#if BTM_DYNAMIC_MEMORY
|
||||
FREE_AND_RESET(btm_cb_ptr);
|
||||
#endif
|
||||
btm_lock_free();
|
||||
btm_sem_free();
|
||||
}
|
||||
|
@@ -152,7 +152,6 @@ typedef struct {
|
||||
tBTM_START_ADV_CMPL_CBACK *p_adv_cb;
|
||||
tBTM_START_STOP_ADV_CMPL_CBACK *p_stop_adv_cb;
|
||||
tBLE_ADDR_TYPE adv_addr_type;
|
||||
BOOLEAN adv_callback_twice;
|
||||
UINT8 evt_type;
|
||||
UINT8 adv_mode;
|
||||
tBLE_BD_ADDR direct_bda;
|
||||
@@ -280,6 +279,9 @@ typedef UINT16 tBTM_BLE_STATE_MASK;
|
||||
#define BTM_LE_RESOLVING_LIST_MAX 0x20
|
||||
#endif
|
||||
|
||||
#define BTM_DUPLICATE_SCAN_EXCEPTIONAL_INFO_ADV_ADDR 0
|
||||
#define BTM_DUPLICATE_SCAN_EXCEPTIONAL_INFO_MESH_LINK_ID 1
|
||||
|
||||
typedef struct {
|
||||
BD_ADDR *resolve_q_random_pseudo;
|
||||
UINT8 *resolve_q_action;
|
||||
@@ -357,6 +359,7 @@ typedef struct {
|
||||
/* current BLE link state */
|
||||
tBTM_BLE_STATE_MASK cur_states; /* bit mask of tBTM_BLE_STATE */
|
||||
UINT8 link_count[2]; /* total link count master and slave*/
|
||||
tBTM_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_CMPL_CBACK *update_exceptional_list_cmp_cb;
|
||||
} tBTM_BLE_CB;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@@ -1135,6 +1135,14 @@ void btm_acl_paging (BT_HDR *p, BD_ADDR dest);
|
||||
UINT8 btm_sec_clr_service_by_psm (UINT16 psm);
|
||||
void btm_sec_clr_temp_auth_service (BD_ADDR bda);
|
||||
|
||||
void btm_lock_init(void);
|
||||
|
||||
void btm_sem_init(void);
|
||||
|
||||
void btm_sem_free(void);
|
||||
|
||||
void btm_lock_free(void);
|
||||
|
||||
/*
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@@ -43,7 +43,7 @@
|
||||
#include "common/bt_trace.h"
|
||||
|
||||
#include "osi/thread.h"
|
||||
|
||||
//#include "osi/mutex.h"
|
||||
// TODO(zachoverflow): remove this horrible hack
|
||||
#include "stack/btu.h"
|
||||
|
||||
@@ -137,6 +137,17 @@ static void btu_ble_rc_param_req_evt(UINT8 *p);
|
||||
static void btu_ble_proc_enhanced_conn_cmpl (UINT8 *p, UINT16 evt_len);
|
||||
//#endif
|
||||
|
||||
extern osi_sem_t adv_enable_sem;
|
||||
extern osi_sem_t adv_data_sem;
|
||||
extern osi_sem_t adv_param_sem;
|
||||
extern osi_sem_t scan_enable_sem;
|
||||
extern osi_sem_t scan_param_sem;
|
||||
extern uint8_t adv_enable_status;
|
||||
extern uint8_t adv_data_status;
|
||||
extern uint8_t adv_param_status;
|
||||
extern uint8_t scan_enable_status;
|
||||
extern uint8_t scan_param_status;
|
||||
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -1026,6 +1037,40 @@ static void btu_hcif_command_complete_evt_on_task(BT_HDR *event)
|
||||
|
||||
static void btu_hcif_command_complete_evt(BT_HDR *response, void *context)
|
||||
{
|
||||
#if (BLE_INCLUDED == TRUE)
|
||||
command_opcode_t opcode;
|
||||
uint8_t *stream = response->data + response->offset + 3;
|
||||
STREAM_TO_UINT16(opcode, stream);
|
||||
switch (opcode) {
|
||||
case HCI_BLE_WRITE_ADV_DATA:
|
||||
adv_data_status = *stream;
|
||||
osi_sem_give(&adv_data_sem);
|
||||
break;
|
||||
case HCI_BLE_WRITE_SCAN_RSP_DATA:
|
||||
adv_data_status = *stream;
|
||||
osi_sem_give(&adv_data_sem);
|
||||
break;
|
||||
case HCI_BLE_WRITE_ADV_ENABLE: {
|
||||
adv_enable_status = *stream;
|
||||
osi_sem_give(&adv_enable_sem);
|
||||
break;
|
||||
}
|
||||
case HCI_BLE_WRITE_ADV_PARAMS:
|
||||
adv_param_status = *stream;
|
||||
osi_sem_give(&adv_param_sem);
|
||||
break;
|
||||
case HCI_BLE_WRITE_SCAN_PARAMS:
|
||||
scan_param_status = *stream;
|
||||
osi_sem_give(&scan_param_sem);
|
||||
break;
|
||||
case HCI_BLE_WRITE_SCAN_ENABLE:
|
||||
scan_enable_status = *stream;
|
||||
osi_sem_give(&scan_enable_sem);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
BT_HDR *event = osi_calloc(sizeof(BT_HDR) + sizeof(command_complete_hack_t));
|
||||
command_complete_hack_t *hack = (command_complete_hack_t *)&event->data[0];
|
||||
|
||||
|
@@ -188,6 +188,8 @@ void gatt_free(void)
|
||||
|
||||
#if (GATTS_INCLUDED == TRUE)
|
||||
for (i = 0; i < GATT_MAX_SR_PROFILES; i++) {
|
||||
gatt_remove_an_item_from_list(&gatt_cb.hdl_list_info, &gatt_cb.hdl_list[i]);
|
||||
gatt_free_attr_value_buffer(&gatt_cb.hdl_list[i]);
|
||||
gatt_free_hdl_buffer(&gatt_cb.hdl_list[i]);
|
||||
}
|
||||
#endif /* #if (GATTS_INCLUDED == TRUE) */
|
||||
|
@@ -2192,9 +2192,10 @@ void gatt_end_operation(tGATT_CLCB *p_clcb, tGATT_STATUS status, void *p_data)
|
||||
(*p_disc_cmpl_cb)(conn_id, disc_type, status);
|
||||
} else if (p_cmpl_cb && op) {
|
||||
(*p_cmpl_cb)(conn_id, op, status, &cb_data);
|
||||
} else
|
||||
} else {
|
||||
GATT_TRACE_WARNING ("gatt_end_operation not sent out op=%d p_disc_cmpl_cb:%p p_cmpl_cb:%p",
|
||||
operation, p_disc_cmpl_cb, p_cmpl_cb);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
@@ -790,4 +790,22 @@ static inline void bdsetany(BD_ADDR a)
|
||||
{
|
||||
bdcpy(a, bd_addr_any);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function bt_rcopy
|
||||
**
|
||||
** Description memory reverse and copy.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
static inline void bt_rcopy(UINT8 *dst, UINT8 const *src, UINT16 len)
|
||||
{
|
||||
src += len;
|
||||
while (len --) {
|
||||
*dst++ = *--src;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@@ -358,6 +358,8 @@ typedef UINT32 tBTM_BLE_AD_MASK;
|
||||
#define BTM_BLE_AD_TYPE_MANU HCI_EIR_MANUFACTURER_SPECIFIC_TYPE /* 0xff */
|
||||
typedef UINT8 tBTM_BLE_AD_TYPE;
|
||||
|
||||
#define BTM_BLE_LONG_ADV_MAX_LEN 249
|
||||
|
||||
/* Security settings used with L2CAP LE COC */
|
||||
#define BTM_SEC_LE_LINK_ENCRYPTED 0x01
|
||||
#define BTM_SEC_LE_LINK_PAIRED_WITHOUT_MITM 0x02
|
||||
@@ -867,6 +869,7 @@ tBTM_BLE_SCAN_SETUP_CBACK bta_ble_scan_setup_cb;
|
||||
typedef void (tBTM_START_ADV_CMPL_CBACK) (UINT8 status);
|
||||
typedef void (tBTM_START_STOP_ADV_CMPL_CBACK) (UINT8 status);
|
||||
|
||||
typedef void (tBTM_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_CMPL_CBACK) (tBTM_STATUS status, uint8_t subcode, uint32_t length, uint8_t *device_info);
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
@@ -949,7 +952,7 @@ tBTM_STATUS BTM_BleSetAdvParams(UINT16 adv_int_min, UINT16 adv_int_max,
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTM_BleSetAdvParamsStartAdv
|
||||
** Function BTM_BleSetAdvParamsAll
|
||||
**
|
||||
** Description This function is called to set all of the advertising parameters.
|
||||
**
|
||||
@@ -958,10 +961,23 @@ tBTM_STATUS BTM_BleSetAdvParams(UINT16 adv_int_min, UINT16 adv_int_max,
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
tBTM_STATUS BTM_BleSetAdvParamsStartAdv(UINT16 adv_int_min, UINT16 adv_int_max, UINT8 adv_type,
|
||||
tBTM_STATUS BTM_BleSetAdvParamsAll(UINT16 adv_int_min, UINT16 adv_int_max, UINT8 adv_type,
|
||||
tBLE_ADDR_TYPE own_bda_type, tBLE_BD_ADDR *p_dir_bda,
|
||||
tBTM_BLE_ADV_CHNL_MAP chnl_map, tBTM_BLE_AFP afp, tBTM_START_ADV_CMPL_CBACK *adv_cb);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTM_BleStartAdv
|
||||
**
|
||||
** Description This function is called to start adv.
|
||||
**
|
||||
** Parameters: None.
|
||||
**
|
||||
** Returns status
|
||||
**
|
||||
*******************************************************************************/
|
||||
tBTM_STATUS BTM_BleStartAdv(void);
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
@@ -978,6 +994,20 @@ tBTM_STATUS BTM_BleSetAdvParamsStartAdv(UINT16 adv_int_min, UINT16 adv_int_max,
|
||||
tBTM_STATUS BTM_BleWriteAdvData(tBTM_BLE_AD_MASK data_mask,
|
||||
tBTM_BLE_ADV_DATA *p_data);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTM_BleWriteLongAdvData
|
||||
**
|
||||
** Description This function is called to write long advertising data.
|
||||
**
|
||||
** Parameters: adv_data: long advertising data
|
||||
** adv_data_len: the length of long advertising data
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
tBTM_STATUS BTM_BleWriteLongAdvData(uint8_t *adv_data, uint8_t adv_data_len);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTM_BleWriteAdvDataRaw
|
||||
@@ -1071,9 +1101,9 @@ void BTM_BleSetScanParams(tGATT_IF client_if, UINT32 scan_interval,
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTM_BleSetScanFilterParams(tGATT_IF client_if, UINT32 scan_interval, UINT32 scan_window,
|
||||
tBLE_SCAN_MODE scan_mode, UINT8 addr_type_own, UINT8 scan_duplicate_filter, tBTM_BLE_SFP scan_filter_policy,
|
||||
tBLE_SCAN_PARAM_SETUP_CBACK scan_setup_status_cback);
|
||||
tBTM_STATUS BTM_BleSetScanFilterParams(tGATT_IF client_if, UINT32 scan_interval, UINT32 scan_window,
|
||||
tBLE_SCAN_MODE scan_mode, UINT8 addr_type_own, UINT8 scan_duplicate_filter, tBTM_BLE_SFP scan_filter_policy,
|
||||
tBLE_SCAN_PARAM_SETUP_CBACK scan_setup_status_cback);
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -2052,6 +2082,22 @@ tBTM_STATUS BTM_BleGetEnergyInfo(tBTM_BLE_ENERGY_INFO_CBACK *p_ener_cback);
|
||||
//extern
|
||||
tBTM_STATUS BTM_SetBleDataLength(BD_ADDR bd_addr, UINT16 tx_pdu_length);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTM_UpdateBleDuplicateExceptionalList
|
||||
**
|
||||
** Description This function is called to update duplicate scan exceptional list.
|
||||
**
|
||||
** Parameters: subcode: add, remove or clean duplicate scan exceptional list.
|
||||
** type: device info type
|
||||
** device_info: device information
|
||||
** update_exceptional_list_cmp_cb: complete callback
|
||||
**
|
||||
** Returns status
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
||||
tBTM_STATUS BTM_UpdateBleDuplicateExceptionalList(uint8_t subcode, uint32_t type, BD_ADDR device_info, tBTM_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_CMPL_CBACK update_exceptional_list_cmp_cb);
|
||||
/*
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@@ -51,6 +51,7 @@
|
||||
#define SLIP_DYNAMIC_MEMORY TRUE
|
||||
#define LLCP_DYNAMIC_MEMORY TRUE
|
||||
#define BTC_SBC_DEC_DYNAMIC_MEMORY TRUE
|
||||
#define BTC_SBC_ENC_DYNAMIC_MEMORY TRUE
|
||||
|
||||
#else /* #if CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY */
|
||||
|
||||
@@ -79,6 +80,7 @@
|
||||
#define SLIP_DYNAMIC_MEMORY FALSE
|
||||
#define LLCP_DYNAMIC_MEMORY FALSE
|
||||
#define BTC_SBC_DEC_DYNAMIC_MEMORY FALSE
|
||||
#define BTC_SBC_ENC_DYNAMIC_MEMORY FALSE
|
||||
|
||||
#endif /* #if CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY */
|
||||
/****************************************************************************
|
||||
|
@@ -45,7 +45,7 @@
|
||||
#define HCI_GRP_VENDOR_SPECIFIC (0x3F << 10) /* 0xFC00 */
|
||||
|
||||
/* Group occupies high 6 bits of the HCI command rest is opcode itself */
|
||||
#define HCI_OGF(p) (UINT8)((0xFC00 & (p)) >> 10)
|
||||
#define HCI_OGF(p) (UINT8)(0x003F & (p >> 10))
|
||||
#define HCI_OCF(p) ( 0x3FF & (p))
|
||||
|
||||
/*
|
||||
@@ -352,27 +352,70 @@
|
||||
#define HCI_BLE_READ_RESOLVABLE_ADDR_LOCAL (0x002C | HCI_GRP_BLE_CMDS)
|
||||
#define HCI_BLE_SET_ADDR_RESOLUTION_ENABLE (0x002D | HCI_GRP_BLE_CMDS)
|
||||
#define HCI_BLE_SET_RAND_PRIV_ADDR_TIMOUT (0x002E | HCI_GRP_BLE_CMDS)
|
||||
// Vendor OGF define
|
||||
#define HCI_VENDOR_OGF 0x3F
|
||||
|
||||
/* LE Get Vendor Capabilities Command OCF */
|
||||
#define HCI_BLE_VENDOR_CAP_OCF (0x0153 | HCI_GRP_VENDOR_SPECIFIC)
|
||||
// ESP vendor group define
|
||||
#define HCI_ESP_GROUP_COMMON 0x01
|
||||
#define HCI_ESP_GROUP_BLE 0x02
|
||||
#define HCI_ESP_GROUP_BT 0x03
|
||||
#define HCI_ESP_GROUP_END 0x07
|
||||
|
||||
//ESP common subcode define
|
||||
#define HCI_SUBCODE_COMMON_INIT 0x00
|
||||
#define HCI_SUBCODE_COMMON_ECHO 0x01
|
||||
#define HCI_SUBCODE_COMMON_MAX 0x7F
|
||||
|
||||
//ESP BLE subcode define
|
||||
#define HCI_SUBCODE_BLE_INIT 0x00
|
||||
#define HCI_SUBCODE_BLE_MULTI_ADV 0x01
|
||||
#define HCI_SUBCODE_BLE_BATCH_SCAN 0x02
|
||||
#define HCI_SUBCODE_BLE_ADV_FILTER 0x03
|
||||
#define HCI_SUBCODE_BLE_TRACK_ADV 0x04
|
||||
#define HCI_SUBCODE_BLE_ENERGY_INFO 0x05
|
||||
#define HCI_SUBCODE_BLE_EXTENDED_SCAN_PARAMS 0x06
|
||||
#define HCI_SUBCODE_BLE_LONG_ADV 0x07
|
||||
#define HCI_SUBCODE_BLE_DUPLICATE_EXCEPTIONAL_LIST 0x08
|
||||
#define HCI_SUBCODE_BLE_MAX 0x7F
|
||||
|
||||
//ESP BT subcode define
|
||||
#define HCI_SUBCODE_BT_INIT 0x00
|
||||
#define HCI_SUBCODE_BT_MAX 0x7F
|
||||
|
||||
#define HCI_ESP_VENDOR_OPCODE_BUILD(ogf, group, subcode) ((ogf << 10) | (group <<7) | (subcode << 0))
|
||||
/*
|
||||
* | OGF | VENDIOR GROUP | GROUP SUBCODE |
|
||||
* | 1 1 1 1 1 1 | 0 0 0 | X X X X X X X | Already Exist
|
||||
* | 1 1 1 1 1 1 | 0 0 1 | X X X X X X X | ESP VENDOR COMMON HCI CMD
|
||||
* | 1 1 1 1 1 1 | 0 1 0 | X X X X X X X | ESP VENDOR BLE HCI CMD
|
||||
* | 1 1 1 1 1 1 | 0 1 1 | X X X X X X X | ESP VENDOR BT HCI CMD
|
||||
* | 1 1 1 1 1 1 | 1 0 0 | X X X X X X X | RESERVED FOR FUTURE USE
|
||||
* | 1 1 1 1 1 1 | 1 0 1 | X X X X X X X | RESERVED FOR FUTURE USE
|
||||
* | 1 1 1 1 1 1 | 1 1 0 | X X X X X X X | RESERVED FOR FUTURE USE
|
||||
* | 1 1 1 1 1 1 | 1 1 1 | X X X X X X X | RESERVED FOR FUTURE USE
|
||||
*/
|
||||
|
||||
// ESP COMMON HCI CMD
|
||||
#define HCI_VENDOR_COMMON_ECHO_CMD_OPCODE HCI_ESP_VENDOR_OPCODE_BUILD(HCI_VENDOR_OGF, HCI_ESP_GROUP_COMMON, HCI_SUBCODE_COMMON_ECHO)
|
||||
|
||||
//ESP BLE HCI CMD
|
||||
/* Multi adv OCF */
|
||||
#define HCI_BLE_MULTI_ADV_OCF (0x0154 | HCI_GRP_VENDOR_SPECIFIC)
|
||||
|
||||
#define HCI_BLE_MULTI_ADV_OCF HCI_ESP_VENDOR_OPCODE_BUILD(HCI_VENDOR_OGF, HCI_ESP_GROUP_BLE, HCI_SUBCODE_BLE_MULTI_ADV)
|
||||
/* Batch scan OCF */
|
||||
#define HCI_BLE_BATCH_SCAN_OCF (0x0156 | HCI_GRP_VENDOR_SPECIFIC)
|
||||
|
||||
#define HCI_BLE_BATCH_SCAN_OCF HCI_ESP_VENDOR_OPCODE_BUILD(HCI_VENDOR_OGF, HCI_ESP_GROUP_BLE, HCI_SUBCODE_BLE_BATCH_SCAN)
|
||||
/* ADV filter OCF */
|
||||
#define HCI_BLE_ADV_FILTER_OCF (0x0157 | HCI_GRP_VENDOR_SPECIFIC)
|
||||
|
||||
#define HCI_BLE_ADV_FILTER_OCF HCI_ESP_VENDOR_OPCODE_BUILD(HCI_VENDOR_OGF, HCI_ESP_GROUP_BLE, HCI_SUBCODE_BLE_ADV_FILTER)
|
||||
/* Tracking OCF */
|
||||
#define HCI_BLE_TRACK_ADV_OCF (0x0158 | HCI_GRP_VENDOR_SPECIFIC)
|
||||
|
||||
#define HCI_BLE_TRACK_ADV_OCF HCI_ESP_VENDOR_OPCODE_BUILD(HCI_VENDOR_OGF, HCI_ESP_GROUP_BLE, HCI_SUBCODE_BLE_TRACK_ADV)
|
||||
/* Energy info OCF */
|
||||
#define HCI_BLE_ENERGY_INFO_OCF (0x0159 | HCI_GRP_VENDOR_SPECIFIC)
|
||||
|
||||
#define HCI_BLE_ENERGY_INFO_OCF HCI_ESP_VENDOR_OPCODE_BUILD(HCI_VENDOR_OGF, HCI_ESP_GROUP_BLE, HCI_SUBCODE_BLE_ENERGY_INFO)
|
||||
/* Extended BLE Scan parameters OCF */
|
||||
#define HCI_BLE_EXTENDED_SCAN_PARAMS_OCF (0x0160 | HCI_GRP_VENDOR_SPECIFIC)
|
||||
#define HCI_BLE_EXTENDED_SCAN_PARAMS_OCF HCI_ESP_VENDOR_OPCODE_BUILD(HCI_VENDOR_OGF, HCI_ESP_GROUP_BLE, HCI_SUBCODE_BLE_EXTENDED_SCAN_PARAMS)
|
||||
/* Long BLE Adv data OCF */
|
||||
#define HCI_VENDOR_BLE_LONG_ADV_DATA HCI_ESP_VENDOR_OPCODE_BUILD(HCI_VENDOR_OGF, HCI_ESP_GROUP_BLE, HCI_SUBCODE_BLE_LONG_ADV)
|
||||
/* BLE update duplicate scan exceptional list */
|
||||
#define HCI_VENDOR_BLE_UPDATE_DUPLICATE_EXCEPTIONAL_LIST HCI_ESP_VENDOR_OPCODE_BUILD(HCI_VENDOR_OGF, HCI_ESP_GROUP_BLE, HCI_SUBCODE_BLE_DUPLICATE_EXCEPTIONAL_LIST)
|
||||
//ESP BT HCI CMD
|
||||
|
||||
/* subcode for multi adv feature */
|
||||
#define BTM_BLE_MULTI_ADV_SET_PARAM 0x01
|
||||
|
@@ -813,17 +813,17 @@ BOOLEAN l2cble_init_direct_conn (tL2C_LCB *p_lcb)
|
||||
memcpy(peer_addr, p_dev_rec->ble.current_addr, 6);
|
||||
} else {
|
||||
/* find security device information but not find the real address information
|
||||
* This state may be directly open whithout scanning. In this case, you must
|
||||
* This state may be directly open without scanning. In this case, you must
|
||||
* use the current adv address of the device to open*/
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//not find security device information, We think this is a new device, connect directly
|
||||
}
|
||||
|
||||
/* It will cause that scanner doesn't send scan request to advertiser
|
||||
* which has sent IRK to us and we have stored the IRK in controller.
|
||||
* It is a design problem of hardware. The temporal solution is not to
|
||||
* send the key to the controller and then resolve the random address in host.
|
||||
* It is a hardware limitation. The preliminary solution is not to
|
||||
* send key to the controller, but to resolve the random address in host.
|
||||
* so we need send the real address information to controller. */
|
||||
/*
|
||||
if (p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) {
|
||||
|
@@ -61,6 +61,7 @@
|
||||
#define BTDM_CFG_CONTROLLER_RUN_APP_CPU (1<<2)
|
||||
#define BTDM_CFG_SCAN_DUPLICATE_OPTIONS (1<<3)
|
||||
#define BTDM_CFG_SEND_ADV_RESERVED_SIZE (1<<4)
|
||||
#define BTDM_CFG_BLE_FULL_SCAN_SUPPORTED (1<<5)
|
||||
|
||||
/* Sleep mode */
|
||||
#define BTDM_MODEM_SLEEP_MODE_NONE (0)
|
||||
@@ -810,6 +811,9 @@ static uint32_t btdm_config_mask_load(void)
|
||||
#if CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE == 1
|
||||
mask |= BTDM_CFG_CONTROLLER_RUN_APP_CPU;
|
||||
#endif
|
||||
#if CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED
|
||||
mask |= BTDM_CFG_BLE_FULL_SCAN_SUPPORTED;
|
||||
#endif /* CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED */
|
||||
mask |= BTDM_CFG_SCAN_DUPLICATE_OPTIONS;
|
||||
|
||||
mask |= BTDM_CFG_SEND_ADV_RESERVED_SIZE;
|
||||
|
Submodule components/bt/lib updated: 16f95952ef...1b7ad41d25
@@ -1,8 +1,7 @@
|
||||
if(CONFIG_BT_ENABLED)
|
||||
if(CONFIG_BT_ENABLED OR CMAKE_BUILD_EARLY_EXPANSION)
|
||||
set(COMPONENT_SRCDIRS ".")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
set(COMPONENT_REQUIRES unity nvs_flash bt)
|
||||
|
||||
register_component()
|
||||
endif()
|
||||
|
||||
set(COMPONENT_REQUIRES unity nvs_flash bt)
|
||||
|
||||
register_component()
|
||||
|
@@ -24,7 +24,7 @@ register_component()
|
||||
# Needed for coap headers in public builds, also.
|
||||
#
|
||||
# TODO: find a way to move this to a port header
|
||||
target_compile_definitions(coap PUBLIC WITH_POSIX)
|
||||
target_compile_definitions(${COMPONENT_TARGET} PUBLIC WITH_POSIX)
|
||||
|
||||
set_source_files_properties(
|
||||
libcoap/src/debug.c
|
||||
|
@@ -31,6 +31,13 @@ typedef enum {
|
||||
SS_QUOTED_ARG_ESCAPED = SS_QUOTED_ARG | SS_FLAG_ESCAPE,
|
||||
} split_state_t;
|
||||
|
||||
/* helper macro, called when done with an argument */
|
||||
#define END_ARG() do { \
|
||||
char_out = 0; \
|
||||
argv[argc++] = next_arg_start; \
|
||||
state = SS_SPACE; \
|
||||
} while(0)
|
||||
|
||||
size_t esp_console_split_argv(char *line, char **argv, size_t argv_size)
|
||||
{
|
||||
const int QUOTE = '"';
|
||||
@@ -47,13 +54,6 @@ size_t esp_console_split_argv(char *line, char **argv, size_t argv_size)
|
||||
}
|
||||
int char_out = -1;
|
||||
|
||||
/* helper function, called when done with an argument */
|
||||
void end_arg() {
|
||||
char_out = 0;
|
||||
argv[argc++] = next_arg_start;
|
||||
state = SS_SPACE;
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case SS_SPACE:
|
||||
if (char_in == SPACE) {
|
||||
@@ -73,7 +73,7 @@ size_t esp_console_split_argv(char *line, char **argv, size_t argv_size)
|
||||
|
||||
case SS_QUOTED_ARG:
|
||||
if (char_in == QUOTE) {
|
||||
end_arg();
|
||||
END_ARG();
|
||||
} else if (char_in == ESCAPE) {
|
||||
state = SS_QUOTED_ARG_ESCAPED;
|
||||
} else {
|
||||
@@ -93,7 +93,7 @@ size_t esp_console_split_argv(char *line, char **argv, size_t argv_size)
|
||||
|
||||
case SS_ARG:
|
||||
if (char_in == SPACE) {
|
||||
end_arg();
|
||||
END_ARG();
|
||||
} else if (char_in == ESCAPE) {
|
||||
state = SS_ARG_ESCAPED;
|
||||
} else {
|
||||
|
@@ -3,10 +3,10 @@ set(COMPONENT_SRCS "cxx_exception_stubs.cpp"
|
||||
set(COMPONENT_REQUIRES)
|
||||
register_component()
|
||||
|
||||
target_link_libraries(cxx stdc++)
|
||||
target_link_libraries(${COMPONENT_TARGET} stdc++)
|
||||
|
||||
target_link_libraries(cxx "-u __cxa_guard_dummy")
|
||||
target_link_libraries(${COMPONENT_TARGET} "-u __cxa_guard_dummy")
|
||||
|
||||
if(NOT CONFIG_CXX_EXCEPTIONS)
|
||||
target_link_libraries(cxx "-u __cxx_fatal_exception")
|
||||
target_link_libraries(${COMPONENT_TARGET} "-u __cxx_fatal_exception")
|
||||
endif()
|
||||
|
@@ -41,8 +41,10 @@ config SPI_MASTER_ISR_IN_IRAM
|
||||
bool "Place SPI master ISR function into IRAM"
|
||||
default y
|
||||
help
|
||||
Place the SPI master ISR in to IRAM to avoid possibly cache miss, or
|
||||
being disabled during flash writing access.
|
||||
Place the SPI master ISR in to IRAM to avoid possible cache miss.
|
||||
|
||||
Also you can forbid the ISR being disabled during flash writing
|
||||
access, by add ESP_INTR_FLAG_IRAM when initializing the driver.
|
||||
|
||||
config SPI_SLAVE_IN_IRAM
|
||||
bool "Place transmitting functions of SPI slave into IRAM"
|
||||
@@ -61,8 +63,10 @@ config SPI_SLAVE_ISR_IN_IRAM
|
||||
bool "Place SPI slave ISR function into IRAM"
|
||||
default y
|
||||
help
|
||||
Place the SPI slave ISR in to IRAM to avoid possibly cache miss, or
|
||||
being disabled during flash writing access.
|
||||
Place the SPI slave ISR in to IRAM to avoid possible cache miss.
|
||||
|
||||
Also you can forbid the ISR being disabled during flash writing
|
||||
access, by add ESP_INTR_FLAG_IRAM when initializing the driver.
|
||||
|
||||
endmenu # SPI Configuration
|
||||
|
||||
|
@@ -79,6 +79,9 @@ static DRAM_ATTR i2c_dev_t* const I2C[I2C_NUM_MAX] = { &I2C0, &I2C1 };
|
||||
#define I2C_SLAVE_SDA_HOLD_DEFAULT (10) /* I2C slave hold time after scl negative edge default value */
|
||||
#define I2C_MASTER_TOUT_CNUM_DEFAULT (8) /* I2C master timeout cycle number of I2C clock, after which the timeout interrupt will be triggered */
|
||||
#define I2C_ACKERR_CNT_MAX (10)
|
||||
#define I2C_FILTER_CYC_NUM_DEF (7) /* The number of apb cycles filtered by default*/
|
||||
#define I2C_CLR_BUS_SCL_NUM (9)
|
||||
#define I2C_CLR_BUS_HALF_PERIOD_US (5)
|
||||
|
||||
typedef struct {
|
||||
uint8_t byte_num; /*!< cmd byte number */
|
||||
@@ -524,7 +527,9 @@ esp_err_t i2c_get_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t *tx_trans_mode,
|
||||
static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num)
|
||||
{
|
||||
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
const int scl_half_period = I2C_CLR_BUS_HALF_PERIOD_US; // use standard 100kHz data rate
|
||||
int sda_in_sig = 0, scl_in_sig = 0;
|
||||
int i = 0;
|
||||
if (i2c_num == I2C_NUM_0) {
|
||||
sda_in_sig = I2CEXT0_SDA_IN_IDX;
|
||||
scl_in_sig = I2CEXT0_SCL_IN_IDX;
|
||||
@@ -535,19 +540,27 @@ static esp_err_t i2c_master_clear_bus(i2c_port_t i2c_num)
|
||||
int scl_io = GPIO.func_in_sel_cfg[scl_in_sig].func_sel;
|
||||
int sda_io = GPIO.func_in_sel_cfg[sda_in_sig].func_sel;
|
||||
I2C_CHECK((GPIO_IS_VALID_OUTPUT_GPIO(scl_io)), I2C_SCL_IO_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
I2C_CHECK((GPIO_IS_VALID_GPIO(sda_io)), I2C_SDA_IO_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
// We do not check whether the SDA line is low
|
||||
// because after some serious interference, the bus may keep high all the time and the i2c bus is out of service.
|
||||
I2C_CHECK((GPIO_IS_VALID_OUTPUT_GPIO(sda_io)), I2C_SDA_IO_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
gpio_set_direction(scl_io, GPIO_MODE_OUTPUT_OD);
|
||||
gpio_set_direction(sda_io, GPIO_MODE_OUTPUT_OD);
|
||||
gpio_set_level(scl_io, 1);
|
||||
gpio_set_direction(sda_io, GPIO_MODE_INPUT_OUTPUT_OD);
|
||||
// If a SLAVE device was in a read operation when the bus was interrupted, the SLAVE device is controlling SDA.
|
||||
// The only bit during the 9 clock cycles of a READ byte the MASTER(ESP32) is guaranteed control over is during the ACK bit
|
||||
// period. If the slave is sending a stream of ZERO bytes, it will only release SDA during the ACK bit period.
|
||||
// So, this reset code needs to synchronize the bit stream with, Either, the ACK bit, Or a 1 bit to correctly generate
|
||||
// a STOP condition.
|
||||
gpio_set_level(scl_io, 0);
|
||||
gpio_set_level(sda_io, 1);
|
||||
gpio_set_level(sda_io, 0);
|
||||
for (int i = 0; i < 9; i++) {
|
||||
gpio_set_level(scl_io, 0);
|
||||
ets_delay_us(scl_half_period);
|
||||
while(!gpio_get_level(sda_io) && (i++ < I2C_CLR_BUS_SCL_NUM)) {
|
||||
gpio_set_level(scl_io, 1);
|
||||
ets_delay_us(scl_half_period);
|
||||
gpio_set_level(scl_io, 0);
|
||||
ets_delay_us(scl_half_period);
|
||||
}
|
||||
gpio_set_level(sda_io, 1);
|
||||
gpio_set_level(sda_io,0); // setup for STOP
|
||||
gpio_set_level(scl_io,1);
|
||||
ets_delay_us(scl_half_period);
|
||||
gpio_set_level(sda_io, 1); // STOP, SDA low -> high while SCL is HIGH
|
||||
i2c_set_pin(i2c_num, sda_io, scl_io, 1, 1, I2C_MODE_MASTER);
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -660,6 +673,8 @@ esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t* i2c_conf)
|
||||
//set timing for stop signal
|
||||
I2C[i2c_num]->scl_stop_hold.time = half_cycle;
|
||||
I2C[i2c_num]->scl_stop_setup.time = half_cycle;
|
||||
//Default, we enable hardware filter
|
||||
i2c_filter_enable(i2c_num, I2C_FILTER_CYC_NUM_DEF);
|
||||
}
|
||||
|
||||
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
|
||||
@@ -693,6 +708,28 @@ esp_err_t i2c_get_period(i2c_port_t i2c_num, int* high_period, int* low_period)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2c_filter_enable(i2c_port_t i2c_num, uint8_t cyc_num)
|
||||
{
|
||||
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
|
||||
I2C[i2c_num]->scl_filter_cfg.thres = cyc_num;
|
||||
I2C[i2c_num]->sda_filter_cfg.thres = cyc_num;
|
||||
I2C[i2c_num]->scl_filter_cfg.en = 1;
|
||||
I2C[i2c_num]->sda_filter_cfg.en = 1;
|
||||
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2c_filter_disable(i2c_port_t i2c_num)
|
||||
{
|
||||
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
|
||||
I2C[i2c_num]->scl_filter_cfg.en = 0;
|
||||
I2C[i2c_num]->sda_filter_cfg.en = 0;
|
||||
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2c_set_start_timing(i2c_port_t i2c_num, int setup_time, int hold_time)
|
||||
{
|
||||
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
@@ -1062,7 +1099,7 @@ esp_err_t i2c_master_read(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t dat
|
||||
return i2c_master_read_static(cmd_handle, data, data_len, ack);
|
||||
} else {
|
||||
if(data_len == 1) {
|
||||
return i2c_master_read_byte(cmd_handle, data, I2C_MASTER_NACK);
|
||||
return i2c_master_read_byte(cmd_handle, data, I2C_MASTER_NACK);
|
||||
} else {
|
||||
esp_err_t ret;
|
||||
if((ret = i2c_master_read_static(cmd_handle, data, data_len - 1, I2C_MASTER_ACK)) != ESP_OK) {
|
||||
@@ -1070,7 +1107,7 @@ esp_err_t i2c_master_read(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t dat
|
||||
}
|
||||
return i2c_master_read_byte(cmd_handle, data + data_len - 1, I2C_MASTER_NACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num)
|
||||
@@ -1281,7 +1318,7 @@ esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle,
|
||||
clear_bus_cnt++;
|
||||
if(clear_bus_cnt >= I2C_ACKERR_CNT_MAX) {
|
||||
i2c_master_clear_bus(i2c_num);
|
||||
clear_bus_cnt = 0;
|
||||
clear_bus_cnt = 0;
|
||||
}
|
||||
ret = ESP_FAIL;
|
||||
} else {
|
||||
|
@@ -86,6 +86,7 @@ typedef struct {
|
||||
i2s_mode_t mode; /*!< I2S Working mode*/
|
||||
uint32_t sample_rate; /*!< I2S sample rate */
|
||||
bool use_apll; /*!< I2S use APLL clock */
|
||||
bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor on underflow */
|
||||
int fixed_mclk; /*!< I2S fixed MLCK clock */
|
||||
} i2s_obj_t;
|
||||
|
||||
@@ -502,6 +503,12 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg)
|
||||
// All buffers are empty. This means we have an underflow on our hands.
|
||||
if (xQueueIsQueueFullFromISR(p_i2s->tx->queue)) {
|
||||
xQueueReceiveFromISR(p_i2s->tx->queue, &dummy, &high_priority_task_awoken);
|
||||
// See if tx descriptor needs to be auto cleared:
|
||||
// This will avoid any kind of noise that may get introduced due to transmission
|
||||
// of previous data from tx descriptor on I2S line.
|
||||
if (p_i2s->tx_desc_auto_clear == true) {
|
||||
memset((void *) dummy, 0, p_i2s->tx->buf_size);
|
||||
}
|
||||
}
|
||||
xQueueSendFromISR(p_i2s->tx->queue, (void*)(&finish_desc->buf), &high_priority_task_awoken);
|
||||
if (p_i2s->i2s_queue) {
|
||||
@@ -991,6 +998,7 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co
|
||||
}
|
||||
|
||||
p_i2s_obj[i2s_num]->use_apll = i2s_config->use_apll;
|
||||
p_i2s_obj[i2s_num]->tx_desc_auto_clear = i2s_config->tx_desc_auto_clear;
|
||||
p_i2s_obj[i2s_num]->fixed_mclk = i2s_config->fixed_mclk;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@@ -420,6 +420,35 @@ esp_err_t i2c_set_period(i2c_port_t i2c_num, int high_period, int low_period);
|
||||
*/
|
||||
esp_err_t i2c_get_period(i2c_port_t i2c_num, int* high_period, int* low_period);
|
||||
|
||||
/**
|
||||
* @brief enable hardware filter on I2C bus
|
||||
* Sometimes the I2C bus is disturbed by high frequency noise(about 20ns), or the rising edge of
|
||||
* the SCL clock is very slow, these may cause the master state machine broken. enable hardware
|
||||
* filter can filter out high frequency interference and make the master more stable.
|
||||
* @note
|
||||
* Enable filter will slow the SCL clock.
|
||||
*
|
||||
* @param i2c_num I2C port number
|
||||
* @param cyc_num the APB cycles need to be filtered(0<= cyc_num <=7).
|
||||
* When the period of a pulse is less than cyc_num * APB_cycle, the I2C controller will ignore this pulse.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t i2c_filter_enable(i2c_port_t i2c_num, uint8_t cyc_num);
|
||||
|
||||
/**
|
||||
* @brief disable filter on I2C bus
|
||||
*
|
||||
* @param i2c_num I2C port number
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t i2c_filter_disable(i2c_port_t i2c_num);
|
||||
|
||||
/**
|
||||
* @brief set I2C master start signal timing
|
||||
*
|
||||
|
@@ -139,6 +139,7 @@ typedef struct {
|
||||
int dma_buf_count; /*!< I2S DMA Buffer Count */
|
||||
int dma_buf_len; /*!< I2S DMA Buffer Length */
|
||||
bool use_apll; /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */
|
||||
bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor if there is underflow condition (helps in avoiding noise in case of data unavailability) */
|
||||
int fixed_mclk; /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0, then the clock output for i2s is fixed and equal to the fixed_mclk value.*/
|
||||
} i2s_config_t;
|
||||
|
||||
|
@@ -80,6 +80,19 @@ typedef enum {
|
||||
RMT_CARRIER_LEVEL_MAX
|
||||
} rmt_carrier_level_t;
|
||||
|
||||
typedef enum {
|
||||
RMT_CHANNEL_UNINIT = 0, /*!< RMT channel uninitialized */
|
||||
RMT_CHANNEL_IDLE = 1, /*!< RMT channel status idle */
|
||||
RMT_CHANNEL_BUSY = 2, /*!< RMT channel status busy */
|
||||
} rmt_channel_status_t;
|
||||
|
||||
/**
|
||||
* @brief Data struct of RMT channel status
|
||||
*/
|
||||
typedef struct {
|
||||
rmt_channel_status_t status[RMT_CHANNEL_MAX]; /*!< Store the current status of each channel */
|
||||
} rmt_channel_status_result_t;
|
||||
|
||||
/**
|
||||
* @brief Data struct of RMT TX configure parameters
|
||||
*/
|
||||
@@ -496,6 +509,7 @@ esp_err_t rmt_set_idle_level(rmt_channel_t channel, bool idle_out_en, rmt_idle_l
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @param status Pointer to accept channel status.
|
||||
* Please refer to RMT_CHnSTATUS_REG(n=0~7) in `rmt_reg.h` for more details of each field.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
@@ -679,6 +693,19 @@ esp_err_t rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int intr
|
||||
*/
|
||||
esp_err_t rmt_driver_uninstall(rmt_channel_t channel);
|
||||
|
||||
/**
|
||||
* @brief Get the current status of eight channels.
|
||||
*
|
||||
* @note Do not call this function if it is possible that `rmt_driver_uninstall` will be called at the same time.
|
||||
*
|
||||
* @param[out] channel_status store the current status of each channel
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter is NULL
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_get_channel_status(rmt_channel_status_result_t *channel_status);
|
||||
|
||||
/**
|
||||
* @brief RMT send waveform from rmt_item array.
|
||||
*
|
||||
|
@@ -87,6 +87,11 @@ typedef struct {
|
||||
int quadhd_io_num; ///< GPIO pin for HD (HolD) signal which is used as D3 in 4-bit communication modes, or -1 if not used.
|
||||
int max_transfer_sz; ///< Maximum transfer size, in bytes. Defaults to 4094 if 0.
|
||||
uint32_t flags; ///< Abilities of bus to be checked by the driver. Or-ed value of ``SPICOMMON_BUSFLAG_*`` flags.
|
||||
int intr_flags; /**< Interrupt flag for the bus to set the priority, and IRAM attribute, see
|
||||
* ``esp_intr_alloc.h``. Note that the EDGE, INTRDISABLED attribute are ignored
|
||||
* by the driver. Note that if ESP_INTR_FLAG_IRAM is set, ALL the callbacks of
|
||||
* the driver, and their callee functions, should be put in the IRAM.
|
||||
*/
|
||||
} spi_bus_config_t;
|
||||
|
||||
|
||||
@@ -96,9 +101,32 @@ typedef struct {
|
||||
* Call this if your driver wants to manage a SPI peripheral.
|
||||
*
|
||||
* @param host Peripheral to claim
|
||||
* @param source The caller indentification string.
|
||||
*
|
||||
* @return True if peripheral is claimed successfully; false if peripheral already is claimed.
|
||||
*/
|
||||
bool spicommon_periph_claim(spi_host_device_t host);
|
||||
bool spicommon_periph_claim(spi_host_device_t host, const char* source);
|
||||
|
||||
// The macro is to keep the back-compatibility of IDF v3.2 and before
|
||||
// In this way we can call spicommon_periph_claim with two arguments, or the host with the source set to the calling function name
|
||||
// When two arguments (host, func) are given, __spicommon_periph_claim2 is called
|
||||
// or if only one arguments (host) is given, __spicommon_periph_claim1 is called
|
||||
#define spicommon_periph_claim(host...) __spicommon_periph_claim(host, 2, 1)
|
||||
#define __spicommon_periph_claim(host, source, n, ...) __spicommon_periph_claim ## n(host, source)
|
||||
#define __spicommon_periph_claim1(host, _) ({ \
|
||||
char* warning_str = "calling spicommon_periph_claim without source string is deprecated.";\
|
||||
spicommon_periph_claim(host, __FUNCTION__); })
|
||||
|
||||
#define __spicommon_periph_claim2(host, func) spicommon_periph_claim(host, func)
|
||||
|
||||
/**
|
||||
* @brief Check whether the spi periph is in use.
|
||||
*
|
||||
* @param host Peripheral to check.
|
||||
*
|
||||
* @return True if in use, otherwise false.
|
||||
*/
|
||||
bool spicommon_periph_in_use(spi_host_device_t host);
|
||||
|
||||
/**
|
||||
* @brief Return the SPI peripheral so another driver can claim it.
|
||||
@@ -119,6 +147,15 @@ bool spicommon_periph_free(spi_host_device_t host);
|
||||
*/
|
||||
bool spicommon_dma_chan_claim(int dma_chan);
|
||||
|
||||
/**
|
||||
* @brief Check whether the spi DMA channel is in use.
|
||||
*
|
||||
* @param dma_chan DMA channel to check.
|
||||
*
|
||||
* @return True if in use, otherwise false.
|
||||
*/
|
||||
bool spicommon_dma_chan_in_use(int dma_chan);
|
||||
|
||||
/**
|
||||
* @brief Return the SPI DMA channel so other driver can claim it, or just to power down DMA.
|
||||
*
|
||||
|
@@ -79,8 +79,26 @@ typedef struct {
|
||||
int spics_io_num; ///< CS GPIO pin for this device, or -1 if not used
|
||||
uint32_t flags; ///< Bitwise OR of SPI_DEVICE_* flags
|
||||
int queue_size; ///< Transaction queue size. This sets how many transactions can be 'in the air' (queued using spi_device_queue_trans but not yet finished using spi_device_get_trans_result) at the same time
|
||||
transaction_cb_t pre_cb; ///< Callback to be called before a transmission is started. This callback is called within interrupt context.
|
||||
transaction_cb_t post_cb; ///< Callback to be called after a transmission has completed. This callback is called within interrupt context.
|
||||
transaction_cb_t pre_cb; /**< Callback to be called before a transmission is started.
|
||||
*
|
||||
* This callback is called within interrupt
|
||||
* context should be in IRAM for best
|
||||
* performance, see "Transferring Speed"
|
||||
* section in the SPI Master documentation for
|
||||
* full details. If not, the callback may crash
|
||||
* during flash operation when the driver is
|
||||
* initialized with ESP_INTR_FLAG_IRAM.
|
||||
*/
|
||||
transaction_cb_t post_cb; /**< Callback to be called after a transmission has completed.
|
||||
*
|
||||
* This callback is called within interrupt
|
||||
* context should be in IRAM for best
|
||||
* performance, see "Transferring Speed"
|
||||
* section in the SPI Master documentation for
|
||||
* full details. If not, the callback may crash
|
||||
* during flash operation when the driver is
|
||||
* initialized with ESP_INTR_FLAG_IRAM.
|
||||
*/
|
||||
} spi_device_interface_config_t;
|
||||
|
||||
|
||||
@@ -150,6 +168,10 @@ typedef struct spi_device_t* spi_device_handle_t; ///< Handle for a device on a
|
||||
* @warning If a DMA channel is selected, any transmit and receive buffer used should be allocated in
|
||||
* DMA-capable memory.
|
||||
*
|
||||
* @warning The ISR of SPI is always executed on the core which calls this
|
||||
* function. Never starve the ISR on this core or the SPI transactions will not
|
||||
* be handled.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if configuration is invalid
|
||||
* - ESP_ERR_INVALID_STATE if host already is in use
|
||||
|
@@ -44,8 +44,26 @@ typedef struct {
|
||||
uint32_t flags; ///< Bitwise OR of SPI_SLAVE_* flags
|
||||
int queue_size; ///< Transaction queue size. This sets how many transactions can be 'in the air' (queued using spi_slave_queue_trans but not yet finished using spi_slave_get_trans_result) at the same time
|
||||
uint8_t mode; ///< SPI mode (0-3)
|
||||
slave_transaction_cb_t post_setup_cb; ///< Callback called after the SPI registers are loaded with new data
|
||||
slave_transaction_cb_t post_trans_cb; ///< Callback called after a transaction is done
|
||||
slave_transaction_cb_t post_setup_cb; /**< Callback called after the SPI registers are loaded with new data.
|
||||
*
|
||||
* This callback is called within interrupt
|
||||
* context should be in IRAM for best
|
||||
* performance, see "Transferring Speed"
|
||||
* section in the SPI Master documentation for
|
||||
* full details. If not, the callback may crash
|
||||
* during flash operation when the driver is
|
||||
* initialized with ESP_INTR_FLAG_IRAM.
|
||||
*/
|
||||
slave_transaction_cb_t post_trans_cb; /**< Callback called after a transaction is done.
|
||||
*
|
||||
* This callback is called within interrupt
|
||||
* context should be in IRAM for best
|
||||
* performance, see "Transferring Speed"
|
||||
* section in the SPI Master documentation for
|
||||
* full details. If not, the callback may crash
|
||||
* during flash operation when the driver is
|
||||
* initialized with ESP_INTR_FLAG_IRAM.
|
||||
*/
|
||||
} spi_slave_interface_config_t;
|
||||
|
||||
/**
|
||||
@@ -55,7 +73,10 @@ struct spi_slave_transaction_t {
|
||||
size_t length; ///< Total data length, in bits
|
||||
size_t trans_len; ///< Transaction data length, in bits
|
||||
const void *tx_buffer; ///< Pointer to transmit buffer, or NULL for no MOSI phase
|
||||
void *rx_buffer; ///< Pointer to receive buffer, or NULL for no MISO phase
|
||||
void *rx_buffer; /**< Pointer to receive buffer, or NULL for no MISO phase.
|
||||
* When the DMA is anabled, must start at WORD boundary (``rx_buffer%4==0``),
|
||||
* and has length of a multiple of 4 bytes.
|
||||
*/
|
||||
void *user; ///< User-defined variable. Can be used to store eg transaction ID.
|
||||
};
|
||||
|
||||
@@ -71,10 +92,14 @@ struct spi_slave_transaction_t {
|
||||
* it. The SPI hardware has two DMA channels to share. This parameter indicates which
|
||||
* one to use.
|
||||
*
|
||||
* @warning If a DMA channel is selected, any transmit and receive buffer used should be allocated in
|
||||
* @warning If a DMA channel is selected, any transmit and receive buffer used should be allocated in
|
||||
* DMA-capable memory.
|
||||
*
|
||||
* @return
|
||||
* @warning The ISR of SPI is always executed on the core which calls this
|
||||
* function. Never starve the ISR on this core or the SPI transactions will not
|
||||
* be handled.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if configuration is invalid
|
||||
* - ESP_ERR_INVALID_STATE if host already is in use
|
||||
* - ESP_ERR_NO_MEM if out of memory
|
||||
@@ -86,7 +111,7 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
|
||||
* @brief Free a SPI bus claimed as a SPI slave interface
|
||||
*
|
||||
* @param host SPI peripheral to free
|
||||
* @return
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
* - ESP_ERR_INVALID_STATE if not all devices on the bus are freed
|
||||
* - ESP_OK on success
|
||||
@@ -110,7 +135,7 @@ esp_err_t spi_slave_free(spi_host_device_t host);
|
||||
* into the transaction description.
|
||||
* @param ticks_to_wait Ticks to wait until there's room in the queue; use portMAX_DELAY to
|
||||
* never time out.
|
||||
* @return
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
@@ -120,19 +145,19 @@ esp_err_t spi_slave_queue_trans(spi_host_device_t host, const spi_slave_transact
|
||||
/**
|
||||
* @brief Get the result of a SPI transaction queued earlier
|
||||
*
|
||||
* This routine will wait until a transaction to the given device (queued earlier with
|
||||
* This routine will wait until a transaction to the given device (queued earlier with
|
||||
* spi_slave_queue_trans) has succesfully completed. It will then return the description of the
|
||||
* completed transaction so software can inspect the result and e.g. free the memory or
|
||||
* completed transaction so software can inspect the result and e.g. free the memory or
|
||||
* re-use the buffers.
|
||||
*
|
||||
* It is mandatory to eventually use this function for any transaction queued by ``spi_slave_queue_trans``.
|
||||
*
|
||||
* @param host SPI peripheral to that is acting as a slave
|
||||
* @param[out] trans_desc Pointer to variable able to contain a pointer to the description of the
|
||||
* @param[out] trans_desc Pointer to variable able to contain a pointer to the description of the
|
||||
* transaction that is executed
|
||||
* @param ticks_to_wait Ticks to wait until there's a returned item; use portMAX_DELAY to never time
|
||||
* out.
|
||||
* @return
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
@@ -143,16 +168,16 @@ esp_err_t spi_slave_get_trans_result(spi_host_device_t host, spi_slave_transacti
|
||||
* @brief Do a SPI transaction
|
||||
*
|
||||
* Essentially does the same as spi_slave_queue_trans followed by spi_slave_get_trans_result. Do
|
||||
* not use this when there is still a transaction queued that hasn't been finalized
|
||||
* not use this when there is still a transaction queued that hasn't been finalized
|
||||
* using spi_slave_get_trans_result.
|
||||
*
|
||||
* @param host SPI peripheral to that is acting as a slave
|
||||
* @param trans_desc Pointer to variable able to contain a pointer to the description of the
|
||||
* @param trans_desc Pointer to variable able to contain a pointer to the description of the
|
||||
* transaction that is executed. Not const because we may want to write status back
|
||||
* into the transaction description.
|
||||
* @param ticks_to_wait Ticks to wait until there's a returned item; use portMAX_DELAY to never time
|
||||
* out.
|
||||
* @return
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
|
@@ -801,7 +801,7 @@ esp_err_t uart_get_collision_flag(uart_port_t uart_num, bool* collision_flag);
|
||||
* light sleep. This function allows setting the threshold value.
|
||||
*
|
||||
* Stop bit and parity bits (if enabled) also contribute to the number of edges.
|
||||
* For example, letter 'a' with ASCII code 97 is encoded as 010001101 on the wire
|
||||
* For example, letter 'a' with ASCII code 97 is encoded as 0100001101 on the wire
|
||||
* (with 8n1 configuration), start and stop bits included. This sequence has 3
|
||||
* positive edges (transitions from 0 to 1). Therefore, to wake up the system
|
||||
* when 'a' is sent, set wakeup_threshold=3.
|
||||
@@ -813,7 +813,10 @@ esp_err_t uart_get_collision_flag(uart_port_t uart_num, bool* collision_flag);
|
||||
* correct baud rate all the time, select REF_TICK as UART clock source,
|
||||
* by setting use_ref_tick field in uart_config_t to true.
|
||||
*
|
||||
* @note in ESP32, UART2 does not support light sleep wakeup feature.
|
||||
* @note in ESP32, the wakeup signal can only be input via IO_MUX (i.e.
|
||||
* GPIO3 should be configured as function_1 to wake up UART0,
|
||||
* GPIO9 should be configured as function_5 to wake up UART1), UART2
|
||||
* does not support light sleep wakeup feature.
|
||||
*
|
||||
* @param uart_num UART number
|
||||
* @param wakeup_threshold number of RX edges for light sleep wakeup, value is 3 .. 0x3ff.
|
||||
|
@@ -48,6 +48,7 @@
|
||||
#define RMT_PSRAM_BUFFER_WARN_STR "Using buffer allocated from psram"
|
||||
#define RMT_TRANSLATOR_NULL_STR "RMT translator is null"
|
||||
#define RMT_TRANSLATOR_UNINIT_STR "RMT translator not init"
|
||||
#define RMT_PARAM_ERR_STR "RMT param error"
|
||||
|
||||
static const char* RMT_TAG = "rmt";
|
||||
static uint8_t s_rmt_driver_channels; // Bitmask (bits 0-7) of installed drivers' channels
|
||||
@@ -90,7 +91,7 @@ rmt_obj_t* p_rmt_obj[RMT_CHANNEL_MAX] = {0};
|
||||
// Event called when transmission is ended
|
||||
static rmt_tx_end_callback_t rmt_tx_end_callback;
|
||||
|
||||
static void rmt_set_tx_wrap_en(rmt_channel_t channel, bool en)
|
||||
static void rmt_set_tx_wrap_en(bool en)
|
||||
{
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.apb_conf.mem_tx_wrap_en = en;
|
||||
@@ -373,7 +374,7 @@ esp_err_t rmt_set_tx_thr_intr_en(rmt_channel_t channel, bool en, uint16_t evt_th
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.tx_lim_ch[channel].limit = evt_thresh;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
rmt_set_tx_wrap_en(channel, true);
|
||||
rmt_set_tx_wrap_en(true);
|
||||
rmt_set_intr_enable_mask(BIT(channel + 24));
|
||||
} else {
|
||||
rmt_clr_intr_enable_mask(BIT(channel + 24));
|
||||
@@ -569,6 +570,8 @@ static void IRAM_ATTR rmt_driver_isr_default(void* arg)
|
||||
p_rmt->tx_len_rem = 0;
|
||||
p_rmt->tx_offset = 0;
|
||||
p_rmt->tx_sub_len = 0;
|
||||
p_rmt->sample_cur = NULL;
|
||||
p_rmt->translator = false;
|
||||
if(rmt_tx_end_callback.function != NULL) {
|
||||
rmt_tx_end_callback.function(channel, rmt_tx_end_callback.arg);
|
||||
}
|
||||
@@ -804,10 +807,8 @@ esp_err_t rmt_write_items(rmt_channel_t channel, const rmt_item32_t* rmt_item, i
|
||||
// fill the memory block first
|
||||
if(item_num >= item_block_len) {
|
||||
rmt_fill_memory(channel, rmt_item, item_block_len, 0);
|
||||
RMT.tx_lim_ch[channel].limit = item_sub_len;
|
||||
RMT.apb_conf.mem_tx_wrap_en = 1;
|
||||
len_rem -= item_block_len;
|
||||
RMT.conf_ch[channel].conf1.tx_conti_mode = 0;
|
||||
rmt_set_tx_loop_mode(channel, false);
|
||||
rmt_set_tx_thr_intr_en(channel, 1, item_sub_len);
|
||||
p_rmt->tx_data = rmt_item + item_block_len;
|
||||
p_rmt->tx_len_rem = len_rem;
|
||||
@@ -930,3 +931,22 @@ esp_err_t rmt_write_sample(rmt_channel_t channel, const uint8_t *src, size_t src
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_get_channel_status(rmt_channel_status_result_t *channel_status)
|
||||
{
|
||||
RMT_CHECK(channel_status != NULL, RMT_PARAM_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
for(int i = 0; i < RMT_CHANNEL_MAX; i++) {
|
||||
channel_status->status[i]= RMT_CHANNEL_UNINIT;
|
||||
if( p_rmt_obj[i] != NULL ) {
|
||||
if( p_rmt_obj[i]->tx_sem != NULL ) {
|
||||
if( xSemaphoreTake(p_rmt_obj[i]->tx_sem, (TickType_t)0) == pdTRUE ) {
|
||||
channel_status->status[i] = RMT_CHANNEL_IDLE;
|
||||
xSemaphoreGive(p_rmt_obj[i]->tx_sem);
|
||||
} else {
|
||||
channel_status->status[i] = RMT_CHANNEL_BUSY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
@@ -52,19 +52,30 @@ typedef struct spi_device_t spi_device_t;
|
||||
|
||||
//Periph 1 is 'claimed' by SPI flash code.
|
||||
static atomic_bool spi_periph_claimed[3] = { ATOMIC_VAR_INIT(true), ATOMIC_VAR_INIT(false), ATOMIC_VAR_INIT(false)};
|
||||
static const char* spi_claiming_func[3] = {NULL, NULL, NULL};
|
||||
static uint8_t spi_dma_chan_enabled = 0;
|
||||
static portMUX_TYPE spi_dma_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
|
||||
//Returns true if this peripheral is successfully claimed, false if otherwise.
|
||||
bool spicommon_periph_claim(spi_host_device_t host)
|
||||
bool spicommon_periph_claim(spi_host_device_t host, const char* source)
|
||||
{
|
||||
bool false_var = false;
|
||||
bool ret = atomic_compare_exchange_strong(&spi_periph_claimed[host], &false_var, true);
|
||||
if (ret) periph_module_enable(spi_periph_signal[host].module);
|
||||
if (ret) {
|
||||
spi_claiming_func[host] = source;
|
||||
periph_module_enable(spi_periph_signal[host].module);
|
||||
} else {
|
||||
ESP_EARLY_LOGE(SPI_TAG, "SPI%d already claimed by %s.", host+1, spi_claiming_func[host]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool spicommon_periph_in_use(spi_host_device_t host)
|
||||
{
|
||||
return atomic_load(&spi_periph_claimed[host]);
|
||||
}
|
||||
|
||||
//Returns true if this peripheral is successfully freed, false if otherwise.
|
||||
bool spicommon_periph_free(spi_host_device_t host)
|
||||
{
|
||||
@@ -102,6 +113,12 @@ bool spicommon_dma_chan_claim (int dma_chan)
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool spicommon_dma_chan_in_use(int dma_chan)
|
||||
{
|
||||
assert(dma_chan==1 || dma_chan == 2);
|
||||
return spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan);
|
||||
}
|
||||
|
||||
bool spicommon_dma_chan_free(int dma_chan)
|
||||
{
|
||||
assert( dma_chan == 1 || dma_chan == 2 );
|
||||
@@ -190,7 +207,7 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
||||
if (use_iomux) {
|
||||
//All SPI iomux pin selections resolve to 1, so we put that here instead of trying to figure
|
||||
//out which FUNC_GPIOx_xSPIxx to grab; they all are defined to 1 anyway.
|
||||
ESP_LOGD(SPI_TAG, "SPI%d use iomux pins.", host );
|
||||
ESP_LOGD(SPI_TAG, "SPI%d use iomux pins.", host+1);
|
||||
if (bus_config->mosi_io_num >= 0) {
|
||||
gpio_iomux_in(bus_config->mosi_io_num, spi_periph_signal[host].spid_in);
|
||||
gpio_iomux_out(bus_config->mosi_io_num, FUNC_SPI, false);
|
||||
@@ -214,7 +231,7 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
||||
temp_flag |= SPICOMMON_BUSFLAG_NATIVE_PINS;
|
||||
} else {
|
||||
//Use GPIO matrix
|
||||
ESP_LOGD(SPI_TAG, "SPI%d use gpio matrix.", host );
|
||||
ESP_LOGD(SPI_TAG, "SPI%d use gpio matrix.", host+1);
|
||||
if (bus_config->mosi_io_num >= 0) {
|
||||
if (mosi_output || (temp_flag&SPICOMMON_BUSFLAG_DUAL)) {
|
||||
gpio_set_direction(bus_config->mosi_io_num, GPIO_MODE_INPUT_OUTPUT);
|
||||
|
@@ -233,8 +233,12 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus
|
||||
|
||||
SPI_CHECK(host>=SPI_HOST && host<=VSPI_HOST, "invalid host", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK( dma_chan >= 0 && dma_chan <= 2, "invalid dma channel", ESP_ERR_INVALID_ARG );
|
||||
SPI_CHECK((bus_config->intr_flags & (ESP_INTR_FLAG_HIGH|ESP_INTR_FLAG_EDGE|ESP_INTR_FLAG_INTRDISABLED))==0, "intr flag not allowed", ESP_ERR_INVALID_ARG);
|
||||
#ifndef CONFIG_SPI_MASTER_ISR_IN_IRAM
|
||||
SPI_CHECK((bus_config->intr_flags & ESP_INTR_FLAG_IRAM)==0, "ESP_INTR_FLAG_IRAM should be disabled when CONFIG_SPI_MASTER_ISR_IN_IRAM is not set.", ESP_ERR_INVALID_ARG);
|
||||
#endif
|
||||
|
||||
spi_chan_claimed=spicommon_periph_claim(host);
|
||||
spi_chan_claimed=spicommon_periph_claim(host, "spi master");
|
||||
SPI_CHECK(spi_chan_claimed, "host already in use", ESP_ERR_INVALID_STATE);
|
||||
|
||||
if ( dma_chan != 0 ) {
|
||||
@@ -284,10 +288,7 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus
|
||||
}
|
||||
}
|
||||
|
||||
int flags = ESP_INTR_FLAG_INTRDISABLED;
|
||||
#ifdef CONFIG_SPI_MASTER_ISR_IN_IRAM
|
||||
flags |= ESP_INTR_FLAG_IRAM;
|
||||
#endif
|
||||
int flags = bus_config->intr_flags | ESP_INTR_FLAG_INTRDISABLED;
|
||||
err = esp_intr_alloc(spicommon_irqsource_for_host(host), flags, spi_intr, (void*)spihost[host], &spihost[host]->intr);
|
||||
if (err != ESP_OK) {
|
||||
ret = err;
|
||||
@@ -442,14 +443,14 @@ esp_err_t spi_bus_add_device(spi_host_device_t host, const spi_device_interface_
|
||||
duty_cycle = (dev_config->duty_cycle_pos==0) ? 128 : dev_config->duty_cycle_pos;
|
||||
eff_clk = spi_cal_clock(apbclk, dev_config->clock_speed_hz, duty_cycle, (uint32_t*)&clk_reg);
|
||||
int freq_limit = spi_get_freq_limit(!(spihost[host]->flags&SPICOMMON_BUSFLAG_NATIVE_PINS), dev_config->input_delay_ns);
|
||||
//GPIO matrix can only change data at 80Mhz rate, which only allows 40MHz SPI clock.
|
||||
SPI_CHECK(eff_clk <= 40*1000*1000 || spihost[host]->flags&SPICOMMON_BUSFLAG_NATIVE_PINS, "80MHz only supported on iomux pins", ESP_ERR_INVALID_ARG);
|
||||
|
||||
//Speed >=40MHz over GPIO matrix needs a dummy cycle, but these don't work for full-duplex connections.
|
||||
spi_get_timing(!(spihost[host]->flags&SPICOMMON_BUSFLAG_NATIVE_PINS), dev_config->input_delay_ns, eff_clk, &dummy_required, &miso_delay);
|
||||
SPI_CHECK( dev_config->flags & SPI_DEVICE_HALFDUPLEX || dummy_required == 0 ||
|
||||
dev_config->flags & SPI_DEVICE_NO_DUMMY,
|
||||
"When GPIO matrix is used in full-duplex mode at frequency > %.1fMHz, device cannot read correct data.\n\
|
||||
Please note the SPI can only work at divisors of 80MHz, and the driver always tries to find the closest frequency to your configuration.\n\
|
||||
"When work in full-duplex mode at frequency > %.1fMHz, device cannot read correct data.\n\
|
||||
Try to use IOMUX pins to increase the frequency limit, or use the half duplex mode.\n\
|
||||
Please note the SPI master can only work at divisors of 80MHz, and the driver always tries to find the closest frequency to your configuration.\n\
|
||||
Specify ``SPI_DEVICE_NO_DUMMY`` to ignore this checking. Then you can output data at higher speed, or read data at your own risk.",
|
||||
ESP_ERR_INVALID_ARG, freq_limit/1000./1000 );
|
||||
|
||||
@@ -498,7 +499,7 @@ Specify ``SPI_DEVICE_NO_DUMMY`` to ignore this checking. Then you can output dat
|
||||
spihost[host]->hw->ctrl2.mosi_delay_mode = 0;
|
||||
spihost[host]->hw->ctrl2.mosi_delay_num = 0;
|
||||
*handle=dev;
|
||||
ESP_LOGD(SPI_TAG, "SPI%d: New device added to CS%d, effective clock: %dkHz", host, freecs, dev->clk_cfg.eff_clk/1000);
|
||||
ESP_LOGD(SPI_TAG, "SPI%d: New device added to CS%d, effective clock: %dkHz", host+1, freecs, dev->clk_cfg.eff_clk/1000);
|
||||
return ESP_OK;
|
||||
|
||||
nomem:
|
||||
@@ -1102,6 +1103,14 @@ static SPI_MASTER_ISR_ATTR esp_err_t check_trans_valid(spi_device_handle_t handl
|
||||
SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && (!(handle->cfg.flags & SPI_DEVICE_HALFDUPLEX))), "incompatible iface params", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK( !(handle->cfg.flags & SPI_DEVICE_HALFDUPLEX) || host->dma_chan == 0 || !(trans_desc->flags & SPI_TRANS_USE_RXDATA || trans_desc->rx_buffer != NULL)
|
||||
|| !(trans_desc->flags & SPI_TRANS_USE_TXDATA || trans_desc->tx_buffer!=NULL), "SPI half duplex mode does not support using DMA with both MOSI and MISO phases.", ESP_ERR_INVALID_ARG );
|
||||
//MOSI phase is skipped only when both tx_buffer and SPI_TRANS_USE_TXDATA are not set.
|
||||
SPI_CHECK(trans_desc->length != 0 || (trans_desc->tx_buffer == NULL && !(trans_desc->flags & SPI_TRANS_USE_TXDATA)),
|
||||
"trans tx_buffer should be NULL and SPI_TRANS_USE_TXDATA should be cleared to skip MOSI phase.", ESP_ERR_INVALID_ARG);
|
||||
//MISO phase is skipped only when both rx_buffer and SPI_TRANS_USE_RXDATA are not set.
|
||||
//If set rxlength=0 in full_duplex mode, it will be automatically set to length
|
||||
SPI_CHECK(!(handle->cfg.flags & SPI_DEVICE_HALFDUPLEX) || trans_desc->rxlength != 0 ||
|
||||
(trans_desc->rx_buffer == NULL && ((trans_desc->flags & SPI_TRANS_USE_RXDATA)==0)),
|
||||
"trans rx_buffer should be NULL and SPI_TRANS_USE_RXDATA should be cleared to skip MISO phase.", ESP_ERR_INVALID_ARG);
|
||||
//In Full duplex mode, default rxlength to be the same as length, if not filled in.
|
||||
// set rxlength to length is ok, even when rx buffer=NULL
|
||||
if (trans_desc->rxlength==0 && !(handle->cfg.flags & SPI_DEVICE_HALFDUPLEX)) {
|
||||
|
@@ -109,8 +109,12 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
|
||||
//We only support HSPI/VSPI, period.
|
||||
SPI_CHECK(VALID_HOST(host), "invalid host", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK( dma_chan >= 0 && dma_chan <= 2, "invalid dma channel", ESP_ERR_INVALID_ARG );
|
||||
SPI_CHECK((bus_config->intr_flags & (ESP_INTR_FLAG_HIGH|ESP_INTR_FLAG_EDGE|ESP_INTR_FLAG_INTRDISABLED))==0, "intr flag not allowed", ESP_ERR_INVALID_ARG);
|
||||
#ifndef CONFIG_SPI_SLAVE_ISR_IN_IRAM
|
||||
SPI_CHECK((bus_config->intr_flags & ESP_INTR_FLAG_IRAM)==0, "ESP_INTR_FLAG_IRAM should be disabled when CONFIG_SPI_SLAVE_ISR_IN_IRAM is not set.", ESP_ERR_INVALID_ARG);
|
||||
#endif
|
||||
|
||||
spi_chan_claimed=spicommon_periph_claim(host);
|
||||
spi_chan_claimed=spicommon_periph_claim(host, "spi slave");
|
||||
SPI_CHECK(spi_chan_claimed, "host already in use", ESP_ERR_INVALID_STATE);
|
||||
|
||||
if ( dma_chan != 0 ) {
|
||||
@@ -174,10 +178,7 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
int flags = ESP_INTR_FLAG_INTRDISABLED;
|
||||
#ifdef CONFIG_SPI_SLAVE_ISR_IN_IRAM
|
||||
flags |= ESP_INTR_FLAG_IRAM;
|
||||
#endif
|
||||
int flags = bus_config->intr_flags | ESP_INTR_FLAG_INTRDISABLED;
|
||||
err = esp_intr_alloc(spicommon_irqsource_for_host(host), flags, spi_intr, (void *)spihost[host], &spihost[host]->intr);
|
||||
if (err != ESP_OK) {
|
||||
ret = err;
|
||||
@@ -297,8 +298,10 @@ esp_err_t SPI_SLAVE_ATTR spi_slave_queue_trans(spi_host_device_t host, const spi
|
||||
SPI_CHECK(spihost[host], "host not slave", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(spihost[host]->dma_chan == 0 || trans_desc->tx_buffer==NULL || esp_ptr_dma_capable(trans_desc->tx_buffer),
|
||||
"txdata not in DMA-capable memory", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(spihost[host]->dma_chan == 0 || trans_desc->rx_buffer==NULL || esp_ptr_dma_capable(trans_desc->rx_buffer),
|
||||
"rxdata not in DMA-capable memory", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(spihost[host]->dma_chan == 0 || trans_desc->rx_buffer==NULL ||
|
||||
(esp_ptr_dma_capable(trans_desc->rx_buffer) && esp_ptr_word_aligned(trans_desc->rx_buffer) &&
|
||||
(trans_desc->length%4==0)),
|
||||
"rxdata not in DMA-capable memory or not WORD aligned", ESP_ERR_INVALID_ARG);
|
||||
|
||||
SPI_CHECK(trans_desc->length <= spihost[host]->max_transfer_sz * 8, "data transfer > host maximum", ESP_ERR_INVALID_ARG);
|
||||
r = xQueueSend(spihost[host]->trans_queue, (void *)&trans_desc, ticks_to_wait);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
set(COMPONENT_SRCDIRS ".")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
set(COMPONENT_REQUIRES unity driver nvs_flash)
|
||||
set(COMPONENT_REQUIRES unity test_utils driver nvs_flash)
|
||||
|
||||
register_component()
|
526
components/driver/test/test_i2c.c
Normal file
526
components/driver/test/test_i2c.c
Normal file
@@ -0,0 +1,526 @@
|
||||
/**
|
||||
* test environment UT_T2_I2C:
|
||||
* please prepare two ESP32-WROVER-KIT board.
|
||||
* Then connect GPIO18 and GPIO18, GPIO19 and GPIO19 between these two boards.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
#include "unity_config.h"
|
||||
#include "driver/i2c.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/i2c_struct.h"
|
||||
#include "soc/i2c_reg.h"
|
||||
#include "esp_system.h"
|
||||
#include "driver/pcnt.h"
|
||||
|
||||
|
||||
#define DATA_LENGTH 512 /*!<Data buffer length for test buffer*/
|
||||
#define RW_TEST_LENGTH 129 /*!<Data length for r/w test, any value from 0-DATA_LENGTH*/
|
||||
#define DELAY_TIME_BETWEEN_ITEMS_MS 1234 /*!< delay time between different test items */
|
||||
|
||||
#define I2C_SLAVE_SCL_IO 19 /*!<gpio number for i2c slave clock */
|
||||
#define I2C_SLAVE_SDA_IO 18 /*!<gpio number for i2c slave data */
|
||||
#define I2C_SLAVE_NUM I2C_NUM_0 /*!<I2C port number for slave dev */
|
||||
#define I2C_SLAVE_TX_BUF_LEN (2*DATA_LENGTH) /*!<I2C slave tx buffer size */
|
||||
#define I2C_SLAVE_RX_BUF_LEN (2*DATA_LENGTH) /*!<I2C slave rx buffer size */
|
||||
|
||||
#define I2C_MASTER_SCL_IO 19 /*!< gpio number for I2C master clock */
|
||||
#define I2C_MASTER_SDA_IO 18 /*!< gpio number for I2C master data */
|
||||
#define I2C_MASTER_NUM I2C_NUM_1 /*!< I2C port number for master dev */
|
||||
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
|
||||
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
|
||||
#define I2C_MASTER_FREQ_HZ 100000 /*!< I2C master clock frequency */
|
||||
|
||||
#define ESP_SLAVE_ADDR 0x28 /*!< ESP32 slave address, you can set any 7bit value */
|
||||
#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
|
||||
#define READ_BIT I2C_MASTER_READ /*!< I2C master read */
|
||||
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
|
||||
#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
|
||||
#define ACK_VAL 0x0 /*!< I2C ack value */
|
||||
#define NACK_VAL 0x1 /*!< I2C nack value */
|
||||
|
||||
#define PULSE_IO 19
|
||||
#define PCNT_INPUT_IO 4
|
||||
#define PCNT_CTRL_FLOATING_IO 5
|
||||
#define HIGHEST_LIMIT 10000
|
||||
#define LOWEST_LIMIT -10000
|
||||
|
||||
static DRAM_ATTR i2c_dev_t *const I2C[I2C_NUM_MAX] = { &I2C0, &I2C1 };
|
||||
|
||||
static esp_err_t i2c_master_read_slave(i2c_port_t i2c_num, uint8_t *data_rd, size_t size)
|
||||
{
|
||||
if (size == 0) {
|
||||
return ESP_OK;
|
||||
}
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( ESP_SLAVE_ADDR << 1 ) | READ_BIT, ACK_CHECK_EN);
|
||||
if (size > 1) {
|
||||
i2c_master_read(cmd, data_rd, size - 1, ACK_VAL);
|
||||
}
|
||||
i2c_master_read_byte(cmd, data_rd + size - 1, NACK_VAL);
|
||||
i2c_master_stop(cmd);
|
||||
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t i2c_master_write_slave(i2c_port_t i2c_num, uint8_t *data_wr, size_t size)
|
||||
{
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
TEST_ESP_OK(i2c_master_write_byte(cmd, ( ESP_SLAVE_ADDR << 1 ) | WRITE_BIT, ACK_CHECK_EN));
|
||||
TEST_ESP_OK(i2c_master_write(cmd, data_wr, size, ACK_CHECK_EN));
|
||||
TEST_ESP_OK(i2c_master_stop(cmd));
|
||||
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 5000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// print the reading buffer
|
||||
static void disp_buf(uint8_t *buf, int len)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < len; i++) {
|
||||
printf("%02x ", buf[i]);
|
||||
if (( i + 1 ) % 16 == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static i2c_config_t i2c_master_init()
|
||||
{
|
||||
i2c_config_t conf_master = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.master.clk_speed = I2C_MASTER_FREQ_HZ,
|
||||
.sda_io_num = I2C_MASTER_SDA_IO,
|
||||
.scl_io_num = I2C_MASTER_SCL_IO,
|
||||
};
|
||||
return conf_master;
|
||||
}
|
||||
|
||||
static i2c_config_t i2c_slave_init()
|
||||
{
|
||||
i2c_config_t conf_slave = {
|
||||
.mode = I2C_MODE_SLAVE,
|
||||
.sda_io_num = I2C_SLAVE_SDA_IO,
|
||||
.scl_io_num = I2C_SLAVE_SCL_IO,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.slave.addr_10bit_en = 0,
|
||||
.slave.slave_addr = ESP_SLAVE_ADDR,
|
||||
};
|
||||
return conf_slave;
|
||||
}
|
||||
|
||||
TEST_CASE("I2C config test", "[i2c]")
|
||||
{
|
||||
// master test
|
||||
i2c_config_t conf_master = i2c_master_init();
|
||||
gpio_pullup_t sda_pull_up_en[2] = {GPIO_PULLUP_DISABLE, GPIO_PULLUP_ENABLE};
|
||||
gpio_pullup_t scl_pull_up_en[2] = {GPIO_PULLUP_DISABLE, GPIO_PULLUP_ENABLE};
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
conf_master.sda_pullup_en = sda_pull_up_en[i];
|
||||
conf_master.scl_pullup_en = scl_pull_up_en[j];
|
||||
TEST_ESP_OK(i2c_param_config(I2C_MASTER_NUM, &conf_master));
|
||||
TEST_ASSERT_EQUAL_INT32(I2C[I2C_MASTER_NUM]->ctr.ms_mode, 1);
|
||||
TEST_ESP_OK(i2c_driver_install(I2C_MASTER_NUM, I2C_MODE_MASTER,
|
||||
I2C_MASTER_RX_BUF_DISABLE,
|
||||
I2C_MASTER_TX_BUF_DISABLE, 0));
|
||||
TEST_ESP_OK(i2c_driver_delete(I2C_MASTER_NUM));
|
||||
}
|
||||
}
|
||||
|
||||
// slave test
|
||||
i2c_config_t conf_slave = i2c_slave_init();
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
conf_master.sda_pullup_en = sda_pull_up_en[i];
|
||||
conf_master.scl_pullup_en = scl_pull_up_en[j];
|
||||
conf_slave.sda_pullup_en = sda_pull_up_en[i];
|
||||
conf_slave.scl_pullup_en = scl_pull_up_en[j];
|
||||
TEST_ESP_OK(i2c_param_config( I2C_SLAVE_NUM, &conf_slave));
|
||||
TEST_ASSERT_EQUAL_INT32(I2C[I2C_SLAVE_NUM] -> ctr.ms_mode, 0);
|
||||
TEST_ESP_OK(i2c_driver_install(I2C_SLAVE_NUM, I2C_MODE_SLAVE,
|
||||
I2C_SLAVE_RX_BUF_LEN,
|
||||
I2C_SLAVE_TX_BUF_LEN, 0));
|
||||
TEST_ESP_OK(i2c_driver_delete(I2C_SLAVE_NUM));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("I2C set and get period test", "[i2c]")
|
||||
{
|
||||
int high_period, low_period;
|
||||
i2c_config_t conf_master = i2c_master_init();
|
||||
TEST_ESP_OK(i2c_param_config(I2C_MASTER_NUM, &conf_master));
|
||||
TEST_ESP_OK(i2c_driver_install(I2C_MASTER_NUM, I2C_MODE_MASTER,
|
||||
I2C_MASTER_RX_BUF_DISABLE,
|
||||
I2C_MASTER_TX_BUF_DISABLE, 0));
|
||||
|
||||
TEST_ESP_OK(i2c_set_period(I2C_MASTER_NUM, I2C_SCL_HIGH_PERIOD_V, I2C_SCL_HIGH_PERIOD_V));
|
||||
TEST_ESP_OK(i2c_get_period(I2C_MASTER_NUM, &high_period, &low_period));
|
||||
TEST_ASSERT_EQUAL_INT(I2C_SCL_HIGH_PERIOD_V, high_period);
|
||||
TEST_ASSERT_EQUAL_INT(I2C_SCL_HIGH_PERIOD_V, low_period);
|
||||
|
||||
TEST_ASSERT_NOT_NULL((void *)i2c_set_period(I2C_MASTER_NUM, I2C_SCL_HIGH_PERIOD_V + 1, I2C_SCL_HIGH_PERIOD_V + 1));
|
||||
|
||||
TEST_ESP_OK(i2c_set_period(I2C_MASTER_NUM, 300, 400));
|
||||
TEST_ESP_OK(i2c_get_period(I2C_MASTER_NUM, &high_period, &low_period));
|
||||
TEST_ASSERT_EQUAL_INT(300, high_period);
|
||||
TEST_ASSERT_EQUAL_INT(400, low_period);
|
||||
TEST_ESP_OK(i2c_driver_delete(I2C_MASTER_NUM));
|
||||
}
|
||||
|
||||
TEST_CASE("I2C config FIFO test", "[i2c]")
|
||||
{
|
||||
TEST_ASSERT_BIT_LOW(1, I2C[I2C_SLAVE_NUM]->fifo_conf.tx_fifo_rst);
|
||||
TEST_ESP_OK(i2c_reset_tx_fifo(I2C_SLAVE_NUM));
|
||||
TEST_ASSERT_BIT_LOW(0, I2C[I2C_SLAVE_NUM]->fifo_conf.tx_fifo_rst);
|
||||
|
||||
TEST_ESP_OK(i2c_reset_rx_fifo(I2C_SLAVE_NUM));
|
||||
TEST_ASSERT_BIT_LOW(0, I2C[I2C_SLAVE_NUM]->fifo_conf.rx_fifo_rst);
|
||||
}
|
||||
|
||||
TEST_CASE("I2C timing test", "[i2c]")
|
||||
{
|
||||
int test_setup_time, test_data_time, test_stop_time, test_hold_time;
|
||||
uint8_t *data_wr = (uint8_t *) malloc(DATA_LENGTH);
|
||||
i2c_config_t conf_master = i2c_master_init();
|
||||
TEST_ESP_OK(i2c_param_config(I2C_MASTER_NUM, &conf_master));
|
||||
TEST_ESP_OK(i2c_driver_install(I2C_MASTER_NUM, I2C_MODE_MASTER,
|
||||
I2C_MASTER_RX_BUF_DISABLE,
|
||||
I2C_MASTER_TX_BUF_DISABLE, 0));
|
||||
|
||||
TEST_ESP_OK(i2c_set_start_timing(I2C_MASTER_NUM, 50, 60));
|
||||
TEST_ESP_OK(i2c_set_data_timing(I2C_MASTER_NUM, 80, 60));
|
||||
TEST_ESP_OK(i2c_set_stop_timing(I2C_MASTER_NUM, 100, 60));
|
||||
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
data_wr[i] = i;
|
||||
}
|
||||
i2c_master_write_slave(I2C_MASTER_NUM, data_wr, RW_TEST_LENGTH);
|
||||
TEST_ESP_OK(i2c_get_start_timing(I2C_MASTER_NUM, &test_setup_time, &test_hold_time));
|
||||
TEST_ESP_OK(i2c_get_data_timing(I2C_MASTER_NUM, &test_data_time, &test_hold_time));
|
||||
TEST_ESP_OK(i2c_get_stop_timing(I2C_MASTER_NUM, &test_stop_time, &test_hold_time));
|
||||
TEST_ASSERT_EQUAL_INT32(50, test_setup_time);
|
||||
TEST_ASSERT_EQUAL_INT32(80, test_data_time);
|
||||
TEST_ASSERT_EQUAL_INT32(100, test_stop_time);
|
||||
TEST_ASSERT_EQUAL_INT32(60, test_hold_time);
|
||||
free(data_wr);
|
||||
i2c_driver_delete(I2C_MASTER_NUM);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("I2C data mode test", "[i2c]")
|
||||
{
|
||||
uint8_t *data_wr = (uint8_t *) malloc(DATA_LENGTH);
|
||||
i2c_trans_mode_t test_tx_trans_mode, test_rx_trans_mode;
|
||||
i2c_config_t conf_master = i2c_master_init();
|
||||
TEST_ESP_OK(i2c_param_config(I2C_MASTER_NUM, &conf_master));
|
||||
TEST_ESP_OK(i2c_driver_install(I2C_MASTER_NUM, I2C_MODE_MASTER,
|
||||
I2C_MASTER_RX_BUF_DISABLE,
|
||||
I2C_MASTER_TX_BUF_DISABLE, 0));
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
data_wr[i] = i;
|
||||
}
|
||||
i2c_master_write_slave(I2C_MASTER_NUM, data_wr, RW_TEST_LENGTH);
|
||||
TEST_ESP_OK(i2c_set_data_mode(I2C_MASTER_NUM, I2C_DATA_MODE_LSB_FIRST, I2C_DATA_MODE_LSB_FIRST));
|
||||
i2c_master_write_slave(I2C_MASTER_NUM, data_wr, RW_TEST_LENGTH);
|
||||
TEST_ASSERT_EQUAL_INT(1, I2C[I2C_MASTER_NUM]->ctr.rx_lsb_first);
|
||||
TEST_ASSERT_EQUAL_INT(1, I2C[I2C_MASTER_NUM]->ctr.tx_lsb_first);
|
||||
|
||||
TEST_ESP_OK(i2c_get_data_mode(I2C_MASTER_NUM, &test_tx_trans_mode, &test_rx_trans_mode));
|
||||
TEST_ASSERT_EQUAL_INT(1, test_tx_trans_mode);
|
||||
TEST_ASSERT_EQUAL_INT(1, test_rx_trans_mode);
|
||||
free(data_wr);
|
||||
i2c_driver_delete(I2C_MASTER_NUM);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("I2C driver memory leaking check", "[i2c]")
|
||||
{
|
||||
esp_err_t ret;
|
||||
i2c_config_t conf_slave = i2c_slave_init();
|
||||
ret = i2c_param_config(I2C_SLAVE_NUM, &conf_slave);
|
||||
TEST_ASSERT(ret == ESP_OK);
|
||||
|
||||
int size = esp_get_free_heap_size();
|
||||
for (uint32_t i = 0; i <= 1000; i++) {
|
||||
ret = i2c_driver_install(I2C_SLAVE_NUM, I2C_MODE_SLAVE,
|
||||
I2C_SLAVE_RX_BUF_LEN,
|
||||
I2C_SLAVE_TX_BUF_LEN, 0);
|
||||
TEST_ASSERT(ret == ESP_OK);
|
||||
vTaskDelay(10 / portTICK_RATE_MS);
|
||||
i2c_driver_delete(I2C_SLAVE_NUM);
|
||||
TEST_ASSERT(ret == ESP_OK);
|
||||
}
|
||||
|
||||
TEST_ASSERT_INT_WITHIN(100, size, esp_get_free_heap_size());
|
||||
}
|
||||
|
||||
static void i2c_master_write_test()
|
||||
{
|
||||
uint8_t *data_wr = (uint8_t *) malloc(DATA_LENGTH);
|
||||
int i;
|
||||
|
||||
i2c_config_t conf_master = i2c_master_init();
|
||||
TEST_ESP_OK(i2c_param_config(I2C_MASTER_NUM, &conf_master));
|
||||
|
||||
TEST_ESP_OK(i2c_driver_install(I2C_MASTER_NUM, I2C_MODE_MASTER,
|
||||
I2C_MASTER_RX_BUF_DISABLE,
|
||||
I2C_MASTER_TX_BUF_DISABLE, 0));
|
||||
unity_wait_for_signal("i2c slave init finish");
|
||||
|
||||
unity_send_signal("master write");
|
||||
for (i = 0; i < DATA_LENGTH / 2; i++) {
|
||||
data_wr[i] = i;
|
||||
}
|
||||
i2c_master_write_slave(I2C_MASTER_NUM, data_wr, DATA_LENGTH / 2);
|
||||
disp_buf(data_wr, i + 1);
|
||||
free(data_wr);
|
||||
unity_wait_for_signal("ready to delete");
|
||||
TEST_ESP_OK(i2c_driver_delete(I2C_MASTER_NUM));
|
||||
}
|
||||
|
||||
static void i2c_slave_read_test()
|
||||
{
|
||||
uint8_t *data_rd = (uint8_t *) malloc(DATA_LENGTH);
|
||||
int size_rd = 0;
|
||||
int len = 0;
|
||||
|
||||
i2c_config_t conf_slave = i2c_slave_init();
|
||||
TEST_ESP_OK(i2c_param_config( I2C_SLAVE_NUM, &conf_slave));
|
||||
TEST_ESP_OK(i2c_driver_install(I2C_SLAVE_NUM, I2C_MODE_SLAVE,
|
||||
I2C_SLAVE_RX_BUF_LEN,
|
||||
I2C_SLAVE_TX_BUF_LEN, 0));
|
||||
unity_send_signal("i2c slave init finish");
|
||||
|
||||
unity_wait_for_signal("master write");
|
||||
while (1) {
|
||||
len = i2c_slave_read_buffer( I2C_SLAVE_NUM, data_rd + size_rd, DATA_LENGTH, 10000 / portTICK_RATE_MS);
|
||||
if (len == 0) {
|
||||
break;
|
||||
}
|
||||
size_rd += len;
|
||||
}
|
||||
disp_buf(data_rd, size_rd);
|
||||
for (int i = 0; i < size_rd; i++) {
|
||||
TEST_ASSERT(data_rd[i] == i);
|
||||
}
|
||||
free(data_rd);
|
||||
unity_send_signal("ready to delete");
|
||||
TEST_ESP_OK(i2c_driver_delete(I2C_SLAVE_NUM));
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("I2C master write slave test", "[i2c][test_env=UT_T2_I2C][timeout=150]", i2c_master_write_test, i2c_slave_read_test);
|
||||
|
||||
static void master_read_slave_test()
|
||||
{
|
||||
uint8_t *data_rd = (uint8_t *) malloc(DATA_LENGTH);
|
||||
memset(data_rd, 0, DATA_LENGTH);
|
||||
i2c_config_t conf_master = i2c_master_init();
|
||||
TEST_ESP_OK(i2c_param_config(I2C_MASTER_NUM, &conf_master));
|
||||
TEST_ESP_OK(i2c_driver_install(I2C_MASTER_NUM, I2C_MODE_MASTER,
|
||||
I2C_MASTER_RX_BUF_DISABLE,
|
||||
I2C_MASTER_TX_BUF_DISABLE, 0));
|
||||
unity_wait_for_signal("i2c slave init finish");
|
||||
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( ESP_SLAVE_ADDR << 1 ) | READ_BIT, ACK_CHECK_EN);
|
||||
|
||||
unity_send_signal("slave write");
|
||||
unity_wait_for_signal("master read");
|
||||
i2c_master_read(cmd, data_rd, RW_TEST_LENGTH-1, ACK_VAL);
|
||||
i2c_master_read_byte(cmd, data_rd + RW_TEST_LENGTH-1, NACK_VAL);
|
||||
i2c_master_stop(cmd);
|
||||
i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 5000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
for (int i = 0; i < RW_TEST_LENGTH; i++) {
|
||||
printf("%d\n", data_rd[i]);
|
||||
TEST_ASSERT(data_rd[i]==i);
|
||||
}
|
||||
free(data_rd);
|
||||
unity_send_signal("ready to delete");
|
||||
i2c_driver_delete(I2C_MASTER_NUM);
|
||||
}
|
||||
|
||||
static void slave_write_buffer_test()
|
||||
{
|
||||
uint8_t *data_wr = (uint8_t *) malloc(DATA_LENGTH);
|
||||
int size_rd;
|
||||
|
||||
i2c_config_t conf_slave = i2c_slave_init();
|
||||
TEST_ESP_OK(i2c_param_config( I2C_SLAVE_NUM, &conf_slave));
|
||||
TEST_ESP_OK(i2c_driver_install(I2C_SLAVE_NUM, I2C_MODE_SLAVE,
|
||||
I2C_SLAVE_RX_BUF_LEN,
|
||||
I2C_SLAVE_TX_BUF_LEN, 0));
|
||||
unity_send_signal("i2c slave init finish");
|
||||
|
||||
unity_wait_for_signal("slave write");
|
||||
for (int i = 0; i < DATA_LENGTH / 2; i++) {
|
||||
data_wr[i] = i;
|
||||
}
|
||||
size_rd = i2c_slave_write_buffer(I2C_SLAVE_NUM, data_wr, RW_TEST_LENGTH, 2000 / portTICK_RATE_MS);
|
||||
disp_buf(data_wr, size_rd);
|
||||
unity_send_signal("master read");
|
||||
unity_wait_for_signal("ready to delete");
|
||||
free(data_wr);
|
||||
i2c_driver_delete(I2C_SLAVE_NUM);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("I2C master read slave test", "[i2c][test_env=UT_T2_I2C][timeout=150]", master_read_slave_test, slave_write_buffer_test);
|
||||
|
||||
static void i2c_master_write_read_test()
|
||||
{
|
||||
uint8_t *data_rd = (uint8_t *) malloc(DATA_LENGTH);
|
||||
memset(data_rd, 0, DATA_LENGTH);
|
||||
uint8_t *data_wr = (uint8_t *) malloc(DATA_LENGTH);
|
||||
|
||||
i2c_config_t conf_master = i2c_master_init();
|
||||
TEST_ESP_OK(i2c_param_config(I2C_MASTER_NUM, &conf_master));
|
||||
TEST_ESP_OK(i2c_driver_install(I2C_MASTER_NUM, I2C_MODE_MASTER,
|
||||
I2C_MASTER_RX_BUF_DISABLE,
|
||||
I2C_MASTER_TX_BUF_DISABLE, 0));
|
||||
unity_wait_for_signal("i2c slave init finish");
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( ESP_SLAVE_ADDR << 1 ) | READ_BIT, ACK_CHECK_EN);
|
||||
|
||||
unity_send_signal("slave write");
|
||||
unity_wait_for_signal("master read and write");
|
||||
i2c_master_read(cmd, data_rd, RW_TEST_LENGTH, ACK_VAL);
|
||||
i2c_master_read_byte(cmd, data_rd + RW_TEST_LENGTH, NACK_VAL);
|
||||
i2c_master_stop(cmd);
|
||||
i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 5000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
disp_buf(data_rd, RW_TEST_LENGTH);
|
||||
for (int i = 0; i < RW_TEST_LENGTH; i++) {
|
||||
TEST_ASSERT(data_rd[i] == i/2);
|
||||
}
|
||||
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
data_wr[i] = i % 3;
|
||||
}
|
||||
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
i2c_master_write_slave(I2C_MASTER_NUM, data_wr, RW_TEST_LENGTH);
|
||||
free(data_wr);
|
||||
free(data_rd);
|
||||
unity_send_signal("slave read");
|
||||
unity_wait_for_signal("ready to delete");
|
||||
i2c_driver_delete(I2C_MASTER_NUM);
|
||||
}
|
||||
|
||||
static void i2c_slave_read_write_test()
|
||||
{
|
||||
uint8_t *data_rd = (uint8_t *) malloc(DATA_LENGTH);
|
||||
memset(data_rd, 0, DATA_LENGTH);
|
||||
uint8_t *data_wr = (uint8_t *) malloc(DATA_LENGTH);
|
||||
int size_rd;
|
||||
|
||||
i2c_config_t conf_slave = i2c_slave_init();
|
||||
TEST_ESP_OK(i2c_param_config( I2C_SLAVE_NUM, &conf_slave));
|
||||
TEST_ESP_OK(i2c_driver_install(I2C_SLAVE_NUM, I2C_MODE_SLAVE,
|
||||
I2C_SLAVE_RX_BUF_LEN,
|
||||
I2C_SLAVE_TX_BUF_LEN, 0));
|
||||
unity_send_signal("i2c slave init finish");
|
||||
unity_wait_for_signal("slave write");
|
||||
|
||||
for (int i = 0; i < DATA_LENGTH / 2; i++) {
|
||||
data_wr[i] = i/2;
|
||||
}
|
||||
size_rd = i2c_slave_write_buffer(I2C_SLAVE_NUM, data_wr, RW_TEST_LENGTH, 2000 / portTICK_RATE_MS);
|
||||
disp_buf(data_wr, size_rd);
|
||||
unity_send_signal("master read and write");
|
||||
unity_wait_for_signal("slave read");
|
||||
size_rd = i2c_slave_read_buffer( I2C_SLAVE_NUM, data_rd, RW_TEST_LENGTH, 1000 / portTICK_RATE_MS);
|
||||
printf("slave read data is:\n");
|
||||
disp_buf(data_rd, size_rd);
|
||||
for (int i = 0; i < RW_TEST_LENGTH; i++) {
|
||||
TEST_ASSERT(data_rd[i] == i % 3);
|
||||
}
|
||||
free(data_wr);
|
||||
free(data_rd);
|
||||
unity_send_signal("ready to delete");
|
||||
i2c_driver_delete(I2C_SLAVE_NUM);
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("I2C read and write test", "[i2c][test_env=UT_T2_I2C][timeout=150]", i2c_master_write_read_test, i2c_slave_read_write_test);
|
||||
|
||||
static void i2c_master_repeat_write()
|
||||
{
|
||||
uint8_t *data_wr = (uint8_t *) malloc(DATA_LENGTH);
|
||||
int times = 3;
|
||||
|
||||
i2c_config_t conf_master = i2c_master_init();
|
||||
TEST_ESP_OK(i2c_param_config(I2C_MASTER_NUM, &conf_master));
|
||||
|
||||
TEST_ESP_OK(i2c_driver_install(I2C_MASTER_NUM, I2C_MODE_MASTER,
|
||||
I2C_MASTER_RX_BUF_DISABLE,
|
||||
I2C_MASTER_TX_BUF_DISABLE, 0));
|
||||
unity_wait_for_signal("i2c slave init finish");
|
||||
|
||||
for (int j = 0; j < times; j++) {
|
||||
for (int i = 0; i < DATA_LENGTH; i++) {
|
||||
data_wr[i] = j + i;
|
||||
}
|
||||
i2c_master_write_slave(I2C_MASTER_NUM, data_wr, RW_TEST_LENGTH);
|
||||
disp_buf(data_wr, RW_TEST_LENGTH);
|
||||
}
|
||||
free(data_wr);
|
||||
unity_send_signal("master write");
|
||||
unity_wait_for_signal("ready to delete");
|
||||
i2c_driver_delete(I2C_MASTER_NUM);
|
||||
}
|
||||
|
||||
static void i2c_slave_repeat_read()
|
||||
{
|
||||
int size_rd = 0;
|
||||
int times = 3;
|
||||
uint8_t *data_rd = (uint8_t *) malloc(DATA_LENGTH * 3);
|
||||
|
||||
i2c_config_t conf_slave = i2c_slave_init();
|
||||
TEST_ESP_OK(i2c_param_config( I2C_SLAVE_NUM, &conf_slave));
|
||||
TEST_ESP_OK(i2c_driver_install(I2C_SLAVE_NUM, I2C_MODE_SLAVE,
|
||||
I2C_SLAVE_RX_BUF_LEN,
|
||||
I2C_SLAVE_TX_BUF_LEN, 0));
|
||||
unity_send_signal("i2c slave init finish");
|
||||
unity_wait_for_signal("master write");
|
||||
|
||||
while (1) {
|
||||
int len = i2c_slave_read_buffer( I2C_SLAVE_NUM, data_rd + size_rd, RW_TEST_LENGTH * 3, 10000 / portTICK_RATE_MS);
|
||||
if (len == 0) {
|
||||
break;
|
||||
}
|
||||
size_rd += len;
|
||||
}
|
||||
disp_buf(data_rd, size_rd);
|
||||
for (int j = 0; j < times; j++) {
|
||||
for (int i = 0; i < RW_TEST_LENGTH; i++) {
|
||||
printf("data: %d, %d\n", data_rd[j * RW_TEST_LENGTH + i], (i % 129 + j));
|
||||
TEST_ASSERT(data_rd[j * RW_TEST_LENGTH + i] == (i % 129 + j));
|
||||
}
|
||||
}
|
||||
free(data_rd);
|
||||
unity_send_signal("ready to delete");
|
||||
i2c_driver_delete(I2C_SLAVE_NUM);
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("I2C repeat write test", "[i2c][test_env=UT_T2_I2C][timeout=150]", i2c_master_repeat_write, i2c_slave_repeat_read);
|
269
components/driver/test/test_i2s.c
Normal file
269
components/driver/test/test_i2s.c
Normal file
@@ -0,0 +1,269 @@
|
||||
/**
|
||||
* I2S test environment UT_T1_I2S:
|
||||
* connect GPIO18 and GPIO19, GPIO25 and GPIO26, GPIO21 and GPIO22
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/i2s.h"
|
||||
#include "unity.h"
|
||||
|
||||
#define SAMPLE_RATE (36000)
|
||||
#define SAMPLE_BITS (16)
|
||||
#define MASTER_BCK_IO 18
|
||||
#define MASTER_WS_IO 25
|
||||
#define SLAVE_BCK_IO 19
|
||||
#define SLAVE_WS_IO 26
|
||||
#define DATA_IN_IO 21
|
||||
#define DATA_OUT_IO 22
|
||||
|
||||
/**
|
||||
* i2s initialize test
|
||||
* 1. i2s_driver_install
|
||||
* 2. i2s_set_pin
|
||||
*/
|
||||
TEST_CASE("I2S basic driver install, uninstall, set pin test", "[i2s]")
|
||||
{
|
||||
// dac, adc i2s
|
||||
i2s_config_t i2s_config = {
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
|
||||
.sample_rate = SAMPLE_RATE,
|
||||
.bits_per_sample = SAMPLE_BITS,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||
.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
|
||||
.dma_buf_count = 6,
|
||||
.dma_buf_len = 60,
|
||||
.use_apll = 0,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 ,
|
||||
};
|
||||
|
||||
//install and start i2s driver
|
||||
TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL));
|
||||
//for internal DAC, this will enable both of the internal channels
|
||||
TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, NULL));
|
||||
//stop & destroy i2s driver
|
||||
TEST_ESP_OK(i2s_driver_uninstall(I2S_NUM_0));
|
||||
|
||||
// normal i2s
|
||||
i2s_pin_config_t pin_config = {
|
||||
.bck_io_num = MASTER_BCK_IO,
|
||||
.ws_io_num = MASTER_WS_IO,
|
||||
.data_out_num = DATA_OUT_IO,
|
||||
.data_in_num = -1
|
||||
};
|
||||
TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL));
|
||||
TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &pin_config));
|
||||
TEST_ESP_OK(i2s_driver_uninstall(I2S_NUM_0));
|
||||
|
||||
//error param test
|
||||
TEST_ASSERT(i2s_driver_install(I2S_NUM_MAX, &i2s_config, 0, NULL) == ESP_ERR_INVALID_ARG);
|
||||
TEST_ASSERT(i2s_driver_install(I2S_NUM_0, NULL, 0, NULL) == ESP_ERR_INVALID_ARG);
|
||||
i2s_config.dma_buf_count = 1;
|
||||
TEST_ASSERT(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL) == ESP_ERR_INVALID_ARG);
|
||||
i2s_config.dma_buf_count = 129;
|
||||
TEST_ASSERT(i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL) == ESP_ERR_INVALID_ARG);
|
||||
TEST_ESP_OK(i2s_driver_uninstall(I2S_NUM_0));
|
||||
}
|
||||
|
||||
TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s][test_env=UT_T1_I2S]")
|
||||
{
|
||||
// master driver installed and send data
|
||||
i2s_config_t master_i2s_config = {
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
|
||||
.sample_rate = SAMPLE_RATE,
|
||||
.bits_per_sample = SAMPLE_BITS,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||
.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
|
||||
.dma_buf_count = 6,
|
||||
.dma_buf_len = 100,
|
||||
.use_apll = 0,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 ,
|
||||
};
|
||||
i2s_pin_config_t master_pin_config = {
|
||||
.bck_io_num = MASTER_BCK_IO,
|
||||
.ws_io_num = MASTER_WS_IO,
|
||||
.data_out_num = DATA_OUT_IO,
|
||||
.data_in_num = -1
|
||||
};
|
||||
TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &master_i2s_config, 0, NULL));
|
||||
TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &master_pin_config));
|
||||
printf("\r\nheap size: %d\n", esp_get_free_heap_size());
|
||||
|
||||
i2s_config_t slave_i2s_config = {
|
||||
.mode = I2S_MODE_SLAVE | I2S_MODE_RX,
|
||||
.sample_rate = SAMPLE_RATE,
|
||||
.bits_per_sample = SAMPLE_BITS,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||
.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
|
||||
.dma_buf_count = 6,
|
||||
.dma_buf_len = 100,
|
||||
.use_apll = 0,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 ,
|
||||
};
|
||||
i2s_pin_config_t slave_pin_config = {
|
||||
.bck_io_num = SLAVE_BCK_IO,
|
||||
.ws_io_num = SLAVE_WS_IO,
|
||||
.data_out_num = -1,
|
||||
.data_in_num = DATA_IN_IO,
|
||||
};
|
||||
// slave driver installed and receive data
|
||||
TEST_ESP_OK(i2s_driver_install(I2S_NUM_1, &slave_i2s_config, 0, NULL));
|
||||
TEST_ESP_OK(i2s_set_pin(I2S_NUM_1, &slave_pin_config));
|
||||
printf("\r\nheap size: %d\n", esp_get_free_heap_size());
|
||||
|
||||
uint8_t* data_wr = (uint8_t*)malloc(sizeof(uint8_t)*400);
|
||||
size_t i2s_bytes_write = 0;
|
||||
size_t bytes_read = 0;
|
||||
int length = 0;
|
||||
uint8_t *i2s_read_buff = (uint8_t*)malloc(sizeof(uint8_t)*10000);
|
||||
|
||||
for(int i=0; i<100; i++) {
|
||||
data_wr[i] = i+1;
|
||||
}
|
||||
int flag=0; // break loop flag
|
||||
int end_position = 0;
|
||||
// write data to slave
|
||||
i2s_write(I2S_NUM_0, data_wr, sizeof(uint8_t)*400, &i2s_bytes_write, 1000 / portTICK_PERIOD_MS);
|
||||
while(!flag){
|
||||
i2s_read(I2S_NUM_1, i2s_read_buff + length, sizeof(uint8_t)*500, &bytes_read, 1000/portMAX_DELAY);
|
||||
if(bytes_read>0) {
|
||||
printf("read data size: %d\n", bytes_read);
|
||||
for(int i=length; i<length + bytes_read; i++) {
|
||||
if(i2s_read_buff[i] == 100) {
|
||||
flag=1;
|
||||
end_position = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
length = length + bytes_read;
|
||||
}
|
||||
// test the readed data right or not
|
||||
for(int i=end_position-99; i<=end_position; i++) {
|
||||
TEST_ASSERT(*(i2s_read_buff + i) == (i-end_position+100));
|
||||
}
|
||||
free(data_wr);
|
||||
free(i2s_read_buff);
|
||||
i2s_driver_uninstall(I2S_NUM_0);
|
||||
i2s_driver_uninstall(I2S_NUM_1);
|
||||
}
|
||||
|
||||
TEST_CASE("I2S write and read test(master rx and slave tx)", "[i2s][test_env=UT_T1_I2S]")
|
||||
{
|
||||
// master driver installed and send data
|
||||
i2s_config_t master_i2s_config = {
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_RX,
|
||||
.sample_rate = SAMPLE_RATE,
|
||||
.bits_per_sample = SAMPLE_BITS,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||
.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
|
||||
.dma_buf_count = 6,
|
||||
.dma_buf_len = 100,
|
||||
.use_apll = 0,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 ,
|
||||
};
|
||||
i2s_pin_config_t master_pin_config = {
|
||||
.bck_io_num = MASTER_BCK_IO,
|
||||
.ws_io_num = MASTER_WS_IO,
|
||||
.data_out_num = -1,
|
||||
.data_in_num = DATA_IN_IO,
|
||||
};
|
||||
TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &master_i2s_config, 0, NULL));
|
||||
TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &master_pin_config));
|
||||
printf("\r\nheap size: %d\n", esp_get_free_heap_size());
|
||||
|
||||
i2s_config_t slave_i2s_config = {
|
||||
.mode = I2S_MODE_SLAVE | I2S_MODE_TX, // Only RX
|
||||
.sample_rate = SAMPLE_RATE,
|
||||
.bits_per_sample = SAMPLE_BITS,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels
|
||||
.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
|
||||
.dma_buf_count = 6,
|
||||
.dma_buf_len = 100,
|
||||
.use_apll = 0,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 ,
|
||||
};
|
||||
i2s_pin_config_t slave_pin_config = {
|
||||
.bck_io_num = SLAVE_BCK_IO,
|
||||
.ws_io_num = SLAVE_WS_IO,
|
||||
.data_out_num = DATA_OUT_IO,
|
||||
.data_in_num = -1
|
||||
};
|
||||
// slave driver installed and receive data
|
||||
TEST_ESP_OK(i2s_driver_install(I2S_NUM_1, &slave_i2s_config, 0, NULL));
|
||||
TEST_ESP_OK(i2s_set_pin(I2S_NUM_1, &slave_pin_config));
|
||||
|
||||
uint8_t* data_wr = (uint8_t*)malloc(sizeof(uint8_t)*400);
|
||||
size_t i2s_bytes_write = 0;
|
||||
size_t bytes_read = 0;
|
||||
int length = 0;
|
||||
uint8_t *i2s_read_buff = (uint8_t*)malloc(sizeof(uint8_t)*100000);
|
||||
|
||||
for(int i=0; i<100; i++) {
|
||||
data_wr[i] = i+1;
|
||||
}
|
||||
// slave write data to master
|
||||
i2s_write(I2S_NUM_1, data_wr, sizeof(uint8_t)*400, &i2s_bytes_write, 1000 / portTICK_PERIOD_MS);
|
||||
|
||||
int flag=0; // break loop flag
|
||||
int end_position = 0;
|
||||
// write data to slave
|
||||
while(!flag){
|
||||
TEST_ESP_OK(i2s_read(I2S_NUM_0, i2s_read_buff + length, 10000-length, &bytes_read, 1000/portMAX_DELAY));
|
||||
if(bytes_read > 0) {
|
||||
for(int i=length; i<length+bytes_read; i++) {
|
||||
if(i2s_read_buff[i] == 100) {
|
||||
flag=1;
|
||||
end_position = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
length = length + bytes_read;
|
||||
}
|
||||
// test the readed data right or not
|
||||
for(int i=end_position-99; i<=end_position; i++) {
|
||||
TEST_ASSERT(*(i2s_read_buff + i) == (i-end_position+100));
|
||||
}
|
||||
free(data_wr);
|
||||
free(i2s_read_buff);
|
||||
i2s_driver_uninstall(I2S_NUM_0);
|
||||
i2s_driver_uninstall(I2S_NUM_1);
|
||||
}
|
||||
|
||||
TEST_CASE("I2S memory leaking test", "[i2s]")
|
||||
{
|
||||
i2s_config_t master_i2s_config = {
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_RX,
|
||||
.sample_rate = SAMPLE_RATE,
|
||||
.bits_per_sample = SAMPLE_BITS,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||
.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
|
||||
.dma_buf_count = 6,
|
||||
.dma_buf_len = 100,
|
||||
.use_apll = 0,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 ,
|
||||
};
|
||||
i2s_pin_config_t master_pin_config = {
|
||||
.bck_io_num = MASTER_BCK_IO,
|
||||
.ws_io_num = MASTER_WS_IO,
|
||||
.data_out_num = -1,
|
||||
.data_in_num = DATA_IN_IO
|
||||
};
|
||||
|
||||
TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &master_i2s_config, 0, NULL));
|
||||
TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &master_pin_config));
|
||||
i2s_driver_uninstall(I2S_NUM_0);
|
||||
int initial_size = esp_get_free_heap_size();
|
||||
|
||||
for(int i=0; i<100; i++) {
|
||||
TEST_ESP_OK(i2s_driver_install(I2S_NUM_0, &master_i2s_config, 0, NULL));
|
||||
TEST_ESP_OK(i2s_set_pin(I2S_NUM_0, &master_pin_config));
|
||||
i2s_driver_uninstall(I2S_NUM_0);
|
||||
TEST_ASSERT(initial_size == esp_get_free_heap_size());
|
||||
}
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
TEST_ASSERT(initial_size == esp_get_free_heap_size());
|
||||
}
|
826
components/driver/test/test_pwm.c
Normal file
826
components/driver/test/test_pwm.c
Normal file
@@ -0,0 +1,826 @@
|
||||
/**
|
||||
* To test PWM, use the PCNT to calculateit to judge it work right or not.
|
||||
* e.g: judge the start and stop.
|
||||
* If started right, the PCNT will count the pulse.
|
||||
* If stopped right, the PCNT will count no pulse.
|
||||
*
|
||||
*
|
||||
* test environment UT_T1_MCPWM:
|
||||
* 1. connect GPIO4 to GPIO5
|
||||
* 2. connect GPIO13 to GPIO12
|
||||
* 3. connect GPIO27 to GPIO14
|
||||
*
|
||||
* all of case separate different timer to test in case that one case cost too much time
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "esp_system.h"
|
||||
#include "driver/mcpwm.h"
|
||||
#include "driver/pcnt.h"
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "soc/mcpwm_reg.h"
|
||||
#include "soc/mcpwm_struct.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
#define GPIO_PWMA_OUT 4
|
||||
#define GPIO_PWMB_OUT 13
|
||||
#define GPIO_CAP_IN 27
|
||||
#define GPIO_SYNC_IN 27
|
||||
#define GPIO_FAULT_IN 27
|
||||
|
||||
#define CAP_SIG_NUM 14
|
||||
#define SYN_SIG_NUM 14
|
||||
#define FAULT_SIG_NUM 14
|
||||
|
||||
#define GPIO_PWMA_PCNT_INPUT 5
|
||||
#define GPIO_PWMB_PCNT_INPUT 12
|
||||
|
||||
#define PCNT_CTRL_FLOATING_IO1 25
|
||||
#define PCNT_CTRL_FLOATING_IO2 26
|
||||
|
||||
#define CAP0_INT_EN BIT(27)
|
||||
#define CAP1_INT_EN BIT(28)
|
||||
#define CAP2_INT_EN BIT(29)
|
||||
|
||||
#define INITIAL_DUTY 10.0
|
||||
#define MCPWM_GPIO_INIT 0
|
||||
|
||||
|
||||
#define HIGHEST_LIMIT 10000
|
||||
#define LOWEST_LIMIT -10000
|
||||
|
||||
static mcpwm_dev_t *MCPWM[2] = {&MCPWM0, &MCPWM1};
|
||||
|
||||
static xQueueHandle cap_queue;
|
||||
static volatile int cap0_times = 0;
|
||||
static volatile int cap1_times = 0;
|
||||
static volatile int cap2_times = 0;
|
||||
|
||||
typedef struct {
|
||||
uint32_t capture_signal;
|
||||
mcpwm_capture_signal_t sel_cap_signal;
|
||||
} capture;
|
||||
|
||||
// universal settings of mcpwm
|
||||
static void mcpwm_basic_config(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io_signals_t mcpwm_b, mcpwm_timer_t timer)
|
||||
{
|
||||
mcpwm_gpio_init(unit, mcpwm_a, GPIO_PWMA_OUT);
|
||||
mcpwm_gpio_init(unit, mcpwm_b, GPIO_PWMB_OUT);
|
||||
mcpwm_config_t pwm_config = {
|
||||
.frequency = 1000,
|
||||
.cmpr_a = 50.0, //duty cycle of PWMxA = 50.0%
|
||||
.cmpr_b = 50.0, //duty cycle of PWMxb = 50.0%
|
||||
.counter_mode = MCPWM_UP_COUNTER,
|
||||
.duty_mode = MCPWM_DUTY_MODE_0,
|
||||
};
|
||||
mcpwm_init(unit, timer, &pwm_config);
|
||||
}
|
||||
|
||||
static void pcnt_init(int pulse_gpio_num, int ctrl_gpio_num)
|
||||
{
|
||||
pcnt_config_t pcnt_config = {
|
||||
.pulse_gpio_num = pulse_gpio_num,
|
||||
.ctrl_gpio_num = ctrl_gpio_num,
|
||||
.channel = PCNT_CHANNEL_0,
|
||||
.unit = PCNT_UNIT_0,
|
||||
.pos_mode = PCNT_COUNT_INC,
|
||||
.neg_mode = PCNT_COUNT_DIS,
|
||||
.lctrl_mode = PCNT_MODE_REVERSE,
|
||||
.hctrl_mode = PCNT_MODE_KEEP,
|
||||
.counter_h_lim = HIGHEST_LIMIT,
|
||||
.counter_l_lim = LOWEST_LIMIT,
|
||||
};
|
||||
TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
|
||||
}
|
||||
|
||||
// initialize the PCNT
|
||||
// PCNT is used to count the MCPWM pulse
|
||||
static int16_t pcnt_count(int pulse_gpio_num, int ctrl_gpio_num, int last_time)
|
||||
{
|
||||
pcnt_config_t pcnt_config = {
|
||||
.pulse_gpio_num = pulse_gpio_num,
|
||||
.ctrl_gpio_num = ctrl_gpio_num,
|
||||
.channel = PCNT_CHANNEL_0,
|
||||
.unit = PCNT_UNIT_0,
|
||||
.pos_mode = PCNT_COUNT_INC,
|
||||
.neg_mode = PCNT_COUNT_DIS,
|
||||
.lctrl_mode = PCNT_MODE_REVERSE,
|
||||
.hctrl_mode = PCNT_MODE_KEEP,
|
||||
.counter_h_lim = HIGHEST_LIMIT,
|
||||
.counter_l_lim = LOWEST_LIMIT,
|
||||
};
|
||||
TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
|
||||
int16_t test_counter;
|
||||
TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
|
||||
TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
|
||||
TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
|
||||
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
|
||||
printf("COUNT: %d\n", test_counter);
|
||||
vTaskDelay(last_time / portTICK_RATE_MS);
|
||||
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
|
||||
printf("COUNT: %d\n", test_counter);
|
||||
return test_counter;
|
||||
}
|
||||
|
||||
// judge the counting value right or not in specific error
|
||||
static void judge_count_value(int allow_error ,int expect_freq)
|
||||
{
|
||||
int16_t countA, countB;
|
||||
|
||||
countA = pcnt_count(GPIO_PWMA_PCNT_INPUT, PCNT_CTRL_FLOATING_IO1, 1000);
|
||||
countB = pcnt_count(GPIO_PWMB_PCNT_INPUT, PCNT_CTRL_FLOATING_IO2, 1000);
|
||||
|
||||
TEST_ASSERT_INT16_WITHIN(allow_error, countA, expect_freq);
|
||||
TEST_ASSERT_INT16_WITHIN(allow_error, countB, expect_freq);
|
||||
}
|
||||
|
||||
// test the duty configuration
|
||||
static void timer_duty_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io_signals_t mcpwm_b, mcpwm_timer_t timer)
|
||||
{
|
||||
mcpwm_basic_config(unit, mcpwm_a, mcpwm_b, timer);
|
||||
vTaskDelay(1000 / portTICK_RATE_MS); // stay this status for a while so that can view its waveform by logic anylyzer
|
||||
|
||||
TEST_ESP_OK(mcpwm_set_duty(unit, timer, MCPWM_OPR_A, (INITIAL_DUTY * 1)));
|
||||
TEST_ESP_OK(mcpwm_set_duty(unit, timer, MCPWM_OPR_B, (INITIAL_DUTY * 2)));
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(mcpwm_get_duty(unit, timer, MCPWM_OPR_A), INITIAL_DUTY * 1);
|
||||
TEST_ASSERT_EQUAL_INT(mcpwm_get_duty(unit, timer, MCPWM_OPR_B), INITIAL_DUTY * 2);
|
||||
vTaskDelay(1000 / portTICK_RATE_MS); // stay this status for a while so that can view its waveform by logic anylyzer
|
||||
|
||||
mcpwm_set_duty(unit, timer, MCPWM_OPR_A, 55.5f);
|
||||
mcpwm_set_duty_type(unit, timer, MCPWM_OPR_A, MCPWM_DUTY_MODE_0);
|
||||
printf("mcpwm check = %f\n", mcpwm_get_duty(unit, timer, MCPWM_OPR_A));
|
||||
|
||||
mcpwm_set_duty_in_us(unit, timer, MCPWM_OPR_B, 500);
|
||||
printf("mcpwm check = %f\n", mcpwm_get_duty(unit, timer, MCPWM_OPR_B));
|
||||
vTaskDelay(1000 / portTICK_RATE_MS); // stay this status for a while so that can view its waveform by logic anylyzer
|
||||
}
|
||||
|
||||
// test the start and stop function work or not
|
||||
static void start_stop_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io_signals_t mcpwm_b, mcpwm_timer_t timer)
|
||||
{
|
||||
mcpwm_basic_config(unit, mcpwm_a, mcpwm_b, timer);
|
||||
judge_count_value(2, 1000);
|
||||
TEST_ESP_OK(mcpwm_stop(unit, timer));
|
||||
vTaskDelay(10 / portTICK_RATE_MS); // wait for a while, stop totally
|
||||
judge_count_value(0, 0);
|
||||
TEST_ESP_OK(mcpwm_start(unit, timer));
|
||||
vTaskDelay(10 / portTICK_RATE_MS); // wait for a while, start totally
|
||||
judge_count_value(2, 1000);
|
||||
}
|
||||
|
||||
// test the deadtime
|
||||
static void deadtime_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io_signals_t mcpwm_b, mcpwm_timer_t timer)
|
||||
{
|
||||
mcpwm_basic_config(unit, mcpwm_a, mcpwm_b, timer);
|
||||
mcpwm_deadtime_type_t deadtime_type[8] = {MCPWM_BYPASS_RED, MCPWM_BYPASS_FED, MCPWM_ACTIVE_HIGH_MODE,
|
||||
MCPWM_ACTIVE_LOW_MODE, MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE, MCPWM_ACTIVE_LOW_COMPLIMENT_MODE,
|
||||
MCPWM_ACTIVE_RED_FED_FROM_PWMXA, MCPWM_ACTIVE_RED_FED_FROM_PWMXB};
|
||||
|
||||
for(int i=0; i<8; i++) {
|
||||
mcpwm_deadtime_enable(unit, timer, deadtime_type[i], 1000, 1000);
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
mcpwm_deadtime_disable(unit, timer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* there are two kind of methods to set the carrier:
|
||||
* 1. by mcpwm_carrier_init
|
||||
* 2. by different single setting function
|
||||
*/
|
||||
static void carrier_with_set_function_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io_signals_t mcpwm_b, mcpwm_timer_t timer,
|
||||
mcpwm_carrier_out_ivt_t invert_or_not, uint8_t period, uint8_t duty, uint8_t os_width)
|
||||
{
|
||||
// no inversion and no one shot
|
||||
mcpwm_basic_config(unit, mcpwm_a, mcpwm_b, timer);
|
||||
TEST_ESP_OK(mcpwm_carrier_enable(unit, timer));
|
||||
TEST_ESP_OK(mcpwm_carrier_set_period(unit, timer, period)); //carrier revolution
|
||||
TEST_ESP_OK(mcpwm_carrier_set_duty_cycle(unit, timer, duty)); // carrier duty
|
||||
judge_count_value(500, 50000/5.6);
|
||||
|
||||
// with invert
|
||||
TEST_ESP_OK(mcpwm_carrier_output_invert(unit, timer, invert_or_not));
|
||||
vTaskDelay(2000 / portTICK_RATE_MS);
|
||||
}
|
||||
|
||||
static void carrier_with_configuration_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io_signals_t mcpwm_b, mcpwm_timer_t timer,
|
||||
mcpwm_carrier_os_t oneshot_or_not, mcpwm_carrier_out_ivt_t invert_or_not, uint8_t period, uint8_t duty, uint8_t os_width)
|
||||
{
|
||||
mcpwm_basic_config(unit, mcpwm_a, mcpwm_b, timer);
|
||||
|
||||
mcpwm_carrier_config_t chop_config;
|
||||
chop_config.carrier_period = period; //carrier period = (period + 1)*800ns
|
||||
chop_config.carrier_duty = duty; // carrier duty cycle, carrier_duty should be less then 8(increment every 12.5%). carrier duty = (3)*12.5%
|
||||
chop_config.carrier_os_mode = oneshot_or_not; //If one shot mode is enabled then set pulse width, if disabled no need to set pulse width
|
||||
chop_config.pulse_width_in_os = os_width; //pulse width of first pulse in one shot mode = (carrier period)*(pulse_width_in_os + 1), should be less then 16.first pulse width = (3 + 1)*carrier_period
|
||||
chop_config.carrier_ivt_mode = invert_or_not; //output signal inversion enable
|
||||
mcpwm_carrier_init(unit, timer, &chop_config);
|
||||
|
||||
if(!oneshot_or_not) {
|
||||
// the pwm frequency is 1000
|
||||
// the carrrier duration in one second is 500ms
|
||||
// the carrier wave count is: 500ms/carrier_period = 500ms/(period + 1)*800ns
|
||||
// = 62500/(period + 1)
|
||||
judge_count_value(500, 62500/(period + 1));
|
||||
} else {
|
||||
judge_count_value(500, 40000/((period + 1))); // (500-500*0.125*3)/((period + 1)*800)
|
||||
}
|
||||
|
||||
TEST_ESP_OK(mcpwm_carrier_disable(unit, timer));
|
||||
judge_count_value(2, 1000);
|
||||
}
|
||||
|
||||
static void get_action_level(mcpwm_fault_input_level_t input_sig, mcpwm_action_on_pwmxa_t action_a, mcpwm_action_on_pwmxb_t action_b, int freq, int allow_err)
|
||||
{
|
||||
if(action_a == MCPWM_NO_CHANGE_IN_MCPWMXA) {
|
||||
TEST_ASSERT_INT16_WITHIN(allow_err, pcnt_count(GPIO_PWMA_PCNT_INPUT, PCNT_CTRL_FLOATING_IO1, 1000), freq);
|
||||
} else if(action_a == MCPWM_FORCE_MCPWMXA_LOW) {
|
||||
TEST_ASSERT(gpio_get_level(GPIO_PWMA_PCNT_INPUT) == 0);
|
||||
} else if(action_a == MCPWM_FORCE_MCPWMXA_HIGH) {
|
||||
TEST_ASSERT(gpio_get_level(GPIO_PWMA_PCNT_INPUT) == 1);
|
||||
}else {
|
||||
int level = gpio_get_level(GPIO_PWMA_PCNT_INPUT);
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
TEST_ASSERT(gpio_get_level(GPIO_PWMA_PCNT_INPUT) == level);
|
||||
}
|
||||
|
||||
if(action_b == MCPWM_NO_CHANGE_IN_MCPWMXB) {
|
||||
TEST_ASSERT_INT16_WITHIN(allow_err, pcnt_count(GPIO_PWMB_PCNT_INPUT, PCNT_CTRL_FLOATING_IO1, 1000), freq);
|
||||
} else if(action_b == MCPWM_FORCE_MCPWMXB_LOW) {
|
||||
TEST_ASSERT(gpio_get_level(GPIO_PWMB_PCNT_INPUT) == 0);
|
||||
} else if(action_b == MCPWM_FORCE_MCPWMXB_HIGH) {
|
||||
TEST_ASSERT(gpio_get_level(GPIO_PWMB_PCNT_INPUT) == 1);
|
||||
}else {
|
||||
int level = gpio_get_level(GPIO_PWMB_PCNT_INPUT);
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
TEST_ASSERT(gpio_get_level(GPIO_PWMB_PCNT_INPUT) == level);
|
||||
}
|
||||
}
|
||||
|
||||
// test the fault event
|
||||
static void cycle_fault_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io_signals_t mcpwm_b, mcpwm_timer_t timer,
|
||||
mcpwm_fault_signal_t fault_sig, mcpwm_fault_input_level_t input_sig, mcpwm_io_signals_t fault_io,
|
||||
mcpwm_action_on_pwmxa_t action_a, mcpwm_action_on_pwmxb_t action_b)
|
||||
{
|
||||
gpio_config_t gp;
|
||||
gp.intr_type = GPIO_INTR_DISABLE;
|
||||
gp.mode = GPIO_MODE_OUTPUT;
|
||||
gp.pin_bit_mask = (1 << FAULT_SIG_NUM);
|
||||
gpio_config(&gp); // gpio configure should be more previous than mcpwm configuration
|
||||
gpio_set_level(FAULT_SIG_NUM, !input_sig);
|
||||
|
||||
pcnt_init(GPIO_PWMA_PCNT_INPUT, PCNT_CTRL_FLOATING_IO1);
|
||||
pcnt_init(GPIO_PWMB_PCNT_INPUT, PCNT_CTRL_FLOATING_IO2);
|
||||
|
||||
mcpwm_basic_config(unit, mcpwm_a, mcpwm_b, timer);
|
||||
mcpwm_gpio_init(unit, fault_io, GPIO_FAULT_IN);
|
||||
|
||||
// cycle mode, it can be triggered more than once
|
||||
printf("cyc test:\n");
|
||||
gpio_set_level(FAULT_SIG_NUM, !input_sig);
|
||||
TEST_ESP_OK(mcpwm_fault_init(unit, input_sig, fault_sig));
|
||||
TEST_ESP_OK(mcpwm_fault_set_cyc_mode(unit, timer, fault_sig, action_a, action_b));
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
gpio_set_level(FAULT_SIG_NUM, input_sig); // trigger the fault event
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
get_action_level(input_sig, action_a, action_b, 1000, 5);
|
||||
TEST_ESP_OK(mcpwm_fault_deinit(unit, fault_sig));
|
||||
}
|
||||
|
||||
static void oneshot_fault_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io_signals_t mcpwm_b, mcpwm_timer_t timer,
|
||||
mcpwm_fault_signal_t fault_sig, mcpwm_fault_input_level_t input_sig, mcpwm_io_signals_t fault_io,
|
||||
mcpwm_action_on_pwmxa_t action_a, mcpwm_action_on_pwmxb_t action_b)
|
||||
{
|
||||
gpio_config_t gp;
|
||||
gp.intr_type = GPIO_INTR_DISABLE;
|
||||
gp.mode = GPIO_MODE_OUTPUT;
|
||||
gp.pin_bit_mask = (1 << FAULT_SIG_NUM);
|
||||
gpio_config(&gp); // gpio configure should be more previous than mcpwm configuration
|
||||
gpio_set_level(FAULT_SIG_NUM, !input_sig);
|
||||
|
||||
pcnt_init(GPIO_PWMA_PCNT_INPUT, PCNT_CTRL_FLOATING_IO1);
|
||||
pcnt_init(GPIO_PWMB_PCNT_INPUT, PCNT_CTRL_FLOATING_IO2);
|
||||
|
||||
mcpwm_basic_config(unit, mcpwm_a, mcpwm_b, timer);
|
||||
mcpwm_gpio_init(unit, fault_io, GPIO_FAULT_IN);
|
||||
|
||||
// one shot mode, it just can be triggered once
|
||||
TEST_ESP_OK(mcpwm_fault_init(unit, input_sig, fault_sig));
|
||||
TEST_ESP_OK(mcpwm_fault_set_oneshot_mode(unit, timer, fault_sig, action_a, action_b));
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
// trigger it
|
||||
gpio_set_level(FAULT_SIG_NUM, input_sig);
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
get_action_level(input_sig, action_a, action_b, 1000, 5);
|
||||
TEST_ESP_OK(mcpwm_fault_deinit(unit, fault_sig));
|
||||
}
|
||||
|
||||
// test the sync event
|
||||
static void sync_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io_signals_t mcpwm_b, mcpwm_timer_t timer,
|
||||
mcpwm_sync_signal_t sync_sig, mcpwm_io_signals_t sync_io)
|
||||
{
|
||||
gpio_config_t gp;
|
||||
gp.intr_type = GPIO_INTR_DISABLE;
|
||||
gp.mode = GPIO_MODE_OUTPUT;
|
||||
gp.pin_bit_mask = (1 << SYN_SIG_NUM);
|
||||
gpio_config(&gp);
|
||||
gpio_set_level(SYN_SIG_NUM, 0);
|
||||
|
||||
mcpwm_gpio_init(unit, mcpwm_a, GPIO_PWMA_OUT);
|
||||
mcpwm_gpio_init(unit, mcpwm_b, GPIO_PWMB_OUT);
|
||||
mcpwm_gpio_init(unit, sync_io, GPIO_SYNC_IN);
|
||||
mcpwm_config_t pwm_config = {
|
||||
.frequency = 1000,
|
||||
.cmpr_a = 50.0, //duty cycle of PWMxA = 50.0%
|
||||
.cmpr_b = 50.0, //duty cycle of PWMxb = 50.0%
|
||||
.counter_mode = MCPWM_UP_COUNTER,
|
||||
.duty_mode = MCPWM_DUTY_MODE_0,
|
||||
};
|
||||
mcpwm_init(unit, timer, &pwm_config);
|
||||
gpio_pulldown_en(GPIO_SYNC_IN);
|
||||
|
||||
mcpwm_sync_enable(unit, timer, sync_sig, 200);
|
||||
gpio_set_level(SYN_SIG_NUM, 1);
|
||||
vTaskDelay(2000 / portTICK_RATE_MS);
|
||||
mcpwm_sync_disable(unit, timer);
|
||||
vTaskDelay(2000 / portTICK_RATE_MS);
|
||||
}
|
||||
|
||||
/**
|
||||
* use interruption to test the capture event
|
||||
* there are two kinds of methods to trigger the capture event:
|
||||
* 1. high level trigger
|
||||
* 2. low level trigger
|
||||
*/
|
||||
static volatile int flag = 0;
|
||||
|
||||
// once capture event happens, will show it
|
||||
static void disp_captured_signal(void *arg)
|
||||
{
|
||||
|
||||
uint32_t *current_cap_value = (uint32_t *)malloc(sizeof(uint32_t) * CAP_SIG_NUM);
|
||||
uint32_t *previous_cap_value = (uint32_t *)malloc(sizeof(uint32_t) * CAP_SIG_NUM);
|
||||
capture evt;
|
||||
for (int i=0; i<1000; i++) {
|
||||
xQueueReceive(cap_queue, &evt, portMAX_DELAY);
|
||||
if (evt.sel_cap_signal == MCPWM_SELECT_CAP0) {
|
||||
current_cap_value[0] = evt.capture_signal - previous_cap_value[0];
|
||||
previous_cap_value[0] = evt.capture_signal;
|
||||
current_cap_value[0] = (current_cap_value[0] / 10000) * (10000000000 / rtc_clk_apb_freq_get());
|
||||
printf("CAP0 : %d us\n", current_cap_value[0]);
|
||||
cap0_times++;
|
||||
}
|
||||
if (evt.sel_cap_signal == MCPWM_SELECT_CAP1) {
|
||||
current_cap_value[1] = evt.capture_signal - previous_cap_value[1];
|
||||
previous_cap_value[1] = evt.capture_signal;
|
||||
current_cap_value[1] = (current_cap_value[1] / 10000) * (10000000000 / rtc_clk_apb_freq_get());
|
||||
printf("CAP1 : %d us\n", current_cap_value[1]);
|
||||
cap1_times++;
|
||||
}
|
||||
if (evt.sel_cap_signal == MCPWM_SELECT_CAP2) {
|
||||
current_cap_value[2] = evt.capture_signal - previous_cap_value[2];
|
||||
previous_cap_value[2] = evt.capture_signal;
|
||||
current_cap_value[2] = (current_cap_value[2] / 10000) * (10000000000 / rtc_clk_apb_freq_get());
|
||||
printf("CAP2 : %d us\n", current_cap_value[2]);
|
||||
cap2_times++;
|
||||
}
|
||||
}
|
||||
free(current_cap_value);
|
||||
free(previous_cap_value);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
// mcpwm event
|
||||
static void IRAM_ATTR isr_handler(void *arg)
|
||||
{
|
||||
mcpwm_unit_t unit = (mcpwm_unit_t)arg;
|
||||
uint32_t mcpwm_intr_status;
|
||||
capture evt;
|
||||
mcpwm_intr_status = MCPWM[unit]->int_st.val; //Read interrupt status
|
||||
if (mcpwm_intr_status & CAP0_INT_EN) { //Check for interrupt on rising edge on CAP0 signal
|
||||
evt.capture_signal = mcpwm_capture_signal_get_value(unit, MCPWM_SELECT_CAP0); //get capture signal counter value
|
||||
evt.sel_cap_signal = MCPWM_SELECT_CAP0;
|
||||
xQueueSendFromISR(cap_queue, &evt, NULL);
|
||||
}
|
||||
if (mcpwm_intr_status & CAP1_INT_EN) { //Check for interrupt on rising edge on CAP0 signal
|
||||
evt.capture_signal = mcpwm_capture_signal_get_value(unit, MCPWM_SELECT_CAP1); //get capture signal counter value
|
||||
evt.sel_cap_signal = MCPWM_SELECT_CAP1;
|
||||
xQueueSendFromISR(cap_queue, &evt, NULL);
|
||||
}
|
||||
if (mcpwm_intr_status & CAP2_INT_EN) { //Check for interrupt on rising edge on CAP0 signal
|
||||
evt.capture_signal = mcpwm_capture_signal_get_value(unit, MCPWM_SELECT_CAP2); //get capture signal counter value
|
||||
evt.sel_cap_signal = MCPWM_SELECT_CAP2;
|
||||
xQueueSendFromISR(cap_queue, &evt, NULL);
|
||||
}
|
||||
MCPWM[unit]->int_clr.val = mcpwm_intr_status;
|
||||
}
|
||||
|
||||
// the produce the capture triggering signal to trigger the capture event
|
||||
static void gpio_test_signal(void *arg)
|
||||
{
|
||||
|
||||
printf("intializing test signal...\n");
|
||||
gpio_config_t gp;
|
||||
gp.intr_type = GPIO_INTR_DISABLE;
|
||||
gp.mode = GPIO_MODE_OUTPUT;
|
||||
gp.pin_bit_mask = 1<<CAP_SIG_NUM;
|
||||
gpio_config(&gp);
|
||||
for (int i=0; i<1000; i++) {
|
||||
//here the period of test signal is 20ms
|
||||
gpio_set_level(CAP_SIG_NUM, 1); //Set high
|
||||
vTaskDelay(10); //delay of 10ms
|
||||
gpio_set_level(CAP_SIG_NUM, 0); //Set low
|
||||
vTaskDelay(10); //delay of 10ms
|
||||
}
|
||||
flag = 1;
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
// capture event test function
|
||||
static void capture_test(mcpwm_unit_t unit, mcpwm_io_signals_t mcpwm_a, mcpwm_io_signals_t mcpwm_b, mcpwm_io_signals_t cap_io, mcpwm_timer_t timer,
|
||||
mcpwm_capture_signal_t cap_sig, mcpwm_capture_on_edge_t cap_edge)
|
||||
{
|
||||
// initialize the capture times
|
||||
cap0_times = 0;
|
||||
cap1_times = 0;
|
||||
cap2_times = 0;
|
||||
|
||||
mcpwm_gpio_init(unit, cap_io, GPIO_CAP_IN);
|
||||
|
||||
cap_queue = xQueueCreate(1, sizeof(capture));
|
||||
xTaskCreate(disp_captured_signal, "mcpwm_config", 4096, (void *)unit, 5, NULL);
|
||||
xTaskCreate(gpio_test_signal, "gpio_test_signal", 4096, NULL, 5, NULL);
|
||||
mcpwm_capture_enable(unit, cap_sig, cap_edge, 0);
|
||||
MCPWM[unit]->int_ena.val = CAP0_INT_EN | CAP1_INT_EN | CAP2_INT_EN; //Enable interrupt on CAP0, CAP1 and CAP2 signal
|
||||
mcpwm_isr_register(unit, isr_handler, (void *)unit, ESP_INTR_FLAG_IRAM, NULL);
|
||||
|
||||
while(flag != 1) {
|
||||
vTaskDelay(10 / portTICK_RATE_MS);
|
||||
}
|
||||
if(cap_sig == MCPWM_SELECT_CAP0) {
|
||||
TEST_ASSERT(1000 == cap0_times);
|
||||
} else if(cap_sig == MCPWM_SELECT_CAP1) {
|
||||
TEST_ASSERT(1000 == cap1_times);
|
||||
}else {
|
||||
TEST_ASSERT(1000 == cap2_times);
|
||||
}
|
||||
flag = 0; // set flag to 0 that it can be used in other case
|
||||
mcpwm_capture_disable(unit, cap_sig);
|
||||
}
|
||||
|
||||
/**
|
||||
* duty test:
|
||||
* 1. mcpwm_set_duty
|
||||
* 2. mcpwm_get_duty
|
||||
*
|
||||
* This case's phenomenon should be viewed by logic analyzer
|
||||
* so set it ignore
|
||||
*/
|
||||
TEST_CASE("MCPWM timer0 duty test and each timer works or not test(logic analyzer)", "[mcpwm][ignore]")
|
||||
{
|
||||
timer_duty_test(MCPWM_UNIT_0, MCPWM0A, MCPWM0B, MCPWM_TIMER_0);
|
||||
timer_duty_test(MCPWM_UNIT_1, MCPWM0A, MCPWM0B, MCPWM_TIMER_0);
|
||||
}
|
||||
|
||||
TEST_CASE("MCPWM timer1 duty test and each timer works or not test(logic analyzer)", "[mcpwm][ignore]")
|
||||
{
|
||||
timer_duty_test(MCPWM_UNIT_0, MCPWM1A, MCPWM1B, MCPWM_TIMER_1);
|
||||
timer_duty_test(MCPWM_UNIT_1, MCPWM1A, MCPWM1B, MCPWM_TIMER_1);
|
||||
}
|
||||
TEST_CASE("MCPWM timer2 duty test and each timer works or not test(logic analyzer)", "[mcpwm][ignore]")
|
||||
{
|
||||
timer_duty_test(MCPWM_UNIT_0, MCPWM2A, MCPWM2B, MCPWM_TIMER_2);
|
||||
timer_duty_test(MCPWM_UNIT_1, MCPWM2A, MCPWM2B, MCPWM_TIMER_2);
|
||||
}
|
||||
|
||||
// the deadtime configuration test
|
||||
// use the logic analyzer to make sure it goes right
|
||||
TEST_CASE("MCPWM timer0 deadtime configuration(logic analyzer)", "[mcpwm][ignore]")
|
||||
{
|
||||
deadtime_test(MCPWM_UNIT_0, MCPWM0A, MCPWM0B, MCPWM_TIMER_0);
|
||||
deadtime_test(MCPWM_UNIT_1, MCPWM0A, MCPWM0B, MCPWM_TIMER_0);
|
||||
}
|
||||
|
||||
TEST_CASE("MCPWM timer1 deadtime configuration(logic analyzer)", "[mcpwm][ignore]")
|
||||
{
|
||||
deadtime_test(MCPWM_UNIT_0, MCPWM1A, MCPWM1B, MCPWM_TIMER_1);
|
||||
deadtime_test(MCPWM_UNIT_1, MCPWM1A, MCPWM1B, MCPWM_TIMER_1);
|
||||
}
|
||||
|
||||
TEST_CASE("MCPWM timer2 deadtime configuration(logic analyzer)", "[mcpwm][ignore]")
|
||||
{
|
||||
deadtime_test(MCPWM_UNIT_0, MCPWM2A, MCPWM2B, MCPWM_TIMER_2);
|
||||
deadtime_test(MCPWM_UNIT_1, MCPWM2A, MCPWM2B, MCPWM_TIMER_2);
|
||||
}
|
||||
|
||||
TEST_CASE("MCPWM timer0 start and stop test", "[mcpwm][test_env=UT_T1_MCPWM]")
|
||||
{
|
||||
start_stop_test(MCPWM_UNIT_0, MCPWM0A, MCPWM0B, MCPWM_TIMER_0);
|
||||
start_stop_test(MCPWM_UNIT_1, MCPWM0A, MCPWM0B, MCPWM_TIMER_0);
|
||||
}
|
||||
|
||||
// mcpwm start and stop test
|
||||
TEST_CASE("MCPWM timer1 start and stop test", "[mcpwm][test_env=UT_T1_MCPWM]")
|
||||
{
|
||||
start_stop_test(MCPWM_UNIT_0, MCPWM1A, MCPWM1B, MCPWM_TIMER_1);
|
||||
start_stop_test(MCPWM_UNIT_1, MCPWM1A, MCPWM1B, MCPWM_TIMER_1);
|
||||
}
|
||||
|
||||
TEST_CASE("MCPWM timer2 start and stop test", "[mcpwm][test_env=UT_T1_MCPWM]")
|
||||
{
|
||||
start_stop_test(MCPWM_UNIT_0, MCPWM2A, MCPWM2B, MCPWM_TIMER_2);
|
||||
start_stop_test(MCPWM_UNIT_1, MCPWM2A, MCPWM2B, MCPWM_TIMER_2);
|
||||
}
|
||||
|
||||
TEST_CASE("MCPWM timer0 carrier test with set function", "[mcpwm][test_env=UT_T1_MCPWM]")
|
||||
{
|
||||
carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM0A, MCPWM0B, MCPWM_TIMER_0,
|
||||
MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
|
||||
carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM0A, MCPWM0B, MCPWM_TIMER_0,
|
||||
MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
|
||||
carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM0A, MCPWM0B, MCPWM_TIMER_0,
|
||||
MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
|
||||
carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM0A, MCPWM0B, MCPWM_TIMER_0,
|
||||
MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
|
||||
}
|
||||
|
||||
TEST_CASE("MCPWM timer1 carrier test with set function", "[mcpwm][test_env=UT_T1_MCPWM]")
|
||||
{
|
||||
carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM1A, MCPWM1B, MCPWM_TIMER_1,
|
||||
MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
|
||||
carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM1A, MCPWM1B, MCPWM_TIMER_1,
|
||||
MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
|
||||
carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM1A, MCPWM1B, MCPWM_TIMER_1,
|
||||
MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
|
||||
carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM1A, MCPWM1B, MCPWM_TIMER_1,
|
||||
MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
|
||||
}
|
||||
|
||||
TEST_CASE("MCPWM timer2 carrier test with set function", "[mcpwm][test_env=UT_T1_MCPWM]")
|
||||
{
|
||||
carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM2A, MCPWM2B, MCPWM_TIMER_2,
|
||||
MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
|
||||
carrier_with_set_function_test(MCPWM_UNIT_0, MCPWM2A, MCPWM2B, MCPWM_TIMER_2,
|
||||
MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
|
||||
carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM2A, MCPWM2B, MCPWM_TIMER_2,
|
||||
MCPWM_CARRIER_OUT_IVT_DIS, 6, 3, 3);
|
||||
carrier_with_set_function_test(MCPWM_UNIT_1, MCPWM2A, MCPWM2B, MCPWM_TIMER_2,
|
||||
MCPWM_CARRIER_OUT_IVT_EN, 6, 3, 3);
|
||||
}
|
||||
|
||||
TEST_CASE("MCPWM timer0 carrier test with configuration function", "[mcpwm][test_env=UT_T1_MCPWM][timeout=120]")
|
||||
{
|
||||
mcpwm_carrier_os_t oneshot[2] = {MCPWM_ONESHOT_MODE_DIS, MCPWM_ONESHOT_MODE_EN};
|
||||
mcpwm_carrier_out_ivt_t invert[2] = {MCPWM_CARRIER_OUT_IVT_DIS, MCPWM_CARRIER_OUT_IVT_EN};
|
||||
for(int i=0; i<2; i++){
|
||||
for(int j=0; j<2; j++) {
|
||||
printf("i=%d, j=%d\n", i, j);
|
||||
carrier_with_configuration_test(MCPWM_UNIT_0, MCPWM0A, MCPWM0B, MCPWM_TIMER_0,
|
||||
oneshot[i], invert[j], 6, 3, 3);
|
||||
carrier_with_configuration_test(MCPWM_UNIT_1, MCPWM0A, MCPWM0B, MCPWM_TIMER_0,
|
||||
oneshot[i], invert[j], 6, 3, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("MCPWM timer1 carrier test with configuration function", "[mcpwm][test_env=UT_T1_MCPWM][timeout=120]")
|
||||
{
|
||||
mcpwm_carrier_os_t oneshot[2] = {MCPWM_ONESHOT_MODE_DIS, MCPWM_ONESHOT_MODE_EN};
|
||||
mcpwm_carrier_out_ivt_t invert[2] = {MCPWM_CARRIER_OUT_IVT_DIS, MCPWM_CARRIER_OUT_IVT_EN};
|
||||
for(int i=0; i<2; i++){
|
||||
for(int j=0; j<2; j++) {
|
||||
carrier_with_configuration_test(MCPWM_UNIT_0, MCPWM1A, MCPWM1B, MCPWM_TIMER_1,
|
||||
oneshot[i], invert[j], 6, 3, 3);
|
||||
carrier_with_configuration_test(MCPWM_UNIT_1, MCPWM1A, MCPWM1B, MCPWM_TIMER_1,
|
||||
oneshot[i], invert[j], 6, 3, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("MCPWM timer2 carrier test with configuration function", "[mcpwm][test_env=UT_T1_MCPWM][timeout=120]")
|
||||
{
|
||||
mcpwm_carrier_os_t oneshot[2] = {MCPWM_ONESHOT_MODE_DIS, MCPWM_ONESHOT_MODE_EN};
|
||||
mcpwm_carrier_out_ivt_t invert[2] = {MCPWM_CARRIER_OUT_IVT_DIS, MCPWM_CARRIER_OUT_IVT_EN};
|
||||
for(int i=0; i<2; i++){
|
||||
for(int j=0; j<2; j++) {
|
||||
carrier_with_configuration_test(MCPWM_UNIT_0, MCPWM2A, MCPWM2B, MCPWM_TIMER_2,
|
||||
oneshot[i], invert[j], 6, 3, 3);
|
||||
carrier_with_configuration_test(MCPWM_UNIT_1, MCPWM2A, MCPWM2B, MCPWM_TIMER_2,
|
||||
oneshot[i], invert[j], 6, 3, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fault event:
|
||||
* Just support high level triggering
|
||||
* There are two types fault event:
|
||||
* 1. one-shot: it just can be triggered once, its effect is forever and it will never be changed although the fault signal change
|
||||
* 2. cycle: it can be triggered more than once, it will changed just as the fault signal changes. If set it triggered by high level,
|
||||
* when the fault signal is high level, the event will be triggered. But the event will disappear as the fault signal disappears
|
||||
*/
|
||||
|
||||
TEST_CASE("MCPWM timer0 cycle fault test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=180]")
|
||||
{
|
||||
// API just supports the high level trigger now, so comment it
|
||||
// mcpwm_fault_input_level_t fault_input[2] = {MCPWM_LOW_LEVEL_TGR, MCPWM_HIGH_LEVEL_TGR};
|
||||
mcpwm_action_on_pwmxa_t action_a[4] = {MCPWM_NO_CHANGE_IN_MCPWMXA, MCPWM_FORCE_MCPWMXA_LOW, MCPWM_FORCE_MCPWMXA_HIGH, MCPWM_TOG_MCPWMXA};
|
||||
mcpwm_action_on_pwmxb_t action_b[4] = {MCPWM_NO_CHANGE_IN_MCPWMXB, MCPWM_FORCE_MCPWMXB_LOW, MCPWM_FORCE_MCPWMXB_HIGH, MCPWM_TOG_MCPWMXB};
|
||||
|
||||
for(int i=0; i<4; i++){
|
||||
for(int j=0; j<4; j++) {
|
||||
printf("i=%d, j=%d\n",i, j);
|
||||
cycle_fault_test(MCPWM_UNIT_0, MCPWM0A, MCPWM0B, MCPWM_TIMER_0,
|
||||
MCPWM_SELECT_F0, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_0,
|
||||
action_a[i], action_b[j]);
|
||||
cycle_fault_test(MCPWM_UNIT_1, MCPWM0A, MCPWM0B, MCPWM_TIMER_0,
|
||||
MCPWM_SELECT_F0, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_0,
|
||||
action_a[i], action_b[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("MCPWM timer1 cycle fault test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=180]")
|
||||
{
|
||||
// API just supports the high level trigger now, so comment it
|
||||
// mcpwm_fault_input_level_t fault_input[2] = {MCPWM_LOW_LEVEL_TGR, MCPWM_HIGH_LEVEL_TGR};
|
||||
mcpwm_action_on_pwmxa_t action_a[4] = {MCPWM_NO_CHANGE_IN_MCPWMXA, MCPWM_FORCE_MCPWMXA_LOW, MCPWM_FORCE_MCPWMXA_HIGH, MCPWM_TOG_MCPWMXA};
|
||||
mcpwm_action_on_pwmxb_t action_b[4] = {MCPWM_NO_CHANGE_IN_MCPWMXB, MCPWM_FORCE_MCPWMXB_LOW, MCPWM_FORCE_MCPWMXB_HIGH, MCPWM_TOG_MCPWMXB};
|
||||
|
||||
for(int i=0; i<4; i++){
|
||||
for(int j=0; j<4; j++) {
|
||||
cycle_fault_test(MCPWM_UNIT_0, MCPWM1A, MCPWM1B, MCPWM_TIMER_1,
|
||||
MCPWM_SELECT_F1, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_1,
|
||||
action_a[i], action_b[j]);
|
||||
cycle_fault_test(MCPWM_UNIT_1, MCPWM1A, MCPWM1B, MCPWM_TIMER_1,
|
||||
MCPWM_SELECT_F1, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_1,
|
||||
action_a[i], action_b[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("MCPWM timer2 cycle fault test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=180][ignore]")
|
||||
{
|
||||
// API just supports the high level trigger now, so comment it
|
||||
// mcpwm_fault_input_level_t fault_input[2] = {MCPWM_LOW_LEVEL_TGR, MCPWM_HIGH_LEVEL_TGR};
|
||||
mcpwm_action_on_pwmxa_t action_a[4] = {MCPWM_NO_CHANGE_IN_MCPWMXA, MCPWM_FORCE_MCPWMXA_LOW, MCPWM_FORCE_MCPWMXA_HIGH, MCPWM_TOG_MCPWMXA};
|
||||
mcpwm_action_on_pwmxb_t action_b[4] = {MCPWM_NO_CHANGE_IN_MCPWMXB, MCPWM_FORCE_MCPWMXB_LOW, MCPWM_FORCE_MCPWMXB_HIGH, MCPWM_TOG_MCPWMXB};
|
||||
|
||||
for(int i=0; i<4; i++){
|
||||
for(int j=0; j<4; j++) {
|
||||
cycle_fault_test(MCPWM_UNIT_0, MCPWM2A, MCPWM2B, MCPWM_TIMER_2,
|
||||
MCPWM_SELECT_F2, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_2,
|
||||
action_a[i], action_b[j]);
|
||||
cycle_fault_test(MCPWM_UNIT_1, MCPWM2A, MCPWM2B, MCPWM_TIMER_2,
|
||||
MCPWM_SELECT_F2, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_2,
|
||||
action_a[i], action_b[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// to debug the "mcpwm_fault_deinit" case. The "MCPWM_NO_CHANGE_IN_MCPWMXA, MCPWM_FORCE_MCPWMXB_HIGH" scenario can work right
|
||||
// however, the mcpwm_fault_deinit can not release the status after "MCPWM_NO_CHANGE_IN_MCPWMXA, MCPWM_FORCE_MCPWMXB_LOW" scenario
|
||||
TEST_CASE("MCPWM timer0 one shot fault test single", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
|
||||
{
|
||||
// API just supports the high level trigger now, so comment it
|
||||
// mcpwm_fault_input_level_t fault_input[2] = {MCPWM_LOW_LEVEL_TGR, MCPWM_HIGH_LEVEL_TGR};
|
||||
mcpwm_action_on_pwmxa_t action_a[4] = {MCPWM_NO_CHANGE_IN_MCPWMXA, MCPWM_FORCE_MCPWMXA_LOW, MCPWM_FORCE_MCPWMXA_HIGH, MCPWM_TOG_MCPWMXA};
|
||||
mcpwm_action_on_pwmxb_t action_b[4] = {MCPWM_NO_CHANGE_IN_MCPWMXB, MCPWM_FORCE_MCPWMXB_LOW, MCPWM_FORCE_MCPWMXB_HIGH, MCPWM_TOG_MCPWMXB};
|
||||
|
||||
oneshot_fault_test(MCPWM_UNIT_0, MCPWM0A, MCPWM0B, MCPWM_TIMER_0,
|
||||
MCPWM_SELECT_F0, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_0,
|
||||
action_a[0], action_b[2]);
|
||||
}
|
||||
|
||||
// the mcpwm_fault_deinit can not release the status after "MCPWM_NO_CHANGE_IN_MCPWMXA, MCPWM_FORCE_MCPWMXB_LOW" scenario
|
||||
// set it ignore
|
||||
// same as the case "MCPWM timer1 one shot fault test" and case "MCPWM timer2 one shot fault test"
|
||||
TEST_CASE("MCPWM timer0 one shot fault test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60][ignore]")
|
||||
{
|
||||
// API just supports the high level trigger now, so comment it
|
||||
// mcpwm_fault_input_level_t fault_input[2] = {MCPWM_LOW_LEVEL_TGR, MCPWM_HIGH_LEVEL_TGR};
|
||||
mcpwm_action_on_pwmxa_t action_a[4] = {MCPWM_NO_CHANGE_IN_MCPWMXA, MCPWM_FORCE_MCPWMXA_LOW, MCPWM_FORCE_MCPWMXA_HIGH, MCPWM_TOG_MCPWMXA};
|
||||
mcpwm_action_on_pwmxb_t action_b[4] = {MCPWM_NO_CHANGE_IN_MCPWMXB, MCPWM_FORCE_MCPWMXB_LOW, MCPWM_FORCE_MCPWMXB_HIGH, MCPWM_TOG_MCPWMXB};
|
||||
|
||||
for(int i=0; i<4; i++){
|
||||
for(int j=0; j<4; j++) {
|
||||
printf("i=%d, j=%d\n",i, j);
|
||||
oneshot_fault_test(MCPWM_UNIT_0, MCPWM0A, MCPWM0B, MCPWM_TIMER_0,
|
||||
MCPWM_SELECT_F0, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_0,
|
||||
action_a[i], action_b[j]);
|
||||
oneshot_fault_test(MCPWM_UNIT_1, MCPWM0A, MCPWM0B, MCPWM_TIMER_0,
|
||||
MCPWM_SELECT_F0, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_0,
|
||||
action_a[i], action_b[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("MCPWM timer1 one shot fault test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60][ignore]")
|
||||
{
|
||||
// API just supports the high level trigger now, so comment it
|
||||
// mcpwm_fault_input_level_t fault_input[2] = {MCPWM_LOW_LEVEL_TGR, MCPWM_HIGH_LEVEL_TGR};
|
||||
mcpwm_action_on_pwmxa_t action_a[4] = {MCPWM_NO_CHANGE_IN_MCPWMXA, MCPWM_FORCE_MCPWMXA_LOW, MCPWM_FORCE_MCPWMXA_HIGH, MCPWM_TOG_MCPWMXA};
|
||||
mcpwm_action_on_pwmxb_t action_b[4] = {MCPWM_NO_CHANGE_IN_MCPWMXB, MCPWM_FORCE_MCPWMXB_LOW, MCPWM_FORCE_MCPWMXB_HIGH, MCPWM_TOG_MCPWMXB};
|
||||
|
||||
for(int i=0; i<4; i++){
|
||||
for(int j=0; j<4; j++) {
|
||||
oneshot_fault_test(MCPWM_UNIT_0, MCPWM1A, MCPWM1B, MCPWM_TIMER_1,
|
||||
MCPWM_SELECT_F1, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_1,
|
||||
action_a[i], action_b[j]);
|
||||
oneshot_fault_test(MCPWM_UNIT_1, MCPWM1A, MCPWM1B, MCPWM_TIMER_1,
|
||||
MCPWM_SELECT_F1, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_1,
|
||||
action_a[i], action_b[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("MCPWM timer2 one shot fault test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60][ignore]")
|
||||
{
|
||||
// API just supports the high level trigger now, so comment it
|
||||
// mcpwm_fault_input_level_t fault_input[2] = {MCPWM_LOW_LEVEL_TGR, MCPWM_HIGH_LEVEL_TGR};
|
||||
mcpwm_action_on_pwmxa_t action_a[4] = {MCPWM_NO_CHANGE_IN_MCPWMXA, MCPWM_FORCE_MCPWMXA_LOW, MCPWM_FORCE_MCPWMXA_HIGH, MCPWM_TOG_MCPWMXA};
|
||||
mcpwm_action_on_pwmxb_t action_b[4] = {MCPWM_NO_CHANGE_IN_MCPWMXB, MCPWM_FORCE_MCPWMXB_LOW, MCPWM_FORCE_MCPWMXB_HIGH, MCPWM_TOG_MCPWMXB};
|
||||
|
||||
for(int i=0; i<4; i++){
|
||||
for(int j=0; j<4; j++) {
|
||||
oneshot_fault_test(MCPWM_UNIT_0, MCPWM2A, MCPWM2B, MCPWM_TIMER_2,
|
||||
MCPWM_SELECT_F2, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_2,
|
||||
action_a[i], action_b[j]);
|
||||
oneshot_fault_test(MCPWM_UNIT_1, MCPWM2A, MCPWM2B, MCPWM_TIMER_2,
|
||||
MCPWM_SELECT_F2, MCPWM_HIGH_LEVEL_TGR, MCPWM_FAULT_2,
|
||||
action_a[i], action_b[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// need to view its phenomenon in logic analyzer
|
||||
// set it ignore
|
||||
TEST_CASE("MCPWM timer0 sync test(logic analyzer)", "[mcpwm][ignore]")
|
||||
{
|
||||
sync_test(MCPWM_UNIT_0, MCPWM0A, MCPWM0B, MCPWM_TIMER_0, MCPWM_SELECT_SYNC0, MCPWM_SYNC_0);
|
||||
TEST_ESP_OK(mcpwm_stop(MCPWM_UNIT_0, MCPWM_TIMER_0)); // make sure can view the next sync signal clearly
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
TEST_ESP_OK(mcpwm_start(MCPWM_UNIT_0, MCPWM_TIMER_0));
|
||||
sync_test(MCPWM_UNIT_1, MCPWM0A, MCPWM0B, MCPWM_TIMER_0, MCPWM_SELECT_SYNC0, MCPWM_SYNC_0);
|
||||
}
|
||||
|
||||
// need to view its phenomenon in logic analyzer
|
||||
// set it ignore
|
||||
TEST_CASE("MCPWM timer1 sync test(logic analyzer)", "[mcpwm][ignore]")
|
||||
{
|
||||
sync_test(MCPWM_UNIT_0, MCPWM1A, MCPWM1B, MCPWM_TIMER_1, MCPWM_SELECT_SYNC1, MCPWM_SYNC_1);
|
||||
TEST_ESP_OK(mcpwm_stop(MCPWM_UNIT_0, MCPWM_TIMER_1)); // make sure can view the next sync signal clearly
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
TEST_ESP_OK(mcpwm_start(MCPWM_UNIT_0, MCPWM_TIMER_1));
|
||||
sync_test(MCPWM_UNIT_1, MCPWM1A, MCPWM1B, MCPWM_TIMER_1, MCPWM_SELECT_SYNC1, MCPWM_SYNC_1);
|
||||
}
|
||||
|
||||
// need to view its phenomenon in logic analyzer
|
||||
// set it ignore
|
||||
TEST_CASE("MCPWM timer2 sync test(logic analyzer)", "[mcpwm][ignore]")
|
||||
{
|
||||
sync_test(MCPWM_UNIT_0, MCPWM2A, MCPWM2B, MCPWM_TIMER_2, MCPWM_SELECT_SYNC2, MCPWM_SYNC_2);
|
||||
TEST_ESP_OK(mcpwm_stop(MCPWM_UNIT_0, MCPWM_TIMER_2)); // make sure can view the next sync signal clearly
|
||||
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||
TEST_ESP_OK(mcpwm_start(MCPWM_UNIT_0, MCPWM_TIMER_2));
|
||||
sync_test(MCPWM_UNIT_1, MCPWM2A, MCPWM2B, MCPWM_TIMER_2, MCPWM_SELECT_SYNC2, MCPWM_SYNC_2);
|
||||
}
|
||||
|
||||
TEST_CASE("MCPWM unit0, timer0 capture test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
|
||||
{
|
||||
capture_test(MCPWM_UNIT_0, MCPWM0A, MCPWM0B, MCPWM_CAP_0, MCPWM_TIMER_0, MCPWM_SELECT_CAP0, MCPWM_POS_EDGE);
|
||||
}
|
||||
|
||||
TEST_CASE("MCPWM uni0, timer1 capture test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
|
||||
{
|
||||
capture_test(MCPWM_UNIT_0, MCPWM1A, MCPWM1B, MCPWM_CAP_1, MCPWM_TIMER_1, MCPWM_SELECT_CAP1, MCPWM_POS_EDGE);
|
||||
}
|
||||
|
||||
TEST_CASE("MCPWM unit0, timer2 capture test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
|
||||
{
|
||||
|
||||
capture_test(MCPWM_UNIT_0, MCPWM2A, MCPWM2B, MCPWM_CAP_2, MCPWM_TIMER_2, MCPWM_SELECT_CAP2, MCPWM_POS_EDGE);
|
||||
}
|
||||
|
||||
TEST_CASE("MCPWM unit1, timer0 capture test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
|
||||
{
|
||||
capture_test(MCPWM_UNIT_1, MCPWM0A, MCPWM0B, MCPWM_CAP_0, MCPWM_TIMER_0, MCPWM_SELECT_CAP0, MCPWM_NEG_EDGE);
|
||||
}
|
||||
|
||||
TEST_CASE("MCPWM unit1, timer1 capture test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
|
||||
{
|
||||
capture_test(MCPWM_UNIT_1, MCPWM1A, MCPWM1B, MCPWM_CAP_1, MCPWM_TIMER_1, MCPWM_SELECT_CAP1, MCPWM_POS_EDGE);
|
||||
}
|
||||
|
||||
TEST_CASE("MCPWM unit1, timer2 capture test", "[mcpwm][test_env=UT_T1_MCPWM][timeout=60]")
|
||||
{
|
||||
capture_test(MCPWM_UNIT_1, MCPWM2A, MCPWM2B, MCPWM_CAP_2, MCPWM_TIMER_2, MCPWM_SELECT_CAP2, MCPWM_POS_EDGE);
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@
|
||||
#include "freertos/ringbuf.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "unity_config.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
const static char TAG[] = "test_spi";
|
||||
|
||||
@@ -1595,4 +1595,4 @@ TEST_CASE("spi poll tasks","[spi]")
|
||||
}
|
||||
|
||||
|
||||
//TODO: add a case when a non-polling transaction happened in the bus-acquiring time and then release the bus then queue a new trans
|
||||
//TODO: add a case when a non-polling transaction happened in the bus-acquiring time and then release the bus then queue a new trans
|
||||
|
@@ -78,12 +78,12 @@ static void slave_init()
|
||||
TEST_ESP_OK( spi_slave_initialize(VSPI_HOST, &buscfg, &slvcfg, 2) );
|
||||
}
|
||||
|
||||
TEST_CASE("test slave startup","[spi]")
|
||||
TEST_CASE("test slave send unaligned","[spi]")
|
||||
{
|
||||
uint8_t master_txbuf[320]=MASTER_SEND;
|
||||
uint8_t master_rxbuf[320];
|
||||
uint8_t slave_txbuf[320]=SLAVE_SEND;
|
||||
uint8_t slave_rxbuf[320];
|
||||
WORD_ALIGNED_ATTR uint8_t master_txbuf[320]=MASTER_SEND;
|
||||
WORD_ALIGNED_ATTR uint8_t master_rxbuf[320];
|
||||
WORD_ALIGNED_ATTR uint8_t slave_txbuf[320]=SLAVE_SEND;
|
||||
WORD_ALIGNED_ATTR uint8_t slave_rxbuf[320];
|
||||
|
||||
spi_device_handle_t spi;
|
||||
//initial master
|
||||
@@ -97,13 +97,13 @@ TEST_CASE("test slave startup","[spi]")
|
||||
int_connect( PIN_NUM_CS, HSPICS0_OUT_IDX, VSPICS0_IN_IDX );
|
||||
int_connect( PIN_NUM_CLK, HSPICLK_OUT_IDX, VSPICLK_IN_IDX );
|
||||
|
||||
for ( int i = 0; i < 3; i ++ ) {
|
||||
for ( int i = 0; i < 4; i ++ ) {
|
||||
//slave send
|
||||
spi_slave_transaction_t slave_t;
|
||||
spi_slave_transaction_t* out;
|
||||
memset(&slave_t, 0, sizeof(spi_slave_transaction_t));
|
||||
slave_t.length=8*32;
|
||||
slave_t.tx_buffer=slave_txbuf+2*i;
|
||||
slave_t.tx_buffer=slave_txbuf+i;
|
||||
slave_t.rx_buffer=slave_rxbuf;
|
||||
TEST_ESP_OK( spi_slave_queue_trans( VSPI_HOST, &slave_t, portMAX_DELAY ) );
|
||||
|
||||
|
@@ -875,6 +875,7 @@ static void uart_rx_intr_handler_default(void *param)
|
||||
//If we fail to push data to ring buffer, we will have to stash the data, and send next time.
|
||||
//Mainly for applications that uses flow control or small ring buffer.
|
||||
if(pdFALSE == xRingbufferSendFromISR(p_uart->rx_ring_buf, p_uart->rx_data_buf, p_uart->rx_stash_len, &HPTaskAwoken)) {
|
||||
p_uart->rx_buffer_full_flg = true;
|
||||
uart_disable_intr_mask(uart_num, UART_RXFIFO_TOUT_INT_ENA_M | UART_RXFIFO_FULL_INT_ENA_M);
|
||||
if (uart_event.type == UART_PATTERN_DET) {
|
||||
if (rx_fifo_len < pat_num) {
|
||||
@@ -893,7 +894,6 @@ static void uart_rx_intr_handler_default(void *param)
|
||||
}
|
||||
}
|
||||
uart_event.type = UART_BUFFER_FULL;
|
||||
p_uart->rx_buffer_full_flg = true;
|
||||
} else {
|
||||
UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
|
||||
if (uart_intr_status & UART_AT_CMD_CHAR_DET_INT_ST_M) {
|
||||
@@ -1164,6 +1164,22 @@ int uart_write_bytes_with_break(uart_port_t uart_num, const char* src, size_t si
|
||||
return uart_tx_all(uart_num, src, size, 1, brk_len);
|
||||
}
|
||||
|
||||
static bool uart_check_buf_full(uart_port_t uart_num)
|
||||
{
|
||||
if(p_uart_obj[uart_num]->rx_buffer_full_flg) {
|
||||
BaseType_t res = xRingbufferSend(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_data_buf, p_uart_obj[uart_num]->rx_stash_len, 1);
|
||||
if(res == pdTRUE) {
|
||||
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
|
||||
p_uart_obj[uart_num]->rx_buffered_len += p_uart_obj[uart_num]->rx_stash_len;
|
||||
p_uart_obj[uart_num]->rx_buffer_full_flg = false;
|
||||
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
|
||||
uart_enable_rx_intr(p_uart_obj[uart_num]->uart_num);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickType_t ticks_to_wait)
|
||||
{
|
||||
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1));
|
||||
@@ -1184,8 +1200,17 @@ int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickTyp
|
||||
p_uart_obj[uart_num]->rx_ptr = data;
|
||||
p_uart_obj[uart_num]->rx_cur_remain = size;
|
||||
} else {
|
||||
xSemaphoreGive(p_uart_obj[uart_num]->rx_mux);
|
||||
return copy_len;
|
||||
//When using dual cores, `rx_buffer_full_flg` may read and write on different cores at same time,
|
||||
//which may lose synchronization. So we also need to call `uart_check_buf_full` once when ringbuffer is empty
|
||||
//to solve the possible asynchronous issues.
|
||||
if(uart_check_buf_full(uart_num)) {
|
||||
//This condition will never be true if `uart_read_bytes`
|
||||
//and `uart_rx_intr_handler_default` are scheduled on the same core.
|
||||
continue;
|
||||
} else {
|
||||
xSemaphoreGive(p_uart_obj[uart_num]->rx_mux);
|
||||
return copy_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(p_uart_obj[uart_num]->rx_cur_remain > length) {
|
||||
@@ -1206,16 +1231,7 @@ int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickTyp
|
||||
vRingbufferReturnItem(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_head_ptr);
|
||||
p_uart_obj[uart_num]->rx_head_ptr = NULL;
|
||||
p_uart_obj[uart_num]->rx_ptr = NULL;
|
||||
if(p_uart_obj[uart_num]->rx_buffer_full_flg) {
|
||||
BaseType_t res = xRingbufferSend(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_data_buf, p_uart_obj[uart_num]->rx_stash_len, 1);
|
||||
if(res == pdTRUE) {
|
||||
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
|
||||
p_uart_obj[uart_num]->rx_buffered_len += p_uart_obj[uart_num]->rx_stash_len;
|
||||
p_uart_obj[uart_num]->rx_buffer_full_flg = false;
|
||||
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
|
||||
uart_enable_rx_intr(p_uart_obj[uart_num]->uart_num);
|
||||
}
|
||||
}
|
||||
uart_check_buf_full(uart_num);
|
||||
}
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user