Compare commits

..

143 Commits

Author SHA1 Message Date
Angus Gratton
6313ea0088 Merge branch 'bugfix/fix_psram_eid_v3.0' into 'release/v3.0'
psram: fix psram eid (backport v3.0)

See merge request idf/esp-idf!3463
2018-10-12 11:41:13 +08:00
Jiang Jiang Jian
735f02c4b7 Merge branch 'bugfix/btdm_bt_mux_active_after_deinit_v3.0' into 'release/v3.0'
component/bt : fix bug that bt mux module is still active even after disable

See merge request idf/esp-idf!3341
2018-10-11 18:49:52 +08:00
Jiang Jiang Jian
d6df10edaf Merge branch 'bugfix/several_bugfix_about_ba_session_setup_v3.0' into 'release/v3.0'
esp32: several fixes about BA session setup (backport v3.0)

See merge request idf/esp-idf!3455
2018-10-11 11:42:22 +08:00
Angus Gratton
d02d2d5170 Merge branch 'fix/spi_master_cmd_addr_lsbfirst_v3.0' into 'release/v3.0'
spi_master: fix the command and address field when LSB_FIRST enabled (Backport v3.0)

See merge request idf/esp-idf!3444
2018-10-11 06:28:38 +08:00
chenjianqiang
80c013ee5a bugfix(psram): fix the error that two macro definitions are undeclared
1. add definition of FLASH_ID_GD25LQ32C
2. modify DPORT_SPI3_CLK_EN as DPORT_SPI_CLK_EN_2
2018-10-10 20:21:01 +08:00
Tian Hao
f2347e5729 component/bt : fix bug that bt mux module is still active even after disable
Resolve the problem following:
    1. when wifi and bluetooth coex, after call esp_bt_controller_disable(), it may cause WiFi cannot TX/RX packets.
       Such as, it cause wifi disconnect, can't probe any SSIDs or etc.
2018-10-10 15:54:13 +08:00
chenjianqiang
8cfb0b207a bugfix(psram): fix psram driver
1. remove use EID to distinguish psram voltage
2. 1V8 64Mbit psram and 3V3 64Mbit psram use the same psram driver(standard spi interface)
3. set cs hold time register as 1
2018-10-10 15:51:18 +08:00
Wangjialin
6d253b4394 feature(psram): add support for 64MBit psram of 1.8v and 3.3v.
1. Add reading psram EID.
2. Configure different clock mode for different EID.
3. add API to get psram size and voltage.
4. Remove unnecessary VSPI claim.

For 32MBit@1.8V and 64MBit@3.3V psram, there should be 2 extra clock cycles after CS get high level.
For 64MBit@1.8 psram, we can just use standard SPI protocol to drive the psram. We also need to increase the HOLD time for CS in this case.

EID for psram:
32MBit 1.8v: 0x20
64MBit 1.8v: 0x26
64MBit 3.3v: 0x46
2018-10-10 15:43:30 +08:00
Angus Gratton
50dc31103f Merge branch 'bugfix/bootloader_gen_secure_boot_digest_v3.0' into 'release/v3.0'
bootloader: Fix secure boot digest generation for image length where (len%128 < 32) (backport v3.0)

See merge request idf/esp-idf!3426
2018-10-10 14:56:37 +08:00
Liu Zhi Fu
3af5384a24 esp32: several fixes about BA session setup
1. Fix the bug that ESP32 will reject the retry AddBA request frame
   if AddBA response frame is failed to sent by WiFi LMAC
2. Fix the bug that AddBA request retrys too frequently
3. Forbid BA session setup for VO queue related TID
2018-10-10 13:51:13 +08:00
Angus Gratton
283c47cbba bootloader: Fix secure boot digest generation for image length where (len%128 < 32) 2018-10-10 11:14:44 +11:00
michael
4ae01aed27 test: modify the command/address test a bit to test the LSBFIRST feature 2018-10-09 00:34:13 +08:00
michael
a5a692ef8c spi: move gpio direction config to common func for coinsistence
(MINOR CHANGE)
2018-10-08 19:04:38 +08:00
Michael (XIAO Xufeng)
3c532e4532 spi_master: fix the command and address field when LSB_FIRST enabled
Resolves https://github.com/espressif/esp-idf/issues/2444.
2018-10-08 19:04:37 +08:00
Angus Gratton
2e8d7fa36d Merge branch 'bugfix/disable_coding_scheme_security_features_v3.0' into 'release/v3.0'
bootloader: Don't enable secure boot or flash encryption for 3/4 Coding Scheme (v3.0)

See merge request idf/esp-idf!3422
2018-10-04 16:37:07 +08:00
Angus Gratton
674cf7520e esptool: Update to v2.5.1
Release notes: https://github.com/espressif/esptool/releases/tag/v2.5.1

Needed to no longer burn keys if 3/4 Coding Scheme is enabled.
2018-10-02 10:03:13 +10:00
Angus Gratton
c990ca4e20 bootloader: Don't enable secure boot or flash encryption for 3/4 Coding Scheme 2018-10-02 10:01:20 +10:00
Jiang Jiang Jian
5b061a0530 Merge branch 'bugfix/wifi_make_esptouch_channel_switch_thread_safe_v3.0' into 'release/v3.0'
esp32: make esp-touch channel switch thread safe

See merge request idf/esp-idf!3354
2018-09-26 19:55:14 +08:00
XiaXiaotian
43d2f940b2 esp32: make esp-touch channel switch thread safe
Fix the crash issue when esp-touch is in progress.
2018-09-25 11:20:29 +08:00
Jiang Jiang Jian
a5533a0b5d Merge branch 'bugfix/fix_the_bug_create_socket_fail_v3.0' into 'release/v3.0'
lwip: fix the bug that failed to create socket (backport v3.0)

See merge request idf/esp-idf!3312
2018-09-20 18:44:30 +08:00
Liu Zhi Fu
5f56d65405 lwip: fix the bug that failed to create socket
Fix the bug that failed to create nonblocking TCP or UDP socket after several times socket create/close
2018-09-19 16:50:39 +08:00
Angus Gratton
fcf9c3d882 Merge branch 'fix/spi_slave_free_cs_v3.0' into 'release/v3.0'
spi_slave: fix the issue rx dma get broken by master unexpected transaction (backport v3.0)

See merge request idf/esp-idf!3293
2018-09-18 08:08:17 +08:00
michael
a7ad8bc873 spi_slave: fix the issue rx dma get broken by master unexpected transaction 2018-09-18 00:49:25 +08:00
Jiang Jiang Jian
438c9bcb35 Merge branch 'bugfix/tw24884_fix_ampdu_sequence_compitable_issue_v3.0' into 'release/v3.0'
esp32: fix AMPDU RX sequence compitability issue (backport v3.0)

See merge request idf/esp-idf!3281
2018-09-17 18:58:52 +08:00
Liu Zhi Fu
328e689cf1 esp32: fix AMPDU RX sequence compitability issue
Fix AMPDU RX sequence compitability issue when connecting to some special APs, such as Mercury, Fast etc.
2018-09-17 14:51:00 +08:00
Jiang Jiang Jian
13732c5753 Merge branch 'bugfix/tw24694_dns_request_no_reply_v3.0' into 'release/v3.0'
lwip: add code for sending gratuitous ARP periodically (backport v3.0)

See merge request idf/esp-idf!3240
2018-09-16 15:18:44 +08:00
Angus Gratton
2544d737c5 Merge branch 'bugfix/ci_github_deploy_v30' into 'release/v3.0'
ci: Fix spurious pipeline failure when deploying a tag to GitHub (backport v3.0)

See merge request idf/esp-idf!3221
2018-09-13 15:36:39 +08:00
zhangyanjiao
8bd10b4808 lwip: add code for sending gratuitous ARP periodically 2018-09-11 15:24:21 +08:00
Jiang Jiang Jian
a975ba6cef Merge branch 'bugfix/fix_the_bug_when_gateway_zero_v3.0' into 'release/v3.0'
esp32: fix the bug that SYSTEM_EVENT_STA_GOT_IP is forbidden when gateway is 0.0.0.0 (backport v3.0)

See merge request idf/esp-idf!3239
2018-09-11 12:07:35 +08:00
zhangyanjiao
9189e1006d esp32: fix the bug that SYSTEM_EVENT_STA_GOT_IP is forbidden when gateway is 0.0.0.0 2018-09-11 11:05:51 +08:00
Angus Gratton
bc8a84e9e4 ci: Fix spurious pipeline failure when deploying a tag to GitHub
Everything succeeds, but because [ -z ${CI_COMMIT_TAG} ] on the last line returns non-zero, it
fails the job.
2018-09-07 15:24:23 +08:00
Jiang Jiang Jian
efe499113c Merge branch 'bugfix/btdm_discovery_ble_v3.0' into 'release/v3.0'
component/bt : fix bug that set discovery mode will stop ble adv

See merge request idf/esp-idf!3190
2018-09-06 14:19:40 +08:00
Jiang Jiang Jian
7331ee2af2 Merge branch 'bugfix/tw25969_esp_derive_local_mac_missing_v3.0' into 'release/v3.0'
defination: fix the bug that esp_derive_local_mac() defination missing (backport v3.0)

See merge request idf/esp-idf!3201
2018-09-05 17:21:36 +08:00
zhangyanjiao
f323fe5fee defination: fix the bug that esp_derive_local_mac() defination missing 2018-09-05 14:45:48 +08:00
Tian Hao
291c4a4fd3 component/bt : fix bug that set discovery mode will stop ble adv
As the bluedroid original implmentation of BR/EDR and BLE dual mode about discovery mode,
when set discovery mode for BR/EDR, it will stop ble advertising.

Reference to https://github.com/espressif/esp-idf/issues/2306
2018-09-04 20:30:43 +08:00
Jiang Jiang Jian
9b1bd0a09f Merge branch 'bugfix/btdm_find_remote_service_by_uuid_always_return_success_v3.0' into 'release/v3.0'
component/bt: Fix bug of SDP find services by uuid always return success (backport 3.0)

See merge request idf/esp-idf!3165
2018-09-04 19:21:47 +08:00
Jiang Jiang Jian
0ba566e0c6 Merge branch 'bugfix/btdm_update_private_address_v3.0' into 'release/v3.0'
component/bt: Update BLE private address after it's private address interval (backport 3.0)

See merge request idf/esp-idf!3171
2018-09-04 19:21:21 +08:00
Jiang Jiang Jian
405b1986c2 Merge branch 'bugfix/btdm_controller_deinit_v3.0' into 'release/v3.0'
bt : fix bug that bluetooth controller init/disable/enable/disable may cause exception

See merge request idf/esp-idf!3149
2018-09-04 15:07:08 +08:00
baohongde
7d2baa3c3d component/bt: Update BLE private address after it's private address interval (backport 3.0)
A cherry-pick of MR !2987
2018-09-03 14:31:40 +08:00
baohongde
530dedbc2d component/bt: Fix bug of SDP find services by uuid always return success (backport 3.0)
A cherry-pick of MR !3036
2018-09-03 11:57:53 +08:00
Jiang Jiang Jian
7c42b55e45 Merge branch 'bugfix/wifi_reorder_mpdu_as_ampdu_v3.0' into 'release/v3.0'
esp32: reorder MPDU as AMPDU (backport v3.0)

See merge request idf/esp-idf!3141
2018-08-31 02:02:14 +08:00
XiaXiaotian
f4022111c8 esp32: reorder MPDU as AMPDU
Some APs transmit AMPDU and MPDU by turns. Moreover, the sequence
    numbers of AMPDU and MPDU are out of order, e.g. MPDU(1253) -
    AMPDU(1251, 1252) - MPDU(1254) - AMPDU(1255, 1256). In order to
    receive both AMPDU and MPDU in order, MPDU must be reordered with
    AMPDU.
2018-08-30 11:59:31 +08:00
Jiang Jiang Jian
53dcd1202d Merge branch 'bugfix/fix_probable_mem_leak_v3.0' into 'release/v3.0'
components/bt: Fix a probable memory leak for BTA_GATTS_CONF_EVT event (backport v3.0)

See merge request idf/esp-idf!3105
2018-08-29 23:09:54 +08:00
Jiang Jiang Jian
ef2c0e8b3e Merge branch 'bugfix/autoip_compilation_backportv3.0' into 'release/v3.0'
LWIP AutoIP Compilation Fixed by defining IP_IS_V4_VAL() (backport v3.0)

See merge request idf/esp-idf!3122
2018-08-29 22:54:42 +08:00
Jiang Jiang Jian
7515dc97b6 Merge branch 'bugfix/btdm_a2dp_sink_pcm_buf_size_for_v3.0' into 'release/v3.0'
bugfix/btdm_a2dp_sink_pcm_buf_size_for_v3.0(backport v3.0)

See merge request idf/esp-idf!3118
2018-08-29 10:19:48 +08:00
Tian Hao
a9c1820385 bt : fix bug that bluetooth controller init/disable/enable/disable may cause exception
1. when one task do deinit/init/disable/enable, especially different cpu
core, it may cause controller crash in ISR handler
2. fix while BLE is scanning, bluetooth controller is disabled cause BLE
scan is not abort.
2018-08-28 21:10:17 +08:00
Jiang Jiang Jian
8fdf200932 Merge branch 'bugfix/btdm_fix_get_error_adv_sometimes_v3.0' into 'release/v3.0'
Component/bt: fix get error adv packet sometimes (backport v3.0)

See merge request idf/esp-idf!3084
2018-08-28 20:04:30 +08:00
Piyush Shah
4cde212817 LWIP AutoIP Compilation Fixed by defining IP_IS_V4_VAL() 2018-08-28 15:23:21 +05:30
zhiweijian
6751373411 Component/bt: fix get error adv packet sometimes 2018-08-28 14:05:44 +08:00
wangmengyang
27fd353752 component/bt: bugfix for incorrect computation of PCM data buffer size in A2DP sink 2018-08-28 11:16:33 +08:00
Jiang Jiang Jian
97603b1d59 Merge branch 'bugfix/btdm_check_slave_feature_before_set_afh_for_v3.0' into 'release/v3.0'
bugfix/btdm_check_slave_feature_before_set_afh_for_v3.0(backport v3.0)

See merge request idf/esp-idf!3104
2018-08-28 10:42:17 +08:00
Hrishikesh Dhayagude
32fd3a3215 components/bt: Fix a probable memory leak for BTA_GATTS_CONF_EVT event (backport v3.0)
Multiple modules register their callback BTA_GATTS_AppRegister().

If any of the callbacks do not free the allocated pointer in
BTA_GATTS_CONF_EVT event, then this can result in memory leak.

So, free the pointer after the callback function is called and remove
the calls to free in the callback functions as it is now not required

Signed-off-by: Hrishikesh Dhayagude <hrishi@espressif.com>
2018-08-27 11:57:14 +05:30
Jiang Jiang Jian
d1c6eb9574 Merge branch 'bugfix/fix_several_wifi_bugs_v3.0' into 'release/v3.0'
esp32: update wifi lib to fix several WiFi bugs (backport v3.0)

See merge request idf/esp-idf!3097
2018-08-27 14:24:11 +08:00
wangmengyang
5ee2d3b90d component/bt: check support of AFH in remote slave device's LM feature when determine whether to send LMP_set_AFH 2018-08-27 11:39:43 +08:00
Jiang Jiang Jian
8618b452f7 Merge branch 'bugfix/btdm_fix_memory_leak_in_security_server_v3.0' into 'release/v3.0'
component/bt: fix memory leak in security server (backport v3.0)

See merge request idf/esp-idf!3016
2018-08-27 10:20:13 +08:00
Angus Gratton
39fb5d7150 Merge branch 'fix/spi_dma_config_in_iram_v3.0' into 'release/v3.0'
spi: fix the issue that spi cannot be used when flash is disabled (backport v3.0)

See merge request idf/esp-idf!3076
2018-08-27 08:13:55 +08:00
Liu Zhi Fu
5dafcf9363 esp32: update wifi lib to fix several WiFi bugs
Fix following WiFi bugs:
1. Shouldn't scan when connect
2. Check beacon length in modem sleep
3. Fix the bug that AP may deauth wrong station when inactivity timer expires
4. Fix the bug that WiFi assert the system when receiving empty MCS in association response frame
2018-08-26 13:05:59 +08:00
Jiang Jiang Jian
3f72a12d97 Merge branch 'bugfix/btdm_fix_CI_scan_case_fail' into 'release/v3.0'
Component/bt: fix CI scan case failed in v3.0

See merge request idf/esp-idf!3074
2018-08-25 16:54:37 +08:00
Jiang Jiang Jian
af4f2ace84 Merge branch 'bugfix/fix_crash_for_http2_request_v3.0' into 'release/v3.0'
fix the crash when http2_request example send/recv fail (backport v3.0)

See merge request idf/esp-idf!3073
2018-08-24 14:01:26 +08:00
Jiang Jiang Jian
e8ad0415cc Merge branch 'bugfix/timer_oneshot_timeout_twice_v3.0' into 'release/v3.0'
component/bt: Some timer oneshot will timeout twice (backport v3.0)

See merge request idf/esp-idf!3064
2018-08-24 14:01:06 +08:00
Jiang Jiang Jian
ac253274a0 Merge branch 'bugfix/btdm_fix_sc_mitm_bond_failed_in_smp_for_iphones_v30' into 'release/v3.0'
Component/bt:  fix SC_MITM_BOND failed in smp for iphones (backport v3.0)

See merge request idf/esp-idf!3045
2018-08-24 11:37:00 +08:00
Jiang Jiang Jian
972107fbc9 Merge branch 'bugfix/sync_ap_loss_to_release_3_0' into 'release/v3.0'
wifi: bugfix of ap loss

See merge request idf/esp-idf!3072
2018-08-24 11:15:41 +08:00
Jiang Jiang Jian
5e9267f846 Merge branch 'bugfix/tw23404_dhcp_NAK_issue_v3.0' into 'release/v3.0'
lwip: optimize LWIP timer

See merge request idf/esp-idf!2964
2018-08-24 11:14:32 +08:00
Michael (XIAO Xufeng)
cfed7c84ce spi: fix the issue that spi cannot be used when flash is disabled
The dma configuration function called in the ISR should be put into the IRAM.

Fixes https://github.com/espressif/esp-idf/issues/2307.
2018-08-24 11:07:18 +08:00
zhiweijian
3870836a90 Component/bt: fix CI scan case failed in v3.0 2018-08-24 10:57:16 +08:00
zhangyanjiao
19f319a55d fix the crash when http2_request example send/recv fail 2018-08-24 10:06:45 +08:00
Deng Xin
0806617971 wifi: bugfix of ap loss 2018-08-23 21:54:15 +08:00
Jiang Jiang Jian
4f346169ff lwip: optimize LWIP timer
Port LWIP timer implementation in LWIP v2.0.3 to IDF v3.0
2018-08-23 20:20:24 +08:00
baohongde
00b895680e component/bt: Some timer oneshot will timeout twice (backport v3.0)
A cherry-pick of MR !2979
2018-08-23 11:02:59 +08:00
Jiang Jiang Jian
997d291d85 Merge branch 'bugfix/btdm_fix_get_bond_list_error_when_connection_with_no_bond_v30' into 'release/v3.0'
Component/bt: fix get bond list error when connection with no bond(backport v3.0)

See merge request idf/esp-idf!3042
2018-08-23 10:38:04 +08:00
Jiang Jiang Jian
5f2660e1f5 Merge branch 'bugfix/btdm_fix_version_excahnge_issue_v30' into 'release/v3.0'
Component/bt: fix version exchange issue(backport v3.0)

See merge request idf/esp-idf!3046
2018-08-23 10:36:39 +08:00
Jiang Jiang Jian
451e4cf3b0 Merge branch 'bugfix/btdm_fix_no_adv_packet_v30' into 'release/v3.0'
component/bt: fix no adv packets(backport v3.0)

See merge request idf/esp-idf!3043
2018-08-22 18:13:28 +08:00
Angus Gratton
132b439359 Merge branch 'bugfix/ulp_fixes_v3.0' into 'release/v3.0'
ULP fixes (backport v3.0)

See merge request idf/esp-idf!3002
2018-08-22 13:37:16 +08:00
Angus Gratton
04ce9050b6 Merge branch 'doc/versions_v3.0' into 'release/v3.0'
docs: Add version-specific include files, version documentation (backport v3.0)

See merge request idf/esp-idf!2975
2018-08-22 13:36:36 +08:00
zhiweijian
27f8ee6b97 Component/bt: fix memory leak in security server 2018-08-21 16:09:04 +08:00
zhiweijian
1c001ecd7a Component/bt: fix version exchange issue
- Android 7.0 version issue
- version exchange late in some phones
- can not get version in smp
2018-08-21 14:55:51 +08:00
zhiweijian
a961984f73 Component/bt: fix SC_MITM_BOND failed in smp for iphones 2018-08-21 14:46:20 +08:00
zwj
2d53799372 component/bt: fix no adv packets 2018-08-21 14:10:36 +08:00
zhiweijian
7275490322 Component/bt: fix get bond list error when connection with no bond 2018-08-21 14:05:14 +08:00
Jiang Jiang Jian
f6a7cda7b6 Merge branch 'bugfix/btdm_ecdh_public_key_not_check_v3.0' into 'release/v3.0'
Bugfix/btdm ecdh public key not check v3.0 (backport v3.0)

See merge request idf/esp-idf!2992
2018-08-14 09:54:10 +08:00
Ivan Grokhotkov
d88b74064d docs: update esp32ulp-binutils download link 2018-08-13 23:34:06 +03:00
Ivan Grokhotkov
b9f6b579f1 ulp: add documentation for JUMPS instruction conditions
Hardware implements conditions LE, LT, GE, and conditions EQ and GT
are implemented in the assembler by emitting two JUMPS instructions
with other conditions.
2018-08-13 23:34:06 +03:00
Ivan Grokhotkov
72ad5a142b ulp: add tests for jumps instruction 2018-08-13 23:34:06 +03:00
Ivan Grokhotkov
d07f9dfbb2 ulp: fix ULP binary format documentation
Fix incorrect offset value (4+2+2+2+2=12) of arbitrary data in ULP
binary format.

Closes https://github.com/espressif/esp-idf/issues/1705.
2018-08-13 23:34:06 +03:00
Ivan Grokhotkov
33250ea678 ulp: use += instead of := when setting component vars
Component which includes component_ulp_common.mk may also need to set
some of the same COMPONENT_XXX variables. Logically, we should combine
the lists of files to embed, ldflags, extra include dirs, etc.

Fixes https://github.com/espressif/esp-idf/issues/2157.
2018-08-13 23:34:06 +03:00
Ivan Grokhotkov
300657162b ulp: fix missing include in esp32/ulp.h header
ulp.h uses some register base addresses, so needs to include soc.h
2018-08-13 23:34:06 +03:00
Ivan Grokhotkov
7fcc76fa06 ulp: fix calculation or ulp_run argument
The argument to ulp_run should be expressed in 32-bit words. Both the
address of ulp_entry and RTC_SLOW_MEM already are uint32_t*, so their
difference is the difference in addresses divided by sizeof(uint32_t).
Therefore the extra division by sizeof(uint32_t) is not needed.
2018-08-13 23:34:06 +03:00
Ivan Grokhotkov
85fbaaf37a docs: fix line endings of ULP docs 2018-08-13 23:34:06 +03:00
Ivan Grokhotkov
da97846483 docs/ulp: fix instruction fetch and execution times 2018-08-13 23:30:07 +03:00
yulong
7aa29a0dbb component/bt: Fixed the vulnerability released by Bluetooth org when using public key not check in the process of ECDH encryption. 2018-08-13 19:46:04 +08:00
Angus Gratton
516d9f0eae Merge branch 'bugfix/spiffs_readdir_recursion_v3.0' into 'release/v3.0'
SPIFFS: fix stack overflow in readdir_r due to recursion (backport v3.0)

See merge request idf/esp-idf!2877
2018-08-13 16:26:31 +08:00
Angus Gratton
bb5789b6ee docs: Move version-related includes to run in sphinx-build not make
Means they show up on ReadTheDocs(!)
2018-08-13 17:32:44 +10:00
Ivan Grokhotkov
f206bc51ff spiffs: add test case for readdir_r with large number of files
Ref. https://esp32.com/viewtopic.php?f=13&t=6486
2018-08-12 16:53:04 +00:00
Konstantin Klitenik
ecc82a3c27 Fix stackoverflow due to recursion in vfs_spiffs_readdir_r 2018-08-12 16:53:04 +00:00
Jiang Jiang Jian
6746be5a09 Merge branch 'bugfix/wifi_fix_next_beacon_and_dtim_time_update_issue' into 'release/v3.0'
esp32: fix next beacon and dtim time update issue when beacon is not

See merge request idf/esp-idf!2970
2018-08-10 21:03:27 +08:00
XiaXiaotian
007d884a85 esp32: fix next beacon and dtim time update issue when beacon is not
received for more than one beacon interval
2018-08-10 11:36:59 +08:00
Angus Gratton
998416c54b README: Add version-specific links
Make it clearer how the README fits in with the docs.
2018-08-10 01:03:08 +00:00
Angus Gratton
873c515ee3 docs: Add version-specific include files, version documentation
* "git clone" command and a small version header are generated
  depending on git properties.
* Add Versions page with details about each version
* Make it clear using master branch is living on the "bleeding
  edge"
2018-08-10 01:03:08 +00:00
Jiang Jiang Jian
ee295c175b Merge branch 'feature/support_for_XM25QU64A_v3.0' into 'release/v3.0'
feature(flash): set QIO mode for XM25QU64A(1V8_8MB_flash) (backport v3.0)

See merge request idf/esp-idf!2813
2018-08-08 20:36:39 +08:00
Angus Gratton
25ed0aa9bb Merge branch 'bugfix/tw24252_fix_nonblocking_tcp_close_issue_v3.0' into 'release/v3.0'
lwip: fix nonblocking tcp close issue (backport v3.0)

See merge request idf/esp-idf!2943
2018-08-08 16:33:07 +08:00
chenjianqiang
4b4614ffb1 feature(flash): support for QIO mode of XM25QU64A 2018-08-08 03:39:19 +00:00
Angus Gratton
21adda8777 Merge branch 'bugfix/ci_github_deploy_v30' into 'release/v3.0'
ci: Simplify github deployment (backport v3.0)

See merge request idf/esp-idf!2875
2018-08-08 07:25:34 +08:00
Jiang Jiang Jian
8ff0f4a616 Merge branch 'bugfix/update_libphy_to_improve_11n_stability' into 'release/v3.0'
esp32: update libphy.a to v3663 to improve 11n TX stability (backport v3.0)

See merge request idf/esp-idf!2937
2018-08-07 20:51:29 +08:00
Liu Zhi Fu
08946da2db lwip: fix nonblocking tcp close issue
Fix assert issue causes by closing nonblocking tcp socket.
2018-08-07 14:31:49 +08:00
Jiang Jiang Jian
90b8a42349 Merge branch 'bugfix/btdm_lmp_trans_coll_state_uncleared_for_v3.0' into 'release/v3.0'
bugfix/btdm_lmp_trans_coll_state_uncleared(backport v3.0)

See merge request idf/esp-idf!2917
2018-08-06 18:39:08 +08:00
Liu Zhi Fu
3c92cd607b esp32: update libphy.a to v3663 to improve 11n TX stability
Fix the bug that WiFi 11n TX may fail in some AP or CMW500 3.5 version
This fix can improve the 11n stability
2018-08-06 17:32:10 +08:00
Angus Gratton
4f3008bfd8 ci: Simplify github deployment
CI_COMMIT_REF_NAME lets us use a single line to git push
2018-08-06 16:30:43 +10:00
Jiang Jiang Jian
dd1fa7c502 Merge branch 'bugfix/autoip_compilation' into 'release/v3.0'
LWIP AutoIP Compilation Fixed by defining IP_IS_V4_VAL()

See merge request idf/esp-idf!2926
2018-08-05 07:30:43 +08:00
wangmengyang
50556b8acb component/bt: bugfix for uncleared LMP transaction collision state after rejecting sniff request from slave
This bug will cause other following LMP transactions, such as (e)SCO link set up transaction to fail
2018-08-04 16:24:37 +00:00
zhangyanjiao
9da0541020 LWIP AutoIP Compilation Fixed by defining IP_IS_V4_VAL() 2018-08-04 15:25:05 +00:00
Jiang Jiang Jian
ab74be7abe Merge branch 'bugfix/btdm_a2dp_disconnect_reason_for_v3.0' into 'release/v3.0'
bugfix/btdm_a2dp_disconnect_reason(backport v3.0)

See merge request idf/esp-idf!2928
2018-08-04 11:58:26 +08:00
wangmengyang
b5c45a4d46 component/bt: retrieve disconnection reason in AVDT when ACL-U link is disconnected 2018-08-03 15:42:55 +08:00
Angus Gratton
225e98dcee Merge branch 'bugfix/py3_link_roles' into 'release/v3.0'
docs: Add build support for python3 (backport v3.0)

See merge request idf/esp-idf!2919
2018-08-03 15:31:12 +08:00
Anuj Deshpande
d66b227e07 docs: Add build support for python3 2018-08-02 12:59:31 +02:00
Jiang Jiang Jian
ce67428c56 Merge branch 'bugfix/add_compatible_of_ccmp_encryption_v_3_0' into 'release/v3.0'
wifi: add compatible to ccmp encryption (backport v3.0)

See merge request idf/esp-idf!2899
2018-08-02 17:47:48 +08:00
Angus Gratton
054e82b4b3 Merge branch 'test/workaround_ci_failures_v3.0' into 'release/v3.0'
CI: erase nvs partition before test (backport v3.0)

See merge request idf/esp-idf!2870
2018-08-01 17:02:50 +08:00
Jiang Jiang Jian
7d4a9db191 Merge branch 'bugfix/btdm_fix_slave_cant_receive_long_packets_in_smp_for_v3.0' into 'release/v3.0'
component/bt: fix slave cant receive long packets in smp for v3.0

See merge request idf/esp-idf!2857
2018-08-01 14:40:05 +08:00
Deng Xin
39f97bb4e8 wifi: add compatible to ccmp encryption 2018-07-31 21:07:46 +08:00
He Yin Ling
8f81157432 CI: add stage host_test:
1. Add `host_test` stage for test jobs running on host.
2. Rename stage `test` to `integration_test`.
2018-07-29 00:26:38 +08:00
He Yin Ling
5141570f24 CI: minor optimize of CI config file:
1. set shorter expire time for artifacts
2. set dependency for example test jobs, to limit the artifacts it downloads
2018-07-29 00:20:15 +08:00
He Yin Ling
f86d512672 CI: remove test report stage:
Test report is not used as expected:

1. we rarely download and use test report
2. current test report method doesn't handle large amount data well,
   need to be replaced by other methods

Test report also make test jobs allow to fail. It breaks the
original flow of Gitlab CI and make user confused.
2018-07-29 00:17:25 +08:00
Jiang Jiang Jian
ab341359f5 Merge branch 'bugfix/ampdu_duplicate_v3.0' into 'release/v3.0'
Wifi: fix ampdu duplicate issue (backport v3.0)

See merge request idf/esp-idf!2804
2018-07-28 17:56:25 +08:00
He Yin Ling
f98da26b38 CI: erase nvs partition before test:
Latest NVS partition bin can't be parsed by old IDF revision. Need to erase before test.
2018-07-28 15:18:10 +08:00
zwj
d0cd624d2b component/bt: fix slave cant receive long packets in smp 2018-07-26 11:39:47 +08:00
Ivan Grokhotkov
c8c4bd099e Merge branch 'bugfix/fix_uart_timeout_bug_when_enable_reftick_v3.0' into 'release/v3.0'
driver(uart): fix uart timeout bug when enable reftick for release v3.0

See merge request idf/esp-idf!2811
2018-07-24 13:16:54 +08:00
Angus Gratton
36c14cf214 Merge branch 'bugfix/add_queueset_critical_sections_v3.0' into 'release/v3.0'
freertos: Add critical sections to queue sets (backport v3.0)

See merge request idf/esp-idf!2788
2018-07-20 10:03:59 +08:00
hou wen xiang
a7c9cf3a6b driver(uart): Fix uart time_out bug when using ref_tick for release v3.0 2018-07-18 17:35:59 +08:00
Jiang Jiang Jian
9aee394dc6 Merge branch 'bugfix/tw23835_add_source_ip_route_for_unicast_v3.0' into 'release/v3.0'
lwip: add source ip based route for unicast packet (backport v3.0)

See merge request idf/esp-idf!2781
2018-07-18 17:34:19 +08:00
chenyudong
05eb9d155f Wifi: fix ampdu duplicate issue
fix ampdu duplicate issue
2018-07-18 14:51:29 +08:00
Jiang Jiang Jian
0669fe8f02 Merge branch 'bugfix/tw23835_add_source_ip_route_for_unicast_v3.0' into 'release/v3.0'
lwip: add source ip based route for unicast packet (backport v3.0)

