Compare commits

...

378 Commits

Author SHA1 Message Date
Ivan Grokhotkov
646d36c728 Merge branch 'feature/nmea-parser' into 'master'
NMEA0183 Parser

See merge request idf/esp-idf!3866
2018-12-07 14:32:04 +08:00
Ivan Grokhotkov
6c868c4bee Merge branch 'bugfix/bbpll_wakeup_reset' into 'master'
soc/rtc: reset BBPLL config when enabling it

See merge request idf/esp-idf!3911
2018-12-07 14:21:59 +08:00
Ivan Grokhotkov
8b885fb935 Merge branch 'docs/add_note_for_ulp_set_wakeup_period' into 'master'
ulp: add note regarding limitation of ulp_set_wakeup_period in deep sleep mode

See merge request idf/esp-idf!3796
2018-12-07 14:07:14 +08:00
Ivan Grokhotkov
def2a13297 Merge branch 'bugfix/app_version' into 'master'
app_update: Fix esp_app_desc unused var for Cmake

See merge request idf/esp-idf!3891
2018-12-07 14:06:17 +08:00
Ivan Grokhotkov
423d7b9a65 Merge branch 'bugfix/sysview_cache_err' into 'master'
app_trace: linker fragment fixes

See merge request idf/esp-idf!3835
2018-12-07 14:04:28 +08:00
Ivan Grokhotkov
893cb83343 Merge branch 'bugfix/vfs_unregister_nested' into 'master'
vfs: fix unregister removing top level VFS instead of nested

See merge request idf/esp-idf!3917
2018-12-07 14:03:34 +08:00
Ivan Grokhotkov
4e77efc36b Merge branch 'bugfix/clang_compatibility' into 'master'
clang compatibility fixes

See merge request idf/esp-idf!3912
2018-12-07 14:03:05 +08:00
Jiang Jiang Jian
b1630084d1 Merge branch 'bugfix/btdm_assert_ble_32768' into 'master'
fix bug that there's very low ratio to cause BLE assert(32768, 0) in rwble.c at line 222

See merge request idf/esp-idf!3915
2018-12-07 13:54:11 +08:00
Konstantin Kondrashov
d4cb14bc65 app_update: Fix esp_app_desc unused var for Cmake 2018-12-07 12:04:40 +08:00
morris
8b7b5821c7 example: add nmea0183 parser example
Add NMEA0183 Parser example to illustrate how to use uart event driver together with esp event library to get GPS information.
2018-12-07 10:57:34 +08:00
Angus Gratton
aae955d1ae Merge branch 'docs/mesh_channel_switch' into 'master'
docs: Add documentation about ESP-MESH channel switching and self organized behavior

See merge request idf/esp-idf!3854
2018-12-07 09:24:51 +08:00
Angus Gratton
560e92b101 Merge branch 'feature/pystyle_examples' into 'master'
examples: Fix Python coding style

See merge request idf/esp-idf!3881
2018-12-07 09:12:56 +08:00
Anton Maklakov
e224b8a43a Merge branch 'bugfix/ci_tag_for_cmake_linter' into 'master'
ci: A small CI stabilizing fix

See merge request idf/esp-idf!3801
2018-12-07 02:39:51 +08:00
Anton Maklakov
3c8a2a099a ci: Fix the choice of runner for the CMake verification, and change .check_job_template tag to host_test 2018-12-07 00:52:20 +08:00
Anton Maklakov
812a49bd0d Merge branch 'bugfix/shell_exit' into 'master'
scripts: Fix shell exit

See merge request idf/esp-idf!3908
2018-12-07 00:49:52 +08:00
Ivan Grokhotkov
61beb16225 vfs: fix unregister removing top level VFS instead of nested
Credits @neoniousTR.

Fixes https://github.com/espressif/esp-idf/pull/2770
2018-12-06 19:43:49 +08:00
Tian Hao
357f2264e6 fix bug that there's very low ratio to cause BLE assert(32768, 0) in rwble.c at line 222 2018-12-06 16:54:14 +08:00
Roland Dobai
57c54f96f1 examples: Fix Python coding style 2018-12-06 09:34:33 +01:00
Ivan Grokhotkov
3150920cb4 heap: __builtin_return_address argument has to be a literal value
Clang does not accept const int as an argument of __builtin_return_address.

Ref LLVM-14
2018-12-06 16:14:14 +08:00
Ivan Grokhotkov
94f2dd27d4 examples/console: don’t use raw string literals in C code
Raw string literals are a C++ feature, and GCC supports them for C as
an extension. Clang doesn’t support them.

Ref LLVM-11
2018-12-06 16:14:14 +08:00
Ivan Grokhotkov
271a2e8e97 console, ulp: don’t use nested functions
These are not supported by clang

Ref LLVM-12
2018-12-06 16:12:47 +08:00
Wang Jia Lin
a36d714d1a Merge branch 'doc/adc_example_doc_improve' into 'master'
doc(adc): Update README.md file of adc example.

See merge request idf/esp-idf!2665
2018-12-06 15:22:50 +08:00
Wang Jia Lin
cbaa4ade42 Merge branch 'doc/pcnt_example_doc_improve' into 'master'
doc(pcnt): Update pcnt example README.md file.

See merge request idf/esp-idf!2666
2018-12-06 15:20:46 +08:00
Ivan Grokhotkov
b21ffc8a0c soc/rtc: reset BBPLL configuration after enabling it
A workaround to reset BBPLL configuration after light sleep. Fixes the
issue that Wi-Fi can not receive packets after waking up from light
sleep.

Ref. https://github.com/espressif/esp-idf/issues/2711
2018-12-06 14:43:24 +08:00
Angus Gratton
8c7a6be627 Merge branch 'bugfix/ldgen_make_escaping' into 'master'
make/ldgen: Fix generation of ldgen.section_infos file when shell is bash

See merge request idf/esp-idf!3893
2018-12-06 13:27:36 +08:00
Angus Gratton
54532c6189 build example tests: Use portable "sed -i" form 2018-12-06 15:28:18 +11:00
Angus Gratton
8ab2f20c3a ldgen make: Use "sed -E" for extended POSIX regular expression syntax w/ BSD sed 2018-12-06 15:28:18 +11:00
hou wen xiang
8e9359b4fd doc(adc): Update README.md file of adc example. 2018-12-06 12:20:29 +08:00
hou wen xiang
062c64fca0 doc(pcnt): Update pcnt example README.md file. 2018-12-06 12:16:45 +08:00
Angus Gratton
ef4a4105f4 make/ldgen: Fix generation of ldgen.section_infos file when shell is bash
bash doesn't escape by default from "echo", so use "printf"

Closes https://github.com/espressif/esp-idf/pull/2797
Closes https://github.com/espressif/esp-idf/issues/2796
2018-12-06 10:20:35 +11:00
Angus Gratton
ff71ea9202 Merge branch 'bugfix/win_path_print' into 'master'
tools: correct printed path on MS Win

See merge request idf/esp-idf!3853
2018-12-06 07:18:32 +08:00
Anton Maklakov
34109c4171 scripts: Fix shell exit. Really exit from current process, not from child process 2018-12-05 21:25:16 +08:00
Angus Gratton
97a3617a27 Merge branch 'bugfix/docs_pystyle' into 'master'
docs: Correct Python coding style

See merge request idf/esp-idf!3859
2018-12-05 17:43:20 +08:00
Angus Gratton
f1b4c18c2a Merge branch 'bugfix/idfpy_monitor_msys' into 'master'
tools: fix idf.py monitor for MSYS

Closes #51

See merge request idf/esp-idf!3839
2018-12-05 17:39:36 +08:00
Jiang Jiang Jian
d3b3f1e4a3 Merge branch 'bugfix/ethernet_enable_second_failure' into 'master'
fix ethernet phy init timeout

See merge request idf/esp-idf!3879
2018-12-05 16:12:19 +08:00
Angus Gratton
9f8587360c ldgen: Fix crash if --sections argument not supplied 2018-12-05 18:29:28 +11:00
Roland Dobai
b56ed1a99e docs: Correct Python coding style 2018-12-05 08:22:33 +01:00
Roland Dobai
4749b118bc tools: fix idf.py monitor for MSYS 2018-12-05 07:52:25 +01:00
Jiang Jiang Jian
eb27686416 Merge branch 'bugfix/btdm_bugs_caused_by_coex' into 'master'
component/bt and esp32:  fix two bluetooth bugs that caused by coexist module

See merge request idf/esp-idf!3860
2018-12-05 14:17:14 +08:00
Ivan Grokhotkov
e92e028679 Merge branch 'feature/sdio_example_gpio_doc' into 'master'
Enhanced readability in README.md (port from Github PR)

See merge request idf/esp-idf!3883
2018-12-05 13:46:33 +08:00
Ivan Grokhotkov
37975c186d Merge branch 'feature/pthread_name_affinity_config' into 'master'
pthread: make affinity and task name configurable

See merge request idf/esp-idf!3878
2018-12-05 13:46:05 +08:00
Ivan Grokhotkov
e04fd42176 Merge branch 'feature/refactoring_ota_part' into 'master'
bootloader/app_update: Refactoring otadata part

See merge request idf/esp-idf!3544
2018-12-05 12:59:34 +08:00
Angus Gratton
d50af8bd53 Merge branch 'bugfix/no_tests_for_unit_test_example' into 'master'
cmake: fix error in converting project variables to namespaced ones

See merge request idf/esp-idf!3887
2018-12-05 12:58:42 +08:00
Angus Gratton
36be9b36dd Merge branch 'bugfix/fix_menuconfig_for_windows' into 'master'
Fix various errors for menuconfig on Windows

Closes #50

See merge request idf/esp-idf!3848
2018-12-05 11:34:49 +08:00
Konstantin Kondrashov
f9522a0eb6 bootloader app_update: Refactoring otadata part 2018-12-05 11:20:03 +08:00
Ivan Grokhotkov
8a7b46aa90 Merge branch 'feature/anti_rollback_exp' into 'master'
esp32: Add firmware version to app

See merge request idf/esp-idf!3461
2018-12-05 11:10:04 +08:00
Renz Christian Bagaporo
b11238df4d ci: add test for setting EXTRA_COMPONENT_DIRS 2018-12-05 10:51:10 +08:00
Renz Christian Bagaporo
0d5660fbde cmake: fix error in converting project variables to namespaced ones
Closes https://github.com/espressif/esp-idf/issues/2764
2018-12-05 10:51:10 +08:00
Angus Gratton
794155f975 Merge branch 'doc/security_features_small_fixes' into 'master'
doc: Small secure boot & flash encryption corrections

See merge request idf/esp-idf!3876
2018-12-05 09:03:30 +08:00
Angus Gratton
a2d0fbb9ab docs: flash encryption: Fix description of behaviour when all bits of FLASH_CRYPT_CNT are set
Correct behaviour is described in section 25.3.3 Flash Decryption Block of the ESP32 TRM
2018-12-05 11:15:00 +11:00
Angus Gratton
441e2d5011 Merge branch 'bugfix/register_structs_stdint' into 'master'
soc: Add "#include <stdint.h>" to all register structs

