forked from espressif/esp-idf
Compare commits
128 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb56d86fde | ||
|
|
db2223818b | ||
|
|
099ae5a1d9 | ||
|
|
9b4e911359 | ||
|
|
00fec53d76 | ||
|
|
ba5f0585af | ||
|
|
bcaac485d3 | ||
|
|
5ce10cb58c | ||
|
|
cba7efc9d2 | ||
|
|
364c0c4ace | ||
|
|
be02f6b423 | ||
|
|
4522476e72 | ||
|
|
6313ea0088 | ||
|
|
735f02c4b7 | ||
|
|
d6df10edaf | ||
|
|
d02d2d5170 | ||
|
|
80c013ee5a | ||
|
|
f2347e5729 | ||
|
|
8cfb0b207a | ||
|
|
6d253b4394 | ||
|
|
50dc31103f | ||
|
|
3af5384a24 | ||
|
|
283c47cbba | ||
|
|
4ae01aed27 | ||
|
|
a5a692ef8c | ||
|
|
3c532e4532 | ||
|
|
2e8d7fa36d | ||
|
|
674cf7520e | ||
|
|
c990ca4e20 | ||
|
|
5b061a0530 | ||
|
|
43d2f940b2 | ||
|
|
a5533a0b5d | ||
|
|
5f56d65405 | ||
|
|
fcf9c3d882 | ||
|
|
a7ad8bc873 | ||
|
|
438c9bcb35 | ||
|
|
328e689cf1 | ||
|
|
13732c5753 | ||
|
|
2544d737c5 | ||
|
|
8bd10b4808 | ||
|
|
a975ba6cef | ||
|
|
9189e1006d | ||
|
|
bc8a84e9e4 | ||
|
|
efe499113c | ||
|
|
7331ee2af2 | ||
|
|
f323fe5fee | ||
|
|
291c4a4fd3 | ||
|
|
9b1bd0a09f | ||
|
|
0ba566e0c6 | ||
|
|
405b1986c2 | ||
|
|
7d2baa3c3d | ||
|
|
530dedbc2d | ||
|
|
7c42b55e45 | ||
|
|
f4022111c8 | ||
|
|
53dcd1202d | ||
|
|
ef2c0e8b3e | ||
|
|
7515dc97b6 | ||
|
|
a9c1820385 | ||
|
|
8fdf200932 | ||
|
|
4cde212817 | ||
|
|
6751373411 | ||
|
|
27fd353752 | ||
|
|
97603b1d59 | ||
|
|
32fd3a3215 | ||
|
|
d1c6eb9574 | ||
|
|
5ee2d3b90d | ||
|
|
8618b452f7 | ||
|
|
39fb5d7150 | ||
|
|
5dafcf9363 | ||
|
|
3f72a12d97 | ||
|
|
af4f2ace84 | ||
|
|
e8ad0415cc | ||
|
|
ac253274a0 | ||
|
|
972107fbc9 | ||
|
|
5e9267f846 | ||
|
|
cfed7c84ce | ||
|
|
3870836a90 | ||
|
|
19f319a55d | ||
|
|
0806617971 | ||
|
|
4f346169ff | ||
|
|
00b895680e | ||
|
|
997d291d85 | ||
|
|
5f2660e1f5 | ||
|
|
451e4cf3b0 | ||
|
|
132b439359 | ||
|
|
04ce9050b6 | ||
|
|
27f8ee6b97 | ||
|
|
1c001ecd7a | ||
|
|
a961984f73 | ||
|
|
2d53799372 | ||
|
|
7275490322 | ||
|
|
f6a7cda7b6 | ||
|
|
d88b74064d | ||
|
|
b9f6b579f1 | ||
|
|
72ad5a142b | ||
|
|
d07f9dfbb2 | ||
|
|
33250ea678 | ||
|
|
300657162b | ||
|
|
7fcc76fa06 | ||
|
|
85fbaaf37a | ||
|
|
da97846483 | ||
|
|
7aa29a0dbb | ||
|
|
516d9f0eae | ||
|
|
bb5789b6ee | ||
|
|
f206bc51ff | ||
|
|
ecc82a3c27 | ||
|
|
6746be5a09 | ||
|
|
007d884a85 | ||
|
|
998416c54b | ||
|
|
873c515ee3 | ||
|
|
ee295c175b | ||
|
|
25ed0aa9bb | ||
|
|
4b4614ffb1 | ||
|
|
21adda8777 | ||
|
|
8ff0f4a616 | ||
|
|
08946da2db | ||
|
|
90b8a42349 | ||
|
|
3c92cd607b | ||
|
|
4f3008bfd8 | ||
|
|
dd1fa7c502 | ||
|
|
50556b8acb | ||
|
|
9da0541020 | ||
|
|
ab74be7abe | ||
|
|
b5c45a4d46 | ||
|
|
225e98dcee | ||
|
|
d66b227e07 | ||
|
|
ce67428c56 | ||
|
|
39f97bb4e8 |
@@ -34,6 +34,7 @@ variables:
|
||||
python $APPLY_BOT_FILTER_SCRIPT || exit 0
|
||||
|
||||
before_script:
|
||||
- source tools/ci/setup_python.sh
|
||||
# apply bot filter in before script
|
||||
- *apply_bot_filter
|
||||
# add gitlab ssh key
|
||||
@@ -54,6 +55,7 @@ before_script:
|
||||
|
||||
.do_nothing_before:
|
||||
before_script: &do_nothing_before
|
||||
- source tools/ci/setup_python.sh
|
||||
# apply bot filter in before script
|
||||
- *apply_bot_filter
|
||||
- echo "Not setting up GitLab key, not fetching submodules"
|
||||
@@ -61,6 +63,7 @@ before_script:
|
||||
|
||||
.add_gitlab_key_before:
|
||||
before_script: &add_gitlab_key_before
|
||||
- source tools/ci/setup_python.sh
|
||||
# apply bot filter in before script
|
||||
- *apply_bot_filter
|
||||
- echo "Not fetching submodules"
|
||||
@@ -270,7 +273,7 @@ test_build_system:
|
||||
- cd test_build_system
|
||||
- ${IDF_PATH}/tools/ci/test_build_system.sh
|
||||
|
||||
push_master_to_github:
|
||||
push_to_github:
|
||||
stage: deploy
|
||||
image: $CI_DOCKER_REGISTRY/esp32-ci-env
|
||||
tags:
|
||||
@@ -281,8 +284,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
|
||||
@@ -293,12 +294,7 @@ 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: host_test
|
||||
|
||||
31
README.md
31
README.md
@@ -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:
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ SECTIONS
|
||||
.iram1.text :
|
||||
{
|
||||
. = ALIGN (16);
|
||||
_loader_text_start = ABSOLUTE(.);
|
||||
*(.entry.text)
|
||||
*(.init.literal)
|
||||
*(.init)
|
||||
@@ -126,6 +127,7 @@ SECTIONS
|
||||
*(.fini)
|
||||
*(.gnu.version)
|
||||
_text_end = ABSOLUTE(.);
|
||||
_loader_text_end = ABSOLUTE(.);
|
||||
_etext = .;
|
||||
} > iram_seg
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
34
components/bootloader_support/include/bootloader_util.h
Normal file
34
components/bootloader_support/include/bootloader_util.h
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* @brief Check if half-open intervals overlap
|
||||
*
|
||||
* @param start1 interval 1 start
|
||||
* @param end1 interval 1 end
|
||||
* @param start2 interval 2 start
|
||||
* @param end2 interval 2 end
|
||||
* @return true iff [start1; end1) overlaps [start2; end2)
|
||||
*/
|
||||
static inline bool bootloader_util_regions_overlap(
|
||||
const intptr_t start1, const intptr_t end1,
|
||||
const intptr_t start2, const intptr_t end2)
|
||||
{
|
||||
return (end1 > start2 && end2 > start1) ||
|
||||
!(end1 <= start2 || end2 <= start1);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -23,10 +23,11 @@
|
||||
#include <bootloader_flash.h>
|
||||
#include <bootloader_random.h>
|
||||
#include <bootloader_sha.h>
|
||||
#include "bootloader_util.h"
|
||||
|
||||
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
|
||||
@@ -42,6 +43,10 @@ static const char *TAG = "esp_image";
|
||||
(Means loaded code isn't executable until after the secure boot check.)
|
||||
*/
|
||||
static uint32_t ram_obfs_value[2];
|
||||
|
||||
/* Range of IRAM used by the loader, defined in ld script */
|
||||
extern int _loader_text_start;
|
||||
extern int _loader_text_end;
|
||||
#endif
|
||||
|
||||
/* Return true if load_addr is an address the bootloader should load into */
|
||||
@@ -286,18 +291,41 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme
|
||||
(do_load)?"load":(is_mapping)?"map":"");
|
||||
}
|
||||
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
/* Before loading segment, check it doesn't clobber bootloader RAM. */
|
||||
if (do_load) {
|
||||
/* Before loading segment, check it doesn't clobber bootloader RAM... */
|
||||
uint32_t end_addr = load_addr + data_len;
|
||||
if (end_addr < 0x40000000) {
|
||||
const intptr_t load_end = load_addr + data_len;
|
||||
if (load_end <= (intptr_t) SOC_DIRAM_DRAM_HIGH) {
|
||||
/* Writing to DRAM */
|
||||
intptr_t sp = (intptr_t)get_sp();
|
||||
if (end_addr > sp - STACK_LOAD_HEADROOM) {
|
||||
ESP_LOGE(TAG, "Segment %d end address 0x%08x too high (bootloader stack 0x%08x liimit 0x%08x)",
|
||||
index, end_addr, sp, sp - STACK_LOAD_HEADROOM);
|
||||
if (load_end > sp - STACK_LOAD_HEADROOM) {
|
||||
/* Bootloader .data/.rodata/.bss is above the stack, so this
|
||||
* also checks that we aren't overwriting these segments.
|
||||
*
|
||||
* TODO: This assumes specific arrangement of sections we have
|
||||
* in the ESP32. Rewrite this in a generic way to support other
|
||||
* layouts.
|
||||
*/
|
||||
ESP_LOGE(TAG, "Segment %d end address 0x%08x too high (bootloader stack 0x%08x limit 0x%08x)",
|
||||
index, load_end, sp, sp - STACK_LOAD_HEADROOM);
|
||||
return ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
} else {
|
||||
/* Writing to IRAM */
|
||||
const intptr_t loader_iram_start = (intptr_t) &_loader_text_start;
|
||||
const intptr_t loader_iram_end = (intptr_t) &_loader_text_end;
|
||||
|
||||
if (bootloader_util_regions_overlap(loader_iram_start, loader_iram_end,
|
||||
load_addr, load_end)) {
|
||||
ESP_LOGE(TAG, "Segment %d (0x%08x-0x%08x) overlaps bootloader IRAM (0x%08x-0x%08x)",
|
||||
index, load_addr, load_end, loader_iram_start, loader_iram_end);
|
||||
return ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // BOOTLOADER_BUILD
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
uint32_t free_page_count = spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA);
|
||||
ESP_LOGD(TAG, "free data page_count 0x%08x",free_page_count);
|
||||
@@ -441,19 +469,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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "unity.h"
|
||||
|
||||
#include "bootloader_util.h"
|
||||
#include "esp_partition.h"
|
||||
#include "esp_ota_ops.h"
|
||||
#include "esp_image_format.h"
|
||||
@@ -47,3 +48,21 @@ TEST_CASE("Verify unit test app image", "[bootloader_support]")
|
||||
TEST_ASSERT_TRUE(data.image_len <= running->size);
|
||||
}
|
||||
|
||||
TEST_CASE("Test regions_overlap", "[bootloader_support]")
|
||||
{
|
||||
TEST_ASSERT( bootloader_util_regions_overlap(1, 2, 1, 2) );
|
||||
|
||||
TEST_ASSERT( bootloader_util_regions_overlap(1, 2, 0, 2) );
|
||||
TEST_ASSERT( bootloader_util_regions_overlap(1, 2, 1, 3) );
|
||||
TEST_ASSERT( bootloader_util_regions_overlap(1, 2, 0, 3) );
|
||||
|
||||
TEST_ASSERT( bootloader_util_regions_overlap(0, 2, 1, 2) );
|
||||
TEST_ASSERT( bootloader_util_regions_overlap(1, 3, 1, 2) );
|
||||
TEST_ASSERT( bootloader_util_regions_overlap(0, 3, 1, 2) );
|
||||
|
||||
TEST_ASSERT( !bootloader_util_regions_overlap(2, 3, 1, 2) );
|
||||
TEST_ASSERT( !bootloader_util_regions_overlap(1, 2, 2, 3) );
|
||||
|
||||
TEST_ASSERT( !bootloader_util_regions_overlap(3, 4, 1, 2) );
|
||||
TEST_ASSERT( !bootloader_util_regions_overlap(1, 2, 3, 4) );
|
||||
}
|
||||
|
||||
@@ -166,8 +166,8 @@ config BLE_SCAN_DUPLICATE
|
||||
config DUPLICATE_SCAN_CACHE_SIZE
|
||||
int "Maximum number of devices in scan duplicate filter"
|
||||
depends on BLE_SCAN_DUPLICATE
|
||||
range 10 200
|
||||
default 20
|
||||
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.
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1404,7 +1404,8 @@ 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;
|
||||
@@ -2570,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;
|
||||
@@ -2582,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) {
|
||||
@@ -2811,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;
|
||||
@@ -2829,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);
|
||||
@@ -3053,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
|
||||
@@ -3077,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 */
|
||||
@@ -3105,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;
|
||||
}
|
||||
|
||||
@@ -3149,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
/*******************************************************************************
|
||||
**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -162,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;
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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__,
|
||||
|
||||
@@ -57,9 +57,9 @@
|
||||
/* 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);
|
||||
@@ -748,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);
|
||||
|
||||
@@ -806,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);
|
||||
|
||||
@@ -131,7 +131,7 @@ typedef enum {
|
||||
* ESP_BLE_PWR_TYPE_SCAN : for scan.
|
||||
* ESP_BLE_PWR_TYPE_DEFAULT : if each connection's TX power is not set, it will use this default value.
|
||||
* if neither in scan mode nor in adv mode, it will use this default value.
|
||||
* If none of power type is set, system will use ESP_PWR_LVL_P1 as default for ADV/SCAN/CONN0-9.
|
||||
* If none of power type is set, system will use ESP_PWR_LVL_P3 as default for ADV/SCAN/CONN0-9.
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_BLE_PWR_TYPE_CONN_HDL0 = 0, /*!< For connection handle 0 */
|
||||
@@ -153,14 +153,22 @@ typedef enum {
|
||||
* @brief Bluetooth TX power level(index), it's just a index corresponding to power(dbm).
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_PWR_LVL_N14 = 0, /*!< Corresponding to -14dbm */
|
||||
ESP_PWR_LVL_N11 = 1, /*!< Corresponding to -11dbm */
|
||||
ESP_PWR_LVL_N8 = 2, /*!< Corresponding to -8dbm */
|
||||
ESP_PWR_LVL_N5 = 3, /*!< Corresponding to -5dbm */
|
||||
ESP_PWR_LVL_N2 = 4, /*!< Corresponding to -2dbm */
|
||||
ESP_PWR_LVL_P1 = 5, /*!< Corresponding to 1dbm */
|
||||
ESP_PWR_LVL_P4 = 6, /*!< Corresponding to 4dbm */
|
||||
ESP_PWR_LVL_P7 = 7, /*!< Corresponding to 7dbm */
|
||||
ESP_PWR_LVL_N12 = 0, /*!< Corresponding to -12dbm */
|
||||
ESP_PWR_LVL_N9 = 1, /*!< Corresponding to -9dbm */
|
||||
ESP_PWR_LVL_N6 = 2, /*!< Corresponding to -6dbm */
|
||||
ESP_PWR_LVL_N3 = 3, /*!< Corresponding to -3dbm */
|
||||
ESP_PWR_LVL_N0 = 4, /*!< Corresponding to 0dbm */
|
||||
ESP_PWR_LVL_P3 = 5, /*!< Corresponding to +3dbm */
|
||||
ESP_PWR_LVL_P6 = 6, /*!< Corresponding to +6dbm */
|
||||
ESP_PWR_LVL_P9 = 7, /*!< Corresponding to +9dbm */
|
||||
ESP_PWR_LVL_N14 = ESP_PWR_LVL_N12, /*!< Backward compatibility! Setting to -14dbm will actually result to -12dbm */
|
||||
ESP_PWR_LVL_N11 = ESP_PWR_LVL_N9, /*!< Backward compatibility! Setting to -11dbm will actually result to -9dbm */
|
||||
ESP_PWR_LVL_N8 = ESP_PWR_LVL_N6, /*!< Backward compatibility! Setting to -8dbm will actually result to -6dbm */
|
||||
ESP_PWR_LVL_N5 = ESP_PWR_LVL_N3, /*!< Backward compatibility! Setting to -5dbm will actually result to -3dbm */
|
||||
ESP_PWR_LVL_N2 = ESP_PWR_LVL_N0, /*!< Backward compatibility! Setting to -2dbm will actually result to 0dbm */
|
||||
ESP_PWR_LVL_P1 = ESP_PWR_LVL_P3, /*!< Backward compatibility! Setting to +1dbm will actually result to +3dbm */
|
||||
ESP_PWR_LVL_P4 = ESP_PWR_LVL_P6, /*!< Backward compatibility! Setting to +4dbm will actually result to +6dbm */
|
||||
ESP_PWR_LVL_P7 = ESP_PWR_LVL_P9, /*!< Backward compatibility! Setting to +7dbm will actually result to +9dbm */
|
||||
} esp_power_level_t;
|
||||
|
||||
/**
|
||||
@@ -180,7 +188,6 @@ esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_
|
||||
*/
|
||||
esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initialize BT controller to allocate task and other resource.
|
||||
* @param cfg: Initial configuration of BT controller.
|
||||
|
||||
Submodule components/bt/lib updated: 959eeeb517...979dd2c742
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
@@ -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, ð_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;
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "esp_err.h"
|
||||
#include "esp_wifi_types.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_wifi.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -161,6 +162,15 @@ void *wifi_realloc( void *ptr, size_t size );
|
||||
*/
|
||||
void *wifi_calloc( size_t n, size_t size );
|
||||
|
||||
/**
|
||||
* @brief Update WiFi MAC time
|
||||
*
|
||||
* @param uint32_t time_delta : time duration since the WiFi/BT common clock is disabled
|
||||
*
|
||||
* @return Always returns ESP_OK
|
||||
*/
|
||||
esp_err_t esp_wifi_internal_update_mac_time( uint32_t time_delta );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -224,6 +224,7 @@ PROVIDE ( lld_evt_env = 0x3ffb9704 );
|
||||
PROVIDE ( lld_evt_elt_wait_get = 0x400468e4 );
|
||||
PROVIDE ( lld_evt_get_next_free_slot = 0x4004692c );
|
||||
PROVIDE ( lld_pdu_adv_pk_desc_tab = 0x3ff98c70 );
|
||||
PROVIDE ( lld_pdu_tx_flush_list = 0x4004a760 );
|
||||
PROVIDE ( lld_pdu_llcp_pk_desc_tab = 0x3ff98b68 );
|
||||
PROVIDE ( lld_pdu_pack = 0x4004ab14 );
|
||||
PROVIDE ( LLM_AA_CT1 = 0x3ff98d8a );
|
||||
|
||||
Submodule components/esp32/lib updated: 798ce93fbf...a0181fa817
@@ -36,6 +36,7 @@
|
||||
#include "phy_init_data.h"
|
||||
#include "esp_coexist.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "esp_wifi_internal.h"
|
||||
|
||||
static const char* TAG = "phy_init";
|
||||
|
||||
@@ -44,6 +45,24 @@ static int s_phy_rf_init_count = 0;
|
||||
|
||||
static _lock_t s_phy_rf_init_lock;
|
||||
|
||||
static inline void phy_update_wifi_mac_time(bool en_clock_stopped)
|
||||
{
|
||||
static uint32_t s_common_clock_disable_time = 0;
|
||||
|
||||
if (en_clock_stopped) {
|
||||
s_common_clock_disable_time = esp_timer_get_time();
|
||||
} else {
|
||||
if (s_common_clock_disable_time) {
|
||||
uint64_t now = esp_timer_get_time();
|
||||
uint32_t diff = now - s_common_clock_disable_time;
|
||||
|
||||
esp_wifi_internal_update_mac_time(diff);
|
||||
s_common_clock_disable_time = 0;
|
||||
ESP_LOGD(TAG, "wifi mac time delta: %u", diff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t esp_phy_rf_init(const esp_phy_init_data_t* init_data,
|
||||
esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data)
|
||||
{
|
||||
@@ -51,6 +70,8 @@ esp_err_t esp_phy_rf_init(const esp_phy_init_data_t* init_data,
|
||||
|
||||
_lock_acquire(&s_phy_rf_init_lock);
|
||||
if (s_phy_rf_init_count == 0) {
|
||||
// Update WiFi MAC time before WiFi/BT common clock is enabled
|
||||
phy_update_wifi_mac_time( false );
|
||||
// Enable WiFi/BT common peripheral clock
|
||||
periph_module_enable(PERIPH_WIFI_BT_COMMON_MODULE);
|
||||
ESP_LOGV(TAG, "register_chipv7_phy, init_data=%p, cal_data=%p, mode=%d",
|
||||
@@ -76,6 +97,8 @@ esp_err_t esp_phy_rf_deinit(void)
|
||||
if (s_phy_rf_init_count == 1) {
|
||||
// Disable PHY and RF.
|
||||
phy_close_rf();
|
||||
// Update WiFi MAC time before disalbe WiFi/BT common peripheral clock
|
||||
phy_update_wifi_mac_time(true);
|
||||
// Disable WiFi/BT common peripheral clock. Do not disable clock for hardware RNG
|
||||
periph_module_disable(PERIPH_WIFI_BT_COMMON_MODULE);
|
||||
} else {
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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:
|
||||
|
||||
Submodule components/esptool_py/esptool updated: 4dab24e1b2...59b8dd8bfe
@@ -107,6 +107,23 @@ config LWIP_ETHARP_TRUST_IP_MAC
|
||||
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
|
||||
|
||||
@@ -945,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 {
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)))
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
/**
|
||||
|
||||
@@ -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++;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
25
components/ulp/test/test_ulp_as.c
Normal file
25
components/ulp/test/test_ulp_as.c
Normal 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);
|
||||
}
|
||||
101
components/ulp/test/ulp/test_jumps.S
Normal file
101
components/ulp/test/ulp/test_jumps.S
Normal 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
|
||||
@@ -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
BIN
docs/_static/choose_version.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
@@ -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
1830
docs/api-guides/ulp_instruction_set.rst
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
15
docs/conf.py
15
docs/conf.py
@@ -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)
|
||||
|
||||
|
||||
140
docs/gen-version-specific-includes.py
Executable file
140
docs/gen-version-specific-includes.py
Executable file
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Python script to generate ReSTructured Text .inc snippets
|
||||
# with version-based content for this IDF version
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
|
||||
TEMPLATES = {
|
||||
"en" : {
|
||||
"git-clone" : {
|
||||
"template" : """
|
||||
To obtain a local copy: open terminal, navigate to the directory you want to put ESP-IDF, and clone the repository using ``git clone`` command::
|
||||
|
||||
cd ~/esp
|
||||
git clone %(clone_args)s--recursive https://github.com/espressif/esp-idf.git
|
||||
|
||||
ESP-IDF will be downloaded into ``~/esp/esp-idf``.
|
||||
|
||||
.. note::
|
||||
|
||||
%(extra_note)s
|
||||
|
||||
.. note::
|
||||
|
||||
%(zipfile_note)s
|
||||
"""
|
||||
,"master" : 'This command will clone the master branch, which has the latest development ("bleeding edge") version of ESP-IDF. It is fully functional and updated on weekly basis with the most recent features and bugfixes.'
|
||||
,"branch" : 'The ``git clone`` option ``-b %s`` tells git to clone the %s in the ESP-IDF repository corresponding to this version of the documentation.'
|
||||
,"zipfile" : {
|
||||
"stable" : 'As a fallback, it is also possible to download a zip file of this stable release from the `Releases page`_. Do not download the "Source code" zip file(s) generated automatically by GitHub, they do not work with ESP-IDF.'
|
||||
,"unstable" : 'GitHub\'s "Download zip file" feature does not work with ESP-IDF, a ``git clone`` is required. As a fallback, `Stable version`_ can be installed without Git.'
|
||||
}, # zipfile
|
||||
}, # git-clone
|
||||
"version-note" : {
|
||||
"master" : """
|
||||
.. note::
|
||||
This is documentation for the master branch (latest version) of ESP-IDF. This version is under continual development. `Stable version`_ documentation is available, as well as other :doc:`/versions`.
|
||||
"""
|
||||
,"stable" : """
|
||||
.. note::
|
||||
This is documentation for stable version %s of ESP-IDF. Other :doc:`/versions` are also available.
|
||||
"""
|
||||
,"branch" : """
|
||||
.. note::
|
||||
This is documentation for %s ``%s`` of ESP-IDF. Other :doc:`/versions` are also available.
|
||||
"""
|
||||
}, # version-note
|
||||
}, # en
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 3:
|
||||
print("Usage: gen-git-clone.py <language> <output file path>")
|
||||
sys.exit(1)
|
||||
|
||||
language = sys.argv[1]
|
||||
out_dir = sys.argv[2]
|
||||
if not os.path.exists(out_dir):
|
||||
print("Creating directory %s" % out_dir)
|
||||
os.mkdir(out_dir)
|
||||
|
||||
template = TEMPLATES[language]
|
||||
|
||||
version, ver_type, is_stable = get_version()
|
||||
|
||||
write_git_clone_inc(template["git-clone"], out_dir, version, ver_type, is_stable)
|
||||
write_version_note(template["version-note"], out_dir, version, ver_type, is_stable)
|
||||
print("Done")
|
||||
|
||||
|
||||
def write_git_clone_inc(template, out_dir, version, ver_type, is_stable):
|
||||
zipfile = template["zipfile"]
|
||||
if version == "master":
|
||||
args = {
|
||||
"clone_args" : "",
|
||||
"extra_note" : template["master"],
|
||||
"zipfile_note" : zipfile["unstable"]
|
||||
}
|
||||
else:
|
||||
args = {
|
||||
"clone_args" : "-b %s " % version,
|
||||
"extra_note" : template["branch"] % (version, ver_type),
|
||||
"zipfile_note" : zipfile["stable"] if is_stable else zipfile["unstable"]
|
||||
}
|
||||
out_file = os.path.join(out_dir, "git-clone.inc")
|
||||
with open(out_file, "w") as f:
|
||||
f.write(template["template"] % args)
|
||||
print("%s written" % out_file)
|
||||
|
||||
|
||||
def write_version_note(template, out_dir, version, ver_type, is_stable):
|
||||
if version == "master":
|
||||
content = template["master"]
|
||||
elif ver_type == "tag" and is_stable:
|
||||
content = template["stable"] % version
|
||||
else:
|
||||
content = template["branch"] % (ver_type, version)
|
||||
out_file = os.path.join(out_dir, "version-note.inc")
|
||||
with open(out_file, "w") as f:
|
||||
f.write(content)
|
||||
print("%s written" % out_file)
|
||||
|
||||
|
||||
def get_version():
|
||||
"""
|
||||
Returns a tuple of (name of branch/tag, type branch/tag, is_stable)
|
||||
"""
|
||||
# Trust what RTD says our version is, if it is set
|
||||
version = os.environ.get("READTHEDOCS_VERSION", None)
|
||||
if version == "latest":
|
||||
return ("master", "branch", False)
|
||||
|
||||
# Otherwise, use git to look for a tag
|
||||
try:
|
||||
tag = subprocess.check_output(["git", "describe", "--tags", "--exact-match"]).strip()
|
||||
is_stable = re.match(r"v[0-9\.]+$", tag) is not None
|
||||
return (tag, "tag", is_stable)
|
||||
except subprocess.CalledProcessError:
|
||||
pass
|
||||
|
||||
# No tag, look for a branch
|
||||
refs = subprocess.check_output(["git", "for-each-ref", "--points-at", "HEAD", "--format", "%(refname)"])
|
||||
print("refs:\n%s" % refs)
|
||||
refs = refs.split("\n")
|
||||
# Note: this looks for branches in 'origin' because GitLab CI doesn't check out a local branch
|
||||
branches = [ r.replace("refs/remotes/origin/","").strip() for r in refs if r.startswith("refs/remotes/origin/") ]
|
||||
if len(branches) == 0:
|
||||
# last resort, return the commit (may happen on Gitlab CI sometimes, unclear why)
|
||||
return (subprocess.check_output(["git", "rev-parse", "--short", "HEAD"]).strip(), "commit", False)
|
||||
if "master" in branches:
|
||||
return ("master", "branch", False)
|
||||
else:
|
||||
return (branches[0], "branch", False) # take whatever the first branch is
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -4,6 +4,7 @@ Get Started
|
||||
|
||||
This document is intended to help users set up the software environment for developement of applications using hardware based on the Espressif ESP32. Through a simple example we would like to illustrate how to use ESP-IDF (Espressif IoT Development Framework), including the menu based configuration, compiling the ESP-IDF and firmware download to ESP32 boards.
|
||||
|
||||
.. include:: /_build/inc/version-note.inc
|
||||
|
||||
Introduction
|
||||
============
|
||||
@@ -113,19 +114,18 @@ Get ESP-IDF
|
||||
|
||||
.. highlight:: bash
|
||||
|
||||
Besides the toolchain (that contains programs to compile and build the application), you also need ESP32 specific API / libraries. They are provided by Espressif in `ESP-IDF repository <https://github.com/espressif/esp-idf>`_. To get it, open terminal, navigate to the directory you want to put ESP-IDF, and clone it using ``git clone`` command::
|
||||
Besides the toolchain (that contains programs to compile and build the application), you also need ESP32 specific API / libraries. They are provided by Espressif in `ESP-IDF repository <https://github.com/espressif/esp-idf>`_.
|
||||
|
||||
cd ~/esp
|
||||
git clone --recursive https://github.com/espressif/esp-idf.git
|
||||
.. include:: /_build/inc/git-clone.inc
|
||||
|
||||
ESP-IDF will be downloaded into ``~/esp/esp-idf``.
|
||||
Consult :doc:`/versions` for information about which version of ESP-IDF to use in a given situation.
|
||||
|
||||
.. note::
|
||||
|
||||
Do not miss the ``--recursive`` option. If you have already cloned ESP-IDF without this option, run another command to get all the submodules::
|
||||
|
||||
cd ~/esp/esp-idf
|
||||
git submodule update --init
|
||||
git submodule update --init --recursive
|
||||
|
||||
|
||||
.. _get-started-setup-path:
|
||||
@@ -299,23 +299,9 @@ Updating ESP-IDF
|
||||
|
||||
After some time of using ESP-IDF, you may want to update it to take advantage of new features or bug fixes. The simplest way to do so is by deleting existing ``esp-idf`` folder and cloning it again, exactly as when doing initial installation described in sections :ref:`get-started-get-esp-idf`.
|
||||
|
||||
Another solution is to update only what has changed. This method is useful if you have slow connection to the GiHub. To do the update run the following commands::
|
||||
If downloading to a new path, remember to :doc:`add-idf_path-to-profile` so that the toolchain scripts know where to find the ESP-IDF in its release specific location.
|
||||
|
||||
cd ~/esp/esp-idf
|
||||
git pull
|
||||
git submodule update --init --recursive
|
||||
|
||||
The ``git pull`` command is fetching and merging changes from ESP-IDF repository on GitHub. Then ``git submodule update --init --recursive`` is updating existing submodules or getting a fresh copy of new ones. On GitHub the submodules are represented as links to other repositories and require this additional command to get them onto your PC.
|
||||
|
||||
If you would like to use specific release of ESP-IDF, e.g. `v2.1`, run::
|
||||
|
||||
cd ~/esp
|
||||
git clone https://github.com/espressif/esp-idf.git esp-idf-v2.1
|
||||
cd esp-idf-v2.1/
|
||||
git checkout v2.1
|
||||
git submodule update --init --recursive
|
||||
|
||||
After that remember to :doc:`add-idf_path-to-profile`, so the toolchain scripts know where to find the ESP-IDF in it's release specific location.
|
||||
Another solution is to update only what has changed. :ref:`The update procedure depends on the version of ESP-IDF you are using <updating>`.
|
||||
|
||||
|
||||
Related Documents
|
||||
@@ -330,3 +316,7 @@ Related Documents
|
||||
eclipse-setup
|
||||
idf-monitor
|
||||
toolchain-setup-scratch
|
||||
|
||||
.. _Stable version: https://docs.espressif.com/projects/esp-idf/en/stable/
|
||||
.. _Releases page: https://github.com/espressif/esp-idf/releases
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ This is the documentation for Espressif IoT Development Framework (`esp-idf <htt
|
||||
H/W Reference <hw-reference/index>
|
||||
API Guides <api-guides/index>
|
||||
Contribute <contribute/index>
|
||||
Versions <versions>
|
||||
Resources <resources>
|
||||
Copyrights <COPYRIGHT>
|
||||
About <about>
|
||||
|
||||
@@ -6,9 +6,9 @@ from repo_util import run_cmd_get_output
|
||||
def get_github_rev():
|
||||
path = run_cmd_get_output('git rev-parse --short HEAD')
|
||||
tag = run_cmd_get_output('git describe --exact-match')
|
||||
print 'Git commit ID: ', path
|
||||
print ('Git commit ID: ', path)
|
||||
if len(tag):
|
||||
print 'Git tag: ', tag
|
||||
print ('Git tag: ', tag)
|
||||
path = tag
|
||||
return path
|
||||
|
||||
|
||||
178
docs/versions.rst
Normal file
178
docs/versions.rst
Normal file
@@ -0,0 +1,178 @@
|
||||
ESP-IDF Versions
|
||||
================
|
||||
|
||||
The ESP-IDF GitHub repository is updated regularly, especially on the "master branch" where new development happens. There are also stable releases which are recommended for production use.
|
||||
|
||||
Releases
|
||||
--------
|
||||
|
||||
Documentation for the current stable version can always be found at this URL:
|
||||
|
||||
https://docs.espressif.com/projects/esp-idf/en/stable/
|
||||
|
||||
Documentation for the latest version ("master branch") can always be found at this URL:
|
||||
|
||||
https://docs.espressif.com/projects/esp-idf/en/latest/
|
||||
|
||||
The full history of releases can be found on the GitHub repository `Releases page`_. There you can find release notes, links to each version of the documentation, and instructions for obtaining each version.
|
||||
|
||||
Documentation for all releases can also be found in the HTML documentation by clicking the "versions" pop up in the bottom-left corner of the page. You can use this popup to switch between versions of the documentation.
|
||||
|
||||
.. image:: _static/choose_version.png
|
||||
|
||||
Which Version Should I Start With?
|
||||
----------------------------------
|
||||
|
||||
- For production purposes, use the `current stable version`_. Stable versions have been manually tested, and are updated with "bugfix releases" which fix bugs without changing other functionality (see `Versioning Scheme`_ for more details).
|
||||
|
||||
- For prototyping, experimentation or for developing new ESP-IDF features, use the `latest version (master branch in Git) <https://docs.espressif.com/projects/esp-idf/en/latest/>`_. The latest version in the master branch has all the latest features and has passed automated testing, but has not been completely manually tested ("bleeding edge").
|
||||
|
||||
- If a required feature is not yet available in a stable release, but you don't want to use the master branch, it is possible to check out a pre-release version or a release branch. It is recommended to start from a stable version and then follow the instructions for :ref:`updating-pre-release` or :ref:`updating-release-branch`.
|
||||
|
||||
See :ref:`updating` if you already have a local copy of ESP-IDF and wish to update it.
|
||||
|
||||
Versioning Scheme
|
||||
-----------------
|
||||
|
||||
ESP-IDF uses `Semantic Versioning <http://semver.org/>`_. This means:
|
||||
|
||||
- Major Releases like ``v3.0`` add new functionality and may change functionality. This includes removing deprecated functionality.
|
||||
|
||||
When updating to a new major release (for example, from ``v2.1`` to ``v3.0``), some of your project's code may need updating and functionality will need to be re-tested. The release notes on the `Releases page`_ include lists of Breaking Changes to refer to.
|
||||
- Minor Releases like ``v3.1`` add new functionality and fix bugs but will not change or remove documented functionality, or make incompatible changes to public APIs.
|
||||
|
||||
If updating to a new minor release (for example, from ``v3.0`` to ``v3.1``) then none of your project's code should need updating, but you should re-test your project. Pay particular attention to items mentioned in the release notes on the `Releases page`_.
|
||||
- Bugfix Releases like ``v3.0.1`` only fix bugs and do not add new functionality.
|
||||
|
||||
If updating to a new bugfix release (for example, from ``v3.0`` to ``v3.0.1``), you should not need to change any code in your project and should only need to re-test functionality relating directly to bugs listed in the release notes on the `Releases page`_.
|
||||
|
||||
Checking The Current Version
|
||||
----------------------------
|
||||
|
||||
The local ESP-IDF version can be checked using git::
|
||||
|
||||
cd $IDF_PATH
|
||||
git describe --tags --dirty
|
||||
|
||||
The version is also compiled into the firmware and can be accessed (as a string) via the macro ``IDF_VER``. The default ESP-IDF bootloader will print the version on boot (these versions in code will not always update, it only changes if that particular source file is recompiled).
|
||||
|
||||
Examples of ESP-IDF versions:
|
||||
|
||||
============================ ==================================================
|
||||
Version String Meaning
|
||||
============================ ==================================================
|
||||
``v3.2-dev-306-gbeb3611ca`` Master branch pre-release, in development for
|
||||
version 3.2. 306 commits after v3.2 development
|
||||
started. Commit identifier ``beb3611ca``.
|
||||
``v3.0.2`` Stable release, tagged ``v3.0.2``.
|
||||
``v3.1-beta1-75-g346d6b0ea`` Beta version in development (on a
|
||||
:ref:`release branch <updating-release-branch>`).
|
||||
75 commits after ``v3.1-beta1`` pre-release tag.
|
||||
Commit identifier ``346d6b0ea``.
|
||||
``v3.0.1-dirty`` Stable release, tagged ``v3.0.1``.
|
||||
There are modifications in the local ESP-IDF
|
||||
directory ("``dirty``").
|
||||
============================ ==================================================
|
||||
|
||||
|
||||
|
||||
Git Workflow
|
||||
------------
|
||||
|
||||
The development (Git) workflow of the Espressif ESP-IDF team is:
|
||||
|
||||
- New work is always added on the master branch (latest version) first. The ESP-IDF version on ``master`` is always tagged with ``-dev`` (for "in development"), for example ``v3.1-dev``.
|
||||
- Changes are first added to an internal Git repository for code review and testing, but are pushed to GitHub after automated testing passes.
|
||||
- When a new version (developed on ``master``) becomes feature complete and "beta" quality, a new branch is made for the release, for example ``release/v3.1``. A pre-release tag is also created, for example ``v3.1-beta1``. You can see a full `list of branches`_ and a `list of tags`_ on GitHub. Beta pre-releases have release notes which may include a significant number of Known Issues.
|
||||
- As testing of the beta version progresses, bug fixes will be added to both the ``master`` branch and the release branch. New features (for the next release) may start being added to ``master`` at the same time.
|
||||
- Once testing is nearly complete a new release candidate is tagged on the release branch, for example ``v3.1-rc1``. This is still a pre-release version.
|
||||
- If no more significant bugs are found or reported then the final Major or Minor Version is tagged, for example ``v3.1``. This version appears on the `Releases page`_.
|
||||
- As bugs are reported in released versions, the fixes will continue to be committed to the same release branch.
|
||||
- Regular bugfix releases are made from the same release branch. After manual testing is complete, a bugfix release is tagged (i.e. ``v3.1.1``) and appears on the `Releases page`_.
|
||||
|
||||
.. _updating:
|
||||
|
||||
Updating ESP-IDF
|
||||
----------------
|
||||
|
||||
Updating ESP-IDF depends on which version(s) you wish to follow:
|
||||
|
||||
- :ref:`updating-stable-releases` is recommended for production use.
|
||||
- :ref:`updating-master` is recommended for latest features, development use, and testing.
|
||||
- :ref:`updating-release-branch` is a compromise between these two.
|
||||
|
||||
.. note:: These guides assume you already have a local copy of ESP-IDF. To get one, follow the :doc:`Getting Started </get-started/index>` guide for any ESP-IDF version.
|
||||
|
||||
.. _`updating-stable-releases`:
|
||||
|
||||
Updating to Stable Release
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To update to new ESP-IDF releases (recommended for production use), this is the process to follow:
|
||||
|
||||
- Check the `Releases page`_ regularly for new releases.
|
||||
- When a bugfix release for a version you are using is released (for example if using ``v3.0.1`` and ``v3.0.2`` is available), check out the new bugfix version into the existing ESP-IDF directory::
|
||||
|
||||
cd $IDF_PATH
|
||||
git fetch
|
||||
git checkout vX.Y.Z
|
||||
git submodule update --init --recursive
|
||||
- When major or minor updates are released, check the Release Notes on the releases page and decide if you would like to update or to stay with your existing release. Updating is via the same Git commands shown above.
|
||||
|
||||
.. note:: If you installed the stable release via zip file rather than using git, it may not be possible to change versions this way. In this case, update by downloading a new zip file and replacing the entire ``IDF_PATH`` directory with its contents.
|
||||
|
||||
|
||||
.. _`updating-pre-release`:
|
||||
|
||||
Updating to a Pre-Release Version
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
It is also possible to ``git checkout`` a tag corresponding to a pre-release version or release candidate, the process is the same as :ref:`updating-stable-releases`.
|
||||
|
||||
Pre-release tags are not always found on the `Releases page`_. Consult the `list of tags`_ on GitHub for a full list. Caveats for using a pre-release are similar to :ref:`updating-release-branch`.
|
||||
|
||||
.. _`updating-master`:
|
||||
|
||||
Updating to Master Branch
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. note:: Using Master branch means living "on the bleeding edge" with the latest ESP-IDF code.
|
||||
|
||||
To use the latest version on the ESP-IDF master branch, this is the process to follow:
|
||||
|
||||
- Check out the master branch locally::
|
||||
|
||||
cd $IDF_PATH
|
||||
git checkout master
|
||||
git pull
|
||||
git submodule update --init --recursive
|
||||
- Periodically, re-run ``git pull`` to pull the latest version of master. Note that you may need to change your project or report bugs after updating master branch.
|
||||
- To switch from ``master`` to a release branch or stable version, run ``git checkout`` as shown in the other sections.
|
||||
|
||||
.. important:: It is strongly recommended to regularly run ``git pull`` and then ``git submodule update --init --recursive`` so a local copy of ``master`` does not get too old. Arbitrary old master branch revisions are effectively unsupportable "snapshots" that may have undocumented bugs. For a semi-stable version, try :ref:`updating-release-branch` instead.
|
||||
|
||||
.. _`updating-release-branch`:
|
||||
|
||||
Updating to a Release Branch
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In stability terms, using a release branch is part-way between using ``master`` branch and only using stable releases. A release branch is always beta quality or better, and receives bug fixes before they appear in each stable release.
|
||||
|
||||
You can find a `list of branches`_ on GitHub.
|
||||
|
||||
For example, to follow the branch for ESP-IDF v3.1, including any bugfixes for future releases like ``v3.1.1``, etc::
|
||||
|
||||
cd $IDF_PATH
|
||||
git fetch
|
||||
git checkout release/v3.1
|
||||
git pull
|
||||
git submodule --update --init --recursive
|
||||
|
||||
Each time you ``git pull`` this branch, ESP-IDF will be updated with fixes for this release.
|
||||
|
||||
.. note:: The is no dedicated documentation for release branches. It is recommended to use the documentation for the closest version to the branch which is currently checked out.
|
||||
|
||||
.. _`Releases page`: http://github.com/espressif/esp-idf/releases
|
||||
.. _`list of branches`: https://github.com/espressif/esp-idf/branches
|
||||
.. _`list of tags`: https://github.com/espressif/esp-idf/tags
|
||||
.. _`current stable version`: https://docs.espressif.com/projects/esp-idf/en/stable/
|
||||
@@ -324,6 +324,9 @@ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param
|
||||
(bd_addr[4] << 8) + bd_addr[5]);
|
||||
ESP_LOGI(GATTS_TABLE_TAG, "address type = %d", param->ble_security.auth_cmpl.addr_type);
|
||||
ESP_LOGI(GATTS_TABLE_TAG, "pair status = %s",param->ble_security.auth_cmpl.success ? "success" : "fail");
|
||||
if(!param->ble_security.auth_cmpl.success) {
|
||||
ESP_LOGI(GATTS_TABLE_TAG, "fail reason = 0x%x",param->ble_security.auth_cmpl.fail_reason);
|
||||
}
|
||||
show_bonded_devices();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -145,6 +145,7 @@ static void http2_task(void *args)
|
||||
}
|
||||
|
||||
sh2lib_free(&hd);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static esp_err_t event_handler(void *ctx, system_event_t *event)
|
||||
|
||||
@@ -80,7 +80,7 @@ static void init_ulp_program()
|
||||
REG_SET_FIELD(SENS_ULP_CP_SLEEP_CYC0_REG, SENS_SLEEP_CYCLES_S0, 3095);
|
||||
|
||||
/* Start the program */
|
||||
err = ulp_run((&ulp_entry - RTC_SLOW_MEM) / sizeof(uint32_t));
|
||||
err = ulp_run(&ulp_entry - RTC_SLOW_MEM);
|
||||
ESP_ERROR_CHECK(err);
|
||||
}
|
||||
|
||||
|
||||
@@ -87,6 +87,6 @@ static void start_ulp_program()
|
||||
ulp_sample_counter = 0;
|
||||
|
||||
/* Start the program */
|
||||
esp_err_t err = ulp_run((&ulp_entry - RTC_SLOW_MEM) / sizeof(uint32_t));
|
||||
esp_err_t err = ulp_run(&ulp_entry - RTC_SLOW_MEM);
|
||||
ESP_ERROR_CHECK(err);
|
||||
}
|
||||
|
||||
14
tools/ci/push_to_github.sh
Executable file
14
tools/ci/push_to_github.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
# gitlab-ci script to push current tested revision (tag or branch) to github
|
||||
|
||||
set -ex
|
||||
|
||||
if [ -n "${CI_COMMIT_TAG}" ]; then
|
||||
# for tags
|
||||
git push github "${CI_COMMIT_TAG}"
|
||||
else
|
||||
# for branches
|
||||
git push github "${CI_COMMIT_SHA}:refs/heads/${CI_COMMIT_REF_NAME}"
|
||||
fi
|
||||
|
||||
49
tools/ci/setup_python.sh
Normal file
49
tools/ci/setup_python.sh
Normal file
@@ -0,0 +1,49 @@
|
||||
#! /bin/bash
|
||||
|
||||
# Regexp for matching job names which are incompatible with Python 3
|
||||
py3_incomp='assign_test|UT|IT'
|
||||
|
||||
if [ -z ${PYTHON_VER+x} ] || [[ $CI_JOB_NAME =~ $py3_incomp ]]; then
|
||||
# Use this version of the Python interpreter if it was not defined before or
|
||||
# the given job is not compatible with Python 3
|
||||
PYTHON_VER=2.7.15
|
||||
fi
|
||||
|
||||
if [ -f /opt/pyenv/activate ];
|
||||
then
|
||||
source /opt/pyenv/activate
|
||||
pyenv global $PYTHON_VER || {
|
||||
echo 'Python' $PYTHON_VER 'is not installed.'
|
||||
INSTALLED_PY_VERS=$(pyenv versions --bare)
|
||||
|
||||
while [ ${#PYTHON_VER} -gt 0 ]
|
||||
do
|
||||
echo 'Tring to locate a match for' $PYTHON_VER
|
||||
|
||||
for ver in ${INSTALLED_PY_VERS[@]}
|
||||
do
|
||||
if [[ $ver == $PYTHON_VER* ]];
|
||||
then
|
||||
pyenv global $ver
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
|
||||
# Removing last character and trying to find some match.
|
||||
# For example, if 3.4.8 was selected but isn't installed then it will try to
|
||||
# find some other installed 3.4.X version, and then some 3.X.X version.
|
||||
PYTHON_VER=${PYTHON_VER: : -1}
|
||||
done
|
||||
}
|
||||
python --version || {
|
||||
echo 'No matching Python interpreter is found!'
|
||||
exit 1
|
||||
}
|
||||
elif command -v python -V 1>/dev/null 2>&1;
|
||||
then
|
||||
python --version
|
||||
echo 'No /opt/pyenv/activate exists and Python from path is used.'
|
||||
else
|
||||
echo 'No /opt/pyenv/activate exists and no Python interpreter is found!'
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user