See merge request idf/esp-idf!2781
2018-07-17 14:12:13 +08:00
Darian Leung
cabb97f9a9 freertos: Add critical sections to queue sets.
Queue sets are not SMP safe. This commit adds
critical sections to queue sets. Unit tests for
queue sets have also been added.
2018-07-16 19:30:46 +08:00
Liu Zhi Fu
41b1db4dc6 lwip: add source ip based route for unicast packet
Add source IP based route for unicast packets forwarding.
2018-07-16 17:11:01 +08:00
Jiang Jiang Jian
8bc76b3684 Merge branch 'bugfix/tw23667_tcp_pcb_purge_assert_v3.0' into 'release/v3.0'
lwip: fix the assertion in tcp_pcb_purge() (backport v3.0)

See merge request idf/esp-idf!2723
2018-07-15 14:53:58 +08:00
Jiang Jiang Jian
245b753904 Merge branch 'bugfix/disable_lwip_trust_ip_by_default_v3.0' into 'release/v3.0'
lwip: disable ETHARP_TRUST_IP_MAC by default (backport v3.0)

See merge request idf/esp-idf!2721
2018-07-15 14:53:46 +08:00
Liu Zhi Fu
86a6c21e79 lwip: fix the assertion in tcp_pcb_purge()
Fix the assertion in tcp_pcb_purge().
2018-07-14 09:59:59 +08:00
Liu Zhi Fu
8cc0379da1 lwip: disable ETHARP_TRUST_IP_MAC by default
Disable ETHARP_TRUST_IP_MAC by default because:
1. The LAN peer may not be trustful
2. The LAN peer may has problem to update its ARP entry
2018-07-14 09:57:47 +08:00
Jiang Jiang Jian
e56bfadc58 Merge branch 'feature/ble_mesh_idf_v3.0' into 'release/v3.0'
Component/bt: add scan duplicate for v3.0

See merge request idf/esp-idf!2445
2018-07-13 19:10:49 +08:00
Ivan Grokhotkov
583e80708b Merge branch 'bugfix/esp_timer_set_alarm_v3.0' into 'release/v3.0'
esp_timer: remove busy loop in esp_timer_impl_set_alarm (backport v3.0)

See merge request idf/esp-idf!2726
2018-07-13 15:00:23 +08:00
zhiweijian
5cf4d8a1ec Component/bt: add scan duplicate for ble mesh in idf3.0 2018-07-12 07:35:13 +00:00
Ivan Grokhotkov
ef3c6ac276 esp_timer: test for monotonic values of esp_timer_get_timer in CI
Reduce test time by increasing overflow rate, make test more robust.
2018-07-09 15:42:30 +08:00
Ivan Grokhotkov
4129436f7e esp_timer: add test for esp_timer_impl_set_alarm
Ref https://github.com/espressif/esp-idf/issues/1891
2018-07-09 15:42:30 +08:00
Ivan Grokhotkov
0808a04ee8 esp_timer: reduce overflow value in unit tests
This allows testing for race conditions which occur near timer
overflow point more effectively.
2018-07-09 12:06:11 +08:00
Ivan Grokhotkov
c99977b67c esp_timer: don’t busy loop in esp_timer_impl_set_alarm
Previously the loop in esp_timer_impl_set_alarm was necessary to catch
the case when timer count wraps around (goes from 2^32 - 1 to 0).
Since ALARM_OVERFLOW_VAL was reduced from 2^32 - 1 to 0xefffffff,
this is no longer necessary.

Fixes https://github.com/espressif/esp-idf/issues/1891
2018-07-09 12:06:11 +08:00
118 changed files with 3386 additions and 1918 deletions

View File