See merge request idf/esp-idf!3875
2018-12-05 08:05:56 +08:00
Anton Maklakov
deaecf164d make: fix unexpected operator warning 2018-12-05 07:54:59 +08:00
Renz Christian Bagaporo
d411175e47 mbedtls, cmake: set host as unix when building in msys 2018-12-05 07:54:59 +08:00
Renz Christian Bagaporo
50d7067391 cmake: fix mconf path for existing mconf
Fixes https://github.com/espressif/esp-idf/issues/2771
Fixes https://github.com/espressif/esp-idf/issues/2722
2018-12-05 07:54:59 +08:00
ThisNameIsNotAllowed
b12c58224d Enhanced readability in README.md
Changed text based GPIO-list to some table based version.
This should enhance the readability.

Resolves https://github.com/espressif/esp-idf/pull/2749
2018-12-04 21:20:32 +08:00
morris
dc043109d7 ethernet: phy init timeout
When ethernet enable again after disable it before, phy init will report timeout.
The cause of this problem is that the enabling of emac clock is too late, and should be placed before phy init.
2018-12-04 17:13:48 +08:00
Jeroen Domburg
d6ee27e313 Merge branch 'feat/spi_check_length_buffer' into 'master'
spi: add checks for slave buffer valid and master length

See merge request idf/esp-idf!3744
2018-12-04 11:48:32 +08:00
Angus Gratton
2b557523ba Merge branch 'bugfix/generic_cmake_gc_sections' into 'master'
generic cmake: Always use gc-sections when linking IDF libraries

See merge request idf/esp-idf!3873
2018-12-04 11:01:51 +08:00
Angus Gratton
2946b5f384 Merge branch 'bugfix/ldgen_cmd_args_too_long' into 'master'
Fix issue with generating linker script using Windows command line

See merge request idf/esp-idf!3865
2018-12-04 10:42:58 +08:00
Angus Gratton
ac1d1aa3c8 doc: secure boot: Explain output of digest_secure_bootloader command
Mentioned on forum https://esp32.com/viewtopic.php?f=13&t=8162&start=10#p34714
2018-12-04 12:34:59 +11:00
Angus Gratton
b45b0f2348 doc: security: Use less ambiguous language about using bot flash encryption & secure boot together 2018-12-04 12:34:38 +11:00
Angus Gratton
7f32995a4c soc: Add "#include <stdint.h>" to all register structs
Closes https://github.com/espressif/esp-idf/issues/2239

TW24912
2018-12-04 11:17:38 +11:00
Angus Gratton
89826e8f47 generic cmake: Always use gc-sections when linking IDF libraries
Required for some IDF binary libraries

Reported on forum: https://esp32.com/viewtopic.php?f=13&t=7535&p=34863#p34852

TW27733
2018-12-04 10:47:00 +11:00
Tian Hao
a9429ee5da component/bt and esp32: fix two bluetooth bugs that caused by coexist module
1. Fix interrupt watchdog timeout in bluetooth "btdm_bb_isr"
    2. Fix BLE assert(512) or assert(1536)  in rwble.c at line 222
    3. Update librtc.a to fix BLE assert(512) in rwble.c at line 222

    The #1 and #2 occurs random.
    The #3 bug occurs in certain scenario:
    	1. If Wifi start softap and BLE is working
    	2. If wifi start station, but do not use normal station operation, such
    		as just use espnow, while BLE is working
    	3. Any other scenario, that wifi works without use software coexist
    		operation, while BLE is working(such as do advertising and ...)

    4. update libcoexist.a version to v1.1.2
2018-12-03 19:41:43 +08:00
Konstantin Kondrashov
3b9cb25fe1 esp32: Add firmware version to app
Added a new structure esp_app_desc_t. It has info about firmware:
version, secure_version, project_name, time/date build and IDF version.
Added the ability to add a custom structure with a description of the firmware.

The esp_app_desc_t is located in fixed place in start of ROM secotor. It is located after structures esp_image_header_t and esp_image_segment_header_t.

app_version is filed from PROJECT_VER variable (if set in custom make file) or PROJECT_PATH/version.txt or git repo (git describe).

Add API to get app_desc from partition.
2018-12-03 16:52:04 +08:00
Mahavir Jain
588ecaae09 ulp: add note regarding limitation of ulp_set_wakeup_period in deep sleep mode 2018-12-03 11:41:10 +05:30
Renz Christian Bagaporo
a7a1c32a8e cmake, make: fix long cmd line args for ldgen 2018-12-03 12:26:38 +08:00
Angus Gratton
3bc970c5f4 Merge branch 'bugfix/partitions_tools_style_check' into 'master'
Remove parttool exemption from style check

See merge request idf/esp-idf!3847
2018-12-03 12:25:39 +08:00
Darian Leung
674f0b1ebd doc: Add mesh channel switching and self organized networking documentation 2018-12-03 11:57:32 +08:00
Angus Gratton
80e6def4b8 Merge branch 'ci/combine_unit_test_and_integration_test' into 'master'
ci: combine unit_test and integration_test stage

See merge request idf/esp-idf!3792
2018-12-03 11:39:26 +08:00
Angus Gratton
554cf77963 Merge branch 'bugfix/convert_to_cmake' into 'master'
Fix minor issue with convert_to_cmake script

See merge request idf/esp-idf!3666
2018-12-03 11:39:12 +08:00
Angus Gratton
fffa98647b Merge branch 'feature/docs_more_on_shared_pins_of_esp-wrover-kit' into 'master'
Extended information on using pins of ESP-WROVER-KIT that are shared among…

See merge request idf/esp-idf!3841
2018-12-03 07:02:40 +08:00
Angus Gratton
7fa98593bc Merge branch 'feature/docs_hw_reference_cn' into 'master'
Provided translation of 'Hardware Reference' into Chinese

See merge request idf/esp-idf!3555
2018-12-03 07:02:33 +08:00
Krzysztof Budzynski
340e7f3b2f Provided translation of 'Hardware Reference' into Chinese 2018-12-03 07:02:33 +08:00
Jiang Jiang Jian
6bd497f9ed Merge branch 'feature/btdm_ble_full_scan_support' into 'master'
component/bt: Added the ble full scan supported feature.

See merge request idf/esp-idf!3820
2018-11-30 21:53:21 +08:00
Jiang Jiang Jian
e07c5a22f2 Merge branch 'doc/RF_calibration' into 'master'
doc: add documentation for RF calibration

See merge request idf/esp-idf!3828
2018-11-30 21:50:29 +08:00
Jiang Jiang Jian
1cffc90e58 Merge branch 'feature/optimize_wifi_log' into 'master'
wifi: add code for setting wifi log level and module

See merge request idf/esp-idf!3710
2018-11-30 21:42:57 +08:00
Darian Leung
f0e8c068d2 docs: Fix mesh doc line wrapping
This commit fixes mesh doc line wrapping by making every
paragraph into a single line.
2018-11-30 21:13:28 +08:00
yulong
0f3eb977cd component/bt: Added the ble full scan supported feature.
1. Add the full scan swith in the menuconfig;
2. Change the bt lib in order to support ble full scan
2018-11-30 20:48:42 +08:00
Roland Dobai
f7281c75c7 tools: correct the coding style of check_python_dependencies.py 2018-11-30 13:43:28 +01:00
Roland Dobai
98bc172f58 tools: correct printed path on MS Win 2018-11-30 13:43:28 +01:00
Renz Christian Bagaporo
a3b581bd8c parttool: remove exemption from style check 2018-11-30 16:39:55 +08:00
Xia Xiaotian
59761b0fcb doc: add documentation for RF calibration
Add an API to erase phy namespace of NVS
2018-11-30 16:26:56 +08:00
zhangyanjiao
e621e0af8b wifi: add code for setting wifi log level and module 2018-11-30 15:24:22 +08:00
Angus Gratton
7458c1c1e2 Merge branch 'feature/ulp-assembler-version-check' into 'master'
Check assembler version

See merge request idf/esp-idf!3156
2018-11-30 14:57:01 +08:00
Angus Gratton
ed21457afc Merge branch 'doc/ledc_example_doc_improve' into 'master'
doc(ledc): Update LEDC example README.md file

See merge request idf/esp-idf!2673
2018-11-30 14:48:25 +08:00
Angus Gratton
a34a27010b Merge branch 'feature/partition_tools' into 'master'
Partition level tools

See merge request idf/esp-idf!3355
2018-11-30 14:15:51 +08:00
Angus Gratton
c22512d27f Merge branch 'bugfix/ldgen_error_messages' into 'master'
ldgen: Improve error output when linker input is invalid

See merge request idf/esp-idf!3824
2018-11-30 11:15:23 +08:00
Ivan Grokhotkov
ba844caa8a app_trace: fix linker fragment not included in Make build 2018-11-30 11:05:43 +08:00
Ivan Grokhotkov
46a948dafa app_trace: require timer driver to be in IRAM
Closes https://github.com/espressif/esp-idf/issues/2760
2018-11-30 11:05:43 +08:00
Angus Gratton
f845af840f Merge branch 'bugfix/build_fail_on_idf_as_lib' into 'master'
cmake: fix error on building idf as lib when env IDF_PATH is not set

See merge request idf/esp-idf!3832
2018-11-30 10:59:18 +08:00
Angus Gratton
4027a7f2c2 Merge branch 'bugfix/i2c_master_clear_bus' into 'master'
fix i2c_master_clear_bus && add i2c_tool example test

See merge request idf/esp-idf!3509
2018-11-30 10:53:39 +08:00
Angus Gratton
afe4c76b6b Merge branch 'doc/heap_basics' into 'master'
docs: Add some more explanation about heap, memory types

See merge request idf/esp-idf!3810
2018-11-30 10:24:51 +08:00
morris
9163e454f1 example_test: using try block to pass the python style check 2018-11-30 10:13:58 +08:00
Wangjialin
924daf7b84 bugfix(i2c): reduce speed of I2C master bus reset routine and release SDA
closes https://github.com/espressif/esp-idf/issues/2494
closes https://github.com/espressif/esp-idf/pull/2493
closes https://github.com/espressif/esp-idf/pull/2496

1. Change bus reset to handle interrupted READ sequences.
2. Slow down I2C to 100khz during reset
3. 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 byte READ 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. The master(ESP32) cannot generate a STOP unless SDA is HIGH. So, this reset code synchronizes the bit stream with, Either, the ACK bit, Or a 1 bit.
2018-11-30 10:08:28 +08:00
chuck todd
e55f9c1e98 1. Slow down I2C to 100khz During Reset
I am stealing this delay coding from @jeremyherbert #2493 pr.

2. Change Bus Reset to handle interrupted READ sequences.

The current code does not handle interrupted READ cycles.

 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 byte READ 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. The master(ESP32) cannot generate a STOP unless SDA is HIGH.

So, this reset code synchronizes the bit stream with, Either, the ACK bit, Or a 1 bit.

3. fix typo

correct `sda_id` to `sda_io` in `i2c_master_clear_bus()` @ryan-ma found it.  This typo was generated when I manually edited this patch on GitHub, I should have done a Copy/Paste operation!
2018-11-30 10:08:28 +08:00
jeremy
34c1d25c7f reduce speed of i2c master bus reset routine and release sda 2018-11-30 10:08:28 +08:00
morris
2b165f99c4 i2c_tool: add i2c_tool example test
1. add example test for i2c-tools
2. make command line arguments number configurable
2018-11-30 10:08:28 +08:00
Angus Gratton
98f9a3c316 Merge branch 'bugfix/flake8' into 'master'
Make the flake8 configuration work regardless of installed plugins

See merge request idf/esp-idf!3838
2018-11-30 09:32:43 +08:00
morris
8dc66d3f0f doc: translate part of build-system
Translate the make_size part in build system.
2018-11-30 12:29:38 +11:00
Angus Gratton
a3a1cc080e docs: Add some more explanation about heap, memory types 2018-11-30 12:29:38 +11:00
krzychb
29b1f86f16 Extended information on using pins of ESP-WROVER-KIT that are shared among peripherals. Inspired by https://esp32.com/viewtopic.php?f=12&t=6856. 2018-11-29 16:56:49 +01:00
Ivan Grokhotkov
499fdbd33d Merge branch 'feature/fatfs_alloc_extram_option' into 'master'
fatfs: add option to prefer ext. RAM for internal buffers

See merge request idf/esp-idf!3821
2018-11-29 22:59:01 +08:00
He Yin Ling
edff003e72 Merge branch 'test/driver_i2c' into 'master'
add i2c case

See merge request idf/esp-idf!1937
2018-11-29 22:53:06 +08:00
Roland Dobai
a26580d0e8 Make the flake8 configuration work regardless of installed plugins 2018-11-29 15:26:39 +01:00
Ivan Grokhotkov
bbeb62547e fatfs: add option to prefer ext. RAM for internal buffers 2018-11-29 19:26:46 +08:00
Mahavir Jain
907b1a9032 mbedtls: align CMake build with corresponding component.mk 2018-11-29 16:23:06 +05:30
houchenyao
147447b13e test: components/driver: i2c case 2018-11-29 18:27:58 +08:00
Mahavir Jain
a3785792eb tools/ci: add test case for convert_to_cmake script
Following issue was already fixed with earlier commit-id f4cfca4353
Here additional build test case is added and marking issue as closed.

Closes: https://github.com/espressif/esp-idf/issues/2660
2018-11-29 15:15:13 +05:30
Ivan Grokhotkov
56e4c6e5a3 Merge branch 'bugfix/menuconfig_fails_on_cmake' into 'master'
Fix menuconfig fail on cmake

Closes #48

See merge request idf/esp-idf!3826
2018-11-29 16:10:21 +08:00
Renz Christian Bagaporo
ba6058ba58 cmake: fix error on building idf as lib when env IDF_PATH is not set 2018-11-29 15:40:16 +08:00
He Yin Ling
add7c49a26 Merge branch 'test/driver_i2s' into 'master'
component/driver:add i2s case

See merge request idf/esp-idf!2117
2018-11-29 14:41:09 +08:00
Renz Christian Bagaporo
da1f3ea12a kconfig: pass env variable to menuconfig invocation 2018-11-29 13:22:10 +08:00
Renz Christian Bagaporo
a2f63c09bf make, ldgen: remove uncessary passed target env variable 2018-11-29 13:21:31 +08:00
Renz Christian Bagaporo
f6375952bb kconfig: specify full path of built mconf 2018-11-29 13:16:13 +08:00
Wang Jia Lin
62cc522f36 Merge branch 'feature/rmt_add_api_get_free_channel' into 'master'
feature(rmt):   Add API get rmt channel's status.

See merge request idf/esp-idf!2440
2018-11-29 11:59:39 +08:00
houchenyao
44fdca94e9 test: components/driver: i2s case 2018-11-29 11:32:40 +08:00
Angus Gratton
073dbe6d1d Merge branch 'bugfix/idf_monitor_tests' into 'master'
Adjust the timeout of the idf_monitor tests

See merge request idf/esp-idf!3802
2018-11-29 11:03:25 +08:00
Angus Gratton
759185b16c Merge branch 'bugfix/bt_ut_build_all' into 'master'
Fix unit test cmake build for BT

See merge request idf/esp-idf!3767
2018-11-29 09:52:55 +08:00
Angus Gratton
d4a5682e7d ldgen: Improve error output when linker input is invalid, don't create output file until end of process 2018-11-29 12:41:35 +11:00
Ivan Grokhotkov
21b3919369 Merge branch 'bugfix/vfs_open_write_close_perf_test' into 'master'
Fix VFS unit test failure ("Open & write & close through VFS passes performance test")

Closes #44

See merge request idf/esp-idf!3759
2018-11-29 09:40:54 +08:00
Ivan Grokhotkov
1d2673eda5 Merge branch 'bugfix/uart_select_buffer' into 'master'
VFS: select() on UART should return immediately when data is buffered

See merge request idf/esp-idf!3803
2018-11-29 09:30:19 +08:00
Per Malmberg
71f57931bd #2743 - Implemented ability to core affinity and thread name for pthreads and thus also for std::thread. 2018-11-28 20:43:09 +01:00
Roland Dobai
738c56e84a Fix VFS_OPEN_WRITE_CLOSE_TIME unit test issue
Closes idf/esp-idf#44
2018-11-28 20:36:08 +01:00
Ivan Grokhotkov
2c7fc07aae Merge branch 'bugfix/various_ldgen_fixes' into 'master'
Fix multiple ldgen issues

Closes #47

See merge request idf/esp-idf!3799
2018-11-29 01:46:02 +08:00
Ivan Grokhotkov
98884b4f6c Merge branch 'bugfix/sysview_trace_taskid' into 'master'
freertos: fix task ID sent to the trace

See merge request idf/esp-idf!3807
2018-11-29 01:45:36 +08:00
Jiang Jiang Jian
7312294648 Merge branch 'bugfix/btdm_rf_reg' into 'master'
fix bug to unsupport rf reg access from hci cmd

See merge request idf/esp-idf!3787
2018-11-28 21:21:20 +08:00
Jiang Jiang Jian
a134141320 Merge branch 'mesh/feature_channel_switch' into 'master'
mesh: add channel switch function

See merge request idf/esp-idf!3772
2018-11-28 20:11:38 +08:00
Renz Christian Bagaporo
b926764385 examples: add otatool and parttool examples 2018-11-28 17:28:20 +08:00
Wang Jia Lin
cc5673435b Merge branch 'bugfix/fix_uart_read_bug_when_using_dual_core' into 'master'
bugfix(uart): fix uart read error bug when using dual core.

See merge request idf/esp-idf!3521
2018-11-28 16:17:13 +08:00
Renz Christian Bagaporo
5e08698039 make: use otatool and parttool for build 2018-11-28 15:57:20 +08:00
Renz Christian Bagaporo
bceec35d0e cmake: use otatool and parttool for build 2018-11-28 15:57:20 +08:00
Renz Christian Bagaporo
8ca6904d55 ota: implement otatool functionality 2018-11-28 15:57:20 +08:00
Renz Christian Bagaporo
88c81c67b7 partition_table: implement new parttool functionality 2018-11-28 15:57:20 +08:00
Angus Gratton
06eebfe15f Merge branch 'bugfix/ignore_windows_conf_tools' into 'master'
gitignore: Add mconf-idf.exe and conf-idf.exe

See merge request idf/esp-idf!3806
2018-11-28 15:46:15 +08:00
kooho
da223fad4e driver(rmt): Add API get rmt channel's status.
closes https://github.com/espressif/esp-idf/issues/1175
closes https://github.com/espressif/esp-idf/issues/2599
closes https://github.com/espressif/esp-idf/issues/2452
2018-11-28 07:20:45 +00:00
Anton Maklakov
87e8757569 bt: Fix unit tests build with CMake 2018-11-28 15:19:04 +08:00
Anton Maklakov
9dde91ce2b modbus: Fix a typo in the docs 2018-11-28 15:19:03 +08:00
hou wen xiang
ade39f823f doc(ledc): Update LEDC example README.md file. 2018-11-28 07:15:56 +00:00
Renz Christian Bagaporo
4c83f456ab cmake: generate sections info for all static libs as in make 2018-11-28 14:24:21 +08:00
Renz Christian Bagaporo
a9c784339d ldgen: fix error on parsing archive from sections info 2018-11-28 14:14:54 +08:00
Renz Christian Bagaporo
22b4c95d1e ldgen: add traceback in case of exception 2018-11-28 14:14:54 +08:00
He Yin Ling
19910c8729 Merge branch 'test/driver_mcpwm' into 'master'
test/mcpwm_case

See merge request idf/esp-idf!1831
2018-11-28 13:56:05 +08:00
Ivan Grokhotkov
8eb40bea51 freertos: pass TCB rather than the array to trace functions 2018-11-28 12:26:34 +08:00
Wang Jia Lin
70554e8caa Merge branch 'doc/uart_lightsleep_wakeup_doc' into 'master'
doc(uart):  update the comment of uart_set_wakeup_threshold

See merge request idf/esp-idf!3556
2018-11-28 11:35:56 +08:00
Angus Gratton
6f8e2b018f Merge branch 'feature/generic_cmake_support' into 'master'
Generic CMake Support

See merge request idf/esp-idf!3543
2018-11-28 10:42:47 +08:00
houchenyao
11faab2c5d test: components/driver: pwm case 2018-11-28 10:42:32 +08:00
Angus Gratton
fac12d0dae Merge branch 'bugfix/windows_install_prerequisites' into 'master'
windows_install_prerequisites: Fix generation of PATH command

See merge request idf/esp-idf!3798
2018-11-28 09:11:08 +08:00
Angus Gratton
f7811671ae gitignore: Add mconf-idf.exe and conf-idf.exe
Problem since f6cd55d2ac

Closes https://github.com/espressif/esp-idf/issues/2751
2018-11-28 12:05:29 +11:00
Anton Maklakov
983cdcb7f4 add_path.sh: Fix reuse the script 2018-11-28 11:08:28 +11:00
qiyuexia
1692896e5e mesh: add channel switch function
1. add network channel switch function.
   - users can obtain the new channel through the event MESH_EVENT_CHANNEL_SWITCH.
   - the entire network will be moved to the same channel as the router without user intervention.
   - if no router is in the network, users can call esp_mesh_switch_channel() on the root side to
     move the entire network to their desired channel.
2. support not configuring the network channel.
3. support not configuring the router BSSID even if the router is hidden.
4. add allow_channel_switch to mesh configuration.
   - if the channel is not specified, this value will be ignored.
   - if the channel is specified and this value is set, when "fail" (mesh_attempts_t) times of parent selection
     or look for networks are reached, device will change to perform a full channel scan for networks that could join.
   - if the channel is specified and this value is set to 0, when a root is not elected, channel switch is not allowed.
     but when a root appears, the root performs a full channel scan during the process of connecting to the router,
     so even allow_channel_switch is set to 0, the root may still switch channel and eventually the entire network
    changes channel.