@@ -1,9 +1,9 @@
stages:
- build
- assign_test
- host_test
- unit_test
- test
- test_report
- integration_test
- deploy
variables:
@@ -133,6 +133,8 @@ build_ssc_01:
build_ssc_02:
<<: *build_ssc_template
# 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_template
artifacts:
@@ -140,7 +142,7 @@ build_esp_idf_tests:
- tools/unit-test-app/output
- components/idf_test/unit_test/TestCaseAll.yml
- components/idf_test/unit_test/CIConfigs/*.yml
expire_in: 6 mos
expire_in: 1 mos
script:
- cd tools/unit-test-app
- make help # make sure kconfig tools are built in single process
@@ -199,6 +201,7 @@ build_examples_06:
build_examples_07:
<<: *build_examples_template
# If you want to add new build example jobs, please add it into dependencies of `.example_test_template`
build_docs:
stage: build
@@ -222,54 +225,44 @@ build_docs:
- make html
- ./check_doc_warnings.sh
test_nvs_on_host:
stage: test
image: $CI_DOCKER_REGISTRY/esp32-ci-env
.host_test_template: &host_test_template
stage: host_test
image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG
tags:
- nvs_host_test
- host_test
dependencies: []
test_nvs_on_host:
<<: *host_test_template
script:
- cd components/nvs_flash/test_nvs_host
- make test
test_partition_table_on_host:
stage: test
image: $CI_DOCKER_REGISTRY/esp32-ci-env
<<: *host_test_template
tags:
- build
dependencies: []
script:
- cd components/partition_table/test_gen_esp32part_host
- ./gen_esp32part_tests.py
test_wl_on_host:
stage: test
image: $CI_DOCKER_REGISTRY/esp32-ci-env
tags:
- wl_host_test
<<: *host_test_template
artifacts:
paths:
- components/wear_levelling/test_wl_host/coverage_report.zip
dependencies: []
script:
- cd components/wear_levelling/test_wl_host
- make test
test_multi_heap_on_host:
stage: test
image: $CI_DOCKER_REGISTRY/esp32-ci-env
tags:
- wl_host_test
<<: *host_test_template
script:
- cd components/heap/test_multi_heap_host
- ./test_all_configs.sh
test_build_system:
stage: test
image: $CI_DOCKER_REGISTRY/esp32-ci-env
tags:
- build_test
dependencies: []
<<: *host_test_template
script:
- ${IDF_PATH}/tools/ci/test_configure_ci_environment.sh
- rm -rf test_build_system
@@ -277,61 +270,7 @@ test_build_system:
- cd test_build_system
- ${IDF_PATH}/tools/ci/test_build_system.sh
test_report:
stage: test_report
image: $CI_DOCKER_REGISTRY/esp32-ci-env
tags:
- report
only:
- master
- triggers
- /^release\/v/
- /^v\d+\.\d+(\.\d+)?($|-)/
variables:
LOG_PATH: "$CI_PROJECT_DIR/$CI_COMMIT_SHA"
TEST_CASE_FILE_PATH: "$CI_PROJECT_DIR/components/idf_test"
REPORT_PATH: "$CI_PROJECT_DIR/CI_Test_Report"
MODULE_UPDATE_FILE: "$CI_PROJECT_DIR/tools/unit-test-app/tools/ModuleDefinition.yml"
#dependencies:
#We need all UT* and IT* artifacts except for only a few other
artifacts:
when: always
paths:
- $REPORT_PATH
- $LOG_PATH
expire_in: 12 mos
script:
# calc log path
- VER_NUM=`git rev-list HEAD | wc -l | awk '{print $1}'`
- SHA_ID=`echo $CI_COMMIT_SHA | cut -c 1-7`
- REVISION="${VER_NUM}_${SHA_ID}"
# replace / to _ in branch name
- ESCAPED_BRANCH_NAME=`echo $CI_COMMIT_REF_NAME | sed 's/\//___/g'`
# result path and artifacts path
- RESULT_PATH="$CI_PROJECT_NAME/$ESCAPED_BRANCH_NAME/$REVISION"
- ARTIFACTS_PATH="$GITLAB_HTTP_SERVER/idf/esp-idf/builds/$CI_JOB_ID/artifacts/browse/$CI_COMMIT_SHA"
# clone test bench
- git clone $GITLAB_SSH_SERVER/yinling/auto_test_script.git
- cd auto_test_script
- python $CHECKOUT_REF_SCRIPT auto_test_script
# generate report
- TEST_RESULT=Pass
- python CITestReport.py -l $LOG_PATH -t $TEST_CASE_FILE_PATH -p $REPORT_PATH -r $RESULT_PATH -a $ARTIFACTS_PATH -m $MODULE_UPDATE_FILE || TEST_RESULT=Fail
# commit to CI-test-result project
- git clone $GITLAB_SSH_SERVER/qa/CI-test-result.git
- rm -rf "CI-test-result/RawData/$RESULT_PATH"
- cp -R $CI_PROJECT_NAME CI-test-result/RawData
- cd CI-test-result
# config git user
- git config --global user.email "ci-test-result@espressif.com"
- git config --global user.name "ci-test-result"
# commit test result
- git add .
- git commit . -m "update test result for $CI_PROJECT_NAME/$CI_COMMIT_REF_NAME/$CI_COMMIT_SHA, pipeline ID $CI_PIPELINE_ID" || exit 0
- git push origin master
- test "${TEST_RESULT}" = "Pass" || exit 1
push_master_to_github:
push_to_github:
stage: deploy
image: $CI_DOCKER_REGISTRY/esp32-ci-env
tags:
@@ -342,8 +281,6 @@ push_master_to_github:
- /^v\d+\.\d+(\.\d+)?($|-)/
when: on_success
dependencies: []
variables:
GITHUB_PUSH_REFS: refs/remotes/origin/release refs/remotes/origin/master
before_script: *do_nothing_before
script:
- mkdir -p ~/.ssh
@@ -354,16 +291,11 @@ push_master_to_github:
- echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
- git remote remove github &>/dev/null || true
- git remote add github git@github.com:espressif/esp-idf.git
# What the next line of script does: goes through the list of refs for all branches we push to github,
# generates a snippet of shell which is evaluated. The snippet checks CI_COMMIT_SHA against the SHA
# (aka objectname) at tip of each branch, and if any SHAs match then it checks out the local branch
# and then pushes that ref to a corresponding github branch
- eval $(git for-each-ref --shell bash --format 'if [ $CI_COMMIT_SHA == %(objectname) ]; then git checkout -B %(refname:strip=3); git push --follow-tags github %(refname:strip=3); fi;' $GITHUB_PUSH_REFS)
- tools/ci/push_to_github.sh
deploy_docs:
stage: deploy
image: $CI_DOCKER_REGISTRY/esp32-ci-env
stage: host_test
image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG
tags:
- deploy
only:
@@ -389,8 +321,8 @@ deploy_docs:
- ssh $DOCS_SERVER -x "cd $DOCS_PATH && tar xzvf $GIT_VER.tar.gz && rm -f latest && ln -s $GIT_VER latest"
check_doc_links:
stage: test
image: $CI_DOCKER_REGISTRY/esp32-ci-env
stage: host_test
image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG
tags:
- check_doc_links
only:
@@ -478,21 +410,28 @@ 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: test
stage: integration_test
when: on_success
only:
- master
- /^release\/v/
- /^v\d+\.\d+(\.\d+)?($|-)/
- triggers
# gitlab ci do not support match job with RegEx or wildcard now in dependencies.
# we have a lot build example jobs and the binaries them exceed the limitation of artifacts.
# we can't artifact them in one job. For example test jobs, download all artifacts from previous stages.
dependencies:
- assign_test
- build_examples_00
- build_examples_01
- build_examples_02
- build_examples_03
- build_examples_04
- build_examples_05
- build_examples_06
- build_examples_07
artifacts:
when: always
paths:
- $LOG_PATH
expire_in: 6 mos
expire_in: 1 mos
variables:
TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw"
TEST_CASE_PATH: "$CI_PROJECT_DIR/examples"
@@ -506,14 +445,13 @@ assign_test:
- python Runner.py $TEST_CASE_PATH -c $CONFIG_FILE
.test_template: &test_template
stage: test
stage: integration_test
when: on_success
only:
- master
- /^release\/v/
- /^v\d+\.\d+(\.\d+)?($|-)/
- triggers
allow_failure: true
dependencies:
- assign_test
- build_ssc_00
@@ -523,7 +461,7 @@ assign_test:
when: always
paths:
- $LOG_PATH
expire_in: 6 mos
expire_in: 1 mos
variables:
LOCAL_ENV_CONFIG_PATH: "$CI_PROJECT_DIR/ci-test-runner-configs/$CI_RUNNER_DESCRIPTION/ESP32_IDF"
LOG_PATH: "$CI_PROJECT_DIR/$CI_COMMIT_SHA"
@@ -564,7 +502,7 @@ nvs_compatible_test:
paths:
- $LOG_PATH
- nvs_wifi.bin
expire_in: 6 mos
expire_in: 1 mos
tags:
- ESP32_IDF
- NVS_Compatible

View File

@@ -4,22 +4,27 @@
ESP-IDF is the official development framework for the [ESP32](https://espressif.com/en/products/hardware/esp32/overview) chip.
# Developing With the ESP-IDF
# Developing With ESP-IDF
## Setting Up ESP-IDF
See setup guides for detailed instructions to set up the ESP-IDF:
* [Windows Setup Guide](https://esp-idf.readthedocs.io/en/latest/get-started/windows-setup.html)
* [Mac OS Setup Guide](https://esp-idf.readthedocs.io/en/latest/get-started/macos-setup.html)
* [Linux Setup Guide](https://esp-idf.readthedocs.io/en/latest/get-started/linux-setup.html)
* [Getting Started Guide for the stable ESP-IDF version](https://docs.espressif.com/projects/esp-idf/en/stable/get-started/)
* [Getting Started Guide for the latest (master branch) ESP-IDF version](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/)
## Finding a Project
As well as the [esp-idf-template](https://github.com/espressif/esp-idf-template) project mentioned in the setup guide, ESP-IDF comes with some example projects in the [examples](examples) directory.
As well as the [esp-idf-template](https://github.com/espressif/esp-idf-template) project mentioned in Getting Started, ESP-IDF comes with some example projects in the [examples](examples) directory.
Once you've found the project you want to work with, change to its directory and you can configure and build it.
To start your own project based on an example, copy the example project directory outside of the ESP-IDF directory.
# Quick Reference
See the Getting Started guide links above for a detailed setup guide. This is a quick reference for common commands when working with ESP-IDF projects:
## Configuring the Project
`make menuconfig`
@@ -36,15 +41,17 @@ Once done configuring, press Escape multiple times to exit and say "Yes" to save
## Compiling the Project
`make all`
`make -j4 all`
... will compile app, bootloader and generate a partition table based on the config.
NOTE: The `-j4` option causes `make` to run 4 parallel jobs. This is much faster than the default single job. The recommended number to pass to this option is `-j(number of CPUs + 1)`.
## Flashing the Project
When `make all` finishes, it will print a command line to use esptool.py to flash the chip. However you can also do this from make by running:
`make flash`
`make -j4 flash`
This will flash the entire project (app, bootloader and partition table) to a new chip. The settings for serial port flashing can be configured with `make menuconfig`.
@@ -56,24 +63,24 @@ The `make monitor` target uses the [idf_monitor tool](https://esp-idf.readthedoc
Exit the monitor by typing Ctrl-].
To flash and monitor output in one pass, you can run:
To build, flash and monitor output in one pass, you can run:
`make flash monitor`
`make -j4 flash monitor`
## Compiling & Flashing Just the App
## Compiling & Flashing Only the App
After the initial flash, you may just want to build and flash just your app, not the bootloader and partition table:
* `make app` - build just the app.
* `make app-flash` - flash just the app.
`make app-flash` will automatically rebuild the app if it needs it.
`make app-flash` will automatically rebuild the app if any source files have changed.
(In normal development there's no downside to reflashing the bootloader and partition table each time, if they haven't changed.)
## Parallel Builds
ESP-IDF supports compiling multiple files in parallel, so all of the above commands can be run as `make -jN` where `N` is the number of parallel make processes to run (generally N should be equal to or one more than the number of CPU cores in your system.)
ESP-IDF supports compiling multiple files in parallel, so all of the above commands can be run as `make -jN` where `N` is the number of parallel make processes to run (generally N should be equal to the number of CPU cores in your system, plus one.)
Multiple make functions can be combined into one. For example: to build the app & bootloader using 5 jobs in parallel, then flash everything, and then display serial output from the ESP32 run:

View File

@@ -35,6 +35,7 @@
#define CMD_WRDI 0x04
#define CMD_RDSR 0x05
#define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */
#define CMD_OTPEN 0x3A /* Enable OTP mode, not all SPI flash uses this command */
static const char *TAG = "qio_mode";
@@ -65,6 +66,11 @@ static void write_status_8b_wrsr2(unsigned new_status);
/* Write 16 bit status using WRSR */
static void write_status_16b_wrsr(unsigned new_status);
/* Read 8 bit status of XM25QU64A */
static unsigned read_status_8b_xmc25qu64a();
/* Write 8 bit status of XM25QU64A */
static void write_status_8b_xmc25qu64a(unsigned new_status);
#define ESP32_D2WD_WP_GPIO 7 /* ESP32-D2WD has this GPIO wired to WP pin of flash */
#ifndef CONFIG_BOOTLOADER_SPI_WP_PIN // Set in menuconfig if SPI flasher config is set to a quad mode
@@ -84,11 +90,12 @@ static void write_status_16b_wrsr(unsigned new_status);
Searching of this table stops when the first match is found.
*/
const static qio_info_t chip_data[] = {
/* Manufacturer, mfg_id, flash_id, id mask, Read Status, Write Status, QIE Bit */
{ "MXIC", 0xC2, 0x2000, 0xFF00, read_status_8b_rdsr, write_status_8b_wrsr, 6 },
{ "ISSI", 0x9D, 0x4000, 0xCF00, read_status_8b_rdsr, write_status_8b_wrsr, 6 }, /* IDs 0x40xx, 0x70xx */
{ "WinBond", 0xEF, 0x4000, 0xFF00, read_status_16b_rdsr_rdsr2, write_status_16b_wrsr, 9 },
{ "GD", 0xC8, 0x6000, 0xFF00, read_status_16b_rdsr_rdsr2, write_status_16b_wrsr, 9 },
/* Manufacturer, mfg_id, flash_id, id mask, Read Status, Write Status, QIE Bit */
{ "MXIC", 0xC2, 0x2000, 0xFF00, read_status_8b_rdsr, write_status_8b_wrsr, 6 },
{ "ISSI", 0x9D, 0x4000, 0xCF00, read_status_8b_rdsr, write_status_8b_wrsr, 6 }, /* IDs 0x40xx, 0x70xx */
{ "WinBond", 0xEF, 0x4000, 0xFF00, read_status_16b_rdsr_rdsr2, write_status_16b_wrsr, 9 },
{ "GD", 0xC8, 0x6000, 0xFF00, read_status_16b_rdsr_rdsr2, write_status_16b_wrsr, 9 },
{ "XM25QU64A", 0x20, 0x3817, 0xFFFF, read_status_8b_xmc25qu64a, write_status_8b_xmc25qu64a, 6 },
/* Final entry is default entry, if no other IDs have matched.
@@ -96,7 +103,7 @@ const static qio_info_t chip_data[] = {
GigaDevice (mfg ID 0xC8, flash IDs including 4016),
FM25Q32 (QOUT mode only, mfg ID 0xA1, flash IDs including 4016)
*/
{ NULL, 0xFF, 0xFFFF, 0xFFFF, read_status_8b_rdsr2, write_status_8b_wrsr2, 1 },
{ NULL, 0xFF, 0xFFFF, 0xFFFF, read_status_8b_rdsr2, write_status_8b_wrsr2, 1 },
};
#define NUM_CHIPS (sizeof(chip_data) / sizeof(qio_info_t))
@@ -252,6 +259,24 @@ static void write_status_16b_wrsr(unsigned new_status)
execute_flash_command(CMD_WRSR, new_status, 16, 0);
}
static unsigned read_status_8b_xmc25qu64a()
{
execute_flash_command(CMD_OTPEN, 0, 0, 0); /* Enter OTP mode */
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
uint32_t read_status = execute_flash_command(CMD_RDSR, 0, 0, 8);
execute_flash_command(CMD_WRDI, 0, 0, 0); /* Exit OTP mode */
return read_status;
}
static void write_status_8b_xmc25qu64a(unsigned new_status)
{
execute_flash_command(CMD_OTPEN, 0, 0, 0); /* Enter OTP mode */
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
execute_flash_command(CMD_WRSR, new_status, 8, 0);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
execute_flash_command(CMD_WRDI, 0, 0, 0); /* Exit OTP mode */
}
static uint32_t execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len)
{
SPIFLASH.user2.usr_command_value = command;

View File

@@ -81,6 +81,8 @@ typedef struct {
_Static_assert(sizeof(esp_image_header_t) == 24, "binary image header should be 24 bytes");
#define ESP_IMAGE_HASH_LEN 32 /* Length of the appended SHA-256 digest */
/* Header of binary image segment */
typedef struct {
uint32_t load_addr;
@@ -142,6 +144,16 @@ esp_err_t esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *
*/
esp_err_t esp_image_verify_bootloader(uint32_t *length);
/**
* @brief Verify the bootloader image.
*
* @param[out] Metadata for the image. Only valid if result is ESP_OK.
*
* @return As per esp_image_load_metadata().
*/
esp_err_t esp_image_verify_bootloader_data(esp_image_metadata_t *data);
typedef struct {
uint32_t drom_addr;
uint32_t drom_load_addr;

View File

@@ -26,7 +26,7 @@
static const char *TAG = "esp_image";
#define HASH_LEN 32 /* SHA-256 digest length */
#define HASH_LEN ESP_IMAGE_HASH_LEN
#define SIXTEEN_MB 0x1000000
#define ESP_ROM_CHECKSUM_INITIAL 0xEF
@@ -441,19 +441,28 @@ static bool should_load(uint32_t load_addr)
esp_err_t esp_image_verify_bootloader(uint32_t *length)
{
esp_image_metadata_t data;
const esp_partition_pos_t bootloader_part = {
.offset = ESP_BOOTLOADER_OFFSET,
.size = ESP_PARTITION_TABLE_OFFSET - ESP_BOOTLOADER_OFFSET,
};
esp_err_t err = esp_image_load(ESP_IMAGE_VERIFY,
&bootloader_part,
&data);
esp_err_t err = esp_image_verify_bootloader_data(&data);
if (length != NULL) {
*length = (err == ESP_OK) ? data.image_len : 0;
}
return err;
}
esp_err_t esp_image_verify_bootloader_data(esp_image_metadata_t *data)
{
if (data == NULL) {
return ESP_ERR_INVALID_ARG;
}
const esp_partition_pos_t bootloader_part = {
.offset = ESP_BOOTLOADER_OFFSET,
.size = ESP_PARTITION_TABLE_OFFSET - ESP_BOOTLOADER_OFFSET,
};
return esp_image_load(ESP_IMAGE_VERIFY,
&bootloader_part,
data);
}
static esp_err_t verify_checksum(bootloader_sha256_handle_t sha_handle, uint32_t checksum_word, esp_image_metadata_t *data)
{
uint32_t unpadded_length = data->image_len;

View File

@@ -62,6 +62,11 @@ esp_err_t esp_flash_encrypt_check_and_update(void)
static esp_err_t initialise_flash_encryption(void)
{
if (REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_CODING_SCHEME_M) {
ESP_LOGE(TAG, "Flash Encryption is currently not supported on hardware with 3/4 Coding Scheme (CODING_SCHEME efuse set)");
return ESP_ERR_NOT_SUPPORTED;
}
/* Before first flash encryption pass, need to initialise key & crypto config */
/* Generate key */

View File

@@ -50,7 +50,7 @@ static bool secure_boot_generate(uint32_t image_len){
const uint32_t *image;
/* hardware secure boot engine only takes full blocks, so round up the
image length. The additional data should all be 0xFF.
image length. The additional data should all be 0xFF (or the appended SHA, if it falls in the same block).
*/
if (image_len % sizeof(digest.iv) != 0) {
image_len = (image_len / sizeof(digest.iv) + 1) * sizeof(digest.iv);
@@ -104,14 +104,20 @@ static inline void burn_efuses()
esp_err_t esp_secure_boot_permanently_enable(void) {
esp_err_t err;
uint32_t image_len = 0;
if (esp_secure_boot_enabled())
{
ESP_LOGI(TAG, "bootloader secure boot is already enabled, continuing..");
return ESP_OK;
}
err = esp_image_verify_bootloader(&image_len);
if (REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_CODING_SCHEME_M) {
ESP_LOGE(TAG, "Secure Boot is currently not supported on hardware with 3/4 Coding Scheme (CODING_SCHEME efuse set)");
return ESP_ERR_NOT_SUPPORTED;
}
/* Verify the bootloader */
esp_image_metadata_t bootloader_data = { 0 };
err = esp_image_verify_bootloader_data(&bootloader_data);
if (err != ESP_OK) {
ESP_LOGE(TAG, "bootloader image appears invalid! error %d", err);
return err;
@@ -150,6 +156,11 @@ esp_err_t esp_secure_boot_permanently_enable(void) {
}
ESP_LOGI(TAG, "Generating secure boot digest...");
uint32_t image_len = bootloader_data.image_len;
if(bootloader_data.image.hash_appended) {
/* Secure boot digest doesn't cover the hash */
image_len -= ESP_IMAGE_HASH_LEN;
}
if (false == secure_boot_generate(image_len)){
ESP_LOGE(TAG, "secure boot generation failed");
return ESP_FAIL;

View File

@@ -156,6 +156,38 @@ config BT_ACL_CONNECTIONS
help
Maximum BT/BLE connection count
config BLE_SCAN_DUPLICATE
bool "BLE Scan Duplicate Options "
depends on BLUEDROID_ENABLED
default y
help
This select enables parameters setting of BLE scan duplicate.
config DUPLICATE_SCAN_CACHE_SIZE
int "Maximum number of devices in scan duplicate filter"
depends on BLE_SCAN_DUPLICATE
range 10 1000
default 500
help
Maximum number of devices which can be recorded in scan duplicate filter.
When the maximum amount of device in the filter is reached, the cache will be refreshed.
config BLE_MESH_SCAN_DUPLICATE_EN
bool "Special duplicate scan mechanism for BLE Mesh scan"
depends on BLE_SCAN_DUPLICATE
default n
help
This enables the BLE scan duplicate for special BLE Mesh scan.
config MESH_DUPLICATE_SCAN_CACHE_SIZE
int "Maximum number of Mesh adv packets in scan duplicate filter"
depends on BLE_MESH_SCAN_DUPLICATE_EN
range 10 200
default 50
help
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 SMP_ENABLE
bool
depends on BLUEDROID_ENABLED

View File

@@ -264,6 +264,13 @@ typedef enum {
3. directed advertising packets addressed to this device.*/
} esp_ble_scan_filter_t;
/// Ble scan duplicate type
typedef enum {
BLE_SCAN_DUPLICATE_DISABLE = 0x0, /*!< the Link Layer should generate advertising reports to the host for each packet received */
BLE_SCAN_DUPLICATE_ENABLE = 0x1, /*!< the Link Layer should filter out duplicate advertising reports to the Host */
BLE_SCAN_DUPLICATE_MAX = 0x2, /*!< 0x02 0xFF, Reserved for future use */
} esp_ble_scan_duplicate_t;
/// Ble scan parameters
typedef struct {
esp_ble_scan_type_t scan_type; /*!< Scan type */
@@ -279,6 +286,9 @@ 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
advertising reports for each packet received */
} esp_ble_scan_params_t;
/// Connection update parameters

View File

@@ -4568,6 +4568,7 @@ void bta_dm_ble_set_scan_fil_params(tBTA_DM_MSG *p_data)
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);
}

View File

@@ -968,6 +968,7 @@ void BTA_DmSetBleScanParams(tGATT_IF client_if, UINT32 scan_interval,
** scan_interval - scan interval
** scan_window - scan window
** scan_mode - scan mode
** scan_duplicate_filter - scan duplicate filter
** scan_param_setup_status_cback - Set scan param status callback
**
** Returns void
@@ -975,7 +976,7 @@ void BTA_DmSetBleScanParams(tGATT_IF client_if, UINT32 scan_interval,
*******************************************************************************/
void BTA_DmSetBleScanFilterParams(tGATT_IF client_if, UINT32 scan_interval,
UINT32 scan_window, tBLE_SCAN_MODE scan_mode, UINT8 scan_fil_poilcy,
UINT8 addr_type_own, tBLE_SCAN_PARAM_SETUP_CBACK scan_param_setup_cback)
UINT8 addr_type_own, UINT8 scan_duplicate_filter, tBLE_SCAN_PARAM_SETUP_CBACK scan_param_setup_cback)
{
tBTA_DM_API_BLE_SCAN_FILTER_PARAMS *p_msg;
@@ -987,6 +988,7 @@ void BTA_DmSetBleScanFilterParams(tGATT_IF client_if, UINT32 scan_interval,
p_msg->scan_window = scan_window;
p_msg->scan_mode = scan_mode;
p_msg->addr_type_own = addr_type_own;
p_msg->scan_duplicate_filter = scan_duplicate_filter;
p_msg->scan_filter_policy = scan_fil_poilcy;
p_msg->scan_param_setup_cback = scan_param_setup_cback;

View File

@@ -485,6 +485,7 @@ typedef struct {
UINT32 scan_window;
tBLE_SCAN_MODE scan_mode;
UINT8 addr_type_own;
UINT8 scan_duplicate_filter;
UINT8 scan_filter_policy;
tBLE_SCAN_PARAM_SETUP_CBACK scan_param_setup_cback;
} tBTA_DM_API_BLE_SCAN_FILTER_PARAMS;

View File

@@ -702,6 +702,10 @@ void bta_gatts_indicate_handle (tBTA_GATTS_CB *p_cb, tBTA_GATTS_DATA *p_msg)
APPL_TRACE_ERROR("%s, malloc failed", __func__);
}
(*p_rcb->p_cback)(BTA_GATTS_CONF_EVT, &cb_data);
if (cb_data.req_data.value != NULL) {
osi_free(cb_data.req_data.value);
cb_data.req_data.value = NULL;
}
}
} else {
APPL_TRACE_ERROR("Not an registered servce attribute ID: 0x%04x",

View File

@@ -1902,6 +1902,7 @@ extern void BTA_DmSetBleScanParams(tGATT_IF client_if, UINT32 scan_interval,
** scan_interval - scan interval
** scan_window - scan window
** scan_mode - scan mode
** scan_duplicate_filter - scan duplicate filter
** scan_param_setup_status_cback - Set scan param status callback
**
** Returns void
@@ -1909,7 +1910,7 @@ extern void BTA_DmSetBleScanParams(tGATT_IF client_if, UINT32 scan_interval,
*******************************************************************************/
extern void BTA_DmSetBleScanFilterParams(tGATT_IF client_if, UINT32 scan_interval,
UINT32 scan_window, tBLE_SCAN_MODE scan_mode, UINT8 scan_fil_poilcy,
UINT8 addr_type_own, tBLE_SCAN_PARAM_SETUP_CBACK scan_param_setup_cback);
UINT8 addr_type_own, UINT8 scan_duplicate_filter, tBLE_SCAN_PARAM_SETUP_CBACK scan_param_setup_cback);
/*******************************************************************************

View File

@@ -175,6 +175,10 @@ static void btc_dm_remove_ble_bonding_keys(void)
static void btc_dm_save_ble_bonding_keys(void)
{
if(!(pairing_cb.ble.is_penc_key_rcvd || pairing_cb.ble.is_pid_key_rcvd || pairing_cb.ble.is_pcsrk_key_rcvd ||
pairing_cb.ble.is_lenc_key_rcvd || pairing_cb.ble.is_lcsrk_key_rcvd || pairing_cb.ble.is_lidk_key_rcvd)) {
return ;
}
bt_bdaddr_t bd_addr;
bdcpy(bd_addr.address, pairing_cb.bd_addr);

View File

@@ -208,10 +208,7 @@ static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
blufi_env.frag_size = p_data->req_data.p_data->mtu - BLUFI_MTU_RESERVED_SIZE;
break;
case BTA_GATTS_CONF_EVT:
LOG_DEBUG("CONIRM EVT\n");
if (p_data && p_data->req_data.value){
osi_free(p_data->req_data.value);
}
LOG_DEBUG("CONFIRM EVT\n");
/* Nothing */
break;
case BTA_GATTS_CREATE_EVT:

View File

@@ -641,7 +641,7 @@ static void btc_media_task_handle_inc_media(tBT_SBC_HDR *p_msg)
OI_STATUS status;
int num_sbc_frames = p_msg->num_frames_to_be_processed;
UINT32 sbc_frame_len = p_msg->len - 1;
availPcmBytes = 2 * sizeof(pcmData);
availPcmBytes = sizeof(pcmData);
if ((btc_media_cb.peer_sep == AVDT_TSEP_SNK) || (btc_media_cb.rx_flush)) {
APPL_TRACE_DEBUG(" State Changed happened in this tick ");
@@ -671,7 +671,7 @@ static void btc_media_task_handle_inc_media(tBT_SBC_HDR *p_msg)
p_msg->len = sbc_frame_len + 1;
}
btc_a2d_data_cb_to_app((uint8_t *)pcmData, (2 * sizeof(pcmData) - availPcmBytes));
btc_a2d_data_cb_to_app((uint8_t *)pcmData, (sizeof(pcmData) - availPcmBytes));
}
/*******************************************************************************

View File

@@ -560,6 +560,7 @@ static void btc_ble_set_scan_params(esp_ble_scan_params_t *scan_params, tBLE_SCA
BLE_ISVALID_PARAM(scan_params->scan_window, BTM_BLE_SCAN_WIN_MIN, BTM_BLE_SCAN_WIN_MAX) &&
BLE_ISVALID_PARAM(scan_params->own_addr_type, BLE_ADDR_TYPE_PUBLIC, BLE_ADDR_TYPE_RPA_RANDOM) &&
BLE_ISVALID_PARAM(scan_params->scan_filter_policy, BLE_SCAN_FILTER_ALLOW_ALL, BLE_SCAN_FILTER_ALLOW_WLIST_PRA_DIR) &&
BLE_ISVALID_PARAM(scan_params->scan_duplicate, BLE_SCAN_DUPLICATE_DISABLE, BLE_SCAN_DUPLICATE_MAX -1) &&
(scan_params->scan_type == BTM_BLE_SCAN_MODE_ACTI || scan_params->scan_type == BTM_BLE_SCAN_MODE_PASS)) {
BTA_DmSetBleScanFilterParams(ESP_DEFAULT_GATT_IF, /*client_if*/
scan_params->scan_interval,
@@ -567,6 +568,7 @@ static void btc_ble_set_scan_params(esp_ble_scan_params_t *scan_params, tBLE_SCA
scan_params->scan_type,
scan_params->scan_filter_policy,
scan_params->own_addr_type,
scan_params->scan_duplicate,
scan_param_setup_cback);
} else {
btc_scan_params_callback(ESP_DEFAULT_GATT_IF, BTM_ILLEGAL_VALUE);

View File

@@ -671,7 +671,7 @@ void btc_gattc_call_handler(btc_msg_t *msg)
btc_ble_gattc_args_t *arg = (btc_ble_gattc_args_t *)(msg->arg);
switch (msg->act) {
case BTC_GATTC_ACT_APP_REGISTER:
LOG_ERROR("%s()", __func__);
LOG_DEBUG("%s()", __func__);
btc_gattc_app_register(arg);
break;
case BTC_GATTC_ACT_APP_UNREGISTER:

View File

@@ -530,9 +530,6 @@ static void btc_gatts_cb_param_copy_free(btc_msg_t *msg, tBTA_GATTS *p_data)
}
break;
case BTA_GATTS_CONF_EVT:
if (p_data && p_data->req_data.value){
osi_free(p_data->req_data.value);
}
break;
default:
break;

View File

@@ -92,6 +92,7 @@ static void hci_hal_env_init(
static void hci_hal_env_deinit(void)
{
fixed_queue_free(hci_hal_env.rx_q, hci_hal_env.allocator->free);
hci_hal_env.rx_q = NULL;
}
static bool hal_open(const hci_hal_callbacks_t *upper_callbacks)
@@ -260,6 +261,10 @@ static int host_recv_pkt_cb(uint8_t *data, uint16_t len)
BT_HDR *pkt;
size_t pkt_size;
if (hci_hal_env.rx_q == NULL) {
return 0;
}
pkt_size = BT_HDR_SIZE + len;
pkt = (BT_HDR *)hci_hal_env.allocator->alloc(pkt_size);
if (!pkt) {

View File

@@ -412,6 +412,7 @@ void avdt_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
{
tAVDT_TC_TBL *p_tbl;
UINT16 disc_rsn = AVDT_DISC_RSN_NORMAL;
tAVDT_CCB *p_ccb;
AVDT_TRACE_DEBUG("avdt_l2c_disconnect_ind_cback lcid: %d, ack_needed: %d\n",
lcid, ack_needed);
/* look up info for this channel */
@@ -420,7 +421,13 @@ void avdt_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
/* send L2CAP disconnect response */
L2CA_DisconnectRsp(lcid);
} else {
disc_rsn = AVDT_DISC_RSN_ABNORMAL;
if ((p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx)) != NULL) {
UINT16 rsn = L2CA_GetDisconnectReason(p_ccb->peer_addr, BT_TRANSPORT_BR_EDR);
if (rsn != 0 && rsn != HCI_ERR_PEER_USER) {
disc_rsn = AVDT_DISC_RSN_ABNORMAL;
AVDT_TRACE_EVENT("avdt link disc rsn 0x%x", rsn);
}
}
}
avdt_ad_tc_close_ind(p_tbl, disc_rsn);

View File

@@ -335,7 +335,7 @@ void btm_acl_created (BD_ADDR bda, DEV_CLASS dc, BD_NAME bdn,
btsnd_hcic_ble_read_remote_feat(p->hci_handle);
} else if (HCI_LE_SLAVE_INIT_FEAT_EXC_SUPPORTED(controller_get_interface()->get_features_ble()->as_array)
&& link_role == HCI_ROLE_SLAVE) {
btsnd_hcic_ble_read_remote_feat(p->hci_handle);
btsnd_hcic_rmt_ver_req (p->hci_handle);
} else {
btm_establish_continue(p);
}
@@ -906,12 +906,17 @@ void btm_read_remote_version_complete (UINT8 *p)
}
#if BLE_INCLUDED == TRUE
if (p_acl_cb->transport == BT_TRANSPORT_LE) {
if (HCI_LE_DATA_LEN_EXT_SUPPORTED(p_acl_cb->peer_le_features)) {
uint16_t data_length = controller_get_interface()->get_ble_default_data_packet_length();
uint16_t data_txtime = controller_get_interface()->get_ble_default_data_packet_txtime();
btsnd_hcic_ble_set_data_length(p_acl_cb->hci_handle, data_length, data_txtime);
if(p_acl_cb->link_role == HCI_ROLE_MASTER) {
if (HCI_LE_DATA_LEN_EXT_SUPPORTED(p_acl_cb->peer_le_features)) {
uint16_t data_length = controller_get_interface()->get_ble_default_data_packet_length();
uint16_t data_txtime = controller_get_interface()->get_ble_default_data_packet_txtime();
btsnd_hcic_ble_set_data_length(p_acl_cb->hci_handle, data_length, data_txtime);
}
l2cble_notify_le_connection (p_acl_cb->remote_addr);
} else {
//slave role, read remote feature
btsnd_hcic_ble_read_remote_feat(p_acl_cb->hci_handle);
}
l2cble_notify_le_connection (p_acl_cb->remote_addr);
}
#endif
break;

View File

@@ -1225,7 +1225,7 @@ void btm_sec_save_le_key(BD_ADDR bd_addr, tBTM_LE_KEY_TYPE key_type, tBTM_LE_KEY
/* Set that link key is known since this shares field with BTM_SEC_FLAG_LKEY_KNOWN flag in btm_api.h*/
p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_KNOWN;
if ( p_keys->pcsrk_key.sec_level == SMP_SEC_AUTHENTICATED) {
if ( p_keys->lenc_key.sec_level == SMP_SEC_AUTHENTICATED) {
p_rec->sec_flags |= BTM_SEC_LE_LINK_KEY_AUTHED;
} else {
p_rec->sec_flags &= ~BTM_SEC_LE_LINK_KEY_AUTHED;
@@ -1942,14 +1942,6 @@ void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len, BOOLEAN enhanced)
handle = HCID_GET_HANDLE (handle);
btm_ble_connected(bda, handle, HCI_ENCRYPT_MODE_DISABLED, role, bda_type, match);
if(role == HCI_ROLE_SLAVE) {
//clear p_cb->state, controller will stop adv when ble connected.
tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
if(p_cb) {
p_cb->adv_mode = BTM_BLE_ADV_DISABLE;
p_cb->state = BTM_BLE_STOP_ADV;
}
}
l2cble_conn_comp (handle, role, bda, bda_type, conn_interval,
conn_latency, conn_timeout);

View File

@@ -65,6 +65,23 @@ static void btm_gen_resolve_paddr_cmpl(tSMP_ENC *p)
p_cb->set_local_privacy_cback = NULL;
}
if (btm_cb.ble_ctr_cb.inq_var.adv_mode == BTM_BLE_ADV_ENABLE){
BTM_TRACE_DEBUG("Advertise with new resolvable private address, now.");
/**
* Restart advertising, using new resolvable private address
*/
btm_ble_stop_adv();
btm_ble_start_adv();
}
if (btm_cb.ble_ctr_cb.inq_var.state == BTM_BLE_SCANNING){
BTM_TRACE_DEBUG("Scan with new resolvable private address, now.");
/**
* Restart scaning, using new resolvable private address
*/
btm_ble_stop_scan();
btm_ble_start_scan();
}
/* start a periodical timer to refresh random addr */
btu_stop_timer_oneshot(&p_cb->raddr_timer_ent);
#if (BTM_BLE_CONFORMANCE_TESTING == TRUE)

View File

@@ -403,7 +403,6 @@ tBTM_STATUS BTM_BleObserve(BOOLEAN start, UINT32 duration,
BTM_BLE_DEFAULT_SFP);
}
p_inq->scan_duplicate_filter = BTM_BLE_DUPLICATE_DISABLE;
status = btm_ble_start_scan();
}
@@ -442,7 +441,6 @@ tBTM_STATUS BTM_BleObserve(BOOLEAN start, UINT32 duration,
tBTM_STATUS BTM_BleScan(BOOLEAN start, UINT32 duration,
tBTM_INQ_RESULTS_CB *p_results_cb, tBTM_CMPL_CB *p_cmpl_cb)
{
tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var;
tBTM_STATUS status = BTM_WRONG_MODE;
if (!controller_get_interface()->supports_ble()) {
@@ -467,7 +465,6 @@ tBTM_STATUS BTM_BleScan(BOOLEAN start, UINT32 duration,
/* enable resolving list */
btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_SCAN);
#endif
p_inq->scan_duplicate_filter = BTM_BLE_DUPLICATE_DISABLE;
status = btm_ble_start_scan();
}
@@ -1370,7 +1367,7 @@ 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,
tBLE_SCAN_MODE scan_mode, UINT8 addr_type_own, tBTM_BLE_SFP scan_filter_policy,
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;
@@ -1407,12 +1404,14 @@ void BTM_BleSetScanFilterParams(tGATT_IF client_if, UINT32 scan_interval, UINT32
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_mode == BTM_BLE_SCAN_MODE_ACTI || scan_mode == BTM_BLE_SCAN_MODE_PASS) &&
(scan_duplicate_filter < BTM_BLE_SCAN_DUPLICATE_MAX)) {
p_cb->scan_type = scan_mode;
p_cb->scan_interval = scan_interval;
p_cb->scan_window = scan_window;
p_cb->sfp = scan_filter_policy;
p_cb->scan_params_set = TRUE;
p_cb->scan_duplicate_filter = scan_duplicate_filter;
btsnd_hcic_ble_set_scan_params(p_cb->scan_type, (UINT16)scan_interval,
(UINT16)scan_window,
@@ -2282,7 +2281,6 @@ tBTM_STATUS btm_ble_start_inquiry (UINT8 mode, UINT8 duration)
/* enable IRK list */
btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_SCAN);
#endif
p_ble_cb->inq_var.scan_duplicate_filter = BTM_BLE_DUPLICATE_DISABLE;
status = btm_ble_start_scan();
} else if ((p_ble_cb->inq_var.scan_interval != BTM_BLE_LOW_LATENCY_SCAN_INT) ||
(p_ble_cb->inq_var.scan_window != BTM_BLE_LOW_LATENCY_SCAN_WIN)) {
@@ -2573,7 +2571,7 @@ static void btm_ble_parse_adv_data(tBTM_INQ_INFO *p_info, UINT8 *p_data,
** Returns void
**
*******************************************************************************/
void btm_ble_cache_adv_data(tBTM_INQ_RESULTS *p_cur, UINT8 data_len, UINT8 *p, UINT8 evt_type)
void btm_ble_cache_adv_data(BD_ADDR bda, tBTM_INQ_RESULTS *p_cur, UINT8 data_len, UINT8 *p, UINT8 evt_type)
{
tBTM_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
UINT8 *p_cache;
@@ -2585,6 +2583,15 @@ void btm_ble_cache_adv_data(tBTM_INQ_RESULTS *p_cur, UINT8 data_len, UINT8 *p, U
memset(p_le_inq_cb->adv_data_cache, 0, BTM_BLE_CACHE_ADV_DATA_MAX);
p_cur->adv_data_len = 0;
p_cur->scan_rsp_len = 0;
}
//Clear the adv cache if the addresses are not equal
if(memcmp(bda, p_le_inq_cb->adv_addr, BD_ADDR_LEN) != 0) {
p_le_inq_cb->adv_len = 0;
memcpy(p_le_inq_cb->adv_addr, bda, BD_ADDR_LEN);
memset(p_le_inq_cb->adv_data_cache, 0, BTM_BLE_CACHE_ADV_DATA_MAX);
p_cur->adv_data_len = 0;
p_cur->scan_rsp_len = 0;
}
if (data_len > 0) {
@@ -2814,7 +2821,7 @@ static void btm_ble_appearance_to_cod(UINT16 appearance, UINT8 *dev_class)
** Returns void
**
*******************************************************************************/
BOOLEAN btm_ble_update_inq_result(tINQ_DB_ENT *p_i, UINT8 addr_type, UINT8 evt_type, UINT8 *p)
BOOLEAN btm_ble_update_inq_result(BD_ADDR bda, tINQ_DB_ENT *p_i, UINT8 addr_type, UINT8 evt_type, UINT8 *p)
{
BOOLEAN to_report = TRUE;
tBTM_INQ_RESULTS *p_cur = &p_i->inq_info.results;
@@ -2832,7 +2839,7 @@ BOOLEAN btm_ble_update_inq_result(tINQ_DB_ENT *p_i, UINT8 addr_type, UINT8 evt_t
BTM_TRACE_WARNING("EIR data too long %d. discard", data_len);
return FALSE;
}
btm_ble_cache_adv_data(p_cur, data_len, p, evt_type);
btm_ble_cache_adv_data(bda, p_cur, data_len, p, evt_type);
p1 = (p + data_len);
STREAM_TO_UINT8 (rssi, p1);
@@ -3056,6 +3063,71 @@ void btm_ble_process_adv_pkt (UINT8 *p_data)
}
}
/*******************************************************************************
**
** Function btm_ble_process_last_adv_pkt
**
** Description This function is called to report last adv packet
**
** Parameters
**
** Returns void
**
*******************************************************************************/
static void btm_ble_process_last_adv_pkt(void)
{
UINT8 result = 0;
UINT8 null_bda[6] = {0};
tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars;
tBTM_INQ_RESULTS_CB *p_inq_results_cb = p_inq->p_inq_results_cb;
tBTM_INQ_RESULTS_CB *p_obs_results_cb = btm_cb.ble_ctr_cb.p_obs_results_cb;
tBTM_INQ_RESULTS_CB *p_scan_results_cb = btm_cb.ble_ctr_cb.p_scan_results_cb;
tBTM_BLE_INQ_CB *p_le_inq_cb = &btm_cb.ble_ctr_cb.inq_var;
tINQ_DB_ENT *p_i = btm_inq_db_find (p_le_inq_cb->adv_addr);
if(memcmp(null_bda, p_le_inq_cb->adv_addr, BD_ADDR_LEN) == 0) {
return;
}
if(p_i == NULL) {
BTM_TRACE_DEBUG("no last adv");
return;
}
if ((result = btm_ble_is_discoverable(p_le_inq_cb->adv_addr, p_i->inq_info.results.ble_evt_type, NULL)) == 0) {
BTM_TRACE_WARNING("%s device is no longer discoverable so discarding advertising packet pkt",
__func__);
return;
}
/* background connection in selective connection mode */
if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_SELECTIVE) {
//do nothing
} else {
if (p_inq_results_cb && (result & BTM_BLE_INQ_RESULT)) {
(p_inq_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
p_le_inq_cb->adv_len = 0;
memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
p_i->inq_info.results.adv_data_len = 0;
p_i->inq_info.results.scan_rsp_len = 0;
}
if (p_obs_results_cb && (result & BTM_BLE_OBS_RESULT)) {
(p_obs_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
p_le_inq_cb->adv_len = 0;
memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
p_i->inq_info.results.adv_data_len = 0;
p_i->inq_info.results.scan_rsp_len = 0;
}
if (p_scan_results_cb && (result & BTM_BLE_DISCO_RESULT)) {
(p_scan_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
p_le_inq_cb->adv_len = 0;
memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
p_i->inq_info.results.adv_data_len = 0;
p_i->inq_info.results.scan_rsp_len = 0;
}
}
}
/*******************************************************************************
**
** Function btm_ble_process_adv_pkt_cont
@@ -3080,6 +3152,13 @@ static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt
BOOLEAN update = TRUE;
UINT8 result = 0;
//if scan duplicate is enabled, the adv packet without scan response is allowed to report to upper layer
if(p_le_inq_cb->scan_duplicate_filter == BTM_BLE_SCAN_DUPLICATE_ENABLE) {
if(memcmp(bda, p_le_inq_cb->adv_addr, BD_ADDR_LEN) != 0) {
btm_ble_process_last_adv_pkt();
}
}
p_i = btm_inq_db_find (bda);
/* Check if this address has already been processed for this inquiry */
@@ -3108,7 +3187,7 @@ static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt
p_inq->inq_cmpl_info.num_resp++;
}
/* update the LE device information in inquiry database */
if (!btm_ble_update_inq_result(p_i, addr_type, evt_type, p)) {
if (!btm_ble_update_inq_result(bda, p_i, addr_type, evt_type, p)) {
return;
}
@@ -3152,12 +3231,24 @@ static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt
} else {
if (p_inq_results_cb && (result & BTM_BLE_INQ_RESULT)) {
(p_inq_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
p_le_inq_cb->adv_len = 0;
memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
p_i->inq_info.results.adv_data_len = 0;
p_i->inq_info.results.scan_rsp_len = 0;
}
if (p_obs_results_cb && (result & BTM_BLE_OBS_RESULT)) {
(p_obs_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
p_le_inq_cb->adv_len = 0;
memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
p_i->inq_info.results.adv_data_len = 0;
p_i->inq_info.results.scan_rsp_len = 0;
}
if (p_scan_results_cb && (result & BTM_BLE_DISCO_RESULT)) {
(p_scan_results_cb)((tBTM_INQ_RESULTS *) &p_i->inq_info.results, p_le_inq_cb->adv_data_cache);
p_le_inq_cb->adv_len = 0;
memset(p_le_inq_cb->adv_addr, 0, BD_ADDR_LEN);
p_i->inq_info.results.adv_data_len = 0;
p_i->inq_info.results.scan_rsp_len = 0;
}
}
}
@@ -3196,6 +3287,9 @@ tBTM_STATUS btm_ble_start_scan(void)
tBTM_STATUS status = BTM_CMD_STARTED;
// recoverly the scan parameters to the controller before start scan
btm_ble_recover_scan_params();
if(p_inq->scan_duplicate_filter > BTM_BLE_DUPLICATE_MAX) {
p_inq->scan_duplicate_filter = BTM_BLE_DUPLICATE_DISABLE;
}
/* start scan, disable duplicate filtering */
if (!btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, p_inq->scan_duplicate_filter)) {
status = BTM_NO_RESOURCES;

View File

@@ -170,16 +170,6 @@ tBTM_STATUS BTM_SetDiscoverability (UINT16 inq_mode, UINT16 window, UINT16 inter
BOOLEAN cod_limited;
BTM_TRACE_API ("BTM_SetDiscoverability\n");
#if (BLE_INCLUDED == TRUE && BLE_INCLUDED == TRUE)
if (controller_get_interface()->supports_ble()) {
if (btm_ble_set_discoverability((UINT16)(inq_mode))
== BTM_SUCCESS) {
btm_cb.btm_inq_vars.discoverable_mode &= (~BTM_BLE_DISCOVERABLE_MASK);
btm_cb.btm_inq_vars.discoverable_mode |= (inq_mode & BTM_BLE_DISCOVERABLE_MASK);
}
}
inq_mode &= ~BTM_BLE_DISCOVERABLE_MASK;
#endif
/*** Check mode parameter ***/
if (inq_mode > BTM_MAX_DISCOVERABLE) {
@@ -601,17 +591,6 @@ tBTM_STATUS BTM_SetConnectability (UINT16 page_mode, UINT16 window, UINT16 inter
BTM_TRACE_API ("BTM_SetConnectability\n");
#if (BLE_INCLUDED == TRUE && BLE_INCLUDED == TRUE)
if (controller_get_interface()->supports_ble()) {
if (btm_ble_set_connectability(page_mode) != BTM_SUCCESS) {
return BTM_NO_RESOURCES;
}
p_inq->connectable_mode &= (~BTM_BLE_CONNECTABLE_MASK);
p_inq->connectable_mode |= (page_mode & BTM_BLE_CONNECTABLE_MASK);
}
page_mode &= ~BTM_BLE_CONNECTABLE_MASK;
#endif
/*** Check mode parameter ***/
if (page_mode != BTM_NON_CONNECTABLE && page_mode != BTM_CONNECTABLE) {
return (BTM_ILLEGAL_VALUE);

View File

@@ -1361,7 +1361,7 @@ tBTM_STATUS BTM_SetEncryption (BD_ADDR bd_addr, tBT_TRANSPORT transport, tBTM_SE
return (BTM_SUCCESS);
}
p_dev_rec->enc_init_by_we = TRUE;
/* enqueue security request if security is active */
if (p_dev_rec->p_callback || (p_dev_rec->sec_state != BTM_SEC_STATE_IDLE)) {
BTM_TRACE_WARNING ("Security Manager: BTM_SetEncryption busy, enqueue request\n");
@@ -4537,7 +4537,7 @@ void btm_sec_disconnected (UINT16 handle, UINT8 reason)
if (!p_dev_rec) {
return;
}
p_dev_rec->enc_init_by_we = FALSE;
transport = (handle == p_dev_rec->hci_handle) ? BT_TRANSPORT_BR_EDR : BT_TRANSPORT_LE;
p_dev_rec->rs_disc_pending = BTM_SEC_RS_NOT_PENDING; /* reset flag */

View File

@@ -906,7 +906,30 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l
case HCI_BLE_CLEAR_WHITE_LIST:
btm_ble_clear_white_list_complete(p, evt_len);
break;
case HCI_BLE_WRITE_ADV_PARAMS: {
uint8_t status;
STREAM_TO_UINT8 (status, p);
if(status != HCI_SUCCESS) {
HCI_TRACE_ERROR("hci write adv params error 0x%x", status);
}
break;
}
case HCI_BLE_RC_PARAM_REQ_REPLY: {
uint8_t status;
STREAM_TO_UINT8 (status, p);
if(status != HCI_SUCCESS) {
HCI_TRACE_ERROR("hci connection params reply command error 0x%x", status);
}
break;
}
case HCI_BLE_RC_PARAM_REQ_NEG_REPLY: {
uint8_t status;
STREAM_TO_UINT8 (status, p);
if(status != HCI_SUCCESS) {
HCI_TRACE_ERROR("hci connection params neg reply command error 0x%x", status);
}
break;
}
case HCI_BLE_REMOVE_WHITE_LIST:
btm_ble_remove_from_white_list_complete(p, evt_len);
break;

View File

@@ -239,23 +239,6 @@ void btu_task_thread_handler(void *arg)
case SIG_BTU_ONESHOT_ALARM: {
TIMER_LIST_ENT *p_tle = (TIMER_LIST_ENT *)e.par;
btu_general_alarm_process(p_tle);
switch (p_tle->event) {
#if (defined(BLE_INCLUDED) && BLE_INCLUDED == TRUE)
case BTU_TTYPE_BLE_RANDOM_ADDR:
btm_ble_timeout(p_tle);
break;
#endif
case BTU_TTYPE_USER_FUNC: {
tUSER_TIMEOUT_FUNC *p_uf = (tUSER_TIMEOUT_FUNC *)p_tle->param;
(*p_uf)(p_tle);
break;
}
default:
// FAIL
LOG_ERROR("Received unexpected oneshot timer event:0x%x\n", p_tle->event);
break;
}
break;
}
case SIG_BTU_L2CAP_ALARM:

View File

@@ -1038,7 +1038,10 @@ BOOLEAN gatt_cl_send_next_cmd_inq(tGATT_TCB *p_tcb)
if (att_ret == GATT_SUCCESS || att_ret == GATT_CONGESTED) {
sent = TRUE;
p_cmd->to_send = FALSE;
p_cmd->p_cmd = NULL;
if(p_cmd->p_cmd) {
osi_free(p_cmd->p_cmd);
p_cmd->p_cmd = NULL;
}
/* dequeue the request if is write command or sign write */
if (p_cmd->op_code != GATT_CMD_WRITE && p_cmd->op_code != GATT_SIGN_CMD_WRITE) {

View File

@@ -2258,6 +2258,7 @@ void gatt_cleanup_upon_disc(BD_ADDR bda, UINT16 reason, tBT_TRANSPORT transport)
GATT_TRACE_DEBUG ("exit gatt_cleanup_upon_disc ");
BTM_Recovery_Pre_State();
}
gatt_delete_dev_from_srv_chg_clt_list(bda);
}
/*******************************************************************************
**

View File

@@ -573,6 +573,12 @@ typedef struct {
tBTM_BLE_REF_VALUE ref_value;
} tBTM_BLE_BATCH_SCAN_CB;
/// Ble scan duplicate type
enum {
BTM_BLE_SCAN_DUPLICATE_DISABLE = 0x0, /*!< the Link Layer should generate advertising reports to the host for each packet received */
BTM_BLE_SCAN_DUPLICATE_ENABLE = 0x1, /*!< the Link Layer should filter out duplicate advertising reports to the Host */
BTM_BLE_SCAN_DUPLICATE_MAX = 0x2, /*!< 0x02 0xFF, Reserved for future use */
};
/* filter selection bit index */
#define BTM_BLE_PF_ADDR_FILTER 0
#define BTM_BLE_PF_SRVC_DATA 1
@@ -1050,6 +1056,7 @@ void BTM_BleSetScanParams(tGATT_IF client_if, UINT32 scan_interval,
** scan_window - Scan window
** scan_type - Scan type
** addr_type_own - owner address type
** scan_duplicate_filter - scan duplicate filter
** scan_filter_policy - scan filter policy
** scan_setup_status_cback - Scan setup status callback
**
@@ -1057,7 +1064,7 @@ void BTM_BleSetScanParams(tGATT_IF client_if, UINT32 scan_interval,
**
*******************************************************************************/
void BTM_BleSetScanFilterParams(tGATT_IF client_if, UINT32 scan_interval, UINT32 scan_window,
tBLE_SCAN_MODE scan_mode, UINT8 addr_type_own, tBTM_BLE_SFP scan_filter_policy,
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);

View File

@@ -55,8 +55,9 @@
#define BTM_BLE_ENC_MASK 0x03
#define BTM_BLE_DUPLICATE_ENABLE 1
#define BTM_BLE_DUPLICATE_DISABLE 0
#define BTM_BLE_DUPLICATE_ENABLE 1
#define BTM_BLE_DUPLICATE_MAX BTM_BLE_DUPLICATE_ENABLE
#define BTM_BLE_GAP_DISC_SCAN_INT 18 /* Interval(scan_int) = 11.25 ms= 0x0010 * 0.625 ms */
#define BTM_BLE_GAP_DISC_SCAN_WIN 18 /* scan_window = 11.25 ms= 0x0010 * 0.625 ms */
@@ -161,7 +162,7 @@ typedef struct {
UINT8 adv_len;
UINT8 adv_data_cache[BTM_BLE_CACHE_ADV_DATA_MAX];
BD_ADDR adv_addr;
/* inquiry BD addr database */
UINT8 num_bd_entries;
UINT8 max_bd_entries;

View File

@@ -614,7 +614,7 @@ typedef struct {
// btla-specific --
#define BTM_SEC_NO_LAST_SERVICE_ID 0
UINT8 last_author_service_id; /* ID of last serviced authorized: Reset after each l2cap connection */
BOOLEAN enc_init_by_we;
} tBTM_SEC_DEV_REC;
#define BTM_SEC_IS_SM4(sm) ((BOOLEAN)(BTM_SM4_TRUE == ((sm)&BTM_SM4_TRUE)))

View File

@@ -1876,7 +1876,7 @@ BOOLEAN L2CA_RemoveFixedChnl (UINT16 fixed_cid, BD_ADDR rem_bda)
p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, transport);
if ( ((p_lcb) == NULL) || (!p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]) ) {
L2CAP_TRACE_WARNING ("L2CA_RemoveFixedChnl() CID: 0x%04x BDA: %08x%04x not connected", fixed_cid,
L2CAP_TRACE_DEBUG ("L2CA_RemoveFixedChnl() CID: 0x%04x BDA: %08x%04x not connected", fixed_cid,
(rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) + rem_bda[3], (rem_bda[4] << 8) + rem_bda[5]);
return (FALSE);
}

View File

@@ -261,6 +261,15 @@ void l2cble_notify_le_connection (BD_ADDR bda)
tACL_CONN *p_acl = btm_bda_to_acl(bda, BT_TRANSPORT_LE) ;
if (p_lcb != NULL && p_acl != NULL && p_lcb->link_state != LST_CONNECTED) {
if(p_acl->link_role == HCI_ROLE_SLAVE) {
//clear p_cb->state, controller will stop adv when ble connected.
tBTM_BLE_INQ_CB *p_cb = &btm_cb.ble_ctr_cb.inq_var;
if(p_cb) {
p_cb->adv_mode = BTM_BLE_ADV_DISABLE;
p_cb->state = BTM_BLE_STOP_ADV;
}
}
/* update link status */
btm_establish_continue(p_acl);
/* update l2cap link status and send callback */

View File

@@ -354,15 +354,17 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset)
type = *p++;
p = sdpu_get_len_from_type (p, type, &list_len);
}
if (list_len && list_len < cpy_len ) {
if (list_len < cpy_len ) {
cpy_len = list_len;
}
#if (SDP_DEBUG_RAW == TRUE)
SDP_TRACE_WARNING("list_len :%d cpy_len:%d raw_size:%d raw_used:%d\n",
SDP_TRACE_DEBUG("list_len :%d cpy_len:%d raw_size:%d raw_used:%d\n",
list_len, cpy_len, p_ccb->p_db->raw_size, p_ccb->p_db->raw_used);
#endif
memcpy (&p_ccb->p_db->raw_data[p_ccb->p_db->raw_used], p, cpy_len);
p_ccb->p_db->raw_used += cpy_len;
if (cpy_len != 0){
memcpy (&p_ccb->p_db->raw_data[p_ccb->p_db->raw_used], p, cpy_len);
p_ccb->p_db->raw_used += cpy_len;
}
}
}
#endif

View File

@@ -58,6 +58,8 @@ extern elliptic_curve_t curve_p256;
void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength);
bool ECC_CheckPointIsInElliCur_P256(Point *p);
#define ECC_PointMult(q, p, n, keyLength) ECC_PointMult_Bin_NAF(q, p, n, keyLength)
void p_256_init_curve(UINT32 keyLength);

View File

@@ -240,4 +240,39 @@ void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength)
multiprecision_mersenns_mult_mod(q->y, q->y, q->z, keyLength);
}
bool ECC_CheckPointIsInElliCur_P256(Point *p)
{
/* y^2 % q */
DWORD y_y_q[KEY_LENGTH_DWORDS_P256] = {0x0};
/* x^2 % q */
DWORD x_x_q[KEY_LENGTH_DWORDS_P256] = {0x0};
/* x % q */
DWORD x_q[KEY_LENGTH_DWORDS_P256] = {0x0};
/* x^2, To prevent overflow, the length of the x square here needs to
be expanded to two times the original one. */
DWORD x_x[2*KEY_LENGTH_DWORDS_P256] = {0x0};
/* y_y_q =(p->y)^2(mod q) */
multiprecision_mersenns_squa_mod(y_y_q, p->y, KEY_LENGTH_DWORDS_P256);
/* Calculate the value of p->x square, x_x = (p->x)^2 */
multiprecision_mult(x_x, p->x, p->x, KEY_LENGTH_DWORDS_P256);
/* The function of the elliptic curve is y^2 = x^3 - 3x + b (mod q) ==>
y^2 = (x^2 - 3)*x + b (mod q),
so we calculate the x^2 - 3 value here */
x_x[0] -= 3;
/* Using math relations. (a*b) % q = ((a%q)*(b%q)) % q ==>
(x^2 - 3)*x = (((x^2 - 3) % q) * x % q) % q */
multiprecision_fast_mod_P256(x_x_q, x_x);
/* x_x = x_x_q * x_q */
multiprecision_mult(x_x, x_x_q, p->x, KEY_LENGTH_DWORDS_P256);
/* x_q = x_x % q */
multiprecision_fast_mod_P256(x_q, x_x);
/* Save the result in x_x_q */
multiprecision_add_mod(x_x_q, x_q, curve_p256.b, KEY_LENGTH_DWORDS_P256);
/* compare the y_y_q and x_x_q, see if they are on a given elliptic curve. */
if (multiprecision_compare(y_y_q, x_x_q, KEY_LENGTH_DWORDS_P256)) {
return false;
} else {
return true;
}
}

View File

@@ -22,6 +22,7 @@
#include "btm_int.h"
#include "l2c_api.h"
#include "smp_int.h"
#include "p_256_ecc_pp.h"
//#include "utils/include/bt_utils.h"
#if SMP_INCLUDED == TRUE
@@ -58,7 +59,7 @@ static bool lmp_version_below(BD_ADDR bda, uint8_t version)
SMP_TRACE_WARNING("%s cannot retrieve LMP version...", __func__);
return false;
}
SMP_TRACE_WARNING("%s LMP version %d < %d", __func__, acl->lmp_version, version);
SMP_TRACE_DEBUG("%s LMP version %d < %d", __func__, acl->lmp_version, version);
return acl->lmp_version < version;
}
@@ -668,6 +669,12 @@ void smp_process_pairing_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
STREAM_TO_ARRAY(p_cb->peer_publ_key.x, p, BT_OCTET32_LEN);
STREAM_TO_ARRAY(p_cb->peer_publ_key.y, p, BT_OCTET32_LEN);
/* In order to prevent the x and y coordinates of the public key from being modified,
we need to check whether the x and y coordinates are on the given elliptic curve. */
if (!ECC_CheckPointIsInElliCur_P256((Point *)&p_cb->peer_publ_key)) {
SMP_TRACE_ERROR("%s, Invalid Public key.", __func__);
smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
}
p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY;
smp_wait_for_both_public_keys(p_cb, NULL);
@@ -1826,7 +1833,7 @@ void smp_set_local_oob_random_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
void smp_link_encrypted(BD_ADDR bda, UINT8 encr_enable)
{
tSMP_CB *p_cb = &smp_cb;
tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda);
SMP_TRACE_DEBUG("%s encr_enable=%d\n", __func__, encr_enable);
if (memcmp(&smp_cb.pairing_bda[0], bda, BD_ADDR_LEN) == 0) {
@@ -1837,6 +1844,16 @@ void smp_link_encrypted(BD_ADDR bda, UINT8 encr_enable)
btm_ble_update_sec_key_size(bda, p_cb->loc_enc_size);
}
smp_sm_event(&smp_cb, SMP_ENCRYPTED_EVT, &encr_enable);
} else if (p_dev_rec && !p_dev_rec->enc_init_by_we) {
/*
if enc_init_by_we is false, it means that client initiates encryption before slave calls esp_ble_set_encryption()
we need initiate pairing_bda and p_cb->role then encryption, for example iPhones
*/
memcpy(&smp_cb.pairing_bda[0], bda, BD_ADDR_LEN);
p_cb->state = SMP_STATE_ENCRYPTION_PENDING;
p_cb->role = HCI_ROLE_SLAVE;
p_dev_rec->enc_init_by_we = FALSE;
smp_sm_event(&smp_cb, SMP_ENCRYPTED_EVT, &encr_enable);
}
}

View File

@@ -105,7 +105,10 @@ static void smp_connect_callback (UINT16 channel, BD_ADDR bd_addr, BOOLEAN conne
if (transport == BT_TRANSPORT_BR_EDR || memcmp(bd_addr, dummy_bda, BD_ADDR_LEN) == 0) {
return;
}
if(!connected && &p_cb->rsp_timer_ent) {
//free timer
btu_free_timer(&p_cb->rsp_timer_ent);
}
if (memcmp(bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) == 0) {
SMP_TRACE_EVENT ("%s() for pairing BDA: %08x%04x Event: %s\n",
__FUNCTION__,

View File

@@ -50,14 +50,16 @@
#define BTDM_CFG_BT_DATA_RELEASE (1<<0)
#define BTDM_CFG_HCI_UART (1<<1)
#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)
/* Other reserved for future */
/* not for user call, so don't put to include file */
extern void btdm_osi_funcs_register(void *osi_funcs);
extern int btdm_controller_init(uint32_t config_mask, esp_bt_controller_config_t *config_opts);
extern int btdm_controller_deinit(void);
extern void btdm_controller_deinit(void);
extern int btdm_controller_enable(esp_bt_mode_t mode);
extern int btdm_controller_disable(esp_bt_mode_t mode);
extern void btdm_controller_disable(void);
extern uint8_t btdm_controller_get_mode(void);
extern const char *btdm_controller_get_compile_version(void);
extern void btdm_rf_bb_init(void);
@@ -600,6 +602,10 @@ static uint32_t btdm_config_mask_load(void)
#if CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE == 1
mask |= BTDM_CFG_CONTROLLER_RUN_APP_CPU;
#endif
mask |= BTDM_CFG_SCAN_DUPLICATE_OPTIONS;
mask |= BTDM_CFG_SEND_ADV_RESERVED_SIZE;
return mask;
}
@@ -742,9 +748,7 @@ esp_err_t esp_bt_controller_deinit(void)
return ESP_ERR_INVALID_STATE;
}
if (btdm_controller_deinit() != 0) {
return ESP_ERR_NO_MEM;
}
btdm_controller_deinit();
periph_module_disable(PERIPH_BT_MODULE);
@@ -800,21 +804,14 @@ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode)
esp_err_t esp_bt_controller_disable(void)
{
int ret;
if (btdm_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) {
return ESP_ERR_INVALID_STATE;
}
ret = btdm_controller_disable(btdm_controller_get_mode());
if (ret < 0) {
return ESP_ERR_INVALID_STATE;
}
btdm_controller_disable();
if (ret == ESP_BT_MODE_IDLE) {
esp_phy_rf_deinit();
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED;
}
esp_phy_rf_deinit();
btdm_controller_status = ESP_BT_CONTROLLER_STATUS_INITED;
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_release(s_pm_lock);

View File

@@ -35,9 +35,19 @@ typedef struct {
uint8_t controller_task_prio; /*!< Bluetooth controller task priority */
uint8_t hci_uart_no; /*!< If use UART1/2 as HCI IO interface, indicate UART number */
uint32_t hci_uart_baudrate; /*!< If use UART1/2 as HCI IO interface, indicate UART baudrate */
uint8_t scan_duplicate_mode; /*!< If use UART1/2 as HCI IO interface, indicate UART baudrate */
uint16_t normal_adv_size; /*!< Normal adv size for scan duplicate */
uint16_t mesh_adv_size; /*!< Mesh adv size for scan duplicate */
uint16_t send_adv_reserved_size; /*!< Controller minimum memory value */
uint32_t controller_debug_flag; /*!< Controller debug log flag */
} esp_bt_controller_config_t;
#ifdef CONFIG_BT_ENABLED
/* While scanning, if the free memory value in controller is less than SCAN_SEND_ADV_RESERVED_SIZE,
the adv packet will be discarded until the memory is restored. */
#define SCAN_SEND_ADV_RESERVED_SIZE 1000
/* open controller log debug when adv lost */
#define CONTROLLER_ADV_LOST_DEBUG_BIT (0<<0)
#ifdef CONFIG_BT_HCI_UART_NO
#define BT_HCI_UART_NO_DEFAULT CONFIG_BT_HCI_UART_NO
@@ -51,11 +61,42 @@ typedef struct {
#define BT_HCI_UART_BAUDRATE_DEFAULT 921600
#endif /* BT_HCI_UART_BAUDRATE_DEFAULT */
/* normal adv cache size */
#ifdef CONFIG_DUPLICATE_SCAN_CACHE_SIZE
#define NORMAL_SCAN_DUPLICATE_CACHE_SIZE CONFIG_DUPLICATE_SCAN_CACHE_SIZE
#else
#define NORMAL_SCAN_DUPLICATE_CACHE_SIZE 20
#endif
#ifndef CONFIG_BLE_MESH_SCAN_DUPLICATE_EN
#define CONFIG_BLE_MESH_SCAN_DUPLICATE_EN FALSE
#endif
#define SCAN_DUPLICATE_MODE_NORMAL_ADV_ONLY 0
#define SCAN_DUPLICATE_MODE_NORMAL_ADV_MESH_ADV 1
#if CONFIG_BLE_MESH_SCAN_DUPLICATE_EN
#define SCAN_DUPLICATE_MODE SCAN_DUPLICATE_MODE_NORMAL_ADV_MESH_ADV
#ifdef CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE
#define MESH_DUPLICATE_SCAN_CACHE_SIZE CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE
#else
#define MESH_DUPLICATE_SCAN_CACHE_SIZE 50
#endif
#else
#define SCAN_DUPLICATE_MODE SCAN_DUPLICATE_MODE_NORMAL_ADV_ONLY
#define MESH_DUPLICATE_SCAN_CACHE_SIZE 0
#endif
#define BT_CONTROLLER_INIT_CONFIG_DEFAULT() { \
.controller_task_stack_size = ESP_TASK_BT_CONTROLLER_STACK, \
.controller_task_prio = ESP_TASK_BT_CONTROLLER_PRIO, \
.hci_uart_no = BT_HCI_UART_NO_DEFAULT, \
.hci_uart_baudrate = BT_HCI_UART_BAUDRATE_DEFAULT, \
.scan_duplicate_mode = SCAN_DUPLICATE_MODE, \
.normal_adv_size = NORMAL_SCAN_DUPLICATE_CACHE_SIZE, \
.mesh_adv_size = MESH_DUPLICATE_SCAN_CACHE_SIZE, \
.send_adv_reserved_size = SCAN_SEND_ADV_RESERVED_SIZE, \
.controller_debug_flag = CONTROLLER_ADV_LOST_DEBUG_BIT, \
};
#else
#define BT_CONTROLLER_INIT_CONFIG_DEFAULT() {0}; _Static_assert(0, "please enable bluetooth in menuconfig to use bt.h");

View File

@@ -46,7 +46,7 @@ typedef enum {
* @brief This is a configuration structure for a SPI bus.
*
* You can use this structure to specify the GPIO pins of the bus. Normally, the driver will use the
* GPIO matrix to route the signals. An exception is made when all signals either can be routed through
* GPIO matrix to route the signals. An exception is made when all signals either can be routed through
* the IO_MUX or are -1. In that case, the IO_MUX is used, allowing for >40MHz speeds.
*
* @note Be advised that the slave driver does not use the quadwp/quadhd lines and fields in spi_bus_config_t refering to these lines will be ignored and can thus safely be left uninitialized.
@@ -81,20 +81,20 @@ bool spicommon_periph_free(spi_host_device_t host);
/**
* @brief Try to claim a SPI DMA channel
*
*
* Call this if your driver wants to use SPI with a DMA channnel.
*
*
* @param dma_chan channel to claim
*
*
* @return True if success; false otherwise.
*/
bool spicommon_dma_chan_claim(int dma_chan);
/**
* @brief Return the SPI DMA channel so other driver can claim it, or just to power down DMA.
*
*
* @param dma_chan channel to return
*
*
* @return True if success; false otherwise.
*/
bool spicommon_dma_chan_free(int dma_chan);
@@ -107,7 +107,7 @@ bool spicommon_dma_chan_free(int dma_chan);
* @brief Connect a SPI peripheral to GPIO pins
*
* This routine is used to connect a SPI peripheral to the IO-pads and DMA channel given in
* the arguments. Depending on the IO-pads requested, the routing is done either using the
* the arguments. Depending on the IO-pads requested, the routing is done either using the
* IO_mux or using the GPIO matrix.
*
* @param host SPI peripheral to be routed
@@ -116,7 +116,7 @@ bool spicommon_dma_chan_free(int dma_chan);
* @param flags Combination of SPICOMMON_BUSFLAG_* flags
* @param[out] is_native A value of 'true' will be written to this address if the GPIOs can be
* routed using the IO_mux, 'false' if the GPIO matrix is used.
* @return
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK on success
*/
@@ -126,7 +126,7 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
* @brief Free the IO used by a SPI peripheral
*
* @param host SPI peripheral to be freed
* @return
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK on success
*/
@@ -180,6 +180,26 @@ void spicommon_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *d
*/
spi_dev_t *spicommon_hw_for_host(spi_host_device_t host);
/** Temporarily connect CS signal input to high to avoid slave detecting unexpected transactions.
*
* @note Don't use this in the application.
*
* @param host The spi host.
*/
void spicommon_freeze_cs(spi_host_device_t host);
/** Use this function instead of cs_initial to avoid overwrite the output config
* This is used in test by internal gpio matrix connections
*
* @note Don't use this in the application.
*
* @param host The spi host.
* @param cs_io_num GPIO number of the CS pin.
* @param iomux The peripheral is using iomux pins.
*/
void spicommon_restore_cs(spi_host_device_t host, int cs_io_num, bool iomux);
/**
* @brief Get the IRQ source for a specific SPI host
*
@@ -201,10 +221,10 @@ typedef void(*dmaworkaround_cb_t)(void *arg);
* @note In some (well-defined) cases in the ESP32 (at least rev v.0 and v.1), a SPI DMA channel will get confused. This can be remedied
* by resetting the SPI DMA hardware in case this happens. Unfortunately, the reset knob used for thsi will reset _both_ DMA channels, and
* as such can only done safely when both DMA channels are idle. These functions coordinate this.
*
*
* Essentially, when a reset is needed, a driver can request this using spicommon_dmaworkaround_req_reset. This is supposed to be called
* with an user-supplied function as an argument. If both DMA channels are idle, this call will reset the DMA subsystem and return true.
* If the other DMA channel is still busy, it will return false; as soon as the other DMA channel is done, however, it will reset the
* with an user-supplied function as an argument. If both DMA channels are idle, this call will reset the DMA subsystem and return true.
* If the other DMA channel is still busy, it will return false; as soon as the other DMA channel is done, however, it will reset the
* DMA subsystem and call the callback. The callback is then supposed to be used to continue the SPI drivers activity.
*
* @param dmachan DMA channel associated with the SPI host that needs a reset

View File

@@ -329,6 +329,7 @@ void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num,
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[cs_io_num], 1);
} else {
//Use GPIO matrix
gpio_set_direction(cs_io_num, GPIO_MODE_INPUT_OUTPUT);
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[cs_io_num], PIN_FUNC_GPIO);
gpio_matrix_out(cs_io_num, io_signal[host].spics_out[cs_num], false, false);
if (cs_num == 0) gpio_matrix_in(cs_io_num, io_signal[host].spics_in, false);
@@ -344,7 +345,7 @@ void spicommon_cs_free(spi_host_device_t host, int cs_io_num)
}
//Set up a list of dma descriptors. dmadesc is an array of descriptors. Data is the buffer to point to.
void spicommon_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *data, bool isrx)
void IRAM_ATTR spicommon_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *data, bool isrx)
{
int n = 0;
while (len) {
@@ -371,6 +372,26 @@ void spicommon_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *d
dmadesc[n - 1].qe.stqe_next = NULL;
}
void spicommon_freeze_cs(spi_host_device_t host)
{
gpio_matrix_in(0x38, io_signal[host].spics_in, false);
}
static void IOMUX_IN(uint32_t gpio, uint32_t signal_idx)
{
GPIO.func_in_sel_cfg[signal_idx].sig_in_sel = 0;
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio]);
}
void spicommon_restore_cs(spi_host_device_t host, int cs_io_num, bool iomux)
{
if (iomux) {
IOMUX_IN(cs_io_num, io_signal[host].spics_in);
} else {
gpio_matrix_in(cs_io_num, io_signal[host].spics_in, false);
}
}
/*
Code for workaround for DMA issue in ESP32 v0/v1 silicon

View File

@@ -21,13 +21,13 @@ is a combination of SPI port and CS pin, plus some information about the specifi
The essence of the interface to a device is a set of queues; one per device. The idea is that to send something to a SPI
device, you allocate a transaction descriptor. It contains some information about the transfer like the lenghth, address,
command etc, plus pointers to transmit and receive buffer. The address of this block gets pushed into the transmit queue.
The SPI driver does its magic, and sends and retrieves the data eventually. The data gets written to the receive buffers,
command etc, plus pointers to transmit and receive buffer. The address of this block gets pushed into the transmit queue.
The SPI driver does its magic, and sends and retrieves the data eventually. The data gets written to the receive buffers,
if needed the transaction descriptor is modified to indicate returned parameters and the entire thing goes into the return
queue, where whatever software initiated the transaction can retrieve it.
The entire thing is run from the SPI interrupt handler. If SPI is done transmitting/receiving but nothing is in the queue,
it will not clear the SPI interrupt but just disable it. This way, when a new thing is sent, pushing the packet into the send
The entire thing is run from the SPI interrupt handler. If SPI is done transmitting/receiving but nothing is in the queue,
it will not clear the SPI interrupt but just disable it. This way, when a new thing is sent, pushing the packet into the send
queue and re-enabling the interrupt will trigger the interrupt again, which can then take care of the sending.
*/
@@ -67,8 +67,8 @@ typedef struct spi_device_t spi_device_t;
/// struct to hold private transaction data (like tx and rx buffer for DMA).
typedef struct {
spi_transaction_t *trans;
typedef struct {
spi_transaction_t *trans;
uint32_t *buffer_to_send; //equals to tx_data, if SPI_TRANS_USE_RXDATA is applied; otherwise if original buffer wasn't in DMA-capable memory, this gets the address of a temporary buffer that is;
//otherwise sets to the original buffer or NULL if no buffer is assigned.
uint32_t *buffer_to_rcv; // similar to buffer_to_send
@@ -140,10 +140,10 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus
goto nomem;
}
#endif //CONFIG_PM_ENABLE
spicommon_bus_initialize_io(host, bus_config, dma_chan, SPICOMMON_BUSFLAG_MASTER|SPICOMMON_BUSFLAG_QUAD, &native);
spihost[host]->no_gpio_matrix=native;
spihost[host]->dma_chan=dma_chan;
if (dma_chan == 0) {
spihost[host]->max_transfer_sz = 32;
@@ -180,7 +180,7 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus
spihost[host]->hw->slave.wr_sta_inten=0;
//Force a transaction done interrupt. This interrupt won't fire yet because we initialized the SPI interrupt as
//disabled. This way, we can just enable the SPI interrupt and the interrupt handler will kick in, handling
//disabled. This way, we can just enable the SPI interrupt and the interrupt handler will kick in, handling
//any transactions that are queued.
spihost[host]->hw->slave.trans_inten=1;
spihost[host]->hw->slave.trans_done=1;
@@ -271,7 +271,6 @@ esp_err_t spi_bus_add_device(spi_host_device_t host, spi_device_interface_config
//Set CS pin, CS options
if (dev_config->spics_io_num >= 0) {
gpio_set_direction(dev_config->spics_io_num, GPIO_MODE_OUTPUT);
spicommon_cs_initialize(host, dev_config->spics_io_num, freecs, spihost[host]->no_gpio_matrix == false);
}
if (dev_config->flags&SPI_DEVICE_CLK_AS_CS) {
@@ -397,7 +396,7 @@ static void IRAM_ATTR spi_intr(void *arg)
/*------------ deal with the in-flight transaction -----------------*/
if (host->cur_cs != NO_CS) {
spi_transaction_t *cur_trans = host->cur_trans_buf.trans;
//Okay, transaction is done.
//Okay, transaction is done.
if (host->cur_trans_buf.buffer_to_rcv && host->dma_chan == 0 ) {
//Need to copy from SPI regs to result buffer.
for (int x=0; x < cur_trans->rxlength; x+=32) {
@@ -411,7 +410,7 @@ static void IRAM_ATTR spi_intr(void *arg)
//Call post-transaction callback, if any
if (host->device[host->cur_cs]->cfg.post_cb) host->device[host->cur_cs]->cfg.post_cb(cur_trans);
//Return transaction descriptor.
xQueueSendFromISR(host->device[host->cur_cs]->ret_queue, &host->cur_trans_buf, &do_yield);
xQueueSendFromISR(host->device[host->cur_cs]->ret_queue, &host->cur_trans_buf, &do_yield);
prevCs=host->cur_cs;
host->cur_cs = NO_CS;
}
@@ -443,7 +442,7 @@ static void IRAM_ATTR spi_intr(void *arg)
host->cur_cs=i;
//We should be done with the transmission.
assert(host->hw->cmd.usr == 0);
//Reconfigure according to device settings, but only if we change CSses.
if (i!=prevCs) {
//Assumes a hardcoded 80MHz Fapb for now. ToDo: figure out something better once we have
@@ -453,7 +452,7 @@ static void IRAM_ATTR spi_intr(void *arg)
//Configure bit order
host->hw->ctrl.rd_bit_order=(dev->cfg.flags & SPI_DEVICE_RXBIT_LSBFIRST)?1:0;
host->hw->ctrl.wr_bit_order=(dev->cfg.flags & SPI_DEVICE_TXBIT_LSBFIRST)?1:0;
//Configure polarity
//SPI iface needs to be configured for a delay in some cases.
int nodelay=0;
@@ -548,7 +547,7 @@ static void IRAM_ATTR spi_intr(void *arg)
host->hw->dma_in_link.start=1;
}
} else {
//DMA temporary workaround: let RX DMA work somehow to avoid the issue in ESP32 v0/v1 silicon
//DMA temporary workaround: let RX DMA work somehow to avoid the issue in ESP32 v0/v1 silicon
if (host->dma_chan != 0 ) {
host->hw->dma_in_link.addr=0;
host->hw->dma_in_link.start=1;
@@ -601,17 +600,38 @@ static void IRAM_ATTR spi_intr(void *arg)
host->hw->user.usr_addr=addrlen?1:0;
host->hw->user.usr_command=cmdlen?1:0;
// output command will be sent from bit 7 to 0 of command_value, and then bit 15 to 8 of the same register field.
if ((dev->cfg.flags & SPI_DEVICE_TXBIT_LSBFIRST)==0) {
/* Output command will be sent from bit 7 to 0 of command_value, and
* then bit 15 to 8 of the same register field. Shift and swap to send
* more straightly.
*/
uint16_t command = trans->cmd << (16-cmdlen); //shift to MSB
host->hw->user2.usr_command_value = (command>>8)|(command<<8); //swap the first and second byte
// shift the address to MSB of addr (and maybe slv_wr_status) register.
// output address will be sent from MSB to LSB of addr register, then comes the MSB to LSB of slv_wr_status register.
if (addrlen>32) {
host->hw->addr = trans->addr >> (addrlen- 32);
// shift the address to MSB of addr (and maybe slv_wr_status) register.
// output address will be sent from MSB to LSB of addr register, then comes the MSB to LSB of slv_wr_status register.
if (addrlen > 32) {
host->hw->addr = trans->addr >> (addrlen - 32);
host->hw->slv_wr_status = trans->addr << (64 - addrlen);
} else {
host->hw->addr = trans->addr << (32 - addrlen);
}
} else {
/* The output command start from bit0 to bit 15, kept as is.
* The output address start from the LSB of the highest byte, i.e.
* addr[24] -> addr[31]
* ...
* addr[0] -> addr[7]
* slv_wr_status[24] -> slv_wr_status[31]
* ...
* slv_wr_status[0] -> slv_wr_status[7]
* So swap the byte order to let the LSB sent first.
*/
host->hw->user2.usr_command_value = trans->cmd;
uint64_t addr = __builtin_bswap64(trans->addr);
host->hw->addr = addr>>32;
host->hw->slv_wr_status = addr;
}
host->hw->user.usr_mosi=( (!(dev->cfg.flags & SPI_DEVICE_HALFDUPLEX) && trans_buf->buffer_to_rcv) || trans_buf->buffer_to_send)?1:0;
host->hw->user.usr_miso=(trans_buf->buffer_to_rcv)?1:0;
@@ -630,13 +650,13 @@ esp_err_t spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *
esp_err_t ret = ESP_OK;
BaseType_t r;
SPI_CHECK(handle!=NULL, "invalid dev handle", ESP_ERR_INVALID_ARG);
//check transmission length
//check transmission length
SPI_CHECK((trans_desc->flags & SPI_TRANS_USE_RXDATA)==0 ||trans_desc->rxlength <= 32, "rxdata transfer > 32 bits without configured DMA", ESP_ERR_INVALID_ARG);
SPI_CHECK((trans_desc->flags & SPI_TRANS_USE_TXDATA)==0 ||trans_desc->length <= 32, "txdata transfer > 32 bits without configured DMA", ESP_ERR_INVALID_ARG);
SPI_CHECK(trans_desc->length <= handle->host->max_transfer_sz*8, "txdata transfer > host maximum", ESP_ERR_INVALID_ARG);
SPI_CHECK(trans_desc->rxlength <= handle->host->max_transfer_sz*8, "rxdata transfer > host maximum", ESP_ERR_INVALID_ARG);
SPI_CHECK((handle->cfg.flags & SPI_DEVICE_HALFDUPLEX) || trans_desc->rxlength <= trans_desc->length, "rx length > tx length in full duplex mode", ESP_ERR_INVALID_ARG);
//check working mode
//check working mode
SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && (handle->cfg.flags & SPI_DEVICE_3WIRE)), "incompatible iface params", ESP_ERR_INVALID_ARG);
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) || handle->host->dma_chan == 0 || !(trans_desc->flags & SPI_TRANS_USE_RXDATA || trans_desc->rx_buffer != NULL)
@@ -655,7 +675,7 @@ esp_err_t spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *
// rx memory assign
if ( trans_desc->flags & SPI_TRANS_USE_RXDATA ) {
trans_buf.buffer_to_rcv = (uint32_t*)&trans_desc->rx_data[0];
} else {
} else {
//if not use RXDATA neither rx_buffer, buffer_to_rcv assigned to NULL
trans_buf.buffer_to_rcv = trans_desc->rx_buffer;
}
@@ -668,12 +688,12 @@ esp_err_t spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *
goto clean_up;
}
}
const uint32_t *txdata;
// tx memory assign
if ( trans_desc->flags & SPI_TRANS_USE_TXDATA ) {
txdata = (uint32_t*)&trans_desc->tx_data[0];
} else {
} else {
//if not use TXDATA neither tx_buffer, tx data assigned to NULL
txdata = trans_desc->tx_buffer ;
}
@@ -686,11 +706,11 @@ esp_err_t spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *
goto clean_up;
}
memcpy( trans_buf.buffer_to_send, txdata, (trans_desc->length+7)/8 );
} else {
} else {
// else use the original buffer (forced-conversion) or assign to NULL
trans_buf.buffer_to_send = (uint32_t*)txdata;
}
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_acquire(handle->host->pm_lock);
#endif
@@ -710,10 +730,10 @@ clean_up:
// free malloc-ed buffer (if needed) before return.
if ( (void*)trans_buf.buffer_to_rcv != trans_desc->rx_buffer && (void*)trans_buf.buffer_to_rcv != &trans_desc->rx_data[0] ) {
free( trans_buf.buffer_to_rcv );
}
}
if ( (void*)trans_buf.buffer_to_send!= trans_desc->tx_buffer && (void*)trans_buf.buffer_to_send != &trans_desc->tx_data[0] ) {
free( trans_buf.buffer_to_send );
}
}
assert( ret != ESP_OK );
return ret;
}
@@ -722,12 +742,12 @@ esp_err_t spi_device_get_trans_result(spi_device_handle_t handle, spi_transactio
{
BaseType_t r;
spi_trans_priv trans_buf;
SPI_CHECK(handle!=NULL, "invalid dev handle", ESP_ERR_INVALID_ARG);
r=xQueueReceive(handle->ret_queue, (void*)&trans_buf, ticks_to_wait);
if (!r) {
// The memory occupied by rx and tx DMA buffer destroyed only when receiving from the queue (transaction finished).
// If timeout, wait and retry.
// If timeout, wait and retry.
// Every on-flight transaction request occupies internal memory as DMA buffer if needed.
return ESP_ERR_TIMEOUT;
}
@@ -736,12 +756,12 @@ esp_err_t spi_device_get_trans_result(spi_device_handle_t handle, spi_transactio
if ( (void*)trans_buf.buffer_to_send != &(*trans_desc)->tx_data[0] && trans_buf.buffer_to_send != (*trans_desc)->tx_buffer ) {
free( trans_buf.buffer_to_send );
}
}
//copy data from temporary DMA-capable buffer back to IRAM buffer and free the temporary one.
if ( (void*)trans_buf.buffer_to_rcv != &(*trans_desc)->rx_data[0] && trans_buf.buffer_to_rcv != (*trans_desc)->rx_buffer ) {
if ( (*trans_desc)->flags & SPI_TRANS_USE_RXDATA ) {
memcpy( (uint8_t*)&(*trans_desc)->rx_data[0], trans_buf.buffer_to_rcv, ((*trans_desc)->rxlength+7)/8 );
memcpy( (uint8_t*)&(*trans_desc)->rx_data[0], trans_buf.buffer_to_rcv, ((*trans_desc)->rxlength+7)/8 );
} else {
memcpy( (*trans_desc)->rx_buffer, trans_buf.buffer_to_rcv, ((*trans_desc)->rxlength+7)/8 );
}

View File

@@ -50,6 +50,7 @@ static const char *SPI_TAG = "spi_slave";
#define VALID_HOST(x) (x>SPI_HOST && x<=VSPI_HOST)
typedef struct {
int id;
spi_slave_interface_config_t cfg;
intr_handle_t intr;
spi_dev_t *hw;
@@ -79,7 +80,7 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
spi_chan_claimed=spicommon_periph_claim(host);
SPI_CHECK(spi_chan_claimed, "host already in use", ESP_ERR_INVALID_STATE);
if ( dma_chan != 0 ) {
dma_chan_claimed=spicommon_dma_chan_claim(dma_chan);
if ( !dma_chan_claimed ) {
@@ -92,10 +93,12 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
if (spihost[host] == NULL) goto nomem;
memset(spihost[host], 0, sizeof(spi_slave_t));
memcpy(&spihost[host]->cfg, slave_config, sizeof(spi_slave_interface_config_t));
spihost[host]->id = host;
spicommon_bus_initialize_io(host, bus_config, dma_chan, SPICOMMON_BUSFLAG_SLAVE, &native);
gpio_set_direction(slave_config->spics_io_num, GPIO_MODE_INPUT);
spicommon_cs_initialize(host, slave_config->spics_io_num, 0, native == false);
spicommon_cs_initialize(host, slave_config->spics_io_num, 0, native==false);
// The slave DMA suffers from unexpected transactions. Forbid reading if DMA is enabled by disabling the CS line.
if (dma_chan != 0) spicommon_freeze_cs(host);
spihost[host]->no_gpio_matrix = native;
spihost[host]->dma_chan = dma_chan;
if (dma_chan != 0) {
@@ -239,9 +242,9 @@ esp_err_t spi_slave_queue_trans(spi_host_device_t host, const spi_slave_transact
BaseType_t r;
SPI_CHECK(VALID_HOST(host), "invalid host", ESP_ERR_INVALID_ARG);
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),
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),
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(trans_desc->length <= spihost[host]->max_transfer_sz * 8, "data transfer > host maximum", ESP_ERR_INVALID_ARG);
@@ -325,8 +328,11 @@ static void IRAM_ATTR spi_intr(void *arg)
if (!host->hw->slave.trans_done) return;
if (host->cur_trans) {
// When DMA is enabled, the slave rx dma suffers from unexpected transactions. Forbid reading until transaction ready.
if (host->dma_chan != 0) spicommon_freeze_cs(host->id);
//when data of cur_trans->length are all sent, the slv_rdata_bit
//will be the length sent-1 (i.e. cur_trans->length-1 ), otherwise
//will be the length sent-1 (i.e. cur_trans->length-1 ), otherwise
//the length sent.
host->cur_trans->trans_len = host->hw->slv_rd_bit.slv_rdata_bit;
if ( host->cur_trans->trans_len == host->cur_trans->length - 1 ) {
@@ -433,6 +439,9 @@ static void IRAM_ATTR spi_intr(void *arg)
host->hw->user.usr_mosi = (trans->tx_buffer == NULL) ? 0 : 1;
host->hw->user.usr_miso = (trans->rx_buffer == NULL) ? 0 : 1;
//The slave rx dma get disturbed by unexpected transaction. Only connect the CS when slave is ready.
if (host->dma_chan != 0) spicommon_restore_cs(host->id, host->cfg.spics_io_num, host->no_gpio_matrix);
//Kick off transfer
host->hw->cmd.usr = 1;
if (host->cfg.post_setup_cb) host->cfg.post_setup_cb(trans);

View File

@@ -390,7 +390,7 @@ TEST_CASE("SPI Master DMA test, TX and RX in different regions", "[spi]")
trans[4].rxlength = 8*4;
trans[4].tx_buffer = data_drom;
trans[4].flags = SPI_TRANS_USE_RXDATA;
trans[5].length = 8*4;
trans[5].flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA;
@@ -412,7 +412,7 @@ TEST_CASE("SPI Master DMA test, TX and RX in different regions", "[spi]")
}
static inline void int_connect( uint32_t gpio, uint32_t sigo, uint32_t sigi )
static inline void int_connect( uint32_t gpio, uint32_t sigo, uint32_t sigi )
{
gpio_matrix_out( gpio, sigo, false, false );
gpio_matrix_in( gpio, sigi, false );
@@ -430,7 +430,7 @@ TEST_CASE("SPI Master DMA test: length, start, not aligned", "[spi]")
esp_err_t ret;
spi_device_handle_t spi;
spi_bus_config_t buscfg={
.miso_io_num=PIN_NUM_MISO,
.miso_io_num=PIN_NUM_MISO,
.mosi_io_num=PIN_NUM_MOSI,
.sclk_io_num=PIN_NUM_CLK,
.quadwp_io_num=-1,
@@ -441,7 +441,7 @@ TEST_CASE("SPI Master DMA test: length, start, not aligned", "[spi]")
.mode=0, //SPI mode 0
.spics_io_num=PIN_NUM_CS, //CS pin
.queue_size=7, //We want to be able to queue 7 transactions at a time
.pre_cb=NULL,
.pre_cb=NULL,
};
//Initialize the SPI bus
ret=spi_bus_initialize(HSPI_HOST, &buscfg, 1);
@@ -454,14 +454,14 @@ TEST_CASE("SPI Master DMA test: length, start, not aligned", "[spi]")
int_connect( PIN_NUM_MOSI, HSPID_OUT_IDX, HSPIQ_IN_IDX );
memset(rx_buf, 0x66, 320);
for ( int i = 0; i < 8; i ++ ) {
memset( rx_buf, 0x66, sizeof(rx_buf));
spi_transaction_t t = {};
t.length = 8*(i+1);
t.rxlength = 0;
t.tx_buffer = tx_buf+2*i;
t.tx_buffer = tx_buf+2*i;
t.rx_buffer = rx_buf + i;
if ( i == 1 ) {
@@ -470,7 +470,7 @@ TEST_CASE("SPI Master DMA test: length, start, not aligned", "[spi]")
} else if ( i == 2 ) {
//test rx length != tx_length
t.rxlength = t.length - 8;
}
}
spi_device_transmit( spi, &t );
for( int i = 0; i < 16; i ++ ) {
@@ -486,7 +486,7 @@ TEST_CASE("SPI Master DMA test: length, start, not aligned", "[spi]")
} else {
//normal check
TEST_ASSERT( memcmp(t.tx_buffer, t.rx_buffer, t.length/8)==0 );
}
}
}
TEST_ASSERT(spi_bus_remove_device(spi) == ESP_OK);
@@ -495,14 +495,15 @@ TEST_CASE("SPI Master DMA test: length, start, not aligned", "[spi]")
static const char MASTER_TAG[] = "test_master";
static const char SLAVE_TAG[] = "test_slave";
DRAM_ATTR static uint8_t master_send[] = {0x93, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0xaa, 0xcc, 0xff, 0xee, 0x55, 0x77, 0x88, 0x43};
//DRAM_ATTR static uint8_t master_send[] = {0x93, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0xaa, 0xcc, 0xff, 0xee, 0x55, 0x77, 0x88, 0x43};
DRAM_ATTR static uint8_t slave_send[] = { 0xaa, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x13, 0x57, 0x9b, 0xdf, 0x24, 0x68, 0xac, 0xe0 };
/*
static void master_init( spi_device_handle_t* spi, int mode, uint32_t speed)
{
esp_err_t ret;
spi_bus_config_t buscfg={
.miso_io_num=PIN_NUM_MISO,
.miso_io_num=PIN_NUM_MISO,
.mosi_io_num=PIN_NUM_MOSI,
.sclk_io_num=PIN_NUM_CLK,
.quadwp_io_num=-1,
@@ -513,7 +514,7 @@ static void master_init( spi_device_handle_t* spi, int mode, uint32_t speed)
.mode=mode, //SPI mode 0
.spics_io_num=PIN_NUM_CS, //CS pin
.queue_size=16, //We want to be able to queue 7 transactions at a time
.pre_cb=NULL,
.pre_cb=NULL,
.cs_ena_pretrans = 0,
};
//Initialize the SPI bus
@@ -546,6 +547,7 @@ static void slave_init(int mode, int dma_chan)
//Initialize SPI slave interface
TEST_ESP_OK( spi_slave_initialize(VSPI_HOST, &buscfg, &slvcfg, dma_chan) );
}
*/
typedef struct {
uint32_t len;
@@ -604,6 +606,7 @@ static void task_slave(void* arg)
t.tx_buffer = txdata.start;
t.rx_buffer = recvbuf+4;
//loop until trans_len != 0 to skip glitches
memset(recvbuf, 0x66, sizeof(recvbuf));
do {
TEST_ESP_OK( spi_slave_transmit( VSPI_HOST, &t, portMAX_DELAY ) );
} while ( t.trans_len == 0 );
@@ -613,118 +616,177 @@ static void task_slave(void* arg)
}
}
TEST_CASE("SPI master variable cmd & addr test","[spi]")
#define TEST_SPI_HOST HSPI_HOST
#define TEST_SLAVE_HOST VSPI_HOST
static uint8_t bitswap(uint8_t in)
{
uint8_t *tx_buf=master_send;
uint8_t rx_buf[320];
uint8_t *rx_buf_ptr = rx_buf;
uint8_t out = 0;
for (int i = 0; i < 8; i++) {
out = out >> 1;
if (in&0x80) out |= 0x80;
in = in << 1;
}
return out;
}
spi_slave_task_context_t slave_context = {};
esp_err_t err = init_slave_context( &slave_context );
TEST_ASSERT( err == ESP_OK );
#define SPI_BUS_TEST_DEFAULT_CONFIG() {\
.miso_io_num=PIN_NUM_MISO, \
.mosi_io_num=PIN_NUM_MOSI,\
.sclk_io_num=PIN_NUM_CLK,\
.quadwp_io_num=-1,\
.quadhd_io_num=-1\
}
#define SPI_DEVICE_TEST_DEFAULT_CONFIG() {\
.clock_speed_hz=10*1000*1000,\
.mode=0,\
.spics_io_num=PIN_NUM_CS,\
.queue_size=16,\
.pre_cb=NULL, \
.cs_ena_pretrans = 0,\
.cs_ena_posttrans = 0,\
}
#define SPI_SLAVE_TEST_DEFAULT_CONFIG() {\
.mode=0,\
.spics_io_num=PIN_NUM_CS,\
.queue_size=3,\
.flags=0,\
}
void test_cmd_addr(spi_slave_task_context_t *slave_context, bool lsb_first)
{
spi_device_handle_t spi;
//initial master, mode 0, 1MHz
master_init( &spi, 0, 1*1000*1000 );
//initial slave, mode 0, no dma
slave_init(0, 0);
ESP_LOGI(MASTER_TAG, ">>>>>>>>> TEST %s FIRST <<<<<<<<<<<", lsb_first?"LSB":"MSB");
//do internal connection
//initial master, mode 0, 1MHz
spi_bus_config_t buscfg=SPI_BUS_TEST_DEFAULT_CONFIG();
TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST, &buscfg, 1));
spi_device_interface_config_t devcfg=SPI_DEVICE_TEST_DEFAULT_CONFIG();
devcfg.clock_speed_hz = 1*1000*1000;
if (lsb_first) devcfg.flags |= SPI_DEVICE_BIT_LSBFIRST;
TEST_ESP_OK(spi_bus_add_device(TEST_SPI_HOST, &devcfg, &spi));
//connecting pins to two peripherals breaks the output, fix it.
int_connect( PIN_NUM_MOSI, HSPID_OUT_IDX, VSPIQ_IN_IDX );
int_connect( PIN_NUM_MISO, VSPIQ_OUT_IDX, HSPID_IN_IDX );
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 < 8; i++) {
//prepare slave tx data
slave_txdata_t slave_txdata = (slave_txdata_t) {
.start = slave_send,
.len = 256,
};
xQueueSend(slave_context->data_to_send, &slave_txdata, portMAX_DELAY);
vTaskDelay(50);
//prepare master tx data
int cmd_bits = (i+1)*2;
int addr_bits = 56-8*i;
int round_up = (cmd_bits+addr_bits+7)/8*8;
addr_bits = round_up - cmd_bits;
spi_transaction_ext_t trans = (spi_transaction_ext_t) {
.base = {
.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
.addr = 0x456789abcdef0123,
.cmd = 0xcdef,
},
.command_bits = cmd_bits,
.address_bits = addr_bits,
};
ESP_LOGI( MASTER_TAG, "===== test%d =====", i );
ESP_LOGI(MASTER_TAG, "cmd_bits %d, addr_bits: %d", cmd_bits, addr_bits);
TEST_ESP_OK(spi_device_transmit(spi, (spi_transaction_t*)&trans));
//wait for both master and slave end
size_t rcv_len;
slave_rxdata_t *rcv_data = xRingbufferReceive(slave_context->data_received, &rcv_len, portMAX_DELAY);
rcv_len-=4;
uint8_t *buffer = rcv_data->data;
ESP_LOGI(SLAVE_TAG, "trans_len: %d", rcv_len);
TEST_ASSERT_EQUAL(rcv_len, (rcv_data->len+7)/8);
TEST_ASSERT_EQUAL(rcv_data->len, cmd_bits+addr_bits);
ESP_LOG_BUFFER_HEX("slave rx", buffer, rcv_len);
uint16_t cmd_expected = trans.base.cmd & (BIT(cmd_bits) - 1);
uint64_t addr_expected = trans.base.addr & ((1ULL<<addr_bits) - 1);
uint8_t *data_ptr = buffer;
uint16_t cmd_got = *(uint16_t*)data_ptr;
data_ptr += cmd_bits/8;
cmd_got = __builtin_bswap16(cmd_got);
cmd_got = cmd_got >> (16-cmd_bits);
int remain_bits = cmd_bits % 8;
uint64_t addr_got = *(uint64_t*)data_ptr;
data_ptr += 8;
addr_got = __builtin_bswap64(addr_got);
addr_got = (addr_got << remain_bits);
addr_got |= (*data_ptr >> (8-remain_bits));
addr_got = addr_got >> (64-addr_bits);
if (lsb_first) {
cmd_got = __builtin_bswap16(cmd_got);
addr_got = __builtin_bswap64(addr_got);
uint8_t *swap_ptr = (uint8_t*)&cmd_got;
swap_ptr[0] = bitswap(swap_ptr[0]);
swap_ptr[1] = bitswap(swap_ptr[1]);
cmd_got = cmd_got >> (16-cmd_bits);
swap_ptr = (uint8_t*)&addr_got;
for (int j = 0; j < 8; j++) swap_ptr[j] = bitswap(swap_ptr[j]);
addr_got = addr_got >> (64-addr_bits);
}
ESP_LOGI(SLAVE_TAG, "cmd_got: %04X, addr_got: %08X%08X", cmd_got, (uint32_t)(addr_got>>32), (uint32_t)addr_got);
TEST_ASSERT_EQUAL_HEX16(cmd_expected, cmd_got);
if (addr_bits > 0) {
TEST_ASSERT_EQUAL_HEX32(addr_expected, addr_got);
TEST_ASSERT_EQUAL_HEX32(addr_expected >> 8, addr_got >> 8);
}
//clean
vRingbufferReturnItem(slave_context->data_received, buffer);
}
TEST_ASSERT(spi_bus_remove_device(spi) == ESP_OK);
TEST_ASSERT(spi_bus_free(TEST_SPI_HOST) == ESP_OK);
}
TEST_CASE("SPI master variable cmd & addr test","[spi]")
{
spi_slave_task_context_t slave_context = {};
esp_err_t err = init_slave_context( &slave_context );
TEST_ASSERT( err == ESP_OK );
TaskHandle_t handle_slave;
xTaskCreate( task_slave, "spi_slave", 4096, &slave_context, 0, &handle_slave);
slave_txdata_t slave_txdata[16];
spi_transaction_ext_t trans[16];
for( int i= 0; i < 16; i ++ ) {
//prepare slave tx data
slave_txdata[i] = (slave_txdata_t) {
.start = slave_send + 4*(i%3),
.len = 256,
};
xQueueSend( slave_context.data_to_send, &slave_txdata[i], portMAX_DELAY );
//prepare master tx data
trans[i] = (spi_transaction_ext_t) {
.base = {
.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR,
.addr = 0x456789ab,
.cmd = 0xcdef,
//initial slave, mode 0, no dma
int dma_chan = 0;
int slave_mode = 0;
spi_bus_config_t slv_buscfg=SPI_BUS_TEST_DEFAULT_CONFIG();
spi_slave_interface_config_t slvcfg=SPI_SLAVE_TEST_DEFAULT_CONFIG();
slvcfg.mode = slave_mode;
//Initialize SPI slave interface
TEST_ESP_OK( spi_slave_initialize(TEST_SLAVE_HOST, &slv_buscfg, &slvcfg, dma_chan) );
.length = 8*i,
.tx_buffer = tx_buf+i,
.rx_buffer = rx_buf_ptr,
},
.command_bits = ((i+1)%3) * 8,
.address_bits = ((i/3)%5) * 8,
};
if ( trans[i].base.length == 0 ) {
trans[i].base.tx_buffer = NULL;
trans[i].base.rx_buffer = NULL;
} else {
rx_buf_ptr += (trans[i].base.length + 31)/32*4;
}
}
vTaskDelay(10);
for ( int i = 0; i < 16; i ++ ) {
TEST_ESP_OK (spi_device_queue_trans( spi, (spi_transaction_t*)&trans[i], portMAX_DELAY ) );
vTaskDelay(10);
}
for( int i= 0; i < 16; i ++ ) {
//wait for both master and slave end
ESP_LOGI( MASTER_TAG, "===== test%d =====", i );
spi_transaction_ext_t *t;
size_t rcv_len;
spi_device_get_trans_result( spi, (spi_transaction_t**)&t, portMAX_DELAY );
TEST_ASSERT( t == &trans[i] );
if ( trans[i].base.length != 0 ) {
ESP_LOG_BUFFER_HEX( "master tx", trans[i].base.tx_buffer, trans[i].base.length/8 );
ESP_LOG_BUFFER_HEX( "master rx", trans[i].base.rx_buffer, trans[i].base.length/8 );
} else {
ESP_LOGI( "master tx", "no data" );
ESP_LOGI( "master rx", "no data" );
}
slave_rxdata_t *rcv_data = xRingbufferReceive( slave_context.data_received, &rcv_len, portMAX_DELAY );
uint8_t *buffer = rcv_data->data;
rcv_len = rcv_data->len;
ESP_LOGI(SLAVE_TAG, "trans_len: %d", rcv_len);
ESP_LOG_BUFFER_HEX( "slave tx", slave_txdata[i].start, (rcv_len+7)/8);
ESP_LOG_BUFFER_HEX( "slave rx", buffer, (rcv_len+7)/8);
//check result
uint8_t *ptr_addr = (uint8_t*)&t->base.addr;
uint8_t *ptr_cmd = (uint8_t*)&t->base.cmd;
for ( int j = 0; j < t->command_bits/8; j ++ ) {
TEST_ASSERT_EQUAL( buffer[j], ptr_cmd[t->command_bits/8-j-1] );
}
for ( int j = 0; j < t->address_bits/8; j ++ ) {
TEST_ASSERT_EQUAL( buffer[t->command_bits/8+j], ptr_addr[t->address_bits/8-j-1] );
}
if ( t->base.length != 0) {
TEST_ASSERT_EQUAL_HEX8_ARRAY(t->base.tx_buffer, buffer + (t->command_bits + t->address_bits)/8, t->base.length/8);
TEST_ASSERT_EQUAL_HEX8_ARRAY(slave_txdata[i].start + (t->command_bits + t->address_bits)/8, t->base.rx_buffer, t->base.length/8);
}
TEST_ASSERT_EQUAL( t->base.length + t->command_bits + t->address_bits, rcv_len );
//clean
vRingbufferReturnItem( slave_context.data_received, buffer );
}
test_cmd_addr(&slave_context, false);
test_cmd_addr(&slave_context, true);
vTaskDelete( handle_slave );
handle_slave = 0;
deinit_slave_context(&slave_context);
TEST_ASSERT(spi_slave_free(VSPI_HOST) == ESP_OK);
TEST_ASSERT(spi_bus_remove_device(spi) == ESP_OK);
TEST_ASSERT(spi_bus_free(HSPI_HOST) == ESP_OK);
TEST_ASSERT(spi_slave_free(TEST_SLAVE_HOST) == ESP_OK);
ESP_LOGI(MASTER_TAG, "test passed.");
}

View File

@@ -43,6 +43,8 @@ static const char* UART_TAG = "uart";
#define UART_EMPTY_THRESH_DEFAULT (10)
#define UART_FULL_THRESH_DEFAULT (120)
#define UART_TOUT_THRESH_DEFAULT (10)
#define UART_CLKDIV_FRAG_BIT_WIDTH (3)
#define UART_TOUT_REF_FACTOR_DEFAULT (UART_CLK_FREQ/(REF_CLK_FREQ<<UART_CLKDIV_FRAG_BIT_WIDTH))
#define UART_TX_IDLE_NUM_DEFAULT (0)
#define UART_PATTERN_DET_QLEN_DEFAULT (10)
@@ -654,7 +656,13 @@ esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
UART[uart_num]->int_clr.val = UART_INTR_MASK;
if(intr_conf->intr_enable_mask & UART_RXFIFO_TOUT_INT_ENA_M) {
UART[uart_num]->conf1.rx_tout_thrhd = ((intr_conf->rx_timeout_thresh) & UART_RX_TOUT_THRHD_V);
//Hardware issue workaround: when using ref_tick, the rx timeout threshold needs increase to 10 times.
//T_ref = T_apb * APB_CLK/(REF_TICK << CLKDIV_FRAG_BIT_WIDTH)
if(UART[uart_num]->conf0.tick_ref_always_on == 0) {
UART[uart_num]->conf1.rx_tout_thrhd = ((intr_conf->rx_timeout_thresh * UART_TOUT_REF_FACTOR_DEFAULT) & UART_RX_TOUT_THRHD_V);
} else {
UART[uart_num]->conf1.rx_tout_thrhd = ((intr_conf->rx_timeout_thresh) & UART_RX_TOUT_THRHD_V);
}
UART[uart_num]->conf1.rx_tout_en = 1;
} else {
UART[uart_num]->conf1.rx_tout_en = 0;

View File

@@ -38,3 +38,7 @@ CFLAGS+=-mfix-esp32-psram-cache-issue
CXXFLAGS+=-mfix-esp32-psram-cache-issue
endif
# Enable dynamic esp_timer overflow value if building unit tests
ifneq ("$(TEST_COMPONENTS_LIST)","")
CPPFLAGS += -DESP_TIMER_DYNAMIC_OVERFLOW_VAL
endif

View File

@@ -82,7 +82,18 @@
* ISR happens follow set_alarm, so change the ALARM_OVERFLOW_VAL to resolve this problem.
* Set it to 0xefffffffUL. The remain 0x10000000UL(about 3 second) is enough to handle ISR.
*/
#define ALARM_OVERFLOW_VAL 0xefffffffUL
#define DEFAULT_ALARM_OVERFLOW_VAL 0xefffffffUL
/* Provision to set lower overflow value for unit testing. Lowering the
* overflow value helps check for race conditions which occur near overflow
* moment.
*/
#ifndef ESP_TIMER_DYNAMIC_OVERFLOW_VAL
#define ALARM_OVERFLOW_VAL DEFAULT_ALARM_OVERFLOW_VAL
#else
static uint32_t s_alarm_overflow_val = DEFAULT_ALARM_OVERFLOW_VAL;
#define ALARM_OVERFLOW_VAL (s_alarm_overflow_val)
#endif
static const char* TAG = "esp_timer_impl";
@@ -206,18 +217,6 @@ void IRAM_ATTR esp_timer_impl_set_alarm(uint64_t timestamp)
// Adjust current time if overflow has happened
bool overflow = timer_overflow_happened();
uint64_t cur_count = REG_READ(FRC_TIMER_COUNT_REG(1));
uint32_t offset = s_timer_ticks_per_us * 2; //remain 2us for more safe
//If overflow is going to happen in 1us, let's wait until it happens,
//else we think it will not happen before new alarm set.
//And we should wait current timer count less than ALARM_OVERFLOW_VAL,
//maybe equals to 0.
if (cur_count + offset >= ALARM_OVERFLOW_VAL) {
do {
overflow = timer_overflow_happened();
cur_count = REG_READ(FRC_TIMER_COUNT_REG(1));
} while(!overflow || cur_count == ALARM_OVERFLOW_VAL);
}
if (overflow) {
assert(time_after_timebase_us > s_timer_us_per_overflow);
@@ -227,13 +226,17 @@ void IRAM_ATTR esp_timer_impl_set_alarm(uint64_t timestamp)
// Calculate desired timer compare value (may exceed 2^32-1)
uint64_t compare_val = time_after_timebase_us * s_timer_ticks_per_us;
uint32_t alarm_reg_val = ALARM_OVERFLOW_VAL;
// Use calculated alarm value if it is less than 2^32-1
// Use calculated alarm value if it is less than ALARM_OVERFLOW_VAL.
// Note that if by the time we update ALARM_REG, COUNT_REG value is higher,
// interrupt will not happen for another ALARM_OVERFLOW_VAL timer ticks,
// so need to check if alarm value is too close in the future (e.g. <2 us away).
const uint32_t offset = s_timer_ticks_per_us * 2;
if (compare_val < ALARM_OVERFLOW_VAL) {
// If we by the time we update ALARM_REG, COUNT_REG value is higher,
// interrupt will not happen for another 2^32 timer ticks, so need to
// check if alarm value is too close in the future (e.g. <1 us away).
if (compare_val < cur_count + offset) {
compare_val = cur_count + offset;
if (compare_val > ALARM_OVERFLOW_VAL) {
compare_val = ALARM_OVERFLOW_VAL;
}
}
alarm_reg_val = (uint32_t) compare_val;
}
@@ -361,3 +364,17 @@ uint64_t IRAM_ATTR esp_timer_impl_get_min_period_us()
{
return 50;
}
#ifdef ESP_TIMER_DYNAMIC_OVERFLOW_VAL
uint32_t esp_timer_impl_get_overflow_val()
{
return s_alarm_overflow_val;
}
void esp_timer_impl_set_overflow_val(uint32_t overflow_val)
{
s_alarm_overflow_val = overflow_val;
/* update alarm value */
esp_timer_impl_update_apb_freq(esp_clk_apb_freq() / 1000000);
}
#endif // ESP_TIMER_DYNAMIC_OVERFLOW_VAL

View File

@@ -103,7 +103,7 @@ esp_err_t system_event_eth_connected_handle_default(system_event_t *event)
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_ETH, &eth_ip);
if (!(ip4_addr_isany_val(eth_ip.ip) || ip4_addr_isany_val(eth_ip.netmask) || ip4_addr_isany_val(eth_ip.gw))) {
if (!(ip4_addr_isany_val(eth_ip.ip) || ip4_addr_isany_val(eth_ip.netmask))) {
system_event_t evt;
//notify event
@@ -214,7 +214,7 @@ esp_err_t system_event_sta_connected_handle_default(system_event_t *event)
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &sta_ip);
tcpip_adapter_get_old_ip_info(TCPIP_ADAPTER_IF_STA, &sta_old_ip);
if (!(ip4_addr_isany_val(sta_ip.ip) || ip4_addr_isany_val(sta_ip.netmask) || ip4_addr_isany_val(sta_ip.gw))) {
if (!(ip4_addr_isany_val(sta_ip.ip) || ip4_addr_isany_val(sta_ip.netmask))) {
system_event_t evt;
evt.event_id = SYSTEM_EVENT_STA_GOT_IP;

View File

@@ -18,8 +18,23 @@
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
typedef enum {
ESP_SPIRAM_SIZE_32MBITS = 0, /*!< SPI RAM size is 32 MBits */
ESP_SPIRAM_SIZE_64MBITS = 1, /*!< SPI RAM size is 64 MBits */
ESP_SPIRAM_SIZE_INVALID, /*!< SPI RAM size is invalid */
} esp_spiram_size_t;
/**
* @brief get SPI RAM size
* @return
* - ESP_SPIRAM_SIZE_INVALID if SPI RAM not enabled or not valid
* - SPI RAM size
*/
esp_spiram_size_t esp_spiram_get_chip_size();
/**
* @brief Initialize spiram interface/hardware. Normally called from cpu_start.c.
*

View File

@@ -290,7 +290,13 @@ esp_err_t esp_wifi_restore(void);
*
* @attention 1. This API only impact WIFI_MODE_STA or WIFI_MODE_APSTA mode
* @attention 2. If the ESP32 is connected to an AP, call esp_wifi_disconnect to disconnect.
*
* @attention 3. The scanning triggered by esp_wifi_start_scan() will not be effective until connection between ESP32 and the AP is established.
* If ESP32 is scanning and connecting at the same time, ESP32 will abort scanning and return a warning message and error
* number ESP_ERR_WIFI_STATE.
* If you want to do reconnection after ESP32 received disconnect event, remember to add the maximum retry time, otherwise the called
* scan will not work. This is especially true when the AP doesn't exist, and you still try reconnection after ESP32 received disconnect
* event with the reason code WIFI_REASON_NO_AP_FOUND.
*
* @return
* - ESP_OK: succeed
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init
@@ -353,6 +359,7 @@ esp_err_t esp_wifi_deauth_sta(uint16_t aid);
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init
* - ESP_ERR_WIFI_NOT_STARTED: WiFi was not started by esp_wifi_start
* - ESP_ERR_WIFI_TIMEOUT: blocking scan is timeout
* - ESP_ERR_WIFI_STATE: wifi still connecting when invoke esp_wifi_scan_start
* - others: refer to error code in esp_err.h
*/
esp_err_t esp_wifi_scan_start(const wifi_scan_config_t *config, bool block);

View File

@@ -117,6 +117,8 @@ extern "C" {
#define ESP_ROM_SPIFLASH_WR_PROTECT (ESP_ROM_SPIFLASH_BP0|ESP_ROM_SPIFLASH_BP1|ESP_ROM_SPIFLASH_BP2)
#define ESP_ROM_SPIFLASH_QE BIT9
#define FLASH_ID_GD25LQ32C 0xC86016
typedef enum {
ESP_ROM_SPIFLASH_QIO_MODE = 0,
ESP_ROM_SPIFLASH_QOUT_MODE,

View File

@@ -23,6 +23,7 @@ we add more types of external RAM memory, this can be made into a more intellige
#include "sdkconfig.h"
#include "esp_attr.h"
#include "esp_err.h"
#include "esp_spiram.h"
#include "spiram_psram.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
@@ -102,6 +103,22 @@ void IRAM_ATTR esp_spiram_init_cache()
#endif
}
esp_spiram_size_t esp_spiram_get_chip_size()
{
if (!spiram_inited) {
ESP_LOGE(TAG, "SPI RAM not initialized");
return ESP_SPIRAM_SIZE_INVALID;
}
psram_size_t psram_size = psram_get_size();
switch (psram_size) {
case PSRAM_SIZE_32MBITS:
return ESP_SPIRAM_SIZE_32MBITS;
case PSRAM_SIZE_64MBITS:
return ESP_SPIRAM_SIZE_64MBITS;
default:
return ESP_SPIRAM_SIZE_INVALID;
}
}
esp_err_t esp_spiram_init()
{

View File

@@ -39,26 +39,39 @@
#if CONFIG_SPIRAM_SUPPORT
//Commands for PSRAM chip
#define PSRAM_READ 0x03
#define PSRAM_FAST_READ 0x0B
#define PSRAM_FAST_READ_DUMMY 0x3
#define PSRAM_FAST_READ_QUAD 0xEB
#define PSRAM_WRITE 0x02
#define PSRAM_QUAD_WRITE 0x38
#define PSRAM_ENTER_QMODE 0x35
#define PSRAM_EXIT_QMODE 0xF5
#define PSRAM_RESET_EN 0x66
#define PSRAM_RESET 0x99
#define PSRAM_SET_BURST_LEN 0xC0
#define PSRAM_DEVICE_ID 0x9F
#define PSRAM_READ 0x03
#define PSRAM_FAST_READ 0x0B
#define PSRAM_FAST_READ_DUMMY 0x3
#define PSRAM_FAST_READ_QUAD 0xEB
#define PSRAM_FAST_READ_QUAD_DUMMY 0x5
#define PSRAM_WRITE 0x02
#define PSRAM_QUAD_WRITE 0x38
#define PSRAM_ENTER_QMODE 0x35
#define PSRAM_EXIT_QMODE 0xF5
#define PSRAM_RESET_EN 0x66
#define PSRAM_RESET 0x99
#define PSRAM_SET_BURST_LEN 0xC0
#define PSRAM_DEVICE_ID 0x9F
#if CONFIG_SPIRAM_TYPE_ESPPSRAM32
typedef enum {
PSRAM_CLK_MODE_NORM = 0, /*!< Normal SPI mode */
PSRAM_CLK_MODE_DCLK = 1, /*!< Two extra clock cycles after CS is set high level */
} psram_clk_mode_t;
#define PSRAM_MFG_ID_M 0xff
#define PSRAM_MFG_ID_S 8
#define PSRAM_MFG_ID_V 0x5d
#define PSRAM_ID_KGD_M 0xff
#define PSRAM_ID_KGD_S 8
#define PSRAM_ID_KGD 0x5d
#define PSRAM_ID_EID_M 0xff
#define PSRAM_ID_EID_S 16
#endif
#define PSRAM_KGD(id) (((id) >> PSRAM_ID_KGD_S) & PSRAM_ID_KGD_M)
#define PSRAM_EID(id) (((id) >> PSRAM_ID_EID_S) & PSRAM_ID_EID_M)
#define PSRAM_IS_VALID(id) (PSRAM_KGD(id) == PSRAM_ID_KGD)
// PSRAM_EID = 0x26 or 0x4x ----> 64MBit psram
// PSRAM_EID = 0x20 ------------> 32MBit psram
#define PSRAM_IS_64MBIT(id) ((PSRAM_EID(id) == 0x26) || ((PSRAM_EID(id) & 0xf0) == 0x40))
#define PSRAM_IS_32MBIT_VER0(id) (PSRAM_EID(id) == 0x20)
// IO-pins for PSRAM. These need to be in the VDD_SIO power domain because all chips we
// currently support are 1.8V parts.
@@ -98,6 +111,8 @@ typedef enum {
} psram_spi_num_t;
static psram_cache_mode_t s_psram_mode = PSRAM_CACHE_MAX;
static psram_clk_mode_t s_clk_mode = PSRAM_CLK_MODE_DCLK;
static uint32_t s_psram_id = 0;
/* dummy_len_plus values defined in ROM for SPI flash configuration */
extern uint8_t g_rom_spiflash_dummy_len_plus[];
@@ -286,7 +301,7 @@ static int psram_cmd_config(psram_spi_num_t spi_num, psram_cmd_t* pInData)
return 0;
}
void psram_cmd_end(int spi_num) {
static void psram_cmd_end(int spi_num) {
while (READ_PERI_REG(SPI_CMD_REG(spi_num)) & SPI_USR);
WRITE_PERI_REG(SPI_USER_REG(spi_num), backup_usr[spi_num]);
WRITE_PERI_REG(SPI_USER1_REG(spi_num), backup_usr1[spi_num]);
@@ -298,17 +313,19 @@ static void psram_disable_qio_mode(psram_spi_num_t spi_num)
{
psram_cmd_t ps_cmd;
uint32_t cmd_exit_qpi;
switch (s_psram_mode) {
case PSRAM_CACHE_F80M_S80M:
cmd_exit_qpi = PSRAM_EXIT_QMODE;
ps_cmd.txDataBitLen = 8;
break;
case PSRAM_CACHE_F80M_S40M:
case PSRAM_CACHE_F40M_S40M:
default:
cmd_exit_qpi = PSRAM_EXIT_QMODE << 8;
ps_cmd.txDataBitLen = 16;
break;
cmd_exit_qpi = PSRAM_EXIT_QMODE;
ps_cmd.txDataBitLen = 8;
if (s_clk_mode == PSRAM_CLK_MODE_DCLK) {
switch (s_psram_mode) {
case PSRAM_CACHE_F80M_S80M:
break;
case PSRAM_CACHE_F80M_S40M:
case PSRAM_CACHE_F40M_S40M:
default:
cmd_exit_qpi = PSRAM_EXIT_QMODE << 8;
ps_cmd.txDataBitLen = 16;
break;
}
}
ps_cmd.txData = &cmd_exit_qpi;
ps_cmd.cmd = 0;
@@ -328,29 +345,34 @@ static void psram_read_id(uint32_t* dev_id)
{
psram_spi_num_t spi_num = PSRAM_SPI_1;
psram_disable_qio_mode(spi_num);
uint32_t addr = (PSRAM_DEVICE_ID << 24) | 0;
uint32_t dummy_bits = 0;
uint32_t dummy_bits = 0 + extra_dummy;
psram_cmd_t ps_cmd;
switch (s_psram_mode) {
case PSRAM_CACHE_F80M_S80M:
dummy_bits = 0 + extra_dummy;
ps_cmd.cmdBitLen = 0;
break;
case PSRAM_CACHE_F80M_S40M:
case PSRAM_CACHE_F40M_S40M:
default:
dummy_bits = 0 + extra_dummy;
ps_cmd.cmdBitLen = 2; //this two bits is used to delay 2 clock cycle
break;
uint32_t addr = 0;
ps_cmd.addrBitLen = 3 * 8;
ps_cmd.cmd = PSRAM_DEVICE_ID;
ps_cmd.cmdBitLen = 8;
if (s_clk_mode == PSRAM_CLK_MODE_DCLK) {
switch (s_psram_mode) {
case PSRAM_CACHE_F80M_S80M:
break;
case PSRAM_CACHE_F80M_S40M:
case PSRAM_CACHE_F40M_S40M:
default:
ps_cmd.cmdBitLen = 2; //this two bits is used to delay 2 clock cycle
ps_cmd.cmd = 0;
addr = (PSRAM_DEVICE_ID << 24) | 0;
ps_cmd.addrBitLen = 4 * 8;
break;
}
}
ps_cmd.cmd = 0;
ps_cmd.addr = &addr;
ps_cmd.addrBitLen = 4 * 8;
ps_cmd.txDataBitLen = 0;
ps_cmd.txData = NULL;
ps_cmd.rxDataBitLen = 4 * 8;
ps_cmd.rxData = dev_id;
ps_cmd.dummyBitLen = dummy_bits;
psram_cmd_config(spi_num, &ps_cmd);
psram_clear_spi_fifo(spi_num);
psram_cmd_recv_start(spi_num, ps_cmd.rxData, ps_cmd.rxDataBitLen / 8, PSRAM_CMD_SPI);
@@ -362,15 +384,18 @@ static esp_err_t IRAM_ATTR psram_enable_qio_mode(psram_spi_num_t spi_num)
{
psram_cmd_t ps_cmd;
uint32_t addr = (PSRAM_ENTER_QMODE << 24) | 0;
switch (s_psram_mode) {
case PSRAM_CACHE_F80M_S80M:
ps_cmd.cmdBitLen = 0;
break;
case PSRAM_CACHE_F80M_S40M:
case PSRAM_CACHE_F40M_S40M:
default:
ps_cmd.cmdBitLen = 2;
break;
ps_cmd.cmdBitLen = 0;
if (s_clk_mode == PSRAM_CLK_MODE_DCLK) {
switch (s_psram_mode) {
case PSRAM_CACHE_F80M_S80M:
break;
case PSRAM_CACHE_F80M_S40M:
case PSRAM_CACHE_F40M_S40M:
default:
ps_cmd.cmdBitLen = 2;
break;
}
}
ps_cmd.cmd = 0;
ps_cmd.addr = &addr;
@@ -473,6 +498,17 @@ static void IRAM_ATTR psram_gpio_config(psram_cache_mode_t mode)
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
}
psram_size_t psram_get_size()
{
if (PSRAM_IS_32MBIT_VER0(s_psram_id)) {
return PSRAM_SIZE_32MBITS;
} else if (PSRAM_IS_64MBIT(s_psram_id)) {
return PSRAM_SIZE_64MBITS;
} else {
return PSRAM_SIZE_MAX;
}
}
//psram gpio init , different working frequency we have different solutions
esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vaddrmode) //psram init
{
@@ -489,17 +525,6 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
return ESP_FAIL;
}
/* note: If the third mode(80Mhz+80Mhz) is enabled, VSPI port will be occupied by the system,
Application code should never touch VSPI hardware in this case. We try to stop applications
from doing this using the drivers by claiming the port for ourselves*/
if (mode == PSRAM_CACHE_F80M_S80M) {
periph_module_enable(PERIPH_VSPI_MODULE);
bool r=spicommon_periph_claim(VSPI_HOST);
if (!r) {
return ESP_ERR_INVALID_STATE;
}
}
WRITE_PERI_REG(GPIO_ENABLE_W1TC_REG, BIT(PSRAM_CLK_IO) | BIT(PSRAM_CS_IO)); //DISABLE OUPUT FOR IO16/17
assert(mode < PSRAM_CACHE_MAX && "we don't support any other mode for now.");
s_psram_mode = mode;
@@ -514,21 +539,7 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
psram_spi_init(PSRAM_SPI_1, mode);
CLEAR_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1), SPI_CS_HOLD);
gpio_matrix_out(PSRAM_CS_IO, SPICS1_OUT_IDX, 0, 0);
gpio_matrix_out(PSRAM_CLK_IO, VSPICLK_OUT_IDX, 0, 0);
//use spi3 clock,but use spi1 data/cs wires
//We get a solid 80MHz clock from SPI3 by setting it up, starting a transaction, waiting until it
//is in progress, then cutting the clock (but not the reset!) to that peripheral.
WRITE_PERI_REG(SPI_ADDR_REG(PSRAM_SPI_3), 32 << 24);
WRITE_PERI_REG(SPI_CLOCK_REG(PSRAM_SPI_3), SPI_CLK_EQU_SYSCLK_M); //SET 80M AND CLEAR OTHERS
SET_PERI_REG_MASK(SPI_CMD_REG(PSRAM_SPI_3), SPI_FLASH_READ_M);
uint32_t spi_status;
while (1) {
spi_status = READ_PERI_REG(SPI_EXT2_REG(PSRAM_SPI_3));
if (spi_status != 0 && spi_status != 1) {
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_2);
break;
}
}
gpio_matrix_out(PSRAM_CLK_IO, SPICLK_OUT_IDX, 0, 0);
break;
case PSRAM_CACHE_F80M_S40M:
case PSRAM_CACHE_F40M_S40M:
@@ -554,13 +565,59 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
WRITE_PERI_REG(GPIO_ENABLE_W1TS_REG, BIT(PSRAM_CS_IO)| BIT(PSRAM_CLK_IO));
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[PSRAM_CS_IO], PIN_FUNC_GPIO);
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[PSRAM_CLK_IO], PIN_FUNC_GPIO);
uint32_t id;
psram_read_id(&id);
if (((id >> PSRAM_MFG_ID_S) & PSRAM_MFG_ID_M) != PSRAM_MFG_ID_V) {
psram_read_id(&s_psram_id);
if (!PSRAM_IS_VALID(s_psram_id)) {
return ESP_FAIL;
}
uint32_t flash_id = g_rom_flashchip.device_id;
if (flash_id == FLASH_ID_GD25LQ32C) {
// Set drive ability for 1.8v flash in 80Mhz.
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA0_U, FUN_DRV_V, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA1_U, FUN_DRV_V, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA2_U, FUN_DRV_V, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA3_U, FUN_DRV_V, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CMD_U, FUN_DRV_V, 3, FUN_DRV_S);
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV_V, 3, FUN_DRV_S);
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[PSRAM_CS_IO], FUN_DRV_V, 3, FUN_DRV_S);
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[PSRAM_CLK_IO], FUN_DRV_V, 3, FUN_DRV_S);
}
if (PSRAM_IS_64MBIT(s_psram_id)) {
// For this psram, we don't need any extra clock cycles after cs get back to high level
s_clk_mode = PSRAM_CLK_MODE_NORM;
gpio_matrix_out(PSRAM_INTERNAL_IO_28, SIG_GPIO_OUT_IDX, 0, 0);
gpio_matrix_out(PSRAM_INTERNAL_IO_29, SIG_GPIO_OUT_IDX, 0, 0);
gpio_matrix_out(PSRAM_CLK_IO, SPICLK_OUT_IDX, 0, 0);
} else if (PSRAM_IS_32MBIT_VER0(s_psram_id)) {
s_clk_mode = PSRAM_CLK_MODE_DCLK;
if (mode == PSRAM_CACHE_F80M_S80M) {
/* note: If the third mode(80Mhz+80Mhz) is enabled for 32MBit 1V8 psram, VSPI port will be
occupied by the system.
Application code should never touch VSPI hardware in this case. We try to stop applications
from doing this using the drivers by claiming the port for ourselves */
periph_module_enable(PERIPH_VSPI_MODULE);
bool r=spicommon_periph_claim(VSPI_HOST);
if (!r) {
return ESP_ERR_INVALID_STATE;
}
gpio_matrix_out(PSRAM_CLK_IO, VSPICLK_OUT_IDX, 0, 0);
//use spi3 clock,but use spi1 data/cs wires
//We get a solid 80MHz clock from SPI3 by setting it up, starting a transaction, waiting until it
//is in progress, then cutting the clock (but not the reset!) to that peripheral.
WRITE_PERI_REG(SPI_ADDR_REG(PSRAM_SPI_3), 32 << 24);
WRITE_PERI_REG(SPI_CLOCK_REG(PSRAM_SPI_3), SPI_CLK_EQU_SYSCLK_M); //SET 80M AND CLEAR OTHERS
SET_PERI_REG_MASK(SPI_CMD_REG(PSRAM_SPI_3), SPI_FLASH_READ_M);
uint32_t spi_status;
while (1) {
spi_status = READ_PERI_REG(SPI_EXT2_REG(PSRAM_SPI_3));
if (spi_status != 0 && spi_status != 1) {
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_2);
break;
}
}
}
}
psram_enable_qio_mode(PSRAM_SPI_1);
psram_cache_init(mode, vaddrmode);
return ESP_OK;
}
@@ -579,27 +636,15 @@ static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psra
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(31)); //flash 1 div clk,80+40;
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(30)); //pre clk div , ONLY IF SPI/SRAM@ DIFFERENT SPEED,JUST FOR SPI0. FLASH DIV 2+SRAM DIV4
WRITE_PERI_REG(SPI_CLOCK_REG(0), SPI_CLK_EQU_SYSCLK_M); //SET 1DIV CLOCK AND RESET OTHER PARAMS
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_RD_SRAM_DUMMY_M); //enable cache read dummy
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_DUMMY + extra_dummy,
SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache : 40m--+1dummy,80m--+2dummy
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_RCMD_M); //enable user mode for cache read command
break;
case PSRAM_CACHE_F80M_S40M:
SET_PERI_REG_MASK(SPI_DATE_REG(0), BIT(31)); //flash 1 div clk
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(30)); //pre clk div , ONLY IF SPI/SRAM@ DIFFERENT SPEED,JUST FOR SPI0.
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_RD_SRAM_DUMMY_M); //enable cache read dummy
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_DUMMY + extra_dummy,
SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache : 40m--+1dummy,80m--+2dummy
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_RCMD_M); //enable user mode for cache read command
break;
case PSRAM_CACHE_F40M_S40M:
default:
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(31)); //flash 1 div clk
CLEAR_PERI_REG_MASK(SPI_DATE_REG(0), BIT(30)); //pre clk div
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_RD_SRAM_DUMMY_M); //enable cache read dummy
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_DUMMY + extra_dummy,
SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache : 40m--+1dummy,80m--+2dummy
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_RCMD_M); //enable user mode for cache read command
break;
}
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_WCMD_M); // cache write command enable
@@ -607,30 +652,38 @@ static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psra
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_SRAM_QIO_M); //enable qio mode for cache command
CLEAR_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_SRAM_DIO_M); //disable dio mode for cache command
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_USR_RD_SRAM_DUMMY_M); //enable cache read dummy
SET_PERI_REG_MASK(SPI_CACHE_SCTRL_REG(0), SPI_CACHE_SRAM_USR_RCMD_M); //enable user mode for cache read command
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_BITLEN, 7,
SPI_CACHE_SRAM_USR_WR_CMD_BITLEN_S);
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_VALUE, PSRAM_QUAD_WRITE,
SPI_CACHE_SRAM_USR_WR_CMD_VALUE_S); //0x38
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 7,
SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_S);
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, PSRAM_FAST_READ_QUAD,
SPI_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_QUAD_DUMMY + extra_dummy,
SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache : 40m--+1dummy,80m--+2dummy
//config sram cache r/w command
switch (psram_cache_mode) {
case PSRAM_CACHE_F80M_S80M: //in this mode , no delay is needed
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_BITLEN, 7,
SPI_CACHE_SRAM_USR_WR_CMD_BITLEN_S);
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_VALUE, PSRAM_QUAD_WRITE,
SPI_CACHE_SRAM_USR_WR_CMD_VALUE_S); //0x38
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 7,
SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_S);
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, PSRAM_FAST_READ,
SPI_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b
break;
case PSRAM_CACHE_F80M_S40M: //is sram is @40M, need 2 cycles of delay
case PSRAM_CACHE_F40M_S40M:
default:
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 15,
SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_S); //read command length, 2 bytes(1byte for delay),sending in qio mode in cache
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, ((PSRAM_FAST_READ) << 8),
SPI_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b, read command value,(0x00 for delay,0x0b for cmd)
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_BITLEN, 15,
SPI_CACHE_SRAM_USR_WR_CMD_BITLEN_S); //write command length,2 bytes(1byte for delay,send in qio mode in cache)
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_VALUE, ((PSRAM_QUAD_WRITE) << 8),
SPI_CACHE_SRAM_USR_WR_CMD_VALUE_S); //0x38, write command value,(0x00 for delay)
if (s_clk_mode == PSRAM_CLK_MODE_DCLK) {
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_V, 15,
SPI_CACHE_SRAM_USR_RD_CMD_BITLEN_S); //read command length, 2 bytes(1byte for delay),sending in qio mode in cache
SET_PERI_REG_BITS(SPI_SRAM_DRD_CMD_REG(0), SPI_CACHE_SRAM_USR_RD_CMD_VALUE_V, ((PSRAM_FAST_READ_QUAD) << 8),
SPI_CACHE_SRAM_USR_RD_CMD_VALUE_S); //0x0b, read command value,(0x00 for delay,0x0b for cmd)
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_BITLEN, 15,
SPI_CACHE_SRAM_USR_WR_CMD_BITLEN_S); //write command length,2 bytes(1byte for delay,send in qio mode in cache)
SET_PERI_REG_BITS(SPI_SRAM_DWR_CMD_REG(0), SPI_CACHE_SRAM_USR_WR_CMD_VALUE, ((PSRAM_QUAD_WRITE) << 8),
SPI_CACHE_SRAM_USR_WR_CMD_VALUE_S); //0x38, write command value,(0x00 for delay)
SET_PERI_REG_BITS(SPI_CACHE_SCTRL_REG(0), SPI_SRAM_DUMMY_CYCLELEN_V, PSRAM_FAST_READ_QUAD_DUMMY + extra_dummy,
SPI_SRAM_DUMMY_CYCLELEN_S); //dummy, psram cache : 40m--+1dummy,80m--+2dummy
}
break;
}
@@ -653,6 +706,11 @@ static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psra
CLEAR_PERI_REG_MASK(SPI_PIN_REG(0), SPI_CS1_DIS_M); //ENABLE SPI0 CS1 TO PSRAM(CS0--FLASH; CS1--SRAM)
if (s_clk_mode == PSRAM_CLK_MODE_NORM) { //different
SET_PERI_REG_MASK(SPI_USER_REG(0), SPI_CS_HOLD);
// Set cs time.
SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S);
}
}
#endif // CONFIG_SPIRAM_SUPPORT