5. add allow_router_switch to mesh router configuration.
   - if the BSSID of router is not specified, this value will be ignored.
   - if the BSSID of router is specified and this value is set, when the router of this specified BSSID fails to be found
     after "fail" (mesh_attempts_t) times, the entire network is allowed to switch to another router with the same SSID.
6. modify the root to perform a full channel scan when esp_wifi_connect().
7. support handling beacon without DS Paramter Set.
2018-11-27 23:36:01 +08:00
kooho
a9c1124763 driver(uart): fixed uart read error bug when using dual core.
closes https://github.com/espressif/esp-idf/issues/2204
2018-11-27 20:53:26 +08:00
Roland Dobai
957cf0ab84 VFS: select() on UART should return immediately when data is buffered 2018-11-27 13:39:00 +01:00
Renz Bagaporo
7e7cc99241 docs: generic cmake support 2018-11-27 19:56:52 +08:00
Renz Christian Bagaporo
f1f0bd4b1c ci: update for running cmake examples 2018-11-27 19:56:52 +08:00
Renz Christian Bagaporo
bec3bb3ba4 make, cmake: display ulp assembler version 2018-11-27 19:40:50 +08:00
Renz Bagaporo
b35c745c4f ulp: check assembler version 2018-11-27 19:25:22 +08:00
Roland Dobai
cedc0b6643 Adjust the timeout of the idf_monitor tests 2018-11-27 09:53:56 +01:00
Renz Christian Bagaporo
90f5432f2a examples: generic cmake support examples 2018-11-27 13:59:26 +08:00
Renz Christian Bagaporo
0908fba1a3 mbedtls: import mbedtls project w/o modification 2018-11-27 13:59:26 +08:00
Renz Christian Bagaporo
37d30c7a6e cmake: separate app from idf lib project
mbedtls: import mbedtls using unmodified cmake file
2018-11-27 13:59:24 +08:00
Angus Gratton
81231fcc4b Merge branch 'feature/i2s_tx_descriptor_auto_clear' into 'master'
i2s: add (optional) support to clear tx descriptor in underflow case

See merge request idf/esp-idf!2397
2018-11-27 13:45:51 +08:00
Angus Gratton
c75c28faf5 Merge branch 'feature/pystyle' into 'master'
Check the Python coding style

See merge request idf/esp-idf!3748
2018-11-27 12:41:17 +08:00
Tian Hao
f3bfdeaeec fix bug to unsupport rf reg access from hci cmd
Always return 0 when read rf register and do nothing when write rf register
2018-11-27 12:00:06 +08:00
Angus Gratton
b7f56e86ba windows_install_prerequisites: Fix generation of PATH command
Accidental regression in 7c8d5d2782 - escape
character didn't move with PATH.

Reported on forum https://esp32.com/viewtopic.php?f=13&t=8201
2018-11-27 09:36:43 +11:00
Roland Dobai
1b464d23a9 tools: Correct coding style of idf_monitor 2018-11-26 15:02:39 +01:00
Roland Dobai
9273de8b43 Check the Python coding style
Closes https://github.com/espressif/esp-idf/pull/2747
2018-11-26 15:02:27 +01:00
Jiang Jiang Jian
90a6c9aada Merge branch 'feature/add_long_range_code' into 'master'
example: add long range code

See merge request idf/esp-idf!3552
2018-11-26 17:03:09 +08:00
Jiang Jiang Jian
9890feaa37 Merge branch 'feature/btdm_add_ble_compatibility_test_demo' into 'master'
Component/bt: add BLE Compatibility Test demo

See merge request idf/esp-idf!3749
2018-11-26 17:00:55 +08:00
He Yin Ling
bf0f02112d ci: combine unit_test and integration_test stage:
The number of runners of integration test is not bottleneck to CI
pipeline performance now. Combine these 2 stages will make integration
test executed even unit test fails. This could help us to collect more
info about test history.
2018-11-26 16:40:32 +08:00
He Yin Ling
1c65f18422 Merge branch 'test/enhanced_junit_test_result' into 'master'
test: enhanced junit test result

See merge request idf/esp-idf!2766
2018-11-26 16:35:08 +08:00
Angus Gratton
03c59658cb Merge branch 'bugfix/test_idf_monitor_hangs' into 'master'
tools: Fix idf_monitor test case occasional hangup or failure

Closes #39

See merge request idf/esp-idf!3651
2018-11-26 15:29:55 +08:00
Angus Gratton
c765035b3a Merge branch 'update/nvs_part_gen' into 'master'
nvs_util: Add changes to nvs part gen util

See merge request idf/esp-idf!3531
2018-11-26 14:26:08 +08:00
michael
cfba157fdd spi_slave: add valid check for DMA buffers
The DMA cannot receive data correctly when the buffer address is not
WORD aligned. Currently we only check whether the buffer is in the DRAM
region.

The DMA always write in WORDs, so the length arguments should also be
multiples of 32 bits.

A check is added to see whether the buffer is WORD aligned and has valid
length.
2018-11-26 03:49:26 +00:00
michael
435adaa22a spi_master: add check for trans len
The driver decide whether use MOSI/MISO phases according to the buffer
address together with the SPI_TRANS_USE_*DATA. However someone may assue
that these phases will be skipped when the ``length``/``rxlength`` is
set to 0. In fact it is a feature that ``rxlength`` is allowed to be
set to 0 when tx and rx have the same length, and the driver fill the
``rxlength`` to ``length``.

An error check is added when the rxlength is 0 but there is data to be
sent.
2018-11-26 03:49:26 +00:00
He Yin Ling
7202aed31e ci: split build unit test job:
it takes long time to build with both make and cmake
2018-11-26 10:07:41 +08:00
He Yin Ling
ca7fa6f01a ci: use artifacts:reports feature of Gitlab CI 2018-11-26 10:07:41 +08:00
He Yin Ling
ef9eaddd88 ci: assign unit test cases in sequence of config and name 2018-11-26 10:07:41 +08:00
He Yin Ling
5b3d09d5c8 test: fix unit test script code style warnings 2018-11-26 10:07:41 +08:00
He Yin Ling
644571f78b test: generate junit test report according to executed cases 2018-11-26 10:07:41 +08:00
He Yin Ling
0ad226b375 tiny-test-fw: support capture raw data in DUT:
test cases might want to use `expect` and get raw data from DUT at the same time. New added capture method provides a way to do that.
2018-11-26 10:07:41 +08:00
Angus Gratton
fa59b1b1c9 Merge branch 'bugfix/fix_cmake_args_issue' into 'master'
Fix CMAKE_ARGS issue for ULP build

See merge request idf/esp-idf!3776
2018-11-26 07:58:09 +08:00
Ivan Grokhotkov
5aa7abb216 Merge branch 'bugfix/spiram_80m_clk_config' into 'master'
clk: fix regression in clock setting for SPIRAM with 80MHz config

See merge request idf/esp-idf!3724
2018-11-25 22:25:19 +08:00
Jiang Jiang Jian
a0468b2bd6 Merge branch 'feature/btdm_add_update_duplicate_scan_exceptional_list_apis' into 'master'
Component/bt: add update duplicate scan exceptional list APIs

See merge request idf/esp-idf!3763
2018-11-25 18:58:53 +08:00
Roland Dobai
608fc23278 tools: Fix idf_monitor test case occasional hangup or failure
Closes idf/esp-idf#39
2018-11-23 13:33:17 +01:00
Mahavir Jain
1751607adf examples: enable option to auto clear I2S tx descriptor on underflow
Closes: https://github.com/espressif/esp-idf/issues/1945
2018-11-23 14:43:20 +05:30
zhangyanjiao
ad22d280c6 wifi: add long range code 2018-11-23 09:09:07 +00:00
Jiang Jiang Jian
64d038c0d5 Merge branch 'bugfix/fix_some_wifi_bugs_1121' into 'master'
esp32: fix some wifi bugs

See merge request idf/esp-idf!3756
2018-11-23 17:08:25 +08:00
Mahavir Jain
765bf674d0 i2s: add (optional) support to clear tx descriptor in underflow case
It has been observed that, in case of underflow (data unavailability) in
I2S transmission, previously filled up tx descriptors continue to get
transmitted on line, causing noise in case of audio use case.

This change adds optional `tx_desc_auto_clear` field during I2S driver intialization
than can zero initialize tx descriptor in case of underflow situation in
interrupt handler itself.

Closes: https://github.com/espressif/esp-idf/issues/1789
2018-11-23 14:31:09 +05:30
zhiweijian
dd3d89db49 Component/bt: add update duplicate scan exceptional list APIs 2018-11-23 16:46:17 +08:00
Renz Christian Bagaporo
3a02a12aa4 cmake: remove unecessary info passed to bootloader build 2018-11-23 16:08:47 +08:00
Renz Christian Bagaporo
552f17e260 ulp: fix passing ulp srcs due to cmake_args bug 2018-11-23 16:08:41 +08:00
Wang Jia Lin
783ff9c455 Merge branch 'bugfix/i2c_hardware_filter_default_enable' into 'master'
driver:  Enable I2C master hardware filter by default.

See merge request idf/esp-idf!3715
2018-11-23 14:23:37 +08:00
Liu Zhi Fu
f874b52f0a esp32: fix some wifi bugs
Fix some WiFi bugs:
1. Enable RX BAR
2. Fix the bug that ESP32 AP negotiates with iphone to 11g
3. Fix the bug that ESP32 STA has ap_loss because CMCC AP contains two SSID
2018-11-23 05:41:41 +00:00
Angus Gratton
a081e5d25e Merge branch 'bugfix/docs_what-you-need' into 'master'
Updated 'What you need' picture

See merge request idf/esp-idf!3725
2018-11-23 11:16:28 +08:00
Angus Gratton
83f6ee9912 Merge branch 'bugfix/docs_https_server' into 'master'
Docs : esp_https_server API references corrected

See merge request idf/esp-idf!3775
2018-11-23 10:44:55 +08:00
Angus Gratton
269e94f387 Merge branch 'bugfix/fix_ldgen_pyparsing_new_version' into 'master'
ldgen: fix issues when using pyparsing 2.3.0

See merge request idf/esp-idf!3739
2018-11-23 10:38:18 +08:00
kooho
33138a3dec driver(i2c): enable I2C master hardware filter by default. 2018-11-23 10:27:59 +08:00
Renz Christian Bagaporo
1600c3144c docs: add pyparsing install to setup guide 2018-11-22 22:09:43 +08:00
Renz Christian Bagaporo
8eeddd287c ldgen: catch exception with python3 compatible style
Closes https://github.com/espressif/esp-idf/issues/2720
2018-11-22 22:09:43 +08:00
He Yin Ling
8e70582cad tiny-test-fw: enhanced junit test report support:
1. replace xunitgen with junit_xml, which can log more info
2. allow test cases to handle junit test report by them own
3. allow test cases to log some info into report via `sysout` tag
2018-11-22 20:49:15 +08:00
Jiang Jiang Jian
e199587a11 Merge branch 'bugfix/btdm_move_func_into_iram' into 'master'
components/bt: Move function in interrupt into IRAM

See merge request idf/esp-idf!3757
2018-11-22 19:17:37 +08:00
Anurag Kar
684f0b0a32 Docs : esp_https_server API references corrected 2018-11-22 15:57:05 +05:30
baohongde
7e142f9d22 components/bt: Move function in interrupt into IRAM
1. Move function in interrupt into IRAM
2. Delete unused code, saving 240B DRAM and some code size
2018-11-22 15:59:53 +08:00
Ivan Grokhotkov
09a01f68ba Merge branch 'bugfix/calloc_recursive' into 'master'
newlib: disable some optimizations for syscalls.c

See merge request idf/esp-idf!3774
2018-11-22 15:24:17 +08:00
Ivan Grokhotkov
8deb885ce3 newlib: disable some optimizations for syscalls.c
Don’t allow the compiler to convert malloc + memset into calloc,
causing a recursive call in _calloc_r. Fixes crash when building with
-O2 optimization level.
2018-11-22 12:19:49 +08:00
Jiang Jiang Jian
6252292d9c Merge branch 'mesh/bugfix_v3.2' into 'master'
mesh: bugfix

See merge request idf/esp-idf!3740
2018-11-22 10:22:06 +08:00
Renz Christian Bagaporo
56ed588d4f tools: install pyparsing using pip 2018-11-22 09:55:31 +08:00
Renz Christian Bagaporo
507328d4db ldgen: fix issues when using pyparsing 2.3.0 2018-11-22 09:55:31 +08:00
zhiweijian
e9ee9384fc Component/bt: add BLE Compatibility Test demo 2018-11-21 19:36:51 +08:00
qiyueixa
86fedc3cbb utest: increase IDF_PERFORMANCE_MAX_VFS_OPEN_WRITE_CLOSE_TIME to 50000 2018-11-21 19:14:07 +08:00
qiyueixa
6c3b5ae5a1 mesh: bugfix
1. fix failture of mesh stop caused by block-sending.
2. fix when FIXED_ROOT is set, 2nd layer devices can not receive mesh event ESP_ERR_MESH_NO_PARENT_FOUND.
3. fix when FIXED_ROOT is set and the root turns off mesh function, 2nd layer devices do not look for new parents.
4. add APIs esp_mesh_disconnect() and esp_mesh_connect().
5. disconnect from parent/router when the DSSS channel in received beacon is different from the home channel.
6. remove nvs task to release 3k bytes memory.
2018-11-21 19:13:41 +08:00
Shivani Tipnis
0c72b08872 nvs_util: update test case 2018-11-21 13:40:24 +05:30
Shivani Tipnis
582c547191 Update README 2018-11-21 12:55:47 +05:30
Shivani Tipnis
c44f15441f Closes https://github.com/espressif/esp-idf/issues/2472 2018-11-21 12:55:47 +05:30
Shivani Tipnis
9db1987892 nvs_util: Add changes to nvs part gen util
nvs_util: Add changes to nvs part gen util

nvs_host_test: Add test case for keygen and keyfile paratmeters
2018-11-21 12:55:47 +05:30
Jiang Jiang Jian
0d7f2d77c2 Merge branch 'feature/btdm_add_set_long_adv_data_api' into 'master'
Component/bt: add set long adv data api

See merge request idf/esp-idf!3722
2018-11-21 11:31:13 +08:00
Mahavir Jain
2a55e957fd ci: add unit test job 2018-11-20 18:55:04 +05:30
Mahavir Jain
bd3806193d unit-test-app: keep CONFIG_SPIRAM_BANKSWITCH_ENABLE enabled only for psram_8m config 2018-11-20 18:54:12 +05:30
Jiang Jiang Jian
e7f9e3f6f6 Merge branch 'bugfix/add_connected_event_after_softap_finish_4_way' into 'master'
wifi: add connected event after softap finish 4 way

See merge request idf/esp-idf!3661
2018-11-20 20:04:12 +08:00
Jiang Jiang Jian
69c9e050b0 Merge branch 'bugfix/btdm_add_check_peer_addr_type_in_set_adv_params' into 'master'
Component/bt: add check peer addr type in set adv params

See merge request idf/esp-idf!3732
2018-11-20 20:02:13 +08:00
Angus Gratton
3970ea60de Merge branch 'bugfix/ldgen_windows_kconfig_paths' into 'master'
ldgen: Fix ENOENT errors on Windows with MSYS2 and GNU Make

See merge request idf/esp-idf!3746
2018-11-20 17:21:11 +08:00
Angus Gratton
c0298a5712 Merge branch 'bugfix/doc_builds_windows' into 'master'
doc: Fix doc builds on Windows MINGW32, add some doc build documentation

See merge request idf/esp-idf!3550
2018-11-20 17:20:40 +08:00
Angus Gratton
92f32f0060 Merge branch 'fix/spi_callback_in_iram' into 'master'
spi: fix the crash when callbacks are not in the IRAM

See merge request idf/esp-idf!3498
2018-11-20 16:25:08 +08:00
Jiang Jiang Jian
ffda37dd16 Merge branch 'feature/btdm_BLE_Blocking_APIs' into 'master'
Component/bt: add BLE Blocking APIs

See merge request idf/esp-idf!3513
2018-11-20 14:40:50 +08:00
Jiang Jiang Jian
b422a42697 Merge branch 'bugfix/btdm_errors_in_comment' into 'master'
components/bt: Some errors in comment

See merge request idf/esp-idf!3703
2018-11-20 14:26:12 +08:00
Angus Gratton
4f4edcf676 ldgen: Fix ENOENT errors on Windows with MSYS2 and GNU Make 2018-11-20 17:25:20 +11:00
Angus Gratton
61ee1bd31f Merge branch 'feature/esp_https_server' into 'master'
Add HTTPS Server component

See merge request idf/esp-idf!3608
2018-11-20 13:58:26 +08:00
Ivan Grokhotkov
46e28d7553 Merge branch 'example/sysview_tracing' into 'master'
SystemView tracing example

See merge request idf/esp-idf!3514
2018-11-20 13:10:19 +08:00
Michael (XIAO Xufeng)
8cddfa35b8 spi: fix the crash when callbacks are not in the IRAM
Introduced in 9c23b8e5 and 4f87a62f. To get higher speed, menuconfig
options are added to put ISR and other functions into the IRAM.  The
interrupt flag ESP_INTR_FLAG_IRAM is also mistakenly set when the ISR is
put into the IRAM. However callbacks, which are wrote by the user, are
called in the master and slave ISR. The user may not be aware of that
these callbacks are not disabled during flash operations. Any cache miss
during flash operation will cause panic.