View File

@@ -26,6 +26,11 @@ typedef enum {
PSRAM_CACHE_MAX,
} psram_cache_mode_t;
typedef enum {
PSRAM_SIZE_32MBITS = 0,
PSRAM_SIZE_64MBITS = 1,
PSRAM_SIZE_MAX,
} psram_size_t;
/*
See the TRM, chapter PID/MPU/MMU, header 'External RAM' for the definitions of these modes.
@@ -34,12 +39,21 @@ Important is that NORMAL works with the app CPU cache disabled, but gives huge c
issues when both app and pro CPU are enabled. LOWHIGH and EVENODD do not have these coherency
issues but cannot be used when the app CPU cache is disabled.
*/
typedef enum {
PSRAM_VADDR_MODE_NORMAL=0, ///< App and pro CPU use their own flash cache for external RAM access
PSRAM_VADDR_MODE_LOWHIGH, ///< App and pro CPU share external RAM caches: pro CPU has low 2M, app CPU has high 2M
PSRAM_VADDR_MODE_EVENODD, ///< App and pro CPU share external RAM caches: pro CPU does even 32yte ranges, app does odd ones.
} psram_vaddr_mode_t;
/**
* @brief get psram size
* @return
* - PSRAM_SIZE_MAX if psram not enabled or not valid
* - PSRAM size
*/
psram_size_t psram_get_size();
/**
* @brief psram cache enable function
*

View File

@@ -147,7 +147,7 @@ esp_err_t esp_efuse_mac_get_default(uint8_t* mac)
esp_err_t system_efuse_read_mac(uint8_t *mac) __attribute__((alias("esp_efuse_mac_get_default")));
esp_err_t esp_efuse_read_mac(uint8_t *mac) __attribute__((alias("esp_efuse_mac_get_default")));
esp_err_t esp_derive_mac(uint8_t* local_mac, const uint8_t* universal_mac)
esp_err_t esp_derive_local_mac(uint8_t* local_mac, const uint8_t* universal_mac)
{
uint8_t idx;
@@ -201,7 +201,7 @@ esp_err_t esp_read_mac(uint8_t* mac, esp_mac_type_t type)
mac[5] += 1;
}
else if (UNIVERSAL_MAC_ADDR_NUM == TWO_UNIVERSAL_MAC_ADDR) {
esp_derive_mac(mac, efuse_mac);
esp_derive_local_mac(mac, efuse_mac);
}
break;
case ESP_MAC_BT:
@@ -220,7 +220,7 @@ esp_err_t esp_read_mac(uint8_t* mac, esp_mac_type_t type)
}
else if (UNIVERSAL_MAC_ADDR_NUM == TWO_UNIVERSAL_MAC_ADDR) {
efuse_mac[5] += 1;
esp_derive_mac(mac, efuse_mac);
esp_derive_local_mac(mac, efuse_mac);
}
break;
default:

View File

@@ -2,8 +2,10 @@
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <sys/param.h>
#include "unity.h"
#include "esp_timer.h"
#include "../esp_timer_impl.h"
#include "esp_heap_caps.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
@@ -14,6 +16,20 @@
#define WITH_PROFILING 1
#endif
extern uint32_t esp_timer_impl_get_overflow_val();
extern void esp_timer_impl_set_overflow_val(uint32_t overflow_val);
static uint32_t s_old_overflow_val;
static void setup_overflow()
{
s_old_overflow_val = esp_timer_impl_get_overflow_val();
esp_timer_impl_set_overflow_val(0x7fffff); /* overflow every ~0.1 sec */}
static void teardown_overflow()
{
esp_timer_impl_set_overflow_val(s_old_overflow_val);
}
TEST_CASE("esp_timer orders timers correctly", "[esp_timer]")
{
@@ -26,6 +42,7 @@ TEST_CASE("esp_timer orders timers correctly", "[esp_timer]")
const size_t num_timers = sizeof(timeouts)/sizeof(timeouts[0]);
esp_timer_handle_t handles[num_timers];
char* names[num_timers];
setup_overflow();
for (size_t i = 0; i < num_timers; ++i) {
asprintf(&names[i], "timer%d", i);
esp_timer_create_args_t args = {
@@ -35,6 +52,7 @@ TEST_CASE("esp_timer orders timers correctly", "[esp_timer]")
TEST_ESP_OK(esp_timer_create(&args, &handles[i]));
TEST_ESP_OK(esp_timer_start_once(handles[i], timeouts[i] * 100));
}
teardown_overflow();
char* stream_str[1024];
FILE* stream = fmemopen(stream_str, sizeof(stream_str), "r+");
TEST_ESP_OK(esp_timer_dump(stream));
@@ -67,6 +85,42 @@ TEST_CASE("esp_timer orders timers correctly", "[esp_timer]")
fclose(stream);
}
TEST_CASE("esp_timer_impl_set_alarm stress test", "[esp_timer]")
{
const int test_time_sec = 10;
void set_alarm_task(void* arg)
{
SemaphoreHandle_t done = (SemaphoreHandle_t) arg;
uint64_t start = esp_timer_impl_get_time();
uint64_t now = start;
int count = 0;
const int delays[] = {50, 5000, 10000000};
const int delays_count = sizeof(delays)/sizeof(delays[0]);
while (now - start < test_time_sec * 1000000) {
now = esp_timer_impl_get_time();
esp_timer_impl_set_alarm(now + delays[count % delays_count]);
++count;
}
xSemaphoreGive(done);
vTaskDelete(NULL);
}
SemaphoreHandle_t done = xSemaphoreCreateCounting(portNUM_PROCESSORS, 0);
setup_overflow();
xTaskCreatePinnedToCore(&set_alarm_task, "set_alarm_0", 4096, done, UNITY_FREERTOS_PRIORITY, NULL, 0);
#if portNUM_PROCESSORS == 2
xTaskCreatePinnedToCore(&set_alarm_task, "set_alarm_1", 4096, done, UNITY_FREERTOS_PRIORITY, NULL, 1);
#endif
TEST_ASSERT(xSemaphoreTake(done, test_time_sec * 2 * 1000 / portTICK_PERIOD_MS));
#if portNUM_PROCESSORS == 2
TEST_ASSERT(xSemaphoreTake(done, test_time_sec * 2 * 1000 / portTICK_PERIOD_MS));
#endif
teardown_overflow();
vSemaphoreDelete(done);
}
TEST_CASE("esp_timer produces correct delay", "[esp_timer]")
{
@@ -89,6 +143,7 @@ TEST_CASE("esp_timer produces correct delay", "[esp_timer]")
const size_t delays_count = sizeof(delays_ms)/sizeof(delays_ms[0]);
ref_clock_init();
setup_overflow();
for (size_t i = 0; i < delays_count; ++i) {
t_end = 0;
int64_t t_start = ref_clock_get();
@@ -102,6 +157,7 @@ TEST_CASE("esp_timer produces correct delay", "[esp_timer]")
TEST_ASSERT_INT32_WITHIN(portTICK_PERIOD_MS, delays_ms[i], ms_diff);
}
teardown_overflow();
ref_clock_deinit();
TEST_ESP_OK( esp_timer_dump(stdout) );
@@ -149,6 +205,7 @@ TEST_CASE("periodic esp_timer produces correct delays", "[esp_timer]")
};
TEST_ESP_OK(esp_timer_create(&create_args, &timer1));
ref_clock_init();
setup_overflow();
args.timer = timer1;
args.t_start = ref_clock_get();
args.done = xSemaphoreCreateBinary();
@@ -160,6 +217,7 @@ TEST_CASE("periodic esp_timer produces correct delays", "[esp_timer]")
for (size_t i = 0; i < NUM_INTERVALS; ++i) {
TEST_ASSERT_INT32_WITHIN(portTICK_PERIOD_MS, (i + 1) * delay_ms, args.intervals[i]);
}
teardown_overflow();
ref_clock_deinit();
TEST_ESP_OK( esp_timer_dump(stdout) );
@@ -316,6 +374,7 @@ TEST_CASE("esp_timer for very short intervals", "[esp_timer]")
esp_timer_handle_t timer1, timer2;
ESP_ERROR_CHECK( esp_timer_create(&timer_args, &timer1) );
ESP_ERROR_CHECK( esp_timer_create(&timer_args, &timer2) );
setup_overflow();
const int timeout_ms = 10;
for (int timeout_delta_us = -150; timeout_delta_us < 150; timeout_delta_us++) {
printf("delta=%d", timeout_delta_us);
@@ -328,6 +387,7 @@ TEST_CASE("esp_timer for very short intervals", "[esp_timer]")
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, esp_timer_stop(timer2));
}
teardown_overflow();
vSemaphoreDelete(semaphore);
}
@@ -344,40 +404,75 @@ TEST_CASE("esp_timer_get_time call takes less than 1us", "[esp_timer]")
TEST_PERFORMANCE_LESS_THAN(ESP_TIMER_GET_TIME_PER_CALL, "%dns", ns_per_call);
}
/* This test runs for about 10 minutes and is disabled in CI.
* Such run time is needed to have FRC2 timer overflow a few times.
*/
TEST_CASE("esp_timer_get_time returns monotonic values", "[esp_timer][ignore]")
TEST_CASE("esp_timer_get_time returns monotonic values", "[esp_timer]")
{
void timer_test_task(void* arg) {
int64_t delta = esp_timer_get_time() - ref_clock_get();
typedef struct {
SemaphoreHandle_t done;
bool pass;
int test_cnt;
int error_cnt;
int64_t total_sq_error;
int64_t max_error;
} test_state_t;
const int iter_count = 1000000000;
for (int i = 0; i < iter_count; ++i) {
int64_t now = esp_timer_get_time();
int64_t ref_now = ref_clock_get();
int64_t diff = now - (ref_now + delta);
void timer_test_task(void* arg) {
test_state_t* state = (test_state_t*) arg;
state->pass = true;
int64_t start_time = ref_clock_get();
int64_t delta = esp_timer_get_time() - start_time;
int64_t now = start_time;
int error_repeat_cnt = 0;
while (now - start_time < 10000000) { /* 10 seconds */
int64_t hs_now = esp_timer_get_time();
now = ref_clock_get();
int64_t diff = hs_now - (now + delta);
/* Allow some difference due to rtos tick interrupting task between
* getting 'now' and 'ref_now'.
*/
TEST_ASSERT_INT32_WITHIN(100, 0, (int) diff);
if (abs(diff) > 100) {
error_repeat_cnt++;
state->error_cnt++;
} else {
error_repeat_cnt = 0;
}
if (error_repeat_cnt > 2) {
printf("diff=%lld\n", diff);
state->pass = false;
}
state->max_error = MAX(state->max_error, abs(diff));
state->test_cnt++;
state->total_sq_error += diff * diff;
}
xSemaphoreGive((SemaphoreHandle_t) arg);
xSemaphoreGive(state->done);
vTaskDelete(NULL);
}
ref_clock_init();
SemaphoreHandle_t done_1 = xSemaphoreCreateBinary();
SemaphoreHandle_t done_2 = xSemaphoreCreateBinary();
setup_overflow();
xTaskCreatePinnedToCore(&timer_test_task, "t1", 4096, (void*) done_1, 6, NULL, 0);
xTaskCreatePinnedToCore(&timer_test_task, "t2", 4096, (void*) done_2, 6, NULL, 1);
test_state_t states[portNUM_PROCESSORS] = {0};
SemaphoreHandle_t done = xSemaphoreCreateCounting(portNUM_PROCESSORS, 0);
for (int i = 0; i < portNUM_PROCESSORS; ++i) {
states[i].done = done;
xTaskCreatePinnedToCore(&timer_test_task, "test", 4096, &states[i], 6, NULL, i);
}
TEST_ASSERT_TRUE( xSemaphoreTake(done_1, portMAX_DELAY) );
TEST_ASSERT_TRUE( xSemaphoreTake(done_2, portMAX_DELAY) );
vSemaphoreDelete(done_1);
vSemaphoreDelete(done_2);
for (int i = 0; i < portNUM_PROCESSORS; ++i) {
TEST_ASSERT_TRUE( xSemaphoreTake(done, portMAX_DELAY) );
printf("CPU%d: %s test_cnt=%d error_cnt=%d std_error=%d |max_error|=%d\n",
i, states[i].pass ? "PASS" : "FAIL",
states[i].test_cnt, states[i].error_cnt,
(int) sqrt(states[i].total_sq_error / states[i].test_cnt), (int) states[i].max_error);
}
vSemaphoreDelete(done);
teardown_overflow();
ref_clock_deinit();
for (int i = 0; i < portNUM_PROCESSORS; ++i) {
TEST_ASSERT(states[i].pass);
}
}
TEST_CASE("Can dump esp_timer stats", "[esp_timer]")

View File

@@ -2458,8 +2458,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
{
BaseType_t xReturn;
//ToDo: figure out locking
// taskENTER_CRITICAL(&pxQueue->mux);
taskENTER_CRITICAL(&(((Queue_t * )xQueueOrSemaphore)->mux));
{
if( ( ( Queue_t * ) xQueueOrSemaphore )->pxQueueSetContainer != NULL )
{
@@ -2478,7 +2477,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
xReturn = pdPASS;
}
}
// taskEXIT_CRITICAL(&pxQueue->mux);
taskEXIT_CRITICAL(&(((Queue_t * )xQueueOrSemaphore)->mux));
return xReturn;
}
@@ -2507,12 +2506,12 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
}
else
{
// taskENTER_CRITICAL(&pxQueue->mux);
taskENTER_CRITICAL(&(pxQueueOrSemaphore->mux));
{
/* The queue is no longer contained in the set. */
pxQueueOrSemaphore->pxQueueSetContainer = NULL;
}
// taskEXIT_CRITICAL(&pxQueue->mux);
taskEXIT_CRITICAL(&(pxQueueOrSemaphore->mux));
xReturn = pdPASS;
}
@@ -2555,9 +2554,15 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
Queue_t *pxQueueSetContainer = pxQueue->pxQueueSetContainer;
BaseType_t xReturn = pdFALSE;
/* This function must be called form a critical section. */
/*
* This function is called with a Queue's / Semaphore's spinlock already
* acquired. Acquiring the Queue set's spinlock is still necessary.
*/
configASSERT( pxQueueSetContainer );
//Acquire the Queue set's spinlock
portENTER_CRITICAL(&(pxQueueSetContainer->mux));
configASSERT( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength );
if( pxQueueSetContainer->uxMessagesWaiting < pxQueueSetContainer->uxLength )
@@ -2588,6 +2593,9 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
mtCOVERAGE_TEST_MARKER();
}
//Release the Queue set's spinlock
portEXIT_CRITICAL(&(pxQueueSetContainer->mux));
return xReturn;
}