Essentially IRAM functions and intrrupt flag ESP_INTR_FLAG_IRAM are
different, the latter means not disabling the ISR during flash
operations.  New bus_config flag intr_flags is offered to help set the
interrupt attribute, including priority level, SHARED, IRAM (not
disabled during flash operations).  It introduced a small BREAK to
IDFv3.1 (but the same as IDFv3.0) that the user has to manually set IRAM
flag now (therefore he's aware of the IRAM thing) to void the ISR being
disabled during flash operations.
2018-11-20 13:07:13 +08:00
Alexey Gerenkov
3139b2d533 example: Adds SystemView tracing example app 2018-11-20 04:09:39 +00:00
Alexey Gerenkov
3eaba1c8ce esp32: Fixes SystemView lock's IRQ state restore 2018-11-20 04:09:39 +00:00
zhiweijian
775c6e5ab7 Component/bt: add set long adv data api 2018-11-20 11:19:51 +08:00
Angus Gratton
4c881708dc Merge branch 'bugfix/ut_building_test_check' into 'master'
esp32, mbedtls: check component name when enabling test flags

See merge request idf/esp-idf!3742
2018-11-20 06:13:58 +08:00
Ivan Grokhotkov
99dd08943c make/ldgen: fix line continuation 2018-11-20 01:27:25 +08:00
Ivan Grokhotkov
8027adaf81 esp32, mbedtls: check component name when enabling test flags
Otherwise flags get enabled even when building tests for other components.
2018-11-20 01:27:24 +08:00
Mahavir Jain
62efef0444 test: spiram: fix and enable test cases for default configuration 2018-11-19 22:40:14 +05:30
Ivan Grokhotkov
00a13bd8d3 Merge branch 'bugfix/init_memctl' into 'master'
bootloader, esp32: add workaround for Tensilica erratum 572

See merge request idf/esp-idf!3605
2018-11-19 18:36:47 +08:00
Ivan Grokhotkov
a46b884a14 Merge branch 'feature/unit_test_example' into 'master'
Move Unity into components, add unit test example

See merge request idf/esp-idf!3562
2018-11-19 18:35:54 +08:00
zhiweijian
3c7819eaf2 Component/bt: add check peer addr type in set adv params 2018-11-19 17:04:48 +08:00
Angus Gratton
6709d26863 Merge branch 'fix/cryptography_version' into 'master'
Update minimum version for cryptography package required

See merge request idf/esp-idf!3712
2018-11-19 15:27:45 +08:00
Angus Gratton
57273d48d4 Merge branch 'doc/translation_eclipse-setup_wangfang' into 'master'
Doc/translation eclipse setup wangfang

See merge request idf/esp-idf!3681
2018-11-19 14:04:04 +08:00
Angus Gratton
6cdfea4251 Merge branch 'fix/spi_freq_limit_check' into 'master'
spi: modify some docs about the freq limit and the ISR

See merge request idf/esp-idf!3686
2018-11-19 14:02:40 +08:00
Shivani Tipnis
e1774cb6f9 Update minimum version for cryptography package required 2018-11-19 11:13:37 +05:30
Angus Gratton
26a6969873 Merge branch 'doc/add_cmake_translation' into 'master'
doc/add_translation_for_cmake_documents

See merge request idf/esp-idf!3636
2018-11-19 12:53:06 +08:00
Angus Gratton
8915f48208 Merge branch 'feature/linker_script_generator' into 'master'
Linker script generator

See merge request idf/esp-idf!2286
2018-11-19 12:43:27 +08:00
Ivan Grokhotkov
964f5a91f7 bootloader, esp32: add workaround for Tensilica erratum 572
If zero-overhead loop buffer is enabled, under certain rare conditions
when executing a zero-overhead loop, the CPU may attempt to execute an invalid instruction. Work around by disabling the buffer.
2018-11-19 04:39:35 +00:00
Ivan Grokhotkov
a5adfd0169 examples: add unit testing example 2018-11-19 12:36:31 +08:00
Ivan Grokhotkov
a98674d78b unity: don't use stdio in runner, fix code style 2018-11-19 12:36:31 +08:00
Ivan Grokhotkov
6091021e83 unity: separate common and IDF specific functionality
New unity component can be used for testing other applications.
Upstream version of Unity is included as a submodule.
Utilities specific to ESP-IDF unit tests (partitions, leak checking
setup/teardown functions, etc) are kept only in unit-test-app.
Kconfig options are added to allow disabling certain Unity features.
2018-11-19 12:36:31 +08:00
Ivan Grokhotkov
d4ef2135f0 ci: support building examples with external components 2018-11-19 12:36:31 +08:00
Ivan Grokhotkov
aa692b3483 vfs: implement fsync for UART VFS 2018-11-19 12:36:31 +08:00
Ivan Grokhotkov
5fb3d59a92 esp32: fix typos in rom/uart.h 2018-11-19 12:36:31 +08:00
Angus Gratton
c9a873c034 Merge branch 'docs/fix-eclipse-windows-steps' into 'master'
Docs: Change makes Eclipse setup inline with Mac OS and Linux.

See merge request idf/esp-idf!3486
2018-11-19 12:15:53 +08:00
Prasad Alatkar
b1189e9645 Docs: Change makes Eclipse setup inline with Mac OS and Linux. 2018-11-19 12:15:53 +08:00
Angus Gratton
8b6436eb2a Merge branch 'doc/translation_linux-setup-scratch_wangfang' into 'master'
Doc/translation linux setup scratch wangfang

See merge request idf/esp-idf!3679
2018-11-19 12:14:45 +08:00
Wang Fang
7d888ff6eb Doc/translation linux setup scratch wangfang 2018-11-19 12:14:45 +08:00
Anurag Kar
1d3f4074de esp_https_server : change config option secure_enable to transport_mode and some minor changes
transport_mode accepts enum httpd_ssl_transport_t instead of true/false.
This will allow for extension to dual mode (server running on both secure and insecure ports) in the future.
2018-11-19 04:00:21 +00:00
Anurag Kar
9a9d18e466 esp_http_server : APIs renamed and context get/set implementations fixed
* http_sess_set_*_override APIs are now the only ones available to set custom recv/send/pending functions
* Fixed side effects to using http_sess_set/get_context inside URI handlers
2018-11-19 04:00:21 +00:00
Anurag Kar
639502ed5d esp_http_server example tests : updated advanced_tests as per API changes 2018-11-19 04:00:21 +00:00
Anurag Kar
aa6066a197 esp_https_server : Docs and API references fixed 2018-11-19 04:00:21 +00:00
Ondřej Hruška
4dd0fa61e9 Add a 'esp_https_server' component allowing to use http_server with OpenSSL 2018-11-19 04:00:21 +00:00
Ondřej Hruška
a10fc02dd9 esp_http_server improvements to allow adding transport layer encryption
Changes:
- renamed `httpd_free_sess_ctx_fn_t` to `httpd_free_ctx_fn_t`
- added a `httpd_handle_t` argument to `httpd_send_func_t` and `httpd_recv_func_t`
- internal function `httpd_sess_get()` is no longer static, as it's used in other
  files besides httpd_sess.c

Bug fixes:
- removed a trailing semicolon from `HTTPD_DEFAULT_CONFIG()`
- fixed issue with failed `select()`, now it automatically closes invalid sockets
  instead of shutting down the entire server

New features:
- `httpd_resp_send()` and `httpd_resp_send_chunk()` now accept -1 as length to use
  `strlen()` internally
- added `httpd_sess_set_ctx()` to accompany `httpd_sess_get_ctx()`
- added a "transport context" to the session structure (next to user context)
- added `httpd_sess_{get,set}_transport_ctx()` to work with this transport context
- added "global user context" and "global transport context" stored in the server
  config (and then the handle); supports a user-provided free_fn
- added a "pending func" to e.g. check for data in the transport layer receive
  buffer
- added functions `httpd_set_sess_{send,recv,pending}_override()` that target
  a session by ID (i.e. not using a request object)
- added `httpd_set_pending_override()`
- added a "open_fn" and "close_fn" - functions called when creating and closing
  a session. These may be used to set up transport layer encryption or some other
  session-wide feature
2018-11-19 04:00:21 +00:00
Deng Xin
5b4e3da759 wifi: add connected event after softap finish 4 way
Background

Softap will send connected event after receive assoc request as before, however, STA didn't connect to softAP if need security. As our mesh design, it will send data packet after receive connected event, so change the current behavior, softAP will send connected event if have encryption
2018-11-19 11:24:42 +08:00
Jiang Jiang Jian
26bcb7f2cf Merge branch 'bugfix/wifi_sta_sniffer_phy_config_bug' into 'master'
wifi: fix wifi sta and sniffer phy config bug

See merge request idf/esp-idf!3566
2018-11-19 10:11:23 +08:00
krzychb
7ef74ee863 Updated 'What you need' picture 2018-11-16 22:18:31 +01:00
Mahavir Jain
e3956787f6 clk: fix regression in clock setting for SPIRAM with 80MHz config
Support for HSPI to output clock for 4M SPIRAM introduced regression
in clock configuration affecting SPIRAM access with 80MHz clock. This
commit fixes the issue.
2018-11-17 00:08:20 +05:30
Ivan Grokhotkov
960c240578 Merge branch 'bugfix/cmake_ut_parsing' into 'master'
cmake: fix for parsing unit test config

See merge request idf/esp-idf!3696
2018-11-16 22:11:14 +08:00
Ivan Grokhotkov
8c9407f22f Merge branch 'bugfix/fat_lock_log' into 'master'
fatfs: Do not log from critical sections

See merge request idf/esp-idf!3683
2018-11-16 21:29:56 +08:00
Renz Christian Bagaporo
364f98b67e cmake: fix for parsing unit test config 2018-11-16 12:00:39 +00:00
Ivan Grokhotkov
96f152341a esp_timer: improve unit test robustness
1. call esp_timer_get_time and ref_clock_get in the same order on
   start and in the loop

2. disable interrupts when calculating delta between ref_clock
   and esp_timer

3. ensure both functions are in cache before calculating the delta
2018-11-16 12:00:39 +00:00
Ivan Grokhotkov
0db8c2e618 Merge branch 'feature/ut_filter_test_groups' into 'master'
unit test: allow filtering tests using TEST_GROUPS

See merge request idf/esp-idf!3695
2018-11-16 19:31:47 +08:00
Ivan Grokhotkov
a55d350f43 Merge branch 'bugfix/adjtime_test2' into 'master'
Resolve ""test for thread safety adjtime and gettimeofday functions" fails randomly"

Closes #37

See merge request idf/esp-idf!3657
2018-11-16 19:21:45 +08:00
Roland Dobai
ad2cdeb476 fatfs: Do not log from critical sections
Logging in the critical section can result in a deadlock when the logger
is redirected to FATFS.

Closes https://github.com/espressif/esp-idf/issues/1693
2018-11-16 11:19:01 +00:00
zhangyanjiao
8be8ea2488 wifi: fix the bug that if station (sleep is enabled) and sniffer are enabled at the same time,
when disable sniffer, station will never enable phy and rf again.

Closes: https://github.com/espressif/esp-idf/issues/2545
2018-11-16 11:16:37 +00:00
Jiang Jiang Jian
6fa2f388ef Merge branch 'bugfix/btdm_controller_disable' into 'master'
Fix two bugs when disable bluetooth controller

See merge request idf/esp-idf!3692
2018-11-16 17:10:37 +08:00
Ivan Grokhotkov
43936ab48a Merge branch 'bugfix/mdns_query_failed_after_init' into 'master'
Fixed: mdns query failed after init

See merge request idf/esp-idf!3480
2018-11-16 16:37:11 +08:00
David Cermak
6309643c1d mdns: added example test for ci runners 2018-11-16 07:22:29 +00:00
David Cermak
d16762a036 mdns: sending search packets also in probing and announcing state
mdns queries did not work properly when send imeadiately after set_hostname, which cuased reinit of pcb and therefore restarted probing, so search packets were blocked until probing finished
closes #2507, closes #2593
2018-11-16 07:22:29 +00:00
Angus Gratton
f2de7602e3 Merge branch 'feature/docs_wireshark_trubleshooting_guide' into 'master'
Added wireshark instruction to provide a common workflow for users submitting diagnostic data for Wi-Fi troubleshooting

See merge request idf/esp-idf!3497
2018-11-16 14:44:58 +08:00
Krzysztof Budzynski
6fbc3c4361 Added wireshark instruction to provide a common workflow for users submitting diagnostic data for Wi-Fi troubleshooting 2018-11-16 14:44:58 +08:00
Renz Bagaporo
63411fc556 tools: implement linker script generation 2018-11-16 12:42:02 +08:00
Konstantin Kondrashov
b00be955ee newlib: Fix UT adjtime 2018-11-16 04:11:55 +00:00
baohongde
ac5a3443a4 components/bt: Some errors in comment 2018-11-16 11:27:22 +08:00
Angus Gratton
b6d7c70238 Merge branch 'doc/console_zh_CN' into 'master'
doc/console: translate console.rst into zh_CN

See merge request idf/esp-idf!3320
2018-11-16 11:21:16 +08:00
Tian Hao
9c9aa4ea4c Fix two bugs when disable bluetooth controller
1. Fix the bug that disable controller suddenly cause crash when ble is working. (585cfba1)
2. Fix the bug that when disable controller, it will cause wifi cannot RX, TX timeout, buffer lack and etc. (f8546145)
2018-11-16 02:42:38 +00:00
Ivan Grokhotkov
7b86247428 unit-test: use TEST_GROUPS to filter tests for psram_vspi and psram_hspi 2018-11-15 12:27:05 +00:00
Ivan Grokhotkov
09e4321e97 unit test: allow filtering tests for configs using TEST_GROUPS 2018-11-15 12:27:05 +00:00
Ivan Grokhotkov
fb56ce7d5c Merge branch 'feature/core_dump_crc' into 'master'
Core Dump CRC

See merge request idf/esp-idf!1290
2018-11-15 15:05:43 +08:00
Alexey Gerenkov
78a7a152d1 esp32: Fixes freezing core dump process when flash write address checks are enabled 2018-11-15 06:13:48 +00:00
Alexey Gerenkov
b152c1020c esp32: Adds logging level to core dump script 2018-11-15 06:13:48 +00:00
Alexey Gerenkov
76e02cadcc esp32: Adds support for core dump format version 2018-11-15 06:13:48 +00:00
Alexey Gerenkov
181a40ae30 esp32: Adds menuconfig option for max tasks number in core dump 2018-11-15 06:13:48 +00:00
Alexey Gerenkov
30e766ee6b esp32: Core dump API to retrieve current core data layout in flash 2018-11-15 06:13:48 +00:00
Alexey Gerenkov
a55cc99f50 esp32: Replaces magic numbers with CRC for core dump in flash 2018-11-15 06:13:48 +00:00
Ivan Grokhotkov
8b5f61eb35 Merge branch 'bugfix/ethernet_fail_twice_init' into 'master'
fix bug of multi-call failure in esp_eth_init

See merge request idf/esp-idf!3673
2018-11-15 12:35:55 +08:00
Jiang Jiang Jian
bbdcff1f45 Merge branch 'bugfix/tw27096_fix_lwip_mbox_free_crash' into 'master'
fix the crash bug caused by sys_mbox_free

See merge request idf/esp-idf!3654
2018-11-15 10:31:35 +08:00
Anton Maklakov
e677bdf5c9 Merge branch 'bugfix/app_template_build' into 'master'
esp-idf-template app: some fixes for the updated template app

See merge request idf/esp-idf!3698
2018-11-15 09:51:00 +08:00
Mahavir Jain
79043882d9 tools: fix cmake build script for sdkconfig test 2018-11-14 22:50:12 +08:00
Anton Maklakov
8e1c91ac7d cmake: fix the creation dummy main to avoid rebuilding 2018-11-14 22:39:54 +08:00
Anton Maklakov
fe5b2c56a4 ci: If there is no sdkconfig, we have to generate one 2018-11-14 19:46:03 +08:00
Ivan Grokhotkov
f1949a59b6 Merge branch 'bugfix/readdir_ut_timeout' into 'master'
spiffs: increase timeout in readdir test

Closes #41

See merge request idf/esp-idf!3687
2018-11-13 22:54:21 +08:00
morris
eec6de57ff ethernet: multi-call failure in esp_eth_init
Because of incomplete state machine, ethernet driver will broken if esp_eth_init is called twice.
Detailed information here: https://ezredmine.espressif.cn:8765/issues/27332
2018-11-13 16:38:45 +08:00
Ivan Grokhotkov
bd34ae0409 Merge branch 'bugfix/ethernet_memory_leak' into 'master'
fix potential memory leak in ethernet driver

See merge request idf/esp-idf!3646
2018-11-13 15:53:47 +08:00
michael
26626dfbf2 spi: add documents explicitly showing the executing core of the ISR
It is an ESP specific FreeRTOS feature that the ISR is always executed
on the core which calls the interrupt register function. In the SPI
driver, the function is always called in the bus initialization
function.

Hence, the ISR will be executed on the core which initialize the driver.

If the core is starved due to higher priority ISRs, or the interrupt is
disabled on the core (spinlock called, etc.), the ISR will not get
executed and SPI transactions will not be handled.

(MINOR CHANGE)

Resolves https://github.com/espressif/esp-idf/issues/2432.
2018-11-13 11:49:31 +08:00
michael
a52ab8ca87 spi_master: modify the error msg a little when over freq limit
The MISO signal will be delayed if the GPIO matrix is enabled.
However, delay also comes from the slave.

Previous code only considers the former case, and assume the frequency
limitations is only violated when GPIO matrix is used.

Now we are able to calculate the freq limit when extenal MISO delay is
given (feature introduced in 9c6c6ec34ab0641ace89aeb9b1a133eb6fae1a18).
The frequency limit is lower when the external MISO delay is large, and
the limit is likely to be violated even with IOMUX.

Resolves https://github.com/espressif/esp-idf/issues/2690.
2018-11-13 11:49:31 +08:00
Ivan Grokhotkov
356fe47ce1 spiffs: increase timeout in readdir test
Timeout of 15 seconds is not sufficient if SPIFFS partition needs to
be formatted, on some of the boards.
2018-11-13 11:41:19 +08:00
liying
08ef71b386 1.Update 8 English cmake files
2.Provide Chinese translation to these 8 cmake files
2018-11-13 11:38:23 +08:00
morris
5fccb73f86 ethernetif: fix potential memory leak
1. If L2_TO_L3_RX_BUF_MODE is not selected, we must assign l2_owner explictly before we call pbuf_free.
2. free intr resource in esp_eth_deinit

Closes https://github.com/espressif/esp-idf/issues/2670
2018-11-13 10:11:48 +08:00
Angus Gratton
beada90b06 Merge branch 'bugfix/cmake_utf_decode' into 'master'
tools: Fix Unicode decode error & indentation error

See merge request idf/esp-idf!3669
2018-11-13 09:54:28 +08:00
Jiang Jiang Jian
ef4a87d62e Merge branch 'bugfix/http_literal_caseinsensitive' into 'master'
Compare case-insensitive URI schemes

See merge request idf/esp-idf!3558
2018-11-12 17:03:06 +08:00
wangfang
df8feaa5c2 Update translation based on review 2018-11-12 16:16:52 +08:00
Ivan Grokhotkov
7efb3926c5 Merge branch 'feature/build_system_multi_target' into 'master'
build system: support for multiple targets (CMake only)

See merge request idf/esp-idf!3499
2018-11-12 15:30:36 +08:00
Jiang Jiang Jian
c7fb749b84 Merge branch 'bugfix/btdm_fix_memory_leak_in_v3.2' into 'master'
Component/bt: fix memory leak in service change char

See merge request idf/esp-idf!3631
2018-11-12 11:27:00 +08:00
Jiang Jiang Jian
ccb3841a9e Merge branch 'feature/btdm_add_vendor_hci_cmd' into 'master'
component/bt: add vendor hci cmd

See merge request idf/esp-idf!3577
2018-11-12 11:26:35 +08:00
wangfang
933dc75294 update translation 2018-11-12 10:15:20 +08:00
Angus Gratton
1e99e61c33 Merge branch 'bugfix/uart_examples_match_template' into 'master'
examples: Fix UART examples to match the template

See merge request idf/esp-idf!3642
2018-11-12 09:19:14 +08:00
Angus Gratton
521fb5d906 Merge branch 'feature/update_board_guides_for_headers' into 'master'
Feature/update board guides for headers

See merge request idf/esp-idf!3590
2018-11-12 09:15:29 +08:00
Natasha
be0123e10e Feature/update board guides for headers 2018-11-12 09:15:29 +08:00
Angus Gratton
3685d325d8 Merge branch 'bugfix/multiple_github_pr' into 'master'
Multiple github PR's

See merge request idf/esp-idf!3665
2018-11-12 09:14:35 +08:00
Angus Gratton
a96deceb27 Merge branch 'feature/cmake_secure_boot_support' into 'master'
CMake : Secure Boot support added

See merge request idf/esp-idf!3522
2018-11-12 09:09:30 +08:00
Ivan Grokhotkov
ccfa134533 build system: support for multiple targets 2018-11-11 21:46:02 +08:00
Ivan Grokhotkov
e2ca285fae confgen.py: allow multiple defaults files 2018-11-11 21:44:35 +08:00
Liu Zhi Fu
4fe3673f35 lwip: fix crash caused by sys_mbox_free
Fix lwip crashed bug caused by sys_mbox_free()
2018-11-11 12:15:51 +08:00
wangfang
a0ab2a15d2 add translation 2018-11-09 19:54:43 +08:00
Jiang Jiang Jian
9859428606 Merge branch 'bugfix/btdm_add_scan_window_interval_check' into 'master'
Component/bt: add scan window and interval check when set scan params

See merge request idf/esp-idf!3581
2018-11-09 19:32:11 +08:00
zwj
baf57b9702 component/bt: add vendor hci cmd 2018-11-09 14:39:04 +08:00
zhiweijian
fb3aa88565 Component/bt: add BLE Blocking APIs 2018-11-09 03:31:08 +00:00
Roland Dobai
90a4e37acd examples: Fix UART examples to match the template 2018-11-08 20:06:03 +01:00
Roland Dobai
f4cfca4353 tools: Fix UTF decode error 2018-11-08 13:02:03 +01:00
Cheppali Umasankar Reddy
f85f64b481 docs: corrected typo event_handler
esp_http_client_config_t has member event_handler not event_handle

Merges https://github.com/espressif/esp-idf/pull/2662
2018-11-08 15:57:13 +05:30
Stephen Bird
0c9f7271a9 Add checks to for CONFIG_MBEDTLS_SSL_ALPN
Merges https://github.com/espressif/esp-idf/pull/2569
2018-11-08 15:57:13 +05:30
Stephen Bird
b5c58557fc bt: Fix bracket warning
Merges https://github.com/espressif/esp-idf/pull/2568
2018-11-08 15:57:12 +05:30
Ondřej Hruška
3ed0f7697d examples: Correct Content-Length in openssl_server example
Before this fix it didn't send all of the response, ending with `</h`

Merges https://github.com/espressif/esp-idf/pull/2535
2018-11-08 15:57:12 +05:30
Damian Reboredo
049c9f7bea esp_http_client: Fix infinite loop on esp_http_client_fetch_headers
error must also be returned if esp_tls_conn_read return 0 because socket  was closed

Merges https://github.com/espressif/esp-idf/pull/2534
2018-11-08 15:57:11 +05:30
Paul Reimer
b358581ab8 heap: Compile heap_task_info.c conditionally on CONFIG_HEAP_TASK_TRACKING in heap CMakeLists.txt
Merges https://github.com/espressif/esp-idf/pull/2498
2018-11-08 15:57:11 +05:30
shawwwn
288d9b75e9 rtc_clk: bugfix: incorrect divider setting in rtc_clk_cpu_freq_to_config()
Merges https://github.com/espressif/esp-idf/pull/2404
2018-11-08 15:57:10 +05:30
mharizanov
17177e352b examples: Fixing possible memory leak, not freeing "run_time" prior to returning
Merges https://github.com/espressif/esp-idf/pull/2367
2018-11-08 15:57:00 +05:30
Jiang Jiang Jian
1b7a4758e3 Merge branch 'bugfix/fix_ble_examples' into 'master'
examples/bluetooth: Miscellaneous fixes in some of the examples

See merge request idf/esp-idf!3549
2018-11-08 18:09:29 +08:00
Jiang Jiang Jian
71f1a34540 Merge branch 'feature/btdm_support_oob_in_SMP' into 'master'
Component/bt: support OOB in SMP

See merge request idf/esp-idf!3496
2018-11-08 16:44:15 +08:00
Angus Gratton
c15e7b18f8 Merge branch 'doc/create_example_zh_CN' into 'master'
translation of creating-examples.rst

See merge request idf/esp-idf!3391
2018-11-08 10:23:14 +08:00
morris
71b9720309 doc/console: translate console.rst into zh_CN 2018-11-07 17:27:15 +08:00
liying
df9d1cc5d4 doc:update_creating_example_cn 2018-11-07 17:18:51 +08:00
morris
5fd76d7490 doc: document of creating-examples_zh_CN
Translated the document of creating-examples into Chinese
2018-11-07 17:17:44 +08:00
Jiang Jiang Jian
05838641ff Merge branch 'bugfix/mesh_start_stop' into 'master'
mesh: update libs

See merge request idf/esp-idf!3569
2018-11-07 14:29:27 +08:00
qiyuexia
2d34a93dc4 mesh: update libs
1. fix ap_loss that occurs when the parent turns off the mesh function and becomes a normal WiFi with a different SSID.
2. add an event MESH_EVENT_NETWORK_STATE that contains information about whether there is a root in the current network.
3. modify the mechanism of mesh IE update.
4. fix a problem in the process of re-voting to select the root, the device that does not meet the conditions of being a root votes for itself.
5. fix an issue that occurs in esp_mesh_recv_toDS() when stopping the mesh.
6. when the user specifies a parent for the device, the device will set the authmode and password of its AP mode to the same value as the specified parent.
7. add two disconnected reason codes MESH_REASON_EMPTY_PASSWORD and MESH_REASON_PARENT_UNENCRYPTED.
2018-11-06 22:55:48 +08:00
Jiang Jiang Jian
b5d7541c09 Merge branch 'bugfix/fix_bt_btc_gatts_arg_deep_copy' into 'master'
components/bt: Fix btc_gatts_arg_deep_copy() and bta_gatts_indicate_handle()

See merge request idf/esp-idf!3058
2018-11-06 21:01:54 +08:00
Hrishikesh Dhayagude
2c353edbc4 components/bt: Fix btc_gatts_arg_deep_copy() and bta_gatts_indicate_handle() 2018-11-06 21:01:54 +08:00
Ivan Grokhotkov
621e316725 Merge branch 'feat/psram_support_hspi' into 'master'
esp32: support to use hspi to output clock for 4M psram

See merge request idf/esp-idf!3377
2018-11-06 20:34:41 +08:00
Anurag Kar
1f6622b2d1 CMake : Secure Boot support added 2018-11-06 17:09:55 +05:30
Jiang Jiang Jian
17c70a4a32 Merge branch 'bugfix/wifi_do_not_load_phy_data_if_fail_to_open_nvs' into 'master'
esp32: do not try to load PHY data if fail to open NVS

See merge request idf/esp-idf!3538
2018-11-06 18:01:58 +08:00
Jiang Jiang Jian
888406231c Merge branch 'bugfix/btdm_fuction_in_isr_is_not_in_iram' into 'master'
components/bt: Put function in isr into iram

See merge request idf/esp-idf!3619
2018-11-06 17:13:34 +08:00
zhiweijian
77668b3912 Component/bt: add scan window and interval check when set scan params 2018-11-06 08:45:25 +00:00
zhiweijian
2e139c7885 Component/bt: fix memory leak in service change char 2018-11-06 08:43:59 +00:00
Ivan Grokhotkov
85d63871ab Merge branch 'feature/partition_api_example' into 'master'
Add partition API examples

See merge request idf/esp-idf!3427
2018-11-06 12:24:27 +08:00
Ivan Grokhotkov
28f1e1597b Merge branch 'bugfix/tickless_idle_single_core' into 'master'
freertos, pm: fix tickless idle not entered in single core mode

See merge request idf/esp-idf!3584
2018-11-06 12:15:03 +08:00
Ivan Grokhotkov
35d1c7b173 Merge branch 'bugfix/freertos_idle_tick_count' into 'master'
freertos: use xTaskQueueMutex to protect tick count

See merge request idf/esp-idf!3478
2018-11-06 12:14:51 +08:00
Ivan Grokhotkov
ddfd62ee66 Merge branch 'bugfix/register_map_LAN8720' into 'master'
ethernet: fix some bugs in Ethernet driver

See merge request idf/esp-idf!3490
2018-11-06 12:13:47 +08:00
Jiang Jiang Jian
ded53bd0ff Merge branch 'bugfix/btdm_allow_a2dp_codec_dynamic_alloc' into 'master'
bugfix/btdm_allow_a2dp_codec_dynamic_allocated

See merge request idf/esp-idf!3598
2018-11-06 11:56:30 +08:00
morris
b6d7675e60 ethernet: fix some bugs in phy&mac driver
1. Original register mapping for LAN8720 has some registers that doesn't exist/support.
So just remove them, and fix the power and init function for LAN8720.
2. GPIO16 and GPIO17 is occupied by PSRAM, so only ETH_CLOCK_GPIO_IN mode is supported in that case if using PSRAM.
3. Fix bug of OTA failing with Ethernet
4. Fix bug of multicast with Ethernet

Closes https://github.com/espressif/esp-idf/issues/2564
Closes https://github.com/espressif/esp-idf/issues/2620
Closes https://github.com/espressif/esp-idf/issues/2657
2018-11-06 11:07:22 +08:00
Ivan Grokhotkov
364f033a49 Merge branch 'feature/vfs_utime' into 'master'
VFS: Implement utime() for FATFS and SPIFFS

See merge request idf/esp-idf!3610
2018-11-06 10:47:02 +08:00
Roland Dobai
fb334baa7c VFS: Implement utime() 2018-11-05 09:54:01 +01:00
kooho
ea963c480c driver(uart):update the comment of uart_set_wakeup_threshold
closes https://github.com/espressif/esp-idf/issues/2627
2018-11-05 13:09:12 +08:00
Ivan Grokhotkov
0716e65955 pm: prevent entering light sleep again immediately after wakeup
When light sleep is finished on one CPU, it is possible that the other
CPU will enter light sleep again very soon, before interrupts on the
first CPU get a chance to run. To avoid such situation, set a flag
for the other CPU to skip light sleep attempt.
2018-11-05 12:18:29 +08:00
Ivan Grokhotkov
22dd3103bd pm: fix entering light sleep in single core mode
Tickless idle/light sleep procedure had a bug in single core mode.
Consider the flow of events:
1. Idle task runs and calls vApplicationIdleHook
2. This calls esp_vApplicationIdleHook, which calls esp_pm_impl_idle_hook, and pm lock for RTOS on the current core is released.
3. Then esp_vApplicationIdleHook calls esp_pm_impl_waiti, which checks that s_entered_light_sleep[core_id]==false and goes into waiti state.
4. Some interrupt happens, calls esp_pm_impl_isr_hook, which takes pm lock for RTOS. PM state goes back to CPU_FREQ_MAX.
5. Once the interrupt is over, vApplicationIdleHook returns, and Idle task continues to run, finally reaching the call to vApplicationSleep.
6. vApplicationSleep does not enter light sleep, because esp_pm_impl_isr_hook has already changed PM state from IDLE to CPU_FREQ_MAX.

This didn’t happen in dual core mode, because waiti state of one CPU was interrupted by CCOMPARE update interrupt from the other CPU, in which case PM lock for FreeRTOS was not taken.

Fix by inverting the meaning of the flag (for convenience) and only setting it to true when vApplicationSleep actually fails to enter light sleep.
2018-11-05 12:18:29 +08:00
Ivan Grokhotkov
ae08bdcc31 freertos: fix compilation warning in single core mode
When tickless idle is enabled
2018-11-05 12:18:29 +08:00
Ivan Grokhotkov
b7841ec313 freertos: use xTaskQueueMutex to protect tick count
Having two different spinlocks is problematic due to possibly
different order in which the locks will be taken. Changing the order
would require significant restructuring of kernel code which is
undesirable.

An additional place where taking xTickCountMutex was needed was in
vApplicationSleep function. Not taking xTickCountMutex resulted in
other CPU sometimes possibly advancing tick count while light sleep
entry/exit was happening. Taking xTickCountMutex in addition to
xTaskQueueMutex has shown a problem that in different code paths,
these two spinlocks could be taken in different order, leading to
(unlikely, but possible) deadlocks.
2018-11-05 03:08:26 +00:00
baohongde
b33cdfc1f5 components/bt: Put function in isr into iram 2018-11-02 16:37:52 +08:00
wangmengyang
7bb83b0056 component/bt: allow dynamic allocation of SBC encoder/decoder buffer used in A2DP to save internal DRAM 2018-10-31 16:11:49 +00:00
Michael (XIAO Xufeng)
ff346f92af psram: add test for 4M psram 2018-10-29 20:26:30 +08:00
Michael (XIAO Xufeng)
20a666fe03 esp32: support to use hspi to output clock for 4MB PSRAM
Resolves https://github.com/espressif/esp-idf/issues/2128.
2018-10-29 20:22:44 +08:00
Michael (XIAO Xufeng)
9b5d0f3322 spi: shown owner of spi host explicitly 2018-10-29 20:22:44 +08:00
Hrishikesh Dhayagude
55dfb79e91 examples/bluetooth: Miscellaneous fixes in some of the examples
This closes:
https://github.com/espressif/esp-idf/issues/2617
https://github.com/espressif/esp-idf/issues/2622

Signed-off-by: Hrishikesh Dhayagude <hrishi@espressif.com>
2018-10-29 11:14:09 +05:30
XiaXiaotian
901e2af793 esp32: do not try to load PHY data if fail to open NVS 2018-10-29 02:24:58 +00:00
Renz Bagaporo
9459526e50 examples: Add partition API examples 2018-10-26 15:46:53 +08:00
Angus Gratton
b47aca1175 doc: Fix doc builds on Windows MINGW32, add some doc build documentation
Using "find" doesn't work properly in MINGW32 Python, even if a MINGW32 find.exe
is on the PATH...
2018-10-26 04:04:56 +00:00
Anton Maklakov
6e6f07ba59 http: Compare case-insensitive URI schemes like as in other places 2018-10-25 21:03:44 +08:00
zhiweijian
4e81705ca2 Component/bt: support OOB in SMP 2018-10-25 07:09:59 +00:00
715 changed files with 30609 additions and 9476 deletions

237
.flake8 Normal file
View 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
View File

@@ -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

View File

@@ -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
View File

@@ -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
View 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
View 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
View File

@@ -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"

View File

@@ -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/"

View File

@@ -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)