View File

@@ -0,0 +1,137 @@
#include <stdio.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "unity.h"
/*
* Basic queue set tests. Multiple queues are added to a queue set then each
* queue is filled in a sequential order. The members returned from the queue
* set must adhered to the order in which the queues were filled.
*/
#define NO_OF_QUEUES 5
#define QUEUE_LEN 4
#define ITEM_SIZE sizeof(uint32_t)
static QueueHandle_t handles[NO_OF_QUEUES];
static QueueSetHandle_t set_handle;
TEST_CASE("Test Queue sets", "[freertos]")
{
//Create queue set, queues, and add queues to queue set
set_handle = xQueueCreateSet(NO_OF_QUEUES * QUEUE_LEN);
for (int i = 0; i < NO_OF_QUEUES; i++) {
handles[i] = xQueueCreate(QUEUE_LEN, ITEM_SIZE);
TEST_ASSERT_MESSAGE(handles[i] != NULL, "Failed to create queue");
TEST_ASSERT_MESSAGE(xQueueAddToSet(handles[i], set_handle) == pdPASS, "Failed to add to queue set");
}
//Fill queue set via filling each queue
for (int i = 0; i < NO_OF_QUEUES; i++) {
for (int j = 0; j < QUEUE_LEN; j++) {
uint32_t item_num = (i * QUEUE_LEN) + j;
TEST_ASSERT_MESSAGE(xQueueSendToBack(handles[i], &item_num, portMAX_DELAY) == pdTRUE, "Failed to send to queue");
}
}
//Check queue set is notified in correct order
for (int i = 0; i < NO_OF_QUEUES; i++) {
for (int j = 0; j < QUEUE_LEN; j++) {
QueueSetMemberHandle_t member = xQueueSelectFromSet(set_handle, portMAX_DELAY);
TEST_ASSERT_EQUAL_MESSAGE(handles[i], member, "Incorrect queue set member returned");
uint32_t item;
xQueueReceive((QueueHandle_t)member, &item, 0);
TEST_ASSERT_EQUAL_MESSAGE(((i * QUEUE_LEN) + j), item, "Incorrect item value");
}
}
//Remove queues from queue set and delete queues
for (int i = 0; i < NO_OF_QUEUES; i++) {
TEST_ASSERT_MESSAGE(xQueueRemoveFromSet(handles[i], set_handle), "Failed to remove from queue set");
vQueueDelete(handles[i]);
}
vQueueDelete(set_handle);
}
/*
* Queue set thread safety test. Test the SMP thread safety by adding two queues
* to a queue set and have a task on each core send to the queues simultaneously.
* Check returned queue set members are valid.
*/
#ifndef CONFIG_FREERTOS_UNICORE
static volatile bool sync_flags[portNUM_PROCESSORS];
static SemaphoreHandle_t sync_sem;
static void send_task(void *arg)
{
QueueHandle_t queue = (QueueHandle_t)arg;
//Wait until task on the other core starts running
xSemaphoreTake(sync_sem, portMAX_DELAY);
sync_flags[xPortGetCoreID()] = true;
while (!sync_flags[!xPortGetCoreID()]) {
;
}
//Fill queue
for (int i = 0; i < QUEUE_LEN; i++) {
uint32_t item = i;
xQueueSendToBack(queue, &item, portMAX_DELAY);
}
xSemaphoreGive(sync_sem);
vTaskDelete(NULL);
}
TEST_CASE("Test Queue sets thread safety", "[freertos]")
{
//Create queue set, queues, and a send task on each core
sync_sem = xSemaphoreCreateCounting(portNUM_PROCESSORS, 0);
QueueHandle_t queue_handles[portNUM_PROCESSORS];
QueueSetHandle_t queueset_handle = xQueueCreateSet(portNUM_PROCESSORS * QUEUE_LEN);
for (int i = 0; i < portNUM_PROCESSORS; i++) {
sync_flags[i] = false;
queue_handles[i] = xQueueCreate(QUEUE_LEN, ITEM_SIZE);
TEST_ASSERT_MESSAGE(xQueueAddToSet(queue_handles[i], queueset_handle) == pdPASS, "Failed to add to queue set");
xTaskCreatePinnedToCore(send_task, "send", 2048, (void *)queue_handles[i], 10, NULL, i);
}
//Start both send tasks
portDISABLE_INTERRUPTS();
for (int i = 0; i < portNUM_PROCESSORS; i++) {
xSemaphoreGive(sync_sem);
}
portENABLE_INTERRUPTS();
vTaskDelay(2);
//Check returned queue set members are valid
uint32_t expect_0 = 0;
uint32_t expect_1 = 0;
for (int i = 0; i < (portNUM_PROCESSORS * QUEUE_LEN); i++) {
QueueSetMemberHandle_t member = xQueueSelectFromSet(queueset_handle, portMAX_DELAY);
uint32_t item;
if (member == queue_handles[0]) {
xQueueReceive((QueueHandle_t)member, &item, 0);
TEST_ASSERT_EQUAL_MESSAGE(expect_0, item, "Incorrect item value");
expect_0++;
} else if (member == queue_handles[1]) {
xQueueReceive((QueueHandle_t)member, &item, 0);
TEST_ASSERT_EQUAL_MESSAGE(expect_1, item, "Incorrect item value");
expect_1++;
} else {
TEST_ASSERT_MESSAGE(0, "Incorrect queue set member returned");
}
}
for (int i = 0; i < portNUM_PROCESSORS; i++) {
xSemaphoreTake(sync_sem, portMAX_DELAY);
}
for (int i = 0; i < portNUM_PROCESSORS; i++) {
xQueueRemoveFromSet(queueset_handle, handles[i]);
vQueueDelete(queue_handles[i]);
}
vQueueDelete(queueset_handle);
}
#endif

View File

@@ -798,7 +798,7 @@ test cases:
- ['R PC_COM C +NIC_START:OK']
- - "SSC SSC1 bleadv -D -z stop"
- ["R SSC1 C +BLEADV"]
- - LOOP 2 2 "['0x20-0x40','0xA0-0xB0']" "['NPDU','PDU']"
- - LOOP 2 2 "['0x20-0x40','0xA0-0xB0']" "['PDU','PDU']"
- [""]
- - "SSC SSC1 bleadv -D -z start -t 2 -i {%s}"
- ["R SSC1 C +BLEADV:OK"]
@@ -842,7 +842,7 @@ test cases:
- ['R PC_COM C +NIC_START:OK']
- - "SSC SSC1 bleadv -D -z stop"
- ["R SSC1 C +BLEADV"]
- - LOOP 2 2 "['0x20-0x40','0xA0-0xB0']" "['NPDU','PDU']"
- - LOOP 2 2 "['0x20-0x40','0xA0-0xB0']" "['PDU','PDU']"
- [""]
- - "SSC SSC1 bleadv -D -z start -t 3 -i {%s}"
- ["R SSC1 C +BLEADV:OK"]
@@ -890,7 +890,7 @@ test cases:
- ["R SSC1 C +BLEADV:OK"]
- - "SSC SSC2 bleadv -D -z stop"
- ["R SSC2 C +BLEADV:OK"]
- - "SSC SSC2 blescan -L -c 0 -s 0"
- - "SSC SSC2 blescan -L -c 0 -s 0 -d 1"
- ["R SSC2 C +BLESCAN:SetScanParam,OK"]
- - "SSC SSC2 blescan -D -z start -t 3 -e 2"
- - 'P SSC2 RE "\+BTSCANEXT:%%s,man,0x1011121314151617181910111213141516171819"%%(<dut1_bt_mac>)'
@@ -944,7 +944,7 @@ test cases:
- ["R SSC2 C +BLEADV:OK"]
- - LOOP 4 2 "[0,1,2,3]"
- ['']
- - "SSC SSC2 blescan -L -c 0 -s 1 -o {%d}"
- - "SSC SSC2 blescan -L -c 0 -s 1 -o {%d} -d 1"
- ["R SSC2 C +BLESCAN:SetScanParam,OK"]
- - "SSC SSC2 blescan -D -z start -t 1"
- ['R SSC2 P <dut1_bt_mac> C Complete']
@@ -1075,7 +1075,7 @@ test cases:
- ["R SSC1 C +BLEADV:OK"]
- - "SSC SSC1 bleadv -D -z start"
- ["R SSC1 C +BLEADV:OK"]
- - "SSC SSC2 blescan -L -c 0"
- - "SSC SSC2 blescan -L -c 0 -d 1"
- ["R SSC2 C +BLESCAN:SetScanParam,OK"]
- - "SSC SSC2 blescan -D -z start -t 1"
- ["R SSC2 P <dut1_bt_mac> C Complete"]
@@ -1538,6 +1538,8 @@ test cases:
- ""
- - "SSC SSC1 bleadv -D -z stop"
- ["R SSC1 C +BLEADV"]
- - "SSC SSC2 blescan -L -c 0 -d 1"
- ['R SSC2 C +BLESCAN']
- - "SSC SSC1 bleadv -R -t 1 -r 0x020AEB06FF1112131415051220004000021901020106"
- ["R SSC1 C +BLEADV:OK"]
- - "SSC SSC1 bleadv -D -z start"
@@ -1584,6 +1586,8 @@ test cases:
- ["R SSC1 C +BLEADV"]
- - "SSC SSC2 bleadv -D -z stop"
- ["R SSC2 C +BLEADV:OK"]
- - "SSC SSC2 blescan -L -c 0 -d 1"
- ['R SSC2 C +BLESCAN']
- - LOOP 4 3 "['0302ABCD','0303ABCD','0504ABCDABCD','0505ABCDABCD',]" "['insrv16,0xABCD','srv16,0xABCD','insrv32,0xABCDABCD','srv32,0xABCDABCD']"
- - "SSC SSC1 bleadv -R -t 1 -r 0x{%s}"
- ["R SSC1 C +BLEADV:OK"]
@@ -1633,6 +1637,8 @@ test cases:
- ["R SSC1 C +BLEADV"]
- - "SSC SSC2 bleadv -D -z stop"
- ["R SSC2 C +BLEADV:OK"]
- - "SSC SSC2 blescan -L -c 0 -d 1"
- ['R SSC2 C +BLESCAN']
- - LOOP 3 3 "['0416ABCDEF','0620ABCDABCDEF','1221ABCDABCDABCDABCDABCDABCDABCDABCDEF',]" "['srvdata,0xABCDEF','srvdata32,0xABCDABCDEF','srvdata128,0xABCDABCDABCDABCDABCDABCDABCDABCDEF']"
- - "SSC SSC1 bleadv -R -t 1 -r 0x{%s}"
- ["R SSC1 C +BLEADV:OK"]
@@ -1671,6 +1677,8 @@ test cases:
- ""
- - "SSC SSC1 bleadv -D -z stop"
- ["R SSC1 C +BLEADV"]
- - "SSC SSC2 blescan -L -c 0 -d 1"
- ['R SSC2 C +BLESCAN']
- - "SSC SSC1 bleadv -R -t 1 -r 0x15FF1011121314151617181910111213141516171819"
- ["R SSC1 C +BLEADV:OK"]
- - "SSC SSC1 bleadv -R -t 2 -r 0x020AEB051220004000021901020106"