View File

@@ -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";

View File

@@ -27,3 +27,5 @@ COMPONENT_SRCDIRS += \
else
COMPONENT_SRCDIRS += gcov
endif
COMPONENT_ADD_LDFRAGMENTS += linker.lf

View 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)

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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);
}

View File

@@ -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)

View 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"

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View 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;
}

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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
View 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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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(&not_app_pos, &app_desc1));
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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()

View File

@@ -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")

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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 */

View File

@@ -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()

View File

@@ -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

View File

@@ -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)

View File

@@ -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) */
/**

View File

@@ -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)

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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 */
};

View File

@@ -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 */

View File

@@ -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) {

View File

@@ -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

View File

@@ -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

View File

@@ -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) */
}

View File

@@ -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));
}
/*******************************************************************************

View File

@@ -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) {

View File

@@ -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, &param, 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);

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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)) { */

View File

@@ -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__);
}
}

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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];

View File

@@ -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) */

View File

@@ -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);
}
}
/*******************************************************************************

View File

@@ -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

View File

@@ -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
}

View File

@@ -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 */
/****************************************************************************

View File

@@ -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

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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()

View File

@@ -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

View File

@@ -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 {

View File

@@ -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()

View File

@@ -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

View File

@@ -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 {

View File

@@ -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;
}

View File

@@ -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
*

View File

@@ -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;

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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

View File

@@ -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
*/

View File

@@ -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.

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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)) {

View File

@@ -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);

View File

@@ -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()

View 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);

View 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());
}

View 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);
}

View File

@@ -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

View File

@@ -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 ) );

View File

@@ -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