View File

@@ -83,7 +83,7 @@ config LWIP_STATS
config LWIP_ETHARP_TRUST_IP_MAC
bool "Enable LWIP ARP trust"
default y
default n
help
Enabling this option allows ARP table to be updated.
@@ -96,6 +96,34 @@ config LWIP_ETHARP_TRUST_IP_MAC
The peer *is* in the ARP table if it requested our address before.
Also notice that this slows down input processing of every IP packet!
There are two known issues in real application if this feature is enabled:
- The LAN peer may have bug to update the ARP table after the ARP entry is aged out.
If the ARP entry on the LAN peer is aged out but failed to be updated, all IP packets
sent from LWIP to the LAN peer will be dropped by LAN peer.
- The LAN peer may not be trustful, the LAN peer may send IP packets to LWIP with
two different MACs, but the same IP address. If this happens, the LWIP has problem
to receive IP packets from LAN peer.
So the recommendation is to disable this option.
Here the LAN peer means the other side to which the ESP station or soft-AP is connected.
config ESP_GRATUITOUS_ARP
bool "Send gratuitous ARP periodically"
default y
help
Enable this option allows to send gratuitous ARP periodically.
This option solve the compatibility issues.If the ARP table of the AP is old, and the AP
doesn't send ARP request to update it's ARP table, this will lead to the STA sending IP packet fail.
Thus we send gratuitous ARP periodically to let AP update it's ARP table.
config GARP_TMR_INTERVAL
int "GARP timer interval(seconds)"
default 60
depends on ESP_GRATUITOUS_ARP
help
Set the timer interval for gratuitous ARP. The default value is 60s
config TCPIP_RECVMBOX_SIZE
int "TCPIP task receive mail box size"
default 32

View File

@@ -407,9 +407,9 @@ netconn_accept(struct netconn *conn, struct netconn **new_conn)
#if TCP_LISTEN_BACKLOG
/* Let the stack know that we have accepted the connection. */
API_MSG_VAR_ALLOC_DONTFAIL(msg);
API_MSG_VAR_REF(msg).msg.conn = conn;
/* don't care for the return value of lwip_netconn_do_recv */
TCPIP_APIMSG_NOERR(&API_MSG_VAR_REF(msg), lwip_netconn_do_recv);
API_MSG_VAR_REF(msg).msg.conn = newconn;
/* don't care for the return value of lwip_netconn_do_accepted */
TCPIP_APIMSG_NOERR(&API_MSG_VAR_REF(msg), lwip_netconn_do_accepted);
API_MSG_VAR_FREE(msg);
#endif /* TCP_LISTEN_BACKLOG */

View File

@@ -536,6 +536,9 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
to the application thread */
newconn->last_err = err;
/* handle backlog counter */
tcp_backlog_delayed(newpcb);
if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) {
ESP_STATS_DROP_INC(esp.acceptmbox_post_fail);
/* When returning != ERR_OK, the pcb is aborted in tcp_process(),
@@ -942,38 +945,33 @@ lwip_netconn_do_close_internal(struct netconn *conn WRITE_DELAYED_PARAM SIG_CLO
#endif /* LWIP_SO_LINGER */
} else {
if (err == ERR_MEM) {
/* Closing failed because of memory shortage */
if (netconn_is_nonblocking(conn)) {
/* Nonblocking close failed */
close_finished = 1;
err = ERR_WOULDBLOCK;
} else {
/* Blocking close, check the timeout */
/* Closing failed because of memory shortage, try again later. Even for
nonblocking netconns, we have to wait since no standard socket application
is prepared for close failing because of resource shortage.
Check the timeout: this is kind of an lwip addition to the standard sockets:
we wait for some time when failing to allocate a segment for the FIN */
#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
s32_t close_timeout = LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT;
/* this is kind of an lwip addition to the standard sockets: we wait
for some time when failing to allocate a segment for the FIN */
s32_t close_timeout = LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT;
#if LWIP_SO_SNDTIMEO
if (conn->send_timeout > 0) {
close_timeout = conn->send_timeout;
}
if (conn->send_timeout > 0) {
close_timeout = conn->send_timeout;
}
#endif /* LWIP_SO_SNDTIMEO */
#if LWIP_SO_LINGER
if (conn->linger >= 0) {
/* use linger timeout (seconds) */
close_timeout = conn->linger * 1000U;
}
if (conn->linger >= 0) {
/* use linger timeout (seconds) */
close_timeout = conn->linger * 1000U;
}
#endif
if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) {
if ((s32_t)(sys_now() - conn->current_msg->msg.sd.time_started) >= close_timeout) {
#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
if (conn->current_msg->msg.sd.polls_left == 0) {
if (conn->current_msg->msg.sd.polls_left == 0) {
#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
close_finished = 1;
if (close) {
/* in this case, we want to RST the connection */
tcp_abort(tpcb);
err = ERR_OK;
}
close_finished = 1;
if (close) {
/* in this case, we want to RST the connection */
tcp_abort(tpcb);
err = ERR_OK;
}
}
} else {
@@ -1503,24 +1501,38 @@ lwip_netconn_do_recv(void *m)
msg->err = ERR_OK;
if (msg->conn->pcb.tcp != NULL) {
if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
#if TCP_LISTEN_BACKLOG
if (msg->conn->pcb.tcp->state == LISTEN) {
tcp_accepted(msg->conn->pcb.tcp);
} else
#endif /* TCP_LISTEN_BACKLOG */
{
u32_t remaining = msg->msg.r.len;
do {
u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining;
tcp_recved(msg->conn->pcb.tcp, recved);
remaining -= recved;
} while (remaining != 0);
}
u32_t remaining = msg->msg.r.len;
do {
u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining;
tcp_recved(msg->conn->pcb.tcp, recved);
remaining -= recved;
} while (remaining != 0);
}
}
TCPIP_APIMSG_ACK(msg);
}
#if TCP_LISTEN_BACKLOG
/** Indicate that a TCP pcb has been accepted
* Called from netconn_accept
*
* @param m the api_msg pointing to the connection
*/
void
lwip_netconn_do_accepted(void *m)
{
struct api_msg_msg *msg = (struct api_msg_msg *)m;
msg->err = ERR_OK;
if (msg->conn->pcb.tcp != NULL) {
if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
tcp_backlog_accepted(msg->conn->pcb.tcp);
}
}
TCPIP_APIMSG_ACK(msg);
}
#endif /* TCP_LISTEN_BACKLOG */
/**
* See if more data needs to be written from a previous call to netconn_write.
* Called initially from lwip_netconn_do_write. If the first call can't send all data

View File

@@ -66,6 +66,13 @@ sys_thread_t g_lwip_task = NULL;
sys_mutex_t lock_tcpip_core;
#endif /* LWIP_TCPIP_CORE_LOCKING */
#if LWIP_TIMERS
/* wait for a message, timeouts are processed while waiting */
#define TCPIP_MBOX_FETCH(mbox, msg) sys_timeouts_mbox_fetch(mbox, msg)
#else /* LWIP_TIMERS */
/* wait for a message with timers disabled (e.g. pass a timer-check trigger into tcpip_thread) */
#define TCPIP_MBOX_FETCH(mbox, msg) sys_mbox_fetch(mbox, msg)
#endif /* LWIP_TIMERS */
/**
* The main lwIP thread. This thread has exclusive access to lwIP core functions
@@ -99,7 +106,7 @@ tcpip_thread(void *arg)
UNLOCK_TCPIP_CORE();
LWIP_TCPIP_THREAD_ALIVE();
/* wait for a message, timeouts are processed while waiting */
sys_timeouts_mbox_fetch(&mbox, (void **)&msg);
TCPIP_MBOX_FETCH(&mbox, (void **)&msg);
LOCK_TCPIP_CORE();

View File

@@ -133,16 +133,14 @@ bool ip4_netif_exist(const ip4_addr_t *src, const ip4_addr_t *dest)
return false;
}
/**
* Source based IPv4 routing hook function. This function works only
* when destination IP is broadcast IP.
* Source based IPv4 routing hook function.
*/
struct netif *
ip4_route_src_hook(const ip4_addr_t *dest, const ip4_addr_t *src)
{
struct netif *netif = NULL;
/* destination IP is broadcast IP? */
if ((src != NULL) && (dest->addr == IPADDR_BROADCAST)) {
if ((src != NULL) && !ip4_addr_isany(src)) {
/* iterate through netifs */
for (netif = netif_list; netif != NULL; netif = netif->next) {
/* is the netif up, does it have a link and a valid address? */

View File

@@ -332,6 +332,16 @@ netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *
#endif /* LWIP_IPV4*/
/**
* Set the netif flags for GARP
*/
#if ESP_GRATUITOUS_ARP
void netif_set_garp_flag(struct netif *netif)
{
netif->flags |= NETIF_FLAG_GARP;
}
#endif
/**
* Remove a network interface from the list of lwIP netifs.
*

View File

@@ -149,6 +149,22 @@ tcp_tmr(void)
}
}
#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG
/** Called when a listen pcb is closed. Iterates one pcb list and removes the
* closed listener pcb from pcb->listener if matching.
*/
static void
tcp_remove_listener(struct tcp_pcb *list, struct tcp_pcb_listen *lpcb)
{
struct tcp_pcb *pcb;
for (pcb = list; pcb != NULL; pcb = pcb->next) {
if (pcb->listener == lpcb) {
pcb->listener = NULL;
}
}
}
#endif
void
tcp_set_fin_wait_1(struct tcp_pcb *pcb)
{
@@ -158,6 +174,70 @@ tcp_set_fin_wait_1(struct tcp_pcb *pcb)
#endif
}
/** Called when a listen pcb is closed. Iterates all pcb lists and removes the
* closed listener pcb from pcb->listener if matching.
*/
static void
tcp_listen_closed(struct tcp_pcb *pcb)
{
#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG
size_t i;
LWIP_ASSERT("pcb != NULL", pcb != NULL);
LWIP_ASSERT("pcb->state == LISTEN", pcb->state == LISTEN);
for (i = 1; i < LWIP_ARRAYSIZE(tcp_pcb_lists); i++) {
tcp_remove_listener(*tcp_pcb_lists[i], (struct tcp_pcb_listen *)pcb);
}
#endif
LWIP_UNUSED_ARG(pcb);
}
#if TCP_LISTEN_BACKLOG
/** @ingroup tcp_raw
* Delay accepting a connection in respect to the listen backlog:
* the number of outstanding connections is increased until
* tcp_backlog_accepted() is called.
*
* ATTENTION: the caller is responsible for calling tcp_backlog_accepted()
* or else the backlog feature will get out of sync!
*
* @param pcb the connection pcb which is not fully accepted yet
*/
void
tcp_backlog_delayed(struct tcp_pcb *pcb)
{
LWIP_ASSERT("pcb != NULL", pcb != NULL);
if ((pcb->flags & TF_BACKLOGPEND) == 0) {
if (pcb->listener != NULL) {
pcb->listener->accepts_pending++;
LWIP_ASSERT("accepts_pending != 0", pcb->listener->accepts_pending != 0);
pcb->flags |= TF_BACKLOGPEND;
}
}
}
/** @ingroup tcp_raw
* A delayed-accept a connection is accepted (or closed/aborted): decreases
* the number of outstanding connections after calling tcp_backlog_delayed().
*
* ATTENTION: the caller is responsible for calling tcp_backlog_accepted()
* or else the backlog feature will get out of sync!
*
* @param pcb the connection pcb which is now fully accepted (or closed/aborted)
*/
void
tcp_backlog_accepted(struct tcp_pcb *pcb)
{
LWIP_ASSERT("pcb != NULL", pcb != NULL);
if ((pcb->flags & TF_BACKLOGPEND) != 0) {
if (pcb->listener != NULL) {
LWIP_ASSERT("accepts_pending != 0", pcb->listener->accepts_pending != 0);
pcb->listener->accepts_pending--;
pcb->flags &= ~TF_BACKLOGPEND;
}
}
}
#endif /* TCP_LISTEN_BACKLOG */
/**
* Closes the TX side of a connection held by the PCB.
* For tcp_close(), a RST is sent if the application didn't receive all data
@@ -227,6 +307,7 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data)
break;
case LISTEN:
err = ERR_OK;
tcp_listen_closed(pcb);
tcp_pcb_remove(&tcp_listen_pcbs.pcbs, pcb);
memp_free(MEMP_TCP_PCB_LISTEN, pcb);
pcb = NULL;
@@ -241,6 +322,7 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data)
case SYN_RCVD:
err = tcp_send_fin(pcb);
if (err == ERR_OK) {
tcp_backlog_accepted(pcb);
MIB2_STATS_INC(mib2.tcpattemptfails);
tcp_set_fin_wait_1(pcb);
}
@@ -408,6 +490,7 @@ tcp_abandon(struct tcp_pcb *pcb, int reset)
pcb->ooseq = NULL;
}
#endif /* TCP_QUEUE_OOSEQ */
tcp_backlog_accepted(pcb);
if (send_rst) {
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n"));
tcp_rst(seqno, ackno, &pcb->local_ip, &pcb->remote_ip, local_port, pcb->remote_port);
@@ -1747,39 +1830,7 @@ tcp_pcb_purge(struct tcp_pcb *pcb)
LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n"));
#if TCP_LISTEN_BACKLOG
if (pcb->state == SYN_RCVD) {
/* Need to find the corresponding listen_pcb and decrease its accepts_pending */
struct tcp_pcb_listen *lpcb;
/*
* The official LWIP will assert the system if tcp_listen_pcbs.listen_pcbs is NULL, it's a bug.
*
* Considering following scenario:
* 1. On TCP server side, one of TCP pcb is in SYNC_RECV state and is waiting for TCP ACK from TCP client.
* 2. The TCP server is closed by application, which causes the tcp_listen_pcbs.listen_pcbs to become NULL.
* 3. When SYNC_RECV state timeout (20s by default), tcp_pcb_purge() is called in tcp_slowtmr(), it asserts
* the system.
* This is a normal scenario, should NOT assert the system. So just remove it.
*
*/
if (tcp_listen_pcbs.listen_pcbs) {
for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
if ((lpcb->local_port == pcb->local_port) &&
(IP_IS_V6_VAL(pcb->local_ip) == IP_IS_V6_VAL(lpcb->local_ip)) &&
(ip_addr_isany(&lpcb->local_ip) ||
ip_addr_cmp(&pcb->local_ip, &lpcb->local_ip))) {
/* port and address of the listen pcb match the timed-out pcb */
LWIP_ASSERT("tcp_pcb_purge: listen pcb does not have accepts pending",
lpcb->accepts_pending > 0);
lpcb->accepts_pending--;
break;
}
}
}
}
#endif /* TCP_LISTEN_BACKLOG */
tcp_backlog_accepted(pcb);
if (pcb->refused_data != NULL) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n"));

View File

@@ -568,6 +568,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
}
#if TCP_LISTEN_BACKLOG
pcb->accepts_pending++;
npcb->flags |= TF_BACKLOGPEND;
#endif /* TCP_LISTEN_BACKLOG */
/* Set up the new PCB. */
ip_addr_copy(npcb->local_ip, *ip_current_dest_addr());
@@ -582,6 +583,10 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
#if LWIP_CALLBACK_API
npcb->accept = pcb->accept;
#endif /* LWIP_CALLBACK_API */
#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG
npcb->listener = pcb;
#endif
/* inherit socket options */
npcb->so_options = pcb->so_options & SOF_INHERITED;
/* Register the new PCB so that we can begin receiving segments
@@ -785,11 +790,19 @@ tcp_process(struct tcp_pcb *pcb)
if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {
pcb->state = ESTABLISHED;
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
#if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG
#if LWIP_CALLBACK_API
LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL);
#endif
/* Call the accept function. */
TCP_EVENT_ACCEPT(pcb, ERR_OK, err);
if (pcb->listener == NULL) {
err = ERR_VAL;
} else {
#endif
tcp_backlog_accepted(pcb);
/* Call the accept function. */
TCP_EVENT_ACCEPT(pcb, ERR_OK, err);
}
if (err != ERR_OK) {
/* If the accept function returns with an error, we abort
* the connection. */

View File

@@ -44,8 +44,6 @@
#include "lwip/timers.h"
#include "lwip/priv/tcp_priv.h"
#if LWIP_TIMERS
#include "lwip/def.h"
#include "lwip/memp.h"
#include "lwip/priv/tcpip_priv.h"
@@ -62,11 +60,71 @@
#include "lwip/sys.h"
#include "lwip/pbuf.h"
#if LWIP_DEBUG_TIMERNAMES
#define HANDLER(x) x, #x
#else /* LWIP_DEBUG_TIMERNAMES */
#define HANDLER(x) x
#endif /* LWIP_DEBUG_TIMERNAMES */
#if ESP_DHCP
extern void dhcps_coarse_tmr(void);
#endif
#if ESP_GRATUITOUS_ARP
extern void garp_tmr(void);
#endif
/** This array contains all stack-internal cyclic timers. To get the number of
* timers, use LWIP_ARRAYSIZE() */
const struct lwip_cyclic_timer lwip_cyclic_timers[] = {
#if LWIP_TCP
/* The TCP timer is a special case: it does not have to run always and
* is triggered to start from TCP using tcp_timer_needed() */
{TCP_TMR_INTERVAL, HANDLER(tcp_tmr)},
#endif /* LWIP_TCP */
#if LWIP_IPV4
#if IP_REASSEMBLY
{IP_TMR_INTERVAL, HANDLER(ip_reass_tmr)},
#endif /* IP_REASSEMBLY */
#if LWIP_ARP
{ARP_TMR_INTERVAL, HANDLER(etharp_tmr)},
#if ESP_GRATUITOUS_ARP
{GARP_TMR_INTERVAL, HANDLER(garp_tmr)},
#endif
#endif /* LWIP_ARP */
#if LWIP_DHCP
{DHCP_COARSE_TIMER_MSECS, HANDLER(dhcp_coarse_tmr)},
{DHCP_FINE_TIMER_MSECS, HANDLER(dhcp_fine_tmr)},
#if ESP_DHCP
{DHCP_COARSE_TIMER_MSECS, HANDLER(dhcps_coarse_tmr)},
#endif
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
{AUTOIP_TMR_INTERVAL, HANDLER(autoip_tmr)},
#endif /* LWIP_AUTOIP */
#if LWIP_IGMP
{IGMP_TMR_INTERVAL, HANDLER(igmp_tmr)},
#endif /* LWIP_IGMP */
#endif /* LWIP_IPV4 */
#if LWIP_DNS
{DNS_TMR_INTERVAL, HANDLER(dns_tmr)},
#endif /* LWIP_DNS */
#if LWIP_IPV6
{ND6_TMR_INTERVAL, HANDLER(nd6_tmr)},
#if LWIP_IPV6_REASS
{IP6_REASS_TMR_INTERVAL, HANDLER(ip6_reass_tmr)},
#endif /* LWIP_IPV6_REASS */
#if LWIP_IPV6_MLD
{MLD6_TMR_INTERVAL, HANDLER(mld6_tmr)},
#endif /* LWIP_IPV6_MLD */
#endif /* LWIP_IPV6 */
};
#if LWIP_TIMERS && !LWIP_TIMERS_CUSTOM
/** The one and only timeout list */
static struct sys_timeo *next_timeout;
#if NO_SYS
static u32_t timeouts_last_time;
#endif /* NO_SYS */
#if LWIP_TCP
/** global variable that shows if the tcp timer is currently scheduled or not */
@@ -111,213 +169,35 @@ tcp_timer_needed(void)
}
#endif /* LWIP_TCP */
#if LWIP_IPV4
#if IP_REASSEMBLY
/**
* Timer callback function that calls ip_reass_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
ip_reass_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip_reass_tmr()\n"));
ip_reass_tmr();
sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
}
#endif /* IP_REASSEMBLY */
#if LWIP_ARP
/**
* Timer callback function that calls etharp_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
arp_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: etharp_tmr()\n"));
etharp_tmr();
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
}
#endif /* LWIP_ARP */
#if LWIP_DHCP
/**
* Timer callback function that calls dhcp_coarse_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
dhcp_timer_coarse(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_coarse_tmr()\n"));
dhcp_coarse_tmr();
#if ESP_DHCP
extern void dhcps_coarse_tmr(void);
dhcps_coarse_tmr();
#endif
sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
}
/**
* Timer callback function that calls dhcp_fine_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
dhcp_timer_fine(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_fine_tmr()\n"));
dhcp_fine_tmr();
sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
}
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
/**
* Timer callback function that calls autoip_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
autoip_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: autoip_tmr()\n"));
autoip_tmr();
sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
}
#endif /* LWIP_AUTOIP */
#if LWIP_IGMP
/**
* Timer callback function that calls igmp_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
igmp_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: igmp_tmr()\n"));
igmp_tmr();
sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
}
#endif /* LWIP_IGMP */
#endif /* LWIP_IPV4 */
#if LWIP_DNS
/**
* Timer callback function that calls dns_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
dns_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dns_tmr()\n"));
dns_tmr();
sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
}
#endif /* LWIP_DNS */
#if LWIP_IPV6
/**
* Timer callback function that calls nd6_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
nd6_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: nd6_tmr()\n"));
nd6_tmr();
sys_timeout(ND6_TMR_INTERVAL, nd6_timer, NULL);
}
#if LWIP_IPV6_REASS
/**
* Timer callback function that calls ip6_reass_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
ip6_reass_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip6_reass_tmr()\n"));
ip6_reass_tmr();
sys_timeout(IP6_REASS_TMR_INTERVAL, ip6_reass_timer, NULL);
}
#endif /* LWIP_IPV6_REASS */
#if LWIP_IPV6_MLD
/**
* Timer callback function that calls mld6_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
mld6_timer(void *arg)
cyclic_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: mld6_tmr()\n"));
mld6_tmr();
sys_timeout(MLD6_TMR_INTERVAL, mld6_timer, NULL);
const struct lwip_cyclic_timer* cyclic = (const struct lwip_cyclic_timer*)arg;
#if LWIP_DEBUG_TIMERNAMES
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: %s()\n", cyclic->handler_name));
#endif
cyclic->handler();
sys_timeout(cyclic->interval_ms, cyclic_timer, arg);
}
#endif /* LWIP_IPV6_MLD */
#endif /* LWIP_IPV6 */
/** Initialize this module */
void sys_timeouts_init(void)
{
#if LWIP_IPV4
#if IP_REASSEMBLY
sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
#endif /* IP_REASSEMBLY */
#if LWIP_ARP
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
#endif /* LWIP_ARP */
#if LWIP_DHCP
size_t i;
/* tcp_tmr() at index 0 is started on demand */
for (i = (LWIP_TCP ? 1 : 0); i < LWIP_ARRAYSIZE(lwip_cyclic_timers); i++) {
/* we have to cast via size_t to get rid of const warning
* (this is OK as cyclic_timer() casts back to const* */
sys_timeout(lwip_cyclic_timers[i].interval_ms, cyclic_timer, LWIP_CONST_CAST(void*, &lwip_cyclic_timers[i]));
}
sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
#endif /* LWIP_AUTOIP */
#if LWIP_IGMP
sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
#endif /* LWIP_IGMP */
#endif /* LWIP_IPV4 */
#if LWIP_DNS
sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
#endif /* LWIP_DNS */
#if LWIP_IPV6
sys_timeout(ND6_TMR_INTERVAL, nd6_timer, NULL);
#if LWIP_IPV6_REASS
sys_timeout(IP6_REASS_TMR_INTERVAL, ip6_reass_timer, NULL);
#endif /* LWIP_IPV6_REASS */
#if LWIP_IPV6_MLD
sys_timeout(MLD6_TMR_INTERVAL, mld6_timer, NULL);
#endif /* LWIP_IPV6_MLD */
#endif /* LWIP_IPV6 */
#if NO_SYS
/* Initialise timestamp for sys_check_timeouts */
timeouts_last_time = sys_now();
#endif
}
/**
@@ -334,19 +214,12 @@ void sys_timeouts_init(void)
void
sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name)
#else /* LWIP_DEBUG_TIMERNAMES */
#if ESP_LIGHT_SLEEP
u32_t LwipTimOutLim = 0; // For light sleep. time out. limit is 3000ms
#endif
void
sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)
#endif /* LWIP_DEBUG_TIMERNAMES */
{
struct sys_timeo *timeout, *t;
#if NO_SYS
u32_t now, diff;
#endif
timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT);
if (timeout == NULL) {
@@ -354,7 +227,6 @@ sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)
return;
}
#if NO_SYS
now = sys_now();
if (next_timeout == NULL) {
diff = 0;
@@ -362,26 +234,15 @@ sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)
} else {
diff = now - timeouts_last_time;
}
#endif
timeout->next = NULL;
timeout->h = handler;
timeout->arg = arg;
#if ESP_LIGHT_SLEEP
if(msecs < LwipTimOutLim)
msecs = LwipTimOutLim;
#endif
#if NO_SYS
timeout->time = msecs + diff;
#else
timeout->time = msecs;
#endif
#if LWIP_DEBUG_TIMERNAMES
timeout->handler_name = handler_name;
LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" handler=%s arg=%p\n",
(void *)timeout, msecs, handler_name, (void *)arg));
(void *)timeout, msecs, handler_name, (void *)arg));
#endif /* LWIP_DEBUG_TIMERNAMES */
if (next_timeout == NULL) {
@@ -399,6 +260,12 @@ sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)
if (t->next == NULL || t->next->time > timeout->time) {
if (t->next != NULL) {
t->next->time -= timeout->time;
} else if (timeout->time > msecs) {
/* If this is the case, 'timeouts_last_time' and 'now' differs too much.
* This can be due to sys_check_timeouts() not being called at the right
* times, but also when stopping in a breakpoint. Anyway, let's assume
* this is not wanted, so add the first timer's time instead of 'diff' */
timeout->time = msecs + next_timeout->time;
}
timeout->next = t->next;
t->next = timeout;
@@ -415,7 +282,7 @@ sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)
*
* @param handler callback function that would be called by the timeout
* @param arg callback argument that would be passed to handler
*/
*/
void
sys_untimeout(sys_timeout_handler handler, void *arg)
{
@@ -445,14 +312,17 @@ sys_untimeout(sys_timeout_handler handler, void *arg)
return;
}
#if NO_SYS
/** Handle timeouts for NO_SYS==1 (i.e. without using
/**
* @ingroup lwip_nosys
* Handle timeouts for NO_SYS==1 (i.e. without using
* tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout
* handler functions when timeouts expire.
*
* Must be called periodically from your main loop.
*/
#if !NO_SYS && !defined __DOXYGEN__
static
#endif /* !NO_SYS */
void
sys_check_timeouts(void)
{
@@ -468,9 +338,7 @@ sys_check_timeouts(void)
/* this cares for wraparounds */
diff = now - timeouts_last_time;
do {
#if PBUF_POOL_FREE_OOSEQ
PBUF_CHECK_FREE_OOSEQ();
#endif /* PBUF_POOL_FREE_OOSEQ */
had_one = 0;
tmptimeout = next_timeout;
if (tmptimeout && (tmptimeout->time <= diff)) {
@@ -483,16 +351,24 @@ sys_check_timeouts(void)
arg = tmptimeout->arg;
#if LWIP_DEBUG_TIMERNAMES
if (handler != NULL) {
LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n",
tmptimeout->handler_name, arg));
LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n",tmptimeout->handler_name, arg));
}
#endif /* LWIP_DEBUG_TIMERNAMES */
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
if (handler != NULL) {
#if !NO_SYS
/* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the
* timeout handler function. */
LOCK_TCPIP_CORE();
#endif /* !NO_SYS */
handler(arg);
#if !NO_SYS
UNLOCK_TCPIP_CORE();
#endif /* !NO_SYS */
}
LWIP_TCPIP_THREAD_ALIVE();
}
/* repeat until all expired timers have been called */
/* repeat until all expired timers have been called */
} while (had_one);
}
}
@@ -511,6 +387,9 @@ sys_restart_timeouts(void)
/** Return the time left before the next timeout is due. If no timeouts are
* enqueued, returns 0xffffffff
*/
#if !NO_SYS
static
#endif /* !NO_SYS */
u32_t
sys_timeouts_sleeptime(void)
{
@@ -526,7 +405,7 @@ sys_timeouts_sleeptime(void)
}
}
#else /* NO_SYS */
#if !NO_SYS
/**
* Wait (forever) for a message to arrive in an mbox.
@@ -538,66 +417,30 @@ sys_timeouts_sleeptime(void)
void
sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
{
u32_t time_needed;
struct sys_timeo *tmptimeout;
sys_timeout_handler handler;
void *arg;
again:
u32_t sleeptime;
again:
if (!next_timeout) {
time_needed = sys_arch_mbox_fetch(mbox, msg, 0);
} else {
if (next_timeout->time > 0) {
time_needed = sys_arch_mbox_fetch(mbox, msg, next_timeout->time);
} else {
time_needed = SYS_ARCH_TIMEOUT;
}
sys_arch_mbox_fetch(mbox, msg, 0);
return;
}
if (time_needed == SYS_ARCH_TIMEOUT) {
/* If time == SYS_ARCH_TIMEOUT, a timeout occurred before a message
could be fetched. We should now call the timeout handler and
deallocate the memory allocated for the timeout. */
tmptimeout = next_timeout;
next_timeout = tmptimeout->next;
handler = tmptimeout->h;
arg = tmptimeout->arg;
#if LWIP_DEBUG_TIMERNAMES
if (handler != NULL) {
LWIP_DEBUGF(TIMERS_DEBUG, ("stmf calling h=%s arg=%p\n",
tmptimeout->handler_name, arg));
}
#endif /* LWIP_DEBUG_TIMERNAMES */
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
if (handler != NULL) {
/* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the
timeout handler function. */
LOCK_TCPIP_CORE();
handler(arg);
UNLOCK_TCPIP_CORE();
}
LWIP_TCPIP_THREAD_ALIVE();
/* We try again to fetch a message from the mbox. */
goto again;
} else {
/* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
occured. The time variable is set to the number of
milliseconds we waited for the message. */
if (time_needed < next_timeout->time) {
next_timeout->time -= time_needed;
} else {
next_timeout->time = 0;
}
}
sleeptime = sys_timeouts_sleeptime();
if (sleeptime == 0 || sys_arch_mbox_fetch(mbox, msg, sleeptime) == SYS_ARCH_TIMEOUT) {
/* If a SYS_ARCH_TIMEOUT value is returned, a timeout occurred
* before a message could be fetched. */
sys_check_timeouts();
/* We try again to fetch a message from the mbox. */
goto again;
}
}
#endif /* NO_SYS */
#else /* LWIP_TIMERS */
#else /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */
/* Satisfy the TCP code which calls this function */
void
tcp_timer_needed(void)
{
}
#endif /* LWIP_TIMERS */
#endif /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */

View File

@@ -52,6 +52,11 @@
#define X8_F "02x"
#endif /* X8_F */
/** C++ const_cast<target_type>(val) equivalent to remove constness from a value (GCC -Wcast-qual) */
#ifndef LWIP_CONST_CAST
#define LWIP_CONST_CAST(target_type, val) ((target_type)((ptrdiff_t)val))
#endif
#ifdef __cplusplus
extern "C" {
#endif

View File

@@ -47,6 +47,8 @@ extern "C" {
#define IPADDR_TYPE_V6 6U
#define IPADDR_TYPE_ANY 46U
#define IP_IS_V4_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_V4)
#if LWIP_IPV4 && LWIP_IPV6
/** A union struct for both IP version's addresses.
* ATTENTION: watch out for its size when adding IPv6 address scope!
@@ -67,6 +69,7 @@ extern const ip_addr_t ip_addr_any_type;
#define IP_IS_ANY_TYPE_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_ANY)
#define IPADDR_ANY_TYPE_INIT { { { { 0ul, 0ul, 0ul, 0ul } } }, IPADDR_TYPE_ANY }
#define IP_IS_V4_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_V4)
#define IP_IS_V6_VAL(ipaddr) (IP_GET_TYPE(&ipaddr) == IPADDR_TYPE_V6)
#define IP_IS_V6(ipaddr) (((ipaddr) != NULL) && IP_IS_V6_VAL(*(ipaddr)))

View File

@@ -99,6 +99,11 @@ extern "C" {
* Set by the netif driver in its init function. */
#define NETIF_FLAG_MLD6 0x40U
#if ESP_GRATUITOUS_ARP
/** If set, the netif will send gratuitous ARP periodically */
#define NETIF_FLAG_GARP 0x80U
#endif
#if LWIP_CHECKSUM_CTRL_PER_NETIF
#define NETIF_CHECKSUM_GEN_IP 0x0001
#define NETIF_CHECKSUM_GEN_UDP 0x0002
@@ -362,6 +367,11 @@ struct netif *netif_add(struct netif *netif,
void netif_set_addr(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask,
const ip4_addr_t *gw);
#endif /* LWIP_IPV4 */
#if ESP_GRATUITOUS_ARP
void netif_set_garp_flag(struct netif *netif);
#endif
void netif_remove(struct netif * netif);
/* Returns a network interface given its name. The name is of the form

View File

@@ -69,11 +69,16 @@
#endif
/**
* NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1
* Mainly for compatibility to old versions.
* LWIP_TIMERS==0: Drop support for sys_timeout and lwip-internal cyclic timers.
* (the array of lwip-internal cyclic timers is still provided)
* (check NO_SYS_NO_TIMERS for compatibility to old versions)
*/
#ifndef NO_SYS_NO_TIMERS
#define NO_SYS_NO_TIMERS 0
#if !defined LWIP_TIMERS || defined __DOXYGEN__
#ifdef NO_SYS_NO_TIMERS
#define LWIP_TIMERS (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS))
#else
#define LWIP_TIMERS 1
#endif
#endif
/**
@@ -313,8 +318,12 @@
* The formula expects settings to be either '0' or '1'.
*/
#ifndef MEMP_NUM_SYS_TIMEOUT
#if ESP_LWIP
#define MEMP_NUM_SYS_TIMEOUT (LWIP_TCP + IP_REASSEMBLY + (LWIP_ARP + (ESP_GRATUITOUS_ARP ? 1 : 0)) + (2*LWIP_DHCP + (ESP_DHCPS_TIMER ? 1 : 0)) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + (PPP_SUPPORT*6*MEMP_NUM_PPP_PCB) + (LWIP_IPV6 ? (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD) : 0))
#else
#define MEMP_NUM_SYS_TIMEOUT (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + (PPP_SUPPORT*6*MEMP_NUM_PPP_PCB) + (LWIP_IPV6 ? (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD) : 0))
#endif
#endif
/**
* MEMP_NUM_NETBUF: the number of struct netbufs.

View File

@@ -169,12 +169,12 @@ struct pbuf_custom {
};
#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
#if LWIP_TCP && TCP_QUEUE_OOSEQ
/** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */
#ifndef PBUF_POOL_FREE_OOSEQ
#define PBUF_POOL_FREE_OOSEQ 1
#endif /* PBUF_POOL_FREE_OOSEQ */
#if NO_SYS && PBUF_POOL_FREE_OOSEQ
#if LWIP_TCP && TCP_QUEUE_OOSEQ && NO_SYS && PBUF_POOL_FREE_OOSEQ
extern volatile u8_t pbuf_free_ooseq_pending;
void pbuf_free_ooseq(void);
/** When not using sys_check_timeouts(), call PBUF_CHECK_FREE_OOSEQ()
@@ -184,8 +184,10 @@ void pbuf_free_ooseq(void);
/* pbuf_alloc() reported PBUF_POOL to be empty -> try to free some \
ooseq queued pbufs now */ \
pbuf_free_ooseq(); }}while(0)
#endif /* NO_SYS && PBUF_POOL_FREE_OOSEQ*/
#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ */
#else /* LWIP_TCP && TCP_QUEUE_OOSEQ && NO_SYS && PBUF_POOL_FREE_OOSEQ */
/* Otherwise declare an empty PBUF_CHECK_FREE_OOSEQ */
#define PBUF_CHECK_FREE_OOSEQ()
#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ && NO_SYS && PBUF_POOL_FREE_OOSEQ*/
/* Initializes the pbuf module. This call is empty for now, but may not be in future. */
#define pbuf_init()

View File

@@ -232,6 +232,9 @@ void lwip_netconn_do_disconnect (void *m);
void lwip_netconn_do_listen (void *m);
void lwip_netconn_do_send (void *m);
void lwip_netconn_do_recv (void *m);
#if TCP_LISTEN_BACKLOG
void lwip_netconn_do_accepted (void *m);
#endif
void lwip_netconn_do_write (void *m);
void lwip_netconn_do_getaddr (void *m);
void lwip_netconn_do_close (void *m);

View File

@@ -138,7 +138,7 @@ typedef u16_t tcpflags_t;
#define TCPWND16(x) (x)
#define TCP_WND_MAX(pcb) TCP_WND(pcb)
typedef u16_t tcpwnd_size_t;
typedef u8_t tcpflags_t;
typedef u16_t tcpflags_t;
#endif
enum tcp_state {
@@ -203,6 +203,9 @@ struct tcp_pcb {
#define TF_NAGLEMEMERR 0x80U /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */
#if LWIP_WND_SCALE
#define TF_WND_SCALE 0x0100U /* Window Scale option enabled */
#endif
#if TCP_LISTEN_BACKLOG
#define TF_BACKLOGPEND 0x0200U /* If this is set, a connection pcb has increased the backlog on its listener */
#endif
/* the rest of the fields are in host byte order
@@ -311,6 +314,10 @@ struct tcp_pcb {
u8_t rcv_scale;
#endif
#if TCP_LISTEN_BACKLOG
struct tcp_pcb_listen *listener;
#endif
#if ESP_STATS_TCP
#define ESP_STATS_TCP_ARRAY_SIZE 20
u16_t retry_cnt[TCP_MAXRTX];
@@ -383,16 +390,17 @@ void tcp_err (struct tcp_pcb *pcb, tcp_err_fn err);
#define tcp_nagle_disabled(pcb) (((pcb)->flags & TF_NODELAY) != 0)
#if TCP_LISTEN_BACKLOG
#define tcp_accepted(pcb) do { \
LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", pcb->state == LISTEN); \
(((struct tcp_pcb_listen *)(pcb))->accepts_pending--); } while(0)
#define tcp_backlog_set(pcb, new_backlog) do { \
LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", (pcb)->state == LISTEN); \
((struct tcp_pcb_listen *)(pcb))->backlog = ((new_backlog) ? (new_backlog) : 1); } while(0)
void tcp_backlog_delayed(struct tcp_pcb* pcb);
void tcp_backlog_accepted(struct tcp_pcb* pcb);
#else /* TCP_LISTEN_BACKLOG */
#define tcp_accepted(pcb) LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", \
(pcb)->state == LISTEN)
#define tcp_backlog_set(pcb, new_backlog)
#define tcp_backlog_delayed(pcb)
#define tcp_backlog_accepted(pcb)
#endif /* TCP_LISTEN_BACKLOG */
#define tcp_accepted(pcb) do { LWIP_UNUSED_ARG(pcb); } while(0) /* compatibility define, not needed any more */
void tcp_recved (struct tcp_pcb *pcb, u16_t len);
err_t tcp_bind (struct tcp_pcb *pcb, const ip_addr_t *ipaddr,

View File

@@ -34,12 +34,6 @@
#define LWIP_HDR_TIMERS_H
#include "lwip/opt.h"
/* Timers are not supported when NO_SYS==1 and NO_SYS_NO_TIMERS==1 */
#define LWIP_TIMERS (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS))
#if LWIP_TIMERS
#include "lwip/err.h"
#if !NO_SYS
#include "lwip/sys.h"
@@ -57,6 +51,26 @@ extern "C" {
#endif /* LWIP_DEBUG*/
#endif
/** Function prototype for a stack-internal timer function that has to be
* called at a defined interval */
typedef void (* lwip_cyclic_timer_handler)(void);
/** This struct contains information about a stack-internal timer function
* that has to be called at a defined interval */
struct lwip_cyclic_timer {
u32_t interval_ms;
lwip_cyclic_timer_handler handler;
#if LWIP_DEBUG_TIMERNAMES
const char* handler_name;
#endif /* LWIP_DEBUG_TIMERNAMES */
};
/** This array contains all stack-internal cyclic timers. To get the number of
* timers, use LWIP_ARRAYSIZE() */
extern const struct lwip_cyclic_timer lwip_cyclic_timers[];
#if LWIP_TIMERS
/** Function prototype for a timeout callback function. Register such a function
* using sys_timeout().
*
@@ -84,18 +98,20 @@ void sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg);
#endif /* LWIP_DEBUG_TIMERNAMES */
void sys_untimeout(sys_timeout_handler handler, void *arg);
void sys_restart_timeouts(void);
#if NO_SYS
void sys_check_timeouts(void);
void sys_restart_timeouts(void);
u32_t sys_timeouts_sleeptime(void);
#else /* NO_SYS */
void sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg);
#endif /* NO_SYS */
#endif /* LWIP_TIMERS */
#ifdef __cplusplus
}
#endif
#endif /* LWIP_TIMERS */
#endif /* LWIP_HDR_TIMERS_H */

View File

@@ -102,6 +102,11 @@ struct etharp_q_entry {
};
#endif /* ARP_QUEUEING */
#if ESP_GRATUITOUS_ARP
#define GARP_TMR_INTERVAL (CONFIG_GARP_TMR_INTERVAL*1000UL)
void garp_tmr(void);
#endif
#define etharp_init() /* Compatibility define, no init needed. */
void etharp_tmr(void);
s8_t etharp_find_addr(struct netif *netif, const ip4_addr_t *ipaddr,

View File

@@ -732,6 +732,7 @@
#define ESP_DHCP_TIMER 1
#define ESP_LWIP_LOGI(...) ESP_LOGI("lwip", __VA_ARGS__)
#define ESP_PING 1
#define ESP_GRATUITOUS_ARP CONFIG_ESP_GRATUITOUS_ARP
#define TCP_WND_DEFAULT CONFIG_TCP_WND_DEFAULT
#define TCP_SND_BUF_DEFAULT CONFIG_TCP_SND_BUF_DEFAULT

View File

@@ -52,6 +52,7 @@
#include "lwip/snmp.h"
#include "lwip/dhcp.h"
#include "lwip/autoip.h"
#include "lwip/netif.h"
#include <string.h>
@@ -129,6 +130,20 @@ static u8_t etharp_cached_entry;
static err_t etharp_request_dst(struct netif *netif, const ip4_addr_t *ipaddr, const struct eth_addr* hw_dst_addr);
#if ESP_GRATUITOUS_ARP
void garp_tmr(void)
{
struct netif* garp_netif = NULL;
for (garp_netif = netif_list; garp_netif != NULL; garp_netif = garp_netif->next) {
if (netif_is_up(garp_netif) && netif_is_link_up(garp_netif) && !ip4_addr_isany_val(*netif_ip4_addr(garp_netif))) {
if ((garp_netif->flags & NETIF_FLAG_ETHARP) && (garp_netif->flags & NETIF_FLAG_GARP)) {
etharp_gratuitous(garp_netif);
}
}
}
}
#endif
#if ARP_QUEUEING
/**

View File

@@ -697,20 +697,23 @@ static int vfs_spiffs_readdir_r(void* ctx, DIR* pdir, struct dirent* entry,
esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
vfs_spiffs_dir_t * dir = (vfs_spiffs_dir_t *)pdir;
struct spiffs_dirent out;
if (SPIFFS_readdir(&dir->d, &out) == 0) {
errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
SPIFFS_clearerr(efs->fs);
if (!errno) {
*out_dirent = NULL;
size_t plen;
char * item_name;
do {
if (SPIFFS_readdir(&dir->d, &out) == 0) {
errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
SPIFFS_clearerr(efs->fs);
if (!errno) {
*out_dirent = NULL;
}
return errno;
}
return errno;
}
const char * item_name = (const char *)out.name;
size_t plen = strlen(dir->path);
item_name = (char *)out.name;
plen = strlen(dir->path);
} while ((plen > 1) && (strncasecmp(dir->path, (const char*)out.name, plen) || out.name[plen] != '/' || !out.name[plen + 1]));
if (plen > 1) {
if (strncasecmp(dir->path, (const char *)out.name, plen) || out.name[plen] != '/' || !out.name[plen+1]) {
return vfs_spiffs_readdir_r(ctx, pdir, entry, out_dirent);
}
item_name += plen + 1;
} else if (item_name[0] == '/') {
item_name++;

View File

@@ -275,6 +275,63 @@ void test_spiffs_opendir_readdir_rewinddir(const char* dir_prefix)
TEST_ASSERT_EQUAL(0, closedir(dir));
}
void test_spiffs_readdir_many_files(const char* dir_prefix)
{
const int n_files = 40;
const int n_folders = 4;
unsigned char file_count[n_files * n_folders];
memset(file_count, 0, sizeof(file_count)/sizeof(file_count[0]));
char file_name[ESP_VFS_PATH_MAX + CONFIG_SPIFFS_OBJ_NAME_LEN];
/* clean stale files before the test */
DIR* dir = opendir(dir_prefix);
if (dir) {
while (true) {
struct dirent* de = readdir(dir);
if (!de) {
break;
}
snprintf(file_name, sizeof(file_name), "%s/%s", dir_prefix, de->d_name);
unlink(file_name);
}
}
/* create files */
for (int d = 0; d < n_folders; ++d) {
printf("filling directory %d\n", d);
for (int f = 0; f < n_files; ++f) {
snprintf(file_name, sizeof(file_name), "%s/%d/%d.txt", dir_prefix, d, f);
test_spiffs_create_file_with_text(file_name, file_name);
}
}
/* list files */
for (int d = 0; d < n_folders; ++d) {
printf("listing files in directory %d\n", d);
snprintf(file_name, sizeof(file_name), "%s/%d", dir_prefix, d);
dir = opendir(file_name);
TEST_ASSERT_NOT_NULL(dir);
while (true) {
struct dirent* de = readdir(dir);
if (!de) {
break;
}
int file_id;
TEST_ASSERT_EQUAL(1, sscanf(de->d_name, "%d.txt", &file_id));
file_count[file_id + d * n_files]++;
}
closedir(dir);
}
/* check that all created files have been seen */
for (int d = 0; d < n_folders; ++d) {
printf("checking that all files have been found in directory %d\n", d);
for (int f = 0; f < n_files; ++f) {
TEST_ASSERT_EQUAL(1, file_count[f + d * n_files]);
}
}
}
typedef struct {
const char* filename;
@@ -499,6 +556,13 @@ TEST_CASE("opendir, readdir, rewinddir, seekdir work as expected", "[spiffs]")
test_teardown();
}
TEST_CASE("readdir with large number of files", "[spiffs][timeout=15]")
{
test_setup();
test_spiffs_readdir_many_files("/spiffs/dir2");
test_teardown();
}
TEST_CASE("multiple tasks can use same volume", "[spiffs]")
{
test_setup();

View File

@@ -26,6 +26,7 @@
#include "lwip/ip6_addr.h"
#include "lwip/nd6.h"
#include "lwip/priv/tcpip_priv.h"
#include "lwip/netif.h"
#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
#include "lwip/dns.h"
#endif
@@ -175,6 +176,11 @@ esp_err_t tcpip_adapter_start(tcpip_adapter_if_t tcpip_if, uint8_t *mac, tcpip_a
netif_init = tcpip_if_to_netif_init_fn(tcpip_if);
assert(netif_init != NULL);
netif_add(esp_netif[tcpip_if], &ip_info->ip, &ip_info->netmask, &ip_info->gw, NULL, netif_init, tcpip_input);
#if ESP_GRATUITOUS_ARP
if (tcpip_if == TCPIP_ADAPTER_IF_STA || tcpip_if == TCPIP_ADAPTER_IF_ETH) {
netif_set_garp_flag(esp_netif[tcpip_if]);
}
#endif
}
if (tcpip_if == TCPIP_ADAPTER_IF_AP) {

View File

@@ -81,7 +81,7 @@ build: $(COMPONENT_BUILD_DIR)/$(ULP_EXPORTS_HEADER) \
$(ULP_EXP_DEP_OBJECTS) : $(ULP_EXPORTS_HEADER) $(ULP_SYM)
# Finally, set all the variables processed by the build system.
COMPONENT_EXTRA_CLEAN := $(ULP_OBJECTS) \
COMPONENT_EXTRA_CLEAN += $(ULP_OBJECTS) \
$(ULP_LD_SCRIPT) \
$(ULP_PREPROCESSED) \
$(ULP_ELF) $(ULP_BIN) \
@@ -91,6 +91,6 @@ COMPONENT_EXTRA_CLEAN := $(ULP_OBJECTS) \
$(ULP_DEP) \
$(ULP_LISTINGS)
COMPONENT_EMBED_FILES := $(COMPONENT_BUILD_DIR)/$(ULP_BIN)
COMPONENT_ADD_LDFLAGS := -l$(COMPONENT_NAME) -T $(COMPONENT_BUILD_DIR)/$(ULP_EXPORTS_LD)
COMPONENT_EXTRA_INCLUDES := $(COMPONENT_BUILD_DIR)
COMPONENT_EMBED_FILES += $(COMPONENT_BUILD_DIR)/$(ULP_BIN)
COMPONENT_ADD_LDFLAGS += -l$(COMPONENT_NAME) -T $(COMPONENT_BUILD_DIR)/$(ULP_EXPORTS_LD)
COMPONENT_EXTRA_INCLUDES += $(COMPONENT_BUILD_DIR)

View File

@@ -17,6 +17,7 @@
#include <stddef.h>
#include <stdlib.h>
#include "esp_err.h"
#include "soc/soc.h"
#ifdef __cplusplus
extern "C" {
@@ -857,7 +858,7 @@ esp_err_t ulp_process_macros_and_load(uint32_t load_addr, const ulp_insn_t* prog
* 3. TEXT_SIZE, size of .text section (2 bytes)
* 4. DATA_SIZE, size of .data section (2 bytes)
* 5. BSS_SIZE, size of .bss section (2 bytes)
* 6. (TEXT_OFFSET - 16) bytes of arbitrary data (will not be loaded into RTC memory)
* 6. (TEXT_OFFSET - 12) bytes of arbitrary data (will not be loaded into RTC memory)
* 7. .text section
* 8. .data section
*

View File

@@ -1 +1,11 @@
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
ULP_APP_NAME = ulp_test
ULP_S_SOURCES = $(addprefix $(COMPONENT_PATH)/ulp/, \
test_jumps.S \
)
ULP_EXP_DEP_OBJECTS := test_ulp_as.o
include $(IDF_PATH)/components/ulp/component_ulp_common.mk
COMPONENT_ADD_LDFLAGS += -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive

View File

@@ -0,0 +1,25 @@
#include <unistd.h>
#include "unity.h"
#include "soc/rtc_cntl_reg.h"
#include "esp32/ulp.h"
#include "ulp_test.h"
extern const uint8_t ulp_test_bin_start[] asm("_binary_ulp_test_bin_start");
extern const uint8_t ulp_test_bin_end[] asm("_binary_ulp_test_bin_end");
TEST_CASE("jumps condition", "[ulp]")
{
esp_err_t err = ulp_load_binary(0, ulp_test_bin_start,
(ulp_test_bin_end - ulp_test_bin_start) / sizeof(uint32_t));
TEST_ESP_OK(err);
REG_CLR_BIT(RTC_CNTL_INT_RAW_REG, RTC_CNTL_ULP_CP_INT_RAW);
TEST_ESP_OK(ulp_run(&ulp_test_jumps - RTC_SLOW_MEM));
usleep(10000);
TEST_ASSERT_NOT_EQUAL(0, REG_GET_BIT(RTC_CNTL_INT_RAW_REG, RTC_CNTL_ULP_CP_INT_RAW));
TEST_ASSERT_EQUAL(0, ulp_jumps_fail & UINT16_MAX);
TEST_ASSERT_EQUAL(1, ulp_jumps_pass & UINT16_MAX);
}

View File

@@ -0,0 +1,101 @@
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/soc_ulp.h"
.bss
.global jumps_pass
jumps_pass:
.long 0
.global jumps_fail
jumps_fail:
.long 0
.text
.global test_jumps
test_jumps:
/* tests for LT (less than) condition */
stage_rst /* cnt = 0 */
jumps test_fail, 0, LT /* 0 < 0: false, should not jump */
jumps 1f, 1, LT /* 0 < 1: true, should jump */
jump test_fail
1:
stage_inc 2 /* cnt = 2 */
jumps 1f, 3, LT /* 2 < 1: true */
jump test_fail
1:
jumps test_fail, 1, LT /* 2 < 1: false */
jumps test_fail, 2, LT /* 2 < 2: false */
/* tests for LE (less or equal) condition */
stage_rst /* cnt = 0 */
jumps 1f, 0, LE /* 0 <= 0: true */
jump test_fail
1:
jumps 1f, 1, LE /* 0 <= 1: true */
jump test_fail
1:
stage_inc 2 /* cnt = 2 */
jumps test_fail, 1, LE /* 2 <= 1: false */
/* tests for EQ (equal) condition */
stage_rst /* cnt = 0 */
jumps 1f, 0, EQ /* 0 = 0: true */
jump test_fail
1:
jumps test_fail, 1, EQ /* 0 = 1: false */
stage_inc 1 /* cnt = 1 */
jumps test_fail, 0, EQ /* 1 = 0: false */
jumps test_fail, 2, EQ /* 1 = 2: false */
jumps 1f, 1, EQ /* 1 = 1: true */
1:
/* tests for GE (greater or equal) condition */
stage_rst /* cnt = 0 */
jumps 1f, 0, GE /* 0 >= 0: true */
jump test_fail
1:
jumps test_fail, 1, GE /* 0 >= 1: false */
stage_inc 1 /* cnt = 1 */
jumps 1f, 0, GE /* 1 >= 0: true */
jump test_fail
1:
jumps 1f, 1, GE /* 1 >= 1: true */
jump test_fail
1:
jumps test_fail, 2, GE /* 1 >= 2: false */
/* tests for GT (greater than) condition */
stage_rst /* cnt = 0 */
jumps test_fail, 0, GT /* 0 > 0: false */
jumps test_fail, 1, GE /* 0 > 1: false */
stage_inc 1 /* cnt = 1 */
jumps 1f, 0, GT /* 1 > 0: true */
jump test_fail
1:
jumps test_fail, 1, GT /* 1 > 1: false */
jumps test_fail, 2, GT /* 1 > 2: false */
jump test_pass
test_fail:
move r0, jumps_fail
move r1, 1
st r1, r0, 0
jump done
test_pass:
move r0, jumps_pass
move r1, 1
st r1, r0, 0
jump done
.global done
done:
wake
halt

View File

@@ -1,6 +1,14 @@
# Makefile for Sphinx documentation
#
# ************ IMPORTANT *****************
#
# ReadTheDocs DOES NOT USE THIS MAKEFILE,
# so any behaviour additions must be
# done via Sphinx Config not here
#
# ****************************************
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
@@ -9,7 +17,7 @@ BUILDDIR = _build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don\'t have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
@@ -19,10 +27,10 @@ ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) -w
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext dependencies version-specific-includes
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo "Please use \`make <target>\' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@@ -44,7 +52,7 @@ help:
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " doctest to run all doctests embedded in the documentation (if enabled) "
clean:
rm -rf $(BUILDDIR)/*

BIN
docs/_static/choose_version.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -15,8 +15,8 @@ Installing the toolchain
ULP coprocessor code is written in assembly and compiled using the `binutils-esp32ulp toolchain`_.
1. Download the toolchain using the links listed on this page:
https://github.com/espressif/binutils-esp32ulp/wiki#downloads
1. Download pre-built binaries of the latest toolchain release from:
https://github.com/espressif/binutils-esp32ulp/releases.
2. Extract the toolchain into a directory, and add the path to the ``bin/`` directory of the toolchain to the ``PATH`` environment variable.
@@ -134,7 +134,7 @@ Each ULP program is embedded into the ESP-IDF application as a binary blob. Appl
Once the program is loaded into RTC memory, application can start it, passing the address of the entry point to ``ulp_run`` function::
ESP_ERROR_CHECK( ulp_run((&ulp_entry - RTC_SLOW_MEM) / sizeof(uint32_t)) );
ESP_ERROR_CHECK( ulp_run(&ulp_entry - RTC_SLOW_MEM) );
.. doxygenfunction:: ulp_run

1830
docs/api-guides/ulp_instruction_set.rst Executable file → Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -32,6 +32,15 @@ os.system("python gen-dxd.py")
# Generate 'kconfig.inc' file from components' Kconfig files
os.system("python gen-kconfig-doc.py > _build/inc/kconfig.inc")
# Generate version-related includes
#
# (Note: this is in a function as it needs to access configuration to get the language)
def generate_version_specific_includes(app):
print("Generating version-specific includes...")
if os.system('python gen-version-specific-includes.py en _build/inc'):
raise RuntimeError('gen-version-specific-includes.py failed')
# http://stackoverflow.com/questions/12772927/specifying-an-online-image-in-sphinx-restructuredtext-format
#
suppress_warnings = ['image.nonlocal_uri']
@@ -314,3 +323,9 @@ if not on_rtd: # only import and set the theme if we're building docs locally
# otherwise, readthedocs.org uses their theme by default, so no need to specify it
# Override RTD CSS theme to introduce the theme corrections
# https://github.com/rtfd/sphinx_rtd_theme/pull/432
def setup(app):
app.add_stylesheet('theme_overrides.css')
generate_version_specific_includes(app)

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