Merge branch 'master' into feature/esp32s2beta_merge

This commit is contained in:
Angus Gratton
2019-10-15 14:59:27 +11:00
committed by Angus Gratton
122 changed files with 2683 additions and 1553 deletions

View File

@@ -1,5 +1,7 @@
# Espressif IoT Development Framework
* [中文版](./README_CN.md)
[![Documentation Status](https://readthedocs.com/projects/espressif-esp-idf/badge/?version=latest)](https://docs.espressif.com/projects/esp-idf/en/latest/?badge=latest)
ESP-IDF is the official development framework for the [ESP32](https://espressif.com/en/products/hardware/esp32/overview) chip.

112
README_CN.md Normal file
View File

@@ -0,0 +1,112 @@
# Espressif 物联网开发框架
* [English Version](./README.md)
[![Documentation Status](https://readthedocs.com/projects/espressif-esp-idf/badge/?version=latest)](https://docs.espressif.com/projects/esp-idf/zh_CN/latest/?badge=latest)
ESP-IDF 是由乐鑫官方推出的针对 [ESP32](https://espressif.com/en/products/hardware/esp32/overview) 系列芯片的开发框架。
# 使用 ESP-IDF 进行开发
## 搭建 ESP-IDF 开发环境
请参阅如下指南搭建 ESP-IDF 的开发环境:
* [ESP-IDF 稳定版本的入门指南](https://docs.espressif.com/projects/esp-idf/en/stable/get-started/)
* [ESP-IDF 开发版本master 分支)的入门指南](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/)
### 非 GitHub 分叉的 ESP-IDF 项目
ESP-IDF 中的子模块采用相对路径([详见 .gitmodules 文件](.gitmodules)),所以它们会指向 GitHub。
如果 ESP-IDF 被分叉到的仓库不在 GitHub 上,那么你需要在克隆结束后运行该[脚本](tools/set-submodules-to-github.sh)。它会为所有的子模块设置绝对路径,接着可以通过 `git submodule update --init --recursive` 完成子模块的更新。
如果 ESP-IDF 是从 GitHub 上克隆得到,则不需要此步骤。
## 寻找项目
除了入门指南中提到的 [esp-idf 模板项目](https://github.com/espressif/esp-idf-template)ESP-IDF 的 [examples](examples) 目录下还带有很多其它示例项目。
一旦找到了需要的项目,便可以进入该目录,执行配置和构建操作。
如果要基于示例工程开始你自己的项目,请将示例工程复制到 ESP-IDF 目录之外。
# 快速参考
详细的使用方法请参考上面入门指南的链接,这里仅仅列举一些 ESP-IDF 项目开发中常用的命令:
## 设置构建环境
(请参考入门指南中列出的详细步骤。)
* 在主机中安装入门指南中提到的构建所依赖的工具。
* 将 ESP-IDF 中的 `tools/` 目录加入 PATH 环境变量中。
* 运行 `python -m pip install -r requirements.txt` 安装 Python 依赖库。
## 配置项目
`idf.py menuconfig`
* 打开项目的文本配置菜单。
* 使用上下键浏览菜单。
* 使用回车键进入子菜单,退出键返回上一级菜单或者退出配置。
* 输入 `?` 查看帮助界面,按下回车键可以退出帮助界面。
* 使用空格键或者 `Y``N` 按键来启用和禁用带复选框“`[*]`”的配置项。
* 高亮某个配置项的同时按下 `?` 键可以显示该选项的帮助文档。
* 输入 `/` 可以搜索指定的配置项。
一旦配置完成,请按下退出键多次以退出配置界面,当提示是否保存新的的配置时,选择 “Yes”。
## 编译项目
`idf.py build`
编译应用程序,引导程序,并根据配置生成分区表。
## 烧写项目
当构建结束,终端会打印出一条命令行,告知如何使用 esptool.py 工具烧写项目到芯片中。但是你还可以运行下面这条命令来自动烧写:
`idf.py -p PORT flash`
将其中的 PORT 替换为系统中实际串口的名字(比如 Windows 下的 `COM3`Linux 下的 `/dev/ttyUSB0`,或者 MacOS 下的 `/dev/cu.usbserial-X`。如果省略 `-p` 选项,`idf.py flash` 会尝试使用第一个可用的串口进行烧写。
这会烧写整个项目(包括应用程序,引导程序和分区表)到芯片中,此外还可以使用 `idf.py menuconfig` 来调整串口烧写相关的配置。
你也不必先运行 `idf.py build`,再运行 `idf.py flash``idf.py flash` 会根据需要自动重新构建项目。
## 观察串口输入
`idf.py monitor` 会调用 [idf_monitor 工具](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/idf-monitor.html)来显示 ESP32 的串口输出。`idf_monitor` 还包含一系列的功能来解析程序崩溃后的输出结果并与设备进行交互。更多详细内容,请参阅[文档](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/idf-monitor.html).
输入 `Ctrl-]` 可退出监视器。
想要一次性执行构建,烧写和监视,可以运行如下命令:
`idf.py flash monitor`
## 仅编译并烧写应用程序
在第一次烧写过后,你可能只想构建并烧写你的应用程序,不包括引导程序和分区表:
* `idf.py app` - 仅构建应用程序。
* `idf.py app-flash` - 仅烧写应用程序。
`idf.py app-flash` 会自动判断是否有源文件发生了改变而后重新构建应用程序。
(在正常的开发中,即使引导程序和分区表没有发生变化,每次都重新烧写它们并不会带来什么危害。)
## 擦除 Flash
`idf.py flash` 并不会擦除 Flash 上所有的内容,但是有时候我们需要设备恢复到完全擦除的状态,尤其是分区表发生了变化或者 OTA 应用升级。要擦除整块 Flash 请运行 `idf.py erase_flash`
这条命令还可以和其余命令整合在一起,`idf.py -p PORT erase_flash flash` 会擦除一切然后重新烧写新的应用程序,引导程序和分区表。
# 其它参考资源
* 最新版的文档https://docs.espressif.com/projects/esp-idf/ ,该文档是由本仓库 [docs 目录](docs) 构建得到。
* 可以前往 [esp32.com 论坛](https://esp32.com/) 提问,挖掘社区资源。
* 如果你在使用中发现了错误或者需要新的功能,请先[查看 GitHub Issues](https://github.com/espressif/esp-idf/issues),确保该问题不会被重复提交。
* 如果你有兴趣为 ESP-IDF 作贡献,请先阅读[贡献指南](https://docs.espressif.com/projects/esp-idf/en/latest/contribute/index.html)。

View File

@@ -28,6 +28,11 @@ typedef enum {
GPIO_NOT_HOLD = 0 /*!< If the GPIO input is not low */
} esp_comm_gpio_hold_t;
typedef enum {
ESP_IMAGE_BOOTLOADER,
ESP_IMAGE_APPLICATION
} esp_image_type;
/**
* @brief Calculate crc for the OTA data select.
*
@@ -159,12 +164,13 @@ uint8_t bootloader_common_get_chip_revision(void);
/**
* @brief Check if the image (bootloader and application) has valid chip ID and revision
*
* @param img_hdr: image header
* @param[in] img_hdr: image header
* @param[in] type: image type, bootloader or application
* @return
* - ESP_OK: image and chip are matched well
* - ESP_FAIL: image doesn't match to the chip
*/
esp_err_t bootloader_common_check_chip_validity(const esp_image_header_t* img_hdr);
esp_err_t bootloader_common_check_chip_validity(const esp_image_header_t* img_hdr, esp_image_type type);
/**
* @brief Configure VDDSDIO, call this API to rise VDDSDIO to 1.9V when VDDSDIO regulator is enabled as 1.8V mode.

View File

@@ -280,20 +280,20 @@ void bootloader_common_vddsdio_configure(void)
}
esp_err_t bootloader_common_check_chip_validity(const esp_image_header_t* img_hdr)
esp_err_t bootloader_common_check_chip_validity(const esp_image_header_t* img_hdr, esp_image_type type)
{
esp_err_t err = ESP_OK;
esp_chip_id_t chip_id = CONFIG_IDF_FIRMWARE_CHIP_ID;
if (chip_id != img_hdr->chip_id) {
ESP_LOGE(TAG, "mismatch chip ID, expect %d, found %d", chip_id, img_hdr->chip_id);
ESP_LOGE(TAG, "mismatch chip ID, expected %d, found %d", chip_id, img_hdr->chip_id);
err = ESP_FAIL;
}
uint8_t revision = bootloader_common_get_chip_revision();
if (revision < img_hdr->min_chip_rev) {
ESP_LOGE(TAG, "can't run on lower chip revision, expect %d, found %d", revision, img_hdr->min_chip_rev);
ESP_LOGE(TAG, "can't run on lower chip revision, expected %d, found %d", revision, img_hdr->min_chip_rev);
err = ESP_FAIL;
} else if (revision != img_hdr->min_chip_rev) {
ESP_LOGI(TAG, "mismatch chip revision, expect %d, found %d", revision, img_hdr->min_chip_rev);
ESP_LOGI(TAG, "chip revision: %d, min. %s chip revision: %d", revision, type == ESP_IMAGE_BOOTLOADER ? "bootloader" : "application", img_hdr->min_chip_rev);
}
return err;
}

View File

@@ -172,7 +172,7 @@ static esp_err_t bootloader_main(void)
/* Check chip ID and minimum chip revision that supported by this image */
uint8_t revision = bootloader_common_get_chip_revision();
ESP_LOGI(TAG, "Chip Revision: %d", revision);
if (bootloader_common_check_chip_validity(&fhdr) != ESP_OK) {
if (bootloader_common_check_chip_validity(&fhdr, ESP_IMAGE_BOOTLOADER) != ESP_OK) {
return ESP_FAIL;
}

View File

@@ -310,7 +310,7 @@ static esp_err_t verify_image_header(uint32_t src_addr, const esp_image_header_t
}
err = ESP_ERR_IMAGE_INVALID;
}
if (bootloader_common_check_chip_validity(image) != ESP_OK) {
if (bootloader_common_check_chip_validity(image, ESP_IMAGE_APPLICATION) != ESP_OK) {
err = ESP_ERR_IMAGE_INVALID;
}
if (!silent) {

View File

@@ -129,6 +129,8 @@ size_t fixed_queue_capacity(fixed_queue_t *queue)
bool fixed_queue_enqueue(fixed_queue_t *queue, void *data, uint32_t timeout)
{
bool status=false; //Flag whether enqueued success
assert(queue != NULL);
assert(data != NULL);
@@ -137,13 +139,13 @@ bool fixed_queue_enqueue(fixed_queue_t *queue, void *data, uint32_t timeout)
}
osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT);
list_append(queue->list, data);
status = list_append(queue->list, data); //Check whether enqueued success
osi_mutex_unlock(&queue->lock);
osi_sem_give(&queue->dequeue_sem);
if(status == true )
osi_sem_give(&queue->dequeue_sem);
return true;
return status;
}
void *fixed_queue_dequeue(fixed_queue_t *queue, uint32_t timeout)

View File

@@ -102,6 +102,7 @@ bool list_insert_after(list_t *list, list_node_t *prev_node, void *data) {
assert(data != NULL);
list_node_t *node = (list_node_t *)osi_calloc(sizeof(list_node_t));
if (!node) {
OSI_TRACE_ERROR("%s osi_calloc failed.\n", __FUNCTION__ );
return false;
}
node->next = prev_node->next;
@@ -120,6 +121,7 @@ bool list_prepend(list_t *list, void *data)
assert(data != NULL);
list_node_t *node = (list_node_t *)osi_calloc(sizeof(list_node_t));
if (!node) {
OSI_TRACE_ERROR("%s osi_calloc failed.\n", __FUNCTION__ );
return false;
}
node->next = list->head;
@@ -138,6 +140,7 @@ bool list_append(list_t *list, void *data)
assert(data != NULL);
list_node_t *node = (list_node_t *)osi_calloc(sizeof(list_node_t));
if (!node) {
OSI_TRACE_ERROR("%s osi_calloc failed.\n", __FUNCTION__ );
return false;
}
node->next = NULL;

View File

@@ -75,12 +75,12 @@ typedef struct {
/* CIND: storage room for indicators value range and their statuses */
static const tBTA_HF_CLIENT_INDICATOR bta_hf_client_indicators[BTA_HF_CLIENT_AT_SUPPORTED_INDICATOR_COUNT] = {
/* name | min | max | name length - used by parser */
{BTA_HF_CLIENT_INDICATOR_BATTERYCHG, 0, 5, sizeof(BTA_HF_CLIENT_INDICATOR_BATTERYCHG)},
{BTA_HF_CLIENT_INDICATOR_SIGNAL, 0, 5, sizeof(BTA_HF_CLIENT_INDICATOR_SIGNAL)},
{BTA_HF_CLIENT_INDICATOR_SERVICE, 0, 1, sizeof(BTA_HF_CLIENT_INDICATOR_SERVICE)},
{BTA_HF_CLIENT_INDICATOR_CALL, 0, 1, sizeof(BTA_HF_CLIENT_INDICATOR_CALL)},
{BTA_HF_CLIENT_INDICATOR_ROAM, 0, 1, sizeof(BTA_HF_CLIENT_INDICATOR_ROAM)},
{BTA_HF_CLIENT_INDICATOR_CALLSETUP, 0, 3, sizeof(BTA_HF_CLIENT_INDICATOR_CALLSETUP)},
{BTA_HF_CLIENT_INDICATOR_SERVICE, 0, 1, sizeof(BTA_HF_CLIENT_INDICATOR_SERVICE)},
{BTA_HF_CLIENT_INDICATOR_SIGNAL, 0, 5, sizeof(BTA_HF_CLIENT_INDICATOR_SIGNAL)},
{BTA_HF_CLIENT_INDICATOR_ROAM, 0, 1, sizeof(BTA_HF_CLIENT_INDICATOR_ROAM)},
{BTA_HF_CLIENT_INDICATOR_BATTERYCHG, 0, 5, sizeof(BTA_HF_CLIENT_INDICATOR_BATTERYCHG)},
{BTA_HF_CLIENT_INDICATOR_CALLHELD, 0, 2, sizeof(BTA_HF_CLIENT_INDICATOR_CALLHELD)}
};
@@ -427,7 +427,7 @@ static void bta_hf_client_handle_ciev(UINT32 index, UINT32 value)
APPL_TRACE_DEBUG("%s index: %u value: %u", __FUNCTION__, index, value);
if (index == 0 || index > BTA_HF_CLIENT_AT_INDICATOR_COUNT) {
if (index >= BTA_HF_CLIENT_AT_INDICATOR_COUNT) {
return;
}
@@ -435,7 +435,7 @@ static void bta_hf_client_handle_ciev(UINT32 index, UINT32 value)
service_availability = value == 0 ? FALSE : TRUE;
}
realind = bta_hf_client_cb.scb.at_cb.indicator_lookup[index - 1];
realind = bta_hf_client_cb.scb.at_cb.indicator_lookup[index];
if (realind >= 0 && realind < BTA_HF_CLIENT_AT_SUPPORTED_INDICATOR_COUNT) {
/* get the real in-array index from lookup table by index it comes at */
@@ -576,15 +576,17 @@ static void bta_hf_client_handle_btrh( UINT16 code)
/* Check if prefix match and skip spaces if any */
#define AT_CHECK_EVENT(buf, event) \
if (strncmp("\r\n"event, buf,sizeof("\r\n"event) - 1) != 0) return buf; \
buf += sizeof("\r\n"event) - 1; \
while (*buf == ' ') buf++;
if (strncmp("\r\n"event,buf,sizeof("\r\n"event) - 1) != 0) \
return buf; \
buf += sizeof("\r\n"event) - 1; \
while (*buf == ' ') buf++;
/* check for <cr><lf> and forward buffer if match */
#define AT_CHECK_RN(buf) \
if (strncmp("\r\n", buf, sizeof("\r\n") - 1) != 0) { \
APPL_TRACE_DEBUG("%s missing end <cr><lf>", __FUNCTION__); \
return NULL;} \
APPL_TRACE_ERROR("%s missing end <cr><lf>", __FUNCTION__); \
return NULL;\
} \
buf += sizeof("\r\n") - 1;
/* skip rest of AT string up to <cr> */
@@ -1029,13 +1031,13 @@ static char *bta_hf_client_parse_cnum(char *buffer)
AT_CHECK_EVENT(buffer, "+CNUM:");
res = sscanf(buffer, ",\"%32[^\"]\",%hu,,%hu%n", numstr, &type, &service, &offset);
res = sscanf(buffer, ",\"%32[^\"]\",%hu%n,,%hu%n", numstr, &type, &offset, &service, &offset);
if (res < 0) {
return NULL;
}
if (res == 0) {
res = sscanf(buffer, ",\"\",%hu,,%hu%n", &type, &service, &offset);
res = sscanf(buffer, ",\"\",%hu%n,,%hu%n", &type, &offset, &service, &offset);
if (res < 0) {
return NULL;
}
@@ -1045,7 +1047,7 @@ static char *bta_hf_client_parse_cnum(char *buffer)
numstr[0] = '\0';
}
if (res < 3) {
if (res < 2) {
return NULL;
}
@@ -1257,7 +1259,7 @@ static void bta_hf_client_at_parse_start(void)
for (i = 0; i < bta_hf_client_psraser_cb_count; i++) {
tmp = bta_hf_client_parser_cb[i](buf);
if (tmp == NULL) {
APPL_TRACE_ERROR("HFPCient: AT event/reply parsing failed, skipping");
APPL_TRACE_ERROR("HFPCient: AT event/reply parsing failed, skipping %d", i);
tmp = bta_hf_client_skip_unknown(buf);
break;
}

View File

@@ -115,15 +115,16 @@ typedef UINT8 tBTA_HF_CLIENT_EVT;
typedef UINT8 tBTA_HF_CLIENT_STATUS;
/* indicator type */
#define BTA_HF_CLIENT_IND_BATTCH 0 /* Battery charge indicator */
#define BTA_HF_CLIENT_IND_SIGNAL 1 /* Signal Strength indicator */
#define BTA_HF_CLIENT_IND_SERVICE 2 /* Service availability indicator */
#define BTA_HF_CLIENT_IND_CALL 3 /* Standard call status indicator*/
#define BTA_HF_CLIENT_IND_ROAM 4 /* Roaming status indicator */
#define BTA_HF_CLIENT_IND_CALLSETUP 5 /* Call setup status indicator */
#define BTA_HF_CLIENT_IND_CALLHELD 6 /* Call hold status indicator */
/* indicator constants HFP 1.1 and later */
#define BTA_HF_CLIENT_IND_CALL 0 /* position of call indicator */
#define BTA_HF_CLIENT_IND_CALLSETUP 1 /* position of callsetup indicator */
#define BTA_HF_CLIENT_IND_SERVICE 2 /* position of service indicator */
/* indicator constants HFP 1.5 and later */
#define BTA_HF_CLIENT_IND_SIGNAL 3 /* position of signal strength indicator */
#define BTA_HF_CLIENT_IND_ROAM 4 /* position of roaming indicator */
#define BTA_HF_CLIENT_IND_BATTCH 5 /* position of battery charge indicator */
#define BTA_HF_CLIENT_IND_CALLHELD 6 /* position of callheld indicator */
#define BTA_HF_CLIENT_IND_BEARER 7 /* position of bearer indicator */
typedef UINT8 tBTA_HF_CLIENT_IND_TYPE;
/* AT commands */

View File

@@ -22,8 +22,8 @@
/**********************************************************
* Thread/Task reference
**********************************************************/
#ifdef CONFIG_BTU_TASK_STACK_SIZE
#define UC_BTU_TASK_STACK_SIZE CONFIG_BTU_TASK_STACK_SIZE
#ifdef CONFIG_BT_BTU_TASK_STACK_SIZE
#define UC_BTU_TASK_STACK_SIZE CONFIG_BT_BTU_TASK_STACK_SIZE
#else
#define UC_BTU_TASK_STACK_SIZE 4096
#endif

View File

@@ -105,6 +105,15 @@ config BT_NIMBLE_DEBUG
help
This enables extra runtime asserts and host debugging
config BT_NIMBLE_SM_SC_DEBUG_KEYS
bool "Use predefined public-private key pair"
default n
depends on BT_NIMBLE_SM_SC
help
If this option is enabled, SM uses predefined DH key pair as described
in Core Specification, Vol. 3, Part H, 2.3.5.6.1. This allows to
decrypt air traffic easily and thus should only be used for debugging.
config BT_NIMBLE_SVC_GAP_DEVICE_NAME
string "BLE GAP default device name"
depends on BT_NIMBLE_ENABLED

View File

@@ -66,6 +66,8 @@ static os_membuf_t ble_hci_evt_lo_buf[
MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))
];
const static char *TAG = "NimBLE";
void ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *cmd_cb,
void *cmd_arg,
ble_hci_trans_rx_acl_fn *acl_cb,
@@ -85,7 +87,9 @@ int ble_hci_trans_hs_cmd_tx(uint8_t *cmd)
assert(cmd != NULL);
*cmd = BLE_HCI_UART_H4_CMD;
len = BLE_HCI_CMD_HDR_LEN + cmd[3] + 1;
while (!esp_vhci_host_check_send_available()) {
if (!esp_vhci_host_check_send_available()) {
ESP_LOGE(TAG, "Controller not ready to receive packets from host at this time, try again after sometime");
return BLE_HS_EAGAIN;
}
esp_vhci_host_send_packet(cmd, len);
@@ -115,8 +119,9 @@ int ble_hci_trans_hs_acl_tx(struct os_mbuf *om)
data[0] = BLE_HCI_UART_H4_ACL;
len++;
while (!esp_vhci_host_check_send_available()) {
vTaskDelay(1000 / portTICK_PERIOD_MS);
if (!esp_vhci_host_check_send_available()) {
ESP_LOGE(TAG, "Controller not ready to receive packets from host at this time, try again after sometime");
return BLE_HS_EAGAIN;
}
os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), &data[1]);

View File

@@ -423,6 +423,14 @@
#endif
#endif
#ifndef MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS
#ifdef CONFIG_BT_NIMBLE_SM_SC_DEBUG_KEYS
#define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (1)
#else
#define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (0)
#endif
#endif
#ifndef MYNEWT_VAL_BLE_HS_AUTO_START
#define MYNEWT_VAL_BLE_HS_AUTO_START (1)
#endif

View File

@@ -1048,7 +1048,7 @@ static int setup_client_ssl_session(coap_session_t *c_session,
coap_log(LOG_ERR, "PKI setup failed\n");
return ret;
}
#if !defined(ESPIDF_VERSION) || defined(CONFIG_MBEDTLS_TLS_SERVER)
#if !defined(ESPIDF_VERSION) ||(defined(CONFIG_MBEDTLS_TLS_SERVER) && defined(CONFIG_MBEDTLS_SSL_ALPN))
if (c_session->proto == COAP_PROTO_TLS) {
const char *alpn_list[2];
@@ -1059,7 +1059,7 @@ static int setup_client_ssl_session(coap_session_t *c_session,
coap_log(LOG_ERR, "ALPN setup failed %d)\n", ret);
}
}
#endif /* !ESPIDF_VERSION || CONFIG_MBEDTLS_TLS_SERVER */
#endif /* !ESPIDF_VERSION || (CONFIG_MBEDTLS_TLS_SERVER && CONFIG_MBEDTLS_SSL_ALPN) */
if (m_context->setup_data.client_sni) {
mbedtls_ssl_set_hostname(&m_env->ssl, m_context->setup_data.client_sni);
}

View File

@@ -71,4 +71,15 @@ menu "Driver configurations"
endmenu # SPI Configuration
menu "UART configuration"
config UART_ISR_IN_IRAM
bool "Place UART ISR function into IRAM"
default n
help
If this option is not selected, UART interrupt will be disabled for a long time and
may cause data lost when doing spi flash operation.
endmenu # UART Configuration
endmenu # Driver configurations

View File

@@ -27,7 +27,6 @@ extern "C"
{
#endif
//Maximum amount of bytes that can be put in one DMA descriptor
#define SPI_MAX_DMA_LEN (4096-4)
@@ -60,6 +59,19 @@ extern "C"
*/
#define SPI_SWAP_DATA_RX(DATA, LEN) (__builtin_bswap32(DATA)>>(32-(LEN)))
#define SPICOMMON_BUSFLAG_SLAVE 0 ///< Initialize I/O in slave mode
#define SPICOMMON_BUSFLAG_MASTER (1<<0) ///< Initialize I/O in master mode
#define SPICOMMON_BUSFLAG_IOMUX_PINS (1<<1) ///< Check using iomux pins. Or indicates the pins are configured through the IO mux rather than GPIO matrix.
#define SPICOMMON_BUSFLAG_SCLK (1<<2) ///< Check existing of SCLK pin. Or indicates CLK line initialized.
#define SPICOMMON_BUSFLAG_MISO (1<<3) ///< Check existing of MISO pin. Or indicates MISO line initialized.
#define SPICOMMON_BUSFLAG_MOSI (1<<4) ///< Check existing of MOSI pin. Or indicates CLK line initialized.
#define SPICOMMON_BUSFLAG_DUAL (1<<5) ///< Check MOSI and MISO pins can output. Or indicates bus able to work under DIO mode.
#define SPICOMMON_BUSFLAG_WPHD (1<<6) ///< Check existing of WP and HD pins. Or indicates WP & HD pins initialized.
#define SPICOMMON_BUSFLAG_QUAD (SPICOMMON_BUSFLAG_DUAL|SPICOMMON_BUSFLAG_WPHD) ///< Check existing of MOSI/MISO/WP/HD pins as output. Or indicates bus able to work under QIO mode.
#define SPICOMMON_BUSFLAG_NATIVE_PINS SPICOMMON_BUSFLAG_IOMUX_PINS
/**
* @brief This is a configuration structure for a SPI bus.
*
@@ -126,283 +138,6 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus
*/
esp_err_t spi_bus_free(spi_host_device_t host);
/** @cond */ //Doxygen command to hide deprecated function (or non-public) from API Reference
/**
* @brief Try to claim a SPI peripheral
*
* Call this if your driver wants to manage a SPI peripheral.
*
* @param host Peripheral to claim
* @param source The caller indentification string.
*
* @note This public API is deprecated.
*
* @return True if peripheral is claimed successfully; false if peripheral already is claimed.
*/
bool spicommon_periph_claim(spi_host_device_t host, const char* source);
/**
* @brief Check whether the spi periph is in use.
*
* @param host Peripheral to check.
*
* @note This public API is deprecated.
*
* @return True if in use, otherwise false.
*/
bool spicommon_periph_in_use(spi_host_device_t host);
/**
* @brief Return the SPI peripheral so another driver can claim it.
*
* @param host Peripheral to return
*
* @note This public API is deprecated.
*
* @return True if peripheral is returned successfully; false if peripheral was free to claim already.
*/
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
*
* @note This public API is deprecated.
*
* @return True if success; false otherwise.
*/
bool spicommon_dma_chan_claim(int dma_chan);
/**
* @brief Check whether the spi DMA channel is in use.
*
* @param dma_chan DMA channel to check.
*
* @note This public API is deprecated.
*
* @return True if in use, otherwise false.
*/
bool spicommon_dma_chan_in_use(int dma_chan);
/**
* @brief Return the SPI DMA channel so other driver can claim it, or just to power down DMA.
*
* @param dma_chan channel to return
*
* @note This public API is deprecated.
*
* @return True if success; false otherwise.
*/
bool spicommon_dma_chan_free(int dma_chan);
/// @note macros deprecated from public API
#define SPICOMMON_BUSFLAG_SLAVE 0 ///< Initialize I/O in slave mode
#define SPICOMMON_BUSFLAG_MASTER (1<<0) ///< Initialize I/O in master mode
#define SPICOMMON_BUSFLAG_IOMUX_PINS (1<<1) ///< Check using iomux pins. Or indicates the pins are configured through the IO mux rather than GPIO matrix.
#define SPICOMMON_BUSFLAG_SCLK (1<<2) ///< Check existing of SCLK pin. Or indicates CLK line initialized.
#define SPICOMMON_BUSFLAG_MISO (1<<3) ///< Check existing of MISO pin. Or indicates MISO line initialized.
#define SPICOMMON_BUSFLAG_MOSI (1<<4) ///< Check existing of MOSI pin. Or indicates CLK line initialized.
#define SPICOMMON_BUSFLAG_DUAL (1<<5) ///< Check MOSI and MISO pins can output. Or indicates bus able to work under DIO mode.
#define SPICOMMON_BUSFLAG_WPHD (1<<6) ///< Check existing of WP and HD pins. Or indicates WP & HD pins initialized.
#define SPICOMMON_BUSFLAG_QUAD (SPICOMMON_BUSFLAG_DUAL|SPICOMMON_BUSFLAG_WPHD) ///< Check existing of MOSI/MISO/WP/HD pins as output. Or indicates bus able to work under QIO mode.
#define SPICOMMON_BUSFLAG_NATIVE_PINS SPICOMMON_BUSFLAG_IOMUX_PINS
/**
* @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
* IO_mux or using the GPIO matrix.
*
* @note This public API is deprecated. Please call ``spi_bus_initialize`` for master
* bus initialization and ``spi_slave_initialize`` for slave initialization.
*
* @param host SPI peripheral to be routed
* @param bus_config Pointer to a spi_bus_config struct detailing the GPIO pins
* @param dma_chan DMA-channel (1 or 2) to use, or 0 for no DMA.
* @param flags Combination of SPICOMMON_BUSFLAG_* flags, set to ensure the pins set are capable with some functions:
* - ``SPICOMMON_BUSFLAG_MASTER``: Initialize I/O in master mode
* - ``SPICOMMON_BUSFLAG_SLAVE``: Initialize I/O in slave mode
* - ``SPICOMMON_BUSFLAG_IOMUX_PINS``: Pins set should match the iomux pins of the controller.
* - ``SPICOMMON_BUSFLAG_SCLK``, ``SPICOMMON_BUSFLAG_MISO``, ``SPICOMMON_BUSFLAG_MOSI``:
* Make sure SCLK/MISO/MOSI is/are set to a valid GPIO. Also check output capability according to the mode.
* - ``SPICOMMON_BUSFLAG_DUAL``: Make sure both MISO and MOSI are output capable so that DIO mode is capable.
* - ``SPICOMMON_BUSFLAG_WPHD`` Make sure WP and HD are set to valid output GPIOs.
* - ``SPICOMMON_BUSFLAG_QUAD``: Combination of ``SPICOMMON_BUSFLAG_DUAL`` and ``SPICOMMON_BUSFLAG_WPHD``.
* @param[out] flags_o A SPICOMMON_BUSFLAG_* flag combination of bus abilities will be written to this address.
* Leave to NULL if not needed.
* - ``SPICOMMON_BUSFLAG_IOMUX_PINS``: The bus is connected to iomux pins.
* - ``SPICOMMON_BUSFLAG_SCLK``, ``SPICOMMON_BUSFLAG_MISO``, ``SPICOMMON_BUSFLAG_MOSI``: The bus has
* CLK/MISO/MOSI connected.
* - ``SPICOMMON_BUSFLAG_DUAL``: The bus is capable with DIO mode.
* - ``SPICOMMON_BUSFLAG_WPHD`` The bus has WP and HD connected.
* - ``SPICOMMON_BUSFLAG_QUAD``: Combination of ``SPICOMMON_BUSFLAG_DUAL`` and ``SPICOMMON_BUSFLAG_WPHD``.
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK on success
*/
esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_config_t *bus_config, int dma_chan, uint32_t flags, uint32_t *flags_o);
/**
* @brief Free the IO used by a SPI peripheral
*
* @note This public API is deprecated. Please call ``spi_bus_free`` for master
* bus deinitialization and ``spi_slave_free`` for slave deinitialization.
*
* @param bus_cfg Bus config struct which defines which pins to be used.
*
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK on success
*/
esp_err_t spicommon_bus_free_io_cfg(const spi_bus_config_t *bus_cfg);
/**
* @brief Initialize a Chip Select pin for a specific SPI peripheral
*
* @note This public API is deprecated. Please call corresponding device initialization
* functions.
*
* @param host SPI peripheral
* @param cs_io_num GPIO pin to route
* @param cs_num CS id to route
* @param force_gpio_matrix If true, CS will always be routed through the GPIO matrix. If false,
* if the GPIO number allows it, the routing will happen through the IO_mux.
*/
void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num, int force_gpio_matrix);
/**
* @brief Free a chip select line
*
* @param cs_gpio_num CS gpio num to free
*
* @note This public API is deprecated.
*/
void spicommon_cs_free_io(int cs_gpio_num);
/**
* @brief Check whether all pins used by a host are through IOMUX.
*
* @param host SPI peripheral
*
* @note This public API is deprecated.
*
* @return false if any pins are through the GPIO matrix, otherwise true.
*/
bool spicommon_bus_using_iomux(spi_host_device_t host);
/**
* @brief Check whether all pins used by a host are through IOMUX.
*
* @param host SPI peripheral
*
* @note This public API is deprecated.
*
* @return false if any pins are through the GPIO matrix, otherwise true.
*/
bool spicommon_bus_using_iomux(spi_host_device_t host);
/**
* @brief Get the IRQ source for a specific SPI host
*
* @param host The SPI host
*
* @note This public API is deprecated.
*
* @return The hosts IRQ source
*/
int spicommon_irqsource_for_host(spi_host_device_t host);
/**
* @brief Get the IRQ source for a specific SPI DMA
*
* @param host The SPI host
*
* @note This public API is deprecated.
*
* @return The hosts IRQ source
*/
int spicommon_irqdma_source_for_host(spi_host_device_t host);
/**
* @brief Get the IRQ source for a specific SPI DMA
*
* @param host The SPI host
*
* @return The hosts IRQ source
*/
int spicommon_irqdma_source_for_host(spi_host_device_t host);
/**
* Callback, to be called when a DMA engine reset is completed
*/
typedef void(*dmaworkaround_cb_t)(void *arg);
/**
* @brief Request a reset for a certain DMA channel
*
* @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
* 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
* @param cb Callback to call in case DMA channel cannot be reset immediately
* @param arg Argument to the callback
*
* @note This public API is deprecated.
*
* @return True when a DMA reset could be executed immediately. False when it could not; in this
* case the callback will be called with the specified argument when the logic can execute
* a reset, after that reset.
*/
bool spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t cb, void *arg);
/**
* @brief Check if a DMA reset is requested but has not completed yet
*
* @note This public API is deprecated.
*
* @return True when a DMA reset is requested but hasn't completed yet. False otherwise.
*/
bool spicommon_dmaworkaround_reset_in_progress(void);
/**
* @brief Mark a DMA channel as idle.
*
* A call to this function tells the workaround logic that this channel will
* not be affected by a global SPI DMA reset.
*
* @note This public API is deprecated.
*/
void spicommon_dmaworkaround_idle(int dmachan);
/**
* @brief Mark a DMA channel as active.
*
* A call to this function tells the workaround logic that this channel will
* be affected by a global SPI DMA reset, and a reset like that should not be attempted.
*
* @note This public API is deprecated.
*/
void spicommon_dmaworkaround_transfer_active(int dmachan);
/** @endcond */
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,267 @@
// Copyright 2010-2019 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.
// Internal header, don't use it in the user code
#pragma once
#include "driver/spi_common.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Try to claim a SPI peripheral
*
* Call this if your driver wants to manage a SPI peripheral.
*
* @param host Peripheral to claim
* @param source The caller indentification string.
*
* @note This public API is deprecated.
*
* @return True if peripheral is claimed successfully; false if peripheral already is claimed.
*/
bool spicommon_periph_claim(spi_host_device_t host, const char* source);
/**
* @brief Check whether the spi periph is in use.
*
* @param host Peripheral to check.
*
* @note This public API is deprecated.
*
* @return True if in use, otherwise false.
*/
bool spicommon_periph_in_use(spi_host_device_t host);
/**
* @brief Return the SPI peripheral so another driver can claim it.
*
* @param host Peripheral to return
*
* @note This public API is deprecated.
*
* @return True if peripheral is returned successfully; false if peripheral was free to claim already.
*/
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
*
* @note This public API is deprecated.
*
* @return True if success; false otherwise.
*/
bool spicommon_dma_chan_claim(int dma_chan);
/**
* @brief Check whether the spi DMA channel is in use.
*
* @param dma_chan DMA channel to check.
*
* @note This public API is deprecated.
*
* @return True if in use, otherwise false.
*/
bool spicommon_dma_chan_in_use(int dma_chan);
/**
* @brief Return the SPI DMA channel so other driver can claim it, or just to power down DMA.
*
* @param dma_chan channel to return
*
* @note This public API is deprecated.
*
* @return True if success; false otherwise.
*/
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
* IO_mux or using the GPIO matrix.
*
* @note This public API is deprecated. Please call ``spi_bus_initialize`` for master
* bus initialization and ``spi_slave_initialize`` for slave initialization.
*
* @param host SPI peripheral to be routed
* @param bus_config Pointer to a spi_bus_config struct detailing the GPIO pins
* @param dma_chan DMA-channel (1 or 2) to use, or 0 for no DMA.
* @param flags Combination of SPICOMMON_BUSFLAG_* flags, set to ensure the pins set are capable with some functions:
* - ``SPICOMMON_BUSFLAG_MASTER``: Initialize I/O in master mode
* - ``SPICOMMON_BUSFLAG_SLAVE``: Initialize I/O in slave mode
* - ``SPICOMMON_BUSFLAG_IOMUX_PINS``: Pins set should match the iomux pins of the controller.
* - ``SPICOMMON_BUSFLAG_SCLK``, ``SPICOMMON_BUSFLAG_MISO``, ``SPICOMMON_BUSFLAG_MOSI``:
* Make sure SCLK/MISO/MOSI is/are set to a valid GPIO. Also check output capability according to the mode.
* - ``SPICOMMON_BUSFLAG_DUAL``: Make sure both MISO and MOSI are output capable so that DIO mode is capable.
* - ``SPICOMMON_BUSFLAG_WPHD`` Make sure WP and HD are set to valid output GPIOs.
* - ``SPICOMMON_BUSFLAG_QUAD``: Combination of ``SPICOMMON_BUSFLAG_DUAL`` and ``SPICOMMON_BUSFLAG_WPHD``.
* @param[out] flags_o A SPICOMMON_BUSFLAG_* flag combination of bus abilities will be written to this address.
* Leave to NULL if not needed.
* - ``SPICOMMON_BUSFLAG_IOMUX_PINS``: The bus is connected to iomux pins.
* - ``SPICOMMON_BUSFLAG_SCLK``, ``SPICOMMON_BUSFLAG_MISO``, ``SPICOMMON_BUSFLAG_MOSI``: The bus has
* CLK/MISO/MOSI connected.
* - ``SPICOMMON_BUSFLAG_DUAL``: The bus is capable with DIO mode.
* - ``SPICOMMON_BUSFLAG_WPHD`` The bus has WP and HD connected.
* - ``SPICOMMON_BUSFLAG_QUAD``: Combination of ``SPICOMMON_BUSFLAG_DUAL`` and ``SPICOMMON_BUSFLAG_WPHD``.
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK on success
*/
esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_config_t *bus_config, int dma_chan, uint32_t flags, uint32_t *flags_o);
/**
* @brief Free the IO used by a SPI peripheral
*
* @note This public API is deprecated. Please call ``spi_bus_free`` for master
* bus deinitialization and ``spi_slave_free`` for slave deinitialization.
*
* @param bus_cfg Bus config struct which defines which pins to be used.
*
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK on success
*/
esp_err_t spicommon_bus_free_io_cfg(const spi_bus_config_t *bus_cfg);
/**
* @brief Initialize a Chip Select pin for a specific SPI peripheral
*
* @note This public API is deprecated. Please call corresponding device initialization
* functions.
*
* @param host SPI peripheral
* @param cs_io_num GPIO pin to route
* @param cs_num CS id to route
* @param force_gpio_matrix If true, CS will always be routed through the GPIO matrix. If false,
* if the GPIO number allows it, the routing will happen through the IO_mux.
*/
void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num, int force_gpio_matrix);
/**
* @brief Free a chip select line
*
* @param cs_gpio_num CS gpio num to free
*
* @note This public API is deprecated.
*/
void spicommon_cs_free_io(int cs_gpio_num);
/**
* @brief Check whether all pins used by a host are through IOMUX.
*
* @param host SPI peripheral
*
* @note This public API is deprecated.
*
* @return false if any pins are through the GPIO matrix, otherwise true.
*/
bool spicommon_bus_using_iomux(spi_host_device_t host);
/**
* @brief Get the IRQ source for a specific SPI host
*
* @param host The SPI host
*
* @note This public API is deprecated.
*
* @return The hosts IRQ source
*/
int spicommon_irqsource_for_host(spi_host_device_t host);
/**
* @brief Get the IRQ source for a specific SPI DMA
*
* @param host The SPI host
*
* @note This public API is deprecated.
*
* @return The hosts IRQ source
*/
int spicommon_irqdma_source_for_host(spi_host_device_t host);
/**
* Callback, to be called when a DMA engine reset is completed
*/
typedef void(*dmaworkaround_cb_t)(void *arg);
/**
* @brief Request a reset for a certain DMA channel
*
* @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
* 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
* @param cb Callback to call in case DMA channel cannot be reset immediately
* @param arg Argument to the callback
*
* @note This public API is deprecated.
*
* @return True when a DMA reset could be executed immediately. False when it could not; in this
* case the callback will be called with the specified argument when the logic can execute
* a reset, after that reset.
*/
bool spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t cb, void *arg);
/**
* @brief Check if a DMA reset is requested but has not completed yet
*
* @note This public API is deprecated.
*
* @return True when a DMA reset is requested but hasn't completed yet. False otherwise.
*/
bool spicommon_dmaworkaround_reset_in_progress(void);
/**
* @brief Mark a DMA channel as idle.
*
* A call to this function tells the workaround logic that this channel will
* not be affected by a global SPI DMA reset.
*
* @note This public API is deprecated.
*/
void spicommon_dmaworkaround_idle(int dmachan);
/**
* @brief Mark a DMA channel as active.
*
* A call to this function tells the workaround logic that this channel will
* be affected by a global SPI DMA reset, and a reset like that should not be attempted.
*
* @note This public API is deprecated.
*/
void spicommon_dmaworkaround_transfer_active(int dmachan);
#ifdef __cplusplus
}
#endif

View File

@@ -27,7 +27,7 @@
#include "driver/gpio.h"
#include "driver/periph_ctrl.h"
#include "esp_heap_caps.h"
#include "driver/spi_common.h"
#include "driver/spi_common_internal.h"
#include "stdatomic.h"
#include "hal/spi_hal.h"

View File

@@ -119,7 +119,7 @@ We have two bits to control the interrupt:
*/
#include <string.h>
#include "driver/spi_common.h"
#include "driver/spi_common_internal.h"
#include "driver/spi_master.h"
#include "soc/spi_periph.h"
#include "esp_types.h"

View File

@@ -17,7 +17,7 @@
#include <hal/spi_ll.h>
#include <hal/spi_slave_hal.h>
#include <soc/lldesc.h>
#include "driver/spi_common.h"
#include "driver/spi_common_internal.h"
#include "driver/spi_slave.h"
#include "soc/spi_periph.h"
#include "esp_types.h"

View File

@@ -24,6 +24,7 @@
#include "sdkconfig.h"
#include "../cache_utils.h"
#include "soc/soc_memory_layout.h"
#include "driver/spi_common_internal.h"
const static char TAG[] = "test_spi";

View File

@@ -28,6 +28,7 @@
#include "driver/gpio.h"
#include "driver/uart_select.h"
#include "sdkconfig.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/clk.h"
#elif CONFIG_IDF_TARGET_ESP32S2BETA
@@ -36,7 +37,11 @@
#define UART_NUM SOC_UART_NUM
#define UART_NUM SOC_UART_NUM
#ifdef CONFIG_UART_ISR_IN_IRAM
#define UART_ISR_ATTR IRAM_ATTR
#else
#define UART_ISR_ATTR
#endif
#define XOFF (char)0x13
#define XON (char)0x11
@@ -327,7 +332,7 @@ esp_err_t uart_get_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t *flo
return ESP_OK;
}
static esp_err_t uart_reset_rx_fifo(uart_port_t uart_num)
static esp_err_t UART_ISR_ATTR uart_reset_rx_fifo(uart_port_t uart_num)
{
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
#if CONFIG_IDF_TARGET_ESP32
@@ -345,7 +350,7 @@ static esp_err_t uart_reset_rx_fifo(uart_port_t uart_num)
return ESP_OK;
}
esp_err_t uart_clear_intr_status(uart_port_t uart_num, uint32_t clr_mask)
esp_err_t UART_ISR_ATTR uart_clear_intr_status(uart_port_t uart_num, uint32_t clr_mask)
{
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
//intr_clr register is write-only
@@ -372,14 +377,14 @@ esp_err_t uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask)
return ESP_OK;
}
static void uart_disable_intr_mask_from_isr(uart_port_t uart_num, uint32_t disable_mask)
static void UART_ISR_ATTR uart_disable_intr_mask_from_isr(uart_port_t uart_num, uint32_t disable_mask)
{
UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
CLEAR_PERI_REG_MASK(UART_INT_ENA_REG(uart_num), disable_mask);
UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
}
static void uart_enable_intr_mask_from_isr(uart_port_t uart_num, uint32_t enable_mask)
static void UART_ISR_ATTR uart_enable_intr_mask_from_isr(uart_port_t uart_num, uint32_t enable_mask)
{
UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
SET_PERI_REG_MASK(UART_INT_CLR_REG(uart_num), enable_mask);
@@ -402,7 +407,7 @@ static esp_err_t uart_pattern_link_free(uart_port_t uart_num)
return ESP_OK;
}
static esp_err_t uart_pattern_enqueue(uart_port_t uart_num, int pos)
static esp_err_t UART_ISR_ATTR uart_pattern_enqueue(uart_port_t uart_num, int pos)
{
UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_FAIL);
esp_err_t ret = ESP_OK;
@@ -815,7 +820,7 @@ esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_
return ESP_OK;
}
static int uart_find_pattern_from_last(uint8_t *buf, int length, uint8_t pat_chr, int pat_num)
static int UART_ISR_ATTR uart_find_pattern_from_last(uint8_t* buf, int length, uint8_t pat_chr, int pat_num)
{
int cnt = 0;
int len = length;
@@ -834,7 +839,7 @@ static int uart_find_pattern_from_last(uint8_t *buf, int length, uint8_t pat_chr
}
//internal isr handler for default driver code.
static void uart_rx_intr_handler_default(void *param)
static void UART_ISR_ATTR uart_rx_intr_handler_default(void *param)
{
uart_obj_t *p_uart = (uart_obj_t *) param;
uint8_t uart_num = p_uart->uart_num;
@@ -1432,7 +1437,13 @@ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_b
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
UART_CHECK((rx_buffer_size > UART_FIFO_LEN), "uart rx buffer length error(>128)", ESP_FAIL);
UART_CHECK((tx_buffer_size > UART_FIFO_LEN) || (tx_buffer_size == 0), "uart tx buffer length error(>128 or 0)", ESP_FAIL);
UART_CHECK((intr_alloc_flags & ESP_INTR_FLAG_IRAM) == 0, "ESP_INTR_FLAG_IRAM set in intr_alloc_flags", ESP_FAIL); /* uart_rx_intr_handler_default is not in IRAM */
#if CONFIG_UART_ISR_IN_IRAM
UART_CHECK((intr_alloc_flags & ESP_INTR_FLAG_IRAM) != 0,
"should set ESP_INTR_FLAG_IRAM flag when CONFIG_UART_ISR_IN_IRAM is enabled", ESP_FAIL);
#else
UART_CHECK((intr_alloc_flags & ESP_INTR_FLAG_IRAM) == 0,
"should not set ESP_INTR_FLAG_IRAM when CONFIG_UART_ISR_IN_IRAM is not enabled", ESP_FAIL);
#endif
if (p_uart_obj[uart_num] == NULL) {
p_uart_obj[uart_num] = (uart_obj_t *) calloc(1, sizeof(uart_obj_t));

View File

@@ -17,6 +17,7 @@
#include <stdbool.h>
#include <sys/socket.h>
#include <fcntl.h>
#include "esp_err.h"
#include "mbedtls/platform.h"
#include "mbedtls/net_sockets.h"

View File

@@ -116,7 +116,7 @@ menu "ESP32-specific"
config SPIRAM_CACHE_WORKAROUND
bool "Enable workaround for bug in SPI RAM cache for Rev1 ESP32s"
depends on SPIRAM_USE_MEMMAP || SPIRAM_USE_CAPS_ALLOC || SPIRAM_USE_MALLOC
depends on (SPIRAM_USE_MEMMAP || SPIRAM_USE_CAPS_ALLOC || SPIRAM_USE_MALLOC) && (ESP32_REV_MIN < 3)
default "y"
help
Revision 1 of the ESP32 has a bug that can cause a write to PSRAM not to take place in some situations
@@ -127,6 +127,8 @@ menu "ESP32-specific"
This will also not use any bits of newlib that are located in ROM, opting for a version that is
compiled with the workaround and located in flash instead.
The workaround is not required for ESP32 revision 3 and above.
config SPIRAM_BANKSWITCH_ENABLE
bool "Enable bank switching for >4MiB external RAM"
default y

View File

@@ -33,7 +33,7 @@
#include "driver/periph_ctrl.h"
#include "xtensa/core-macros.h"
#include "bootloader_clock.h"
#include "driver/spi_common.h"
#include "driver/spi_common_internal.h"
/* Number of cycles to wait from the 32k XTAL oscillator to consider it running.
* Larger values increase startup delay. Smaller values may cause false positive

View File

@@ -33,7 +33,7 @@
#include "soc/efuse_periph.h"
#include "soc/spi_caps.h"
#include "driver/gpio.h"
#include "driver/spi_common.h"
#include "driver/spi_common_internal.h"
#include "driver/periph_ctrl.h"
#include "bootloader_common.h"
@@ -469,7 +469,7 @@ static esp_err_t IRAM_ATTR psram_enable_qio_mode(psram_spi_num_t spi_num)
void psram_set_cs_timing(psram_spi_num_t spi_num, psram_clk_mode_t clk_mode)
{
if (clk_mode == PSRAM_CLK_MODE_NORM) {
if (clk_mode == PSRAM_CLK_MODE_NORM) {
SET_PERI_REG_MASK(SPI_USER_REG(spi_num), SPI_CS_HOLD_M | SPI_CS_SETUP_M);
// Set cs time.
SET_PERI_REG_BITS(SPI_CTRL2_REG(spi_num), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S);
@@ -566,7 +566,7 @@ static void IRAM_ATTR psram_gpio_config(psram_io_t *psram_io, psram_cache_mode_t
gpio_matrix_in(psram_io->psram_spiwp_sd3_io, SPIWP_IN_IDX, 0);
gpio_matrix_out(psram_io->psram_spihd_sd2_io, SPIHD_OUT_IDX, 0, 0);
gpio_matrix_in(psram_io->psram_spihd_sd2_io, SPIHD_IN_IDX, 0);
//select pin function gpio
if ((psram_io->flash_clk_io == SPI_IOMUX_PIN_NUM_CLK) && (psram_io->flash_clk_io != psram_io->psram_clk_io)) {
//flash clock signal should come from IO MUX.
@@ -671,7 +671,7 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
// If flash mode is set to QIO or QOUT, the WP pin is equal the value configured in bootloader.
// If flash mode is set to DIO or DOUT, the WP pin should config it via menuconfig.
#if CONFIG_FLASHMODE_QIO || CONFIG_FLASHMODE_QOUT
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_FLASHMODE_QOUT
psram_io.psram_spiwp_sd3_io = CONFIG_BOOTLOADER_SPI_WP_PIN;
#else
psram_io.psram_spiwp_sd3_io = CONFIG_SPIRAM_SPIWP_SD3_PIN;
@@ -685,7 +685,7 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
CLEAR_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1), SPI_USR_PREP_HOLD_M);
psram_spi_init(PSRAM_SPI_1, mode);
switch (mode) {
case PSRAM_CACHE_F80M_S80M:
gpio_matrix_out(psram_io.psram_clk_io, SPICLK_OUT_IDX, 0, 0);
@@ -754,7 +754,7 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
gpio_matrix_out(PSRAM_INTERNAL_IO_29, SIG_GPIO_OUT_IDX, 0, 0);
gpio_matrix_out(psram_io.psram_clk_io, SPICLK_OUT_IDX, 0, 0);
}
// Update cs timing according to psram driving method.
psram_set_cs_timing(PSRAM_SPI_1, s_clk_mode);
psram_set_cs_timing(_SPI_CACHE_PORT, s_clk_mode);

View File

@@ -230,12 +230,11 @@ void esp_restart_noos(void) __attribute__ ((noreturn));
void IRAM_ATTR esp_restart(void)
{
int i;
for (i = 0; i < SHUTDOWN_HANDLERS_NO; i++) {
if (shutdown_handlers[i]) {
shutdown_handlers[i]();
}
}
for (int i = SHUTDOWN_HANDLERS_NO - 1; i >= 0; i--) {
if (shutdown_handlers[i]) {
shutdown_handlers[i]();
}
}
// Disable scheduler on this core.
vTaskSuspendAll();

View File

@@ -1,7 +1,7 @@
#include "esp_heap_caps.h"
#include "unity.h"
#include "esp_log.h"
#include "driver/spi_common.h"
#include "driver/spi_common_internal.h"
#include "sdkconfig.h"
static const char TAG[] = "test_psram";

View File

@@ -30,4 +30,28 @@ else()
-fno-stack-protector)
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY LINK_LIBRARIES "-Wl,--gc-sections")
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-Wl,--gc-sections")
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY LINK_INTERFACE_MULTIPLICITY 4)
# List of components needed for the error codes list
set(optional_reqs ulp
efuse
esp_http_client
esp_http_server
bootloader_support
nvs_flash
esp_wifi
app_update
lwip
spi_flash
wpa_supplicant
tcpip_adapter)
idf_build_get_property(build_components BUILD_COMPONENTS)
foreach(req ${optional_reqs})
if(req IN_LIST build_components)
idf_component_get_property(req_lib ${req} COMPONENT_LIB)
target_link_libraries(${COMPONENT_LIB} PRIVATE ${req_lib})
endif()
endforeach()
endif()

View File

@@ -40,9 +40,10 @@ menu "Common ESP-related"
config ESP_IPC_TASK_STACK_SIZE
int "Inter-Processor Call (IPC) task stack size"
default 1024
range 512 65536 if !ESP32_APPTRACE_ENABLE
range 2048 65536 if ESP32_APPTRACE_ENABLE
default 2048 if ESP32_APPTRACE_ENABLE
default 1024
help
Configure the IPC tasks stack size. One IPC task runs on each core
(in dual core mode), and allows for cross-core function calls.

View File

@@ -148,9 +148,14 @@ esp_err_t esp_eth_transmit(esp_eth_handle_t hdl, uint8_t *buf, uint32_t length);
* @param[out] buf: buffer to preserve the received packet
* @param[out] length: length of the received packet
*
* @note Before this function got invoked, the value of "length" should set by user, equals the size of buffer.
* After the function returned, the value of "length" means the real length of received data.
*
* @return
* - ESP_OK: receive frame buffer successfully
* - ESP_ERR_INVALID_ARG: receive frame buffer failed because of some invalid argument
* - ESP_ERR_INVALID_SIZE: input buffer size is not enough to hold the incoming data.
* in this case, value of returned "length" indicates the real size of incoming data.
* - ESP_FAIL: receive frame buffer failed because some other error occurred
*/
esp_err_t esp_eth_receive(esp_eth_handle_t hdl, uint8_t *buf, uint32_t *length);

View File

@@ -99,10 +99,14 @@ struct esp_eth_mac_s {
* @param[out] length: length of the received packet
*
* @note Memory of buf is allocated in the Layer2, make sure it get free after process.
* @note Before this function got invoked, the value of "length" should set by user, equals the size of buffer.
* After the function returned, the value of "length" means the real length of received data.
*
* @return
* - ESP_OK: receive packet successfully
* - ESP_ERR_INVALID_ARG: receive packet failed because of invalid argument
* - ESP_ERR_INVALID_SIZE: input buffer size is not enough to hold the incoming data.
* in this case, value of returned "length" indicates the real size of incoming data.
* - ESP_FAIL: receive packet failed because some other error occurred
*
*/

View File

@@ -38,7 +38,6 @@ static const char *TAG = "emac_dm9051";
} \
} while (0)
#define RX_QUEUE_WAIT_MS (100)
#define DM9051_SPI_LOCK_TIMEOUT_MS (50)
#define DM9051_PHY_OPERATION_TIMEOUT_US (1000)
@@ -308,6 +307,30 @@ static esp_err_t dm9051_memory_read(emac_dm9051_t *emac, uint8_t *buffer, uint32
return ret;
}
/**
* @brief peek buffer from dm9051 internal memory (without internal cursor moved)
*/
static esp_err_t dm9051_memory_peek(emac_dm9051_t *emac, uint8_t *buffer, uint32_t len)
{
esp_err_t ret = ESP_OK;
spi_transaction_t trans = {
.cmd = DM9051_SPI_RD,
.addr = DM9051_MRCMDX1,
.length = len * 8,
.rx_buffer = buffer
};
if (dm9051_lock(emac)) {
if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) {
ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__);
ret = ESP_FAIL;
}
dm9051_unlock(emac);
} else {
ret = ESP_ERR_TIMEOUT;
}
return ret;
}
/**
* @brief read mac address from internal registers
*/
@@ -501,26 +524,27 @@ static void emac_dm9051_task(void *arg)
uint8_t *buffer = NULL;
uint32_t length = 0;
while (1) {
if (ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(RX_QUEUE_WAIT_MS))) {
/* clear interrupt status */
dm9051_register_read(emac, DM9051_ISR, &status);
dm9051_register_write(emac, DM9051_ISR, status);
/* packet received */
if (status & ISR_PR) {
do {
buffer = (uint8_t *)heap_caps_malloc(ETH_MAX_PACKET_SIZE, MALLOC_CAP_DMA);
if (emac->parent.receive(&emac->parent, buffer, &length) == ESP_OK) {
/* pass the buffer to stack (e.g. TCP/IP layer) */
if (length) {
emac->eth->stack_input(emac->eth, buffer, length);
} else {
free(buffer);
}
// block indefinitely until some task notifies me
ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
/* clear interrupt status */
dm9051_register_read(emac, DM9051_ISR, &status);
dm9051_register_write(emac, DM9051_ISR, status);
/* packet received */
if (status & ISR_PR) {
do {
length = ETH_MAX_PACKET_SIZE;
buffer = (uint8_t *)heap_caps_malloc(length, MALLOC_CAP_DMA);
if (emac->parent.receive(&emac->parent, buffer, &length) == ESP_OK) {
/* pass the buffer to stack (e.g. TCP/IP layer) */
if (length) {
emac->eth->stack_input(emac->eth, buffer, length);
} else {
free(buffer);
}
} while (emac->packets_remain);
}
} else {
free(buffer);
}
} while (emac->packets_remain);
}
}
vTaskDelete(NULL);
@@ -744,13 +768,26 @@ static esp_err_t emac_dm9051_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t
if (rxbyte > 1) {
MAC_CHECK(dm9051_stop(emac) == ESP_OK, "stop dm9051 failed", err, ESP_FAIL);
/* reset rx fifo pointer */
MAC_CHECK(dm9051_register_write(emac, DM9051_MPTRCR, MPTRCR_RST_RX) == ESP_OK, "write MPTRCR failed", err, ESP_FAIL);
MAC_CHECK(dm9051_register_write(emac, DM9051_MPTRCR, MPTRCR_RST_RX) == ESP_OK,
"write MPTRCR failed", err, ESP_FAIL);
ets_delay_us(10);
MAC_CHECK(dm9051_start(emac) == ESP_OK, "start dm9051 failed", err, ESP_FAIL);
MAC_CHECK(false, "reset rx fifo pointer", err, ESP_FAIL);
} else if (rxbyte) {
MAC_CHECK(dm9051_memory_read(emac, (uint8_t *)&header, sizeof(header)) == ESP_OK, "read rx header failed", err, ESP_FAIL);
MAC_CHECK(dm9051_memory_peek(emac, (uint8_t *)&header, sizeof(header)) == ESP_OK,
"peek rx header failed", err, ESP_FAIL);
rx_len = header.length_low + (header.length_high << 8);
/* check if the buffer can hold all the incoming data */
if (*length < rx_len - 4) {
ESP_LOGE(TAG, "buffer size too small");
/* tell upper layer the size we need */
*length = rx_len - 4;
ret = ESP_ERR_INVALID_SIZE;
goto err;
}
MAC_CHECK(*length >= rx_len - 4, "buffer size too small", err, ESP_ERR_INVALID_SIZE);
MAC_CHECK(dm9051_memory_read(emac, (uint8_t *)&header, sizeof(header)) == ESP_OK,
"read rx header failed", err, ESP_FAIL);
MAC_CHECK(dm9051_memory_read(emac, buf, rx_len) == ESP_OK, "read rx data failed", err, ESP_FAIL);
MAC_CHECK(!(header.status & 0xBF), "receive status error: %xH", err, ESP_FAIL, header.status);
*length = rx_len - 4; // substract the CRC length (4Bytes)
@@ -818,9 +855,10 @@ static esp_err_t emac_dm9051_del(esp_eth_mac_t *mac)
esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config, const eth_mac_config_t *mac_config)
{
esp_eth_mac_t *ret = NULL;
emac_dm9051_t *emac = NULL;
MAC_CHECK(dm9051_config, "can't set dm9051 specific config to null", err, NULL);
MAC_CHECK(mac_config, "can't set mac config to null", err, NULL);
emac_dm9051_t *emac = calloc(1, sizeof(emac_dm9051_t));
emac = calloc(1, sizeof(emac_dm9051_t));
MAC_CHECK(emac, "calloc emac failed", err, NULL);
/* bind methods and attributes */
emac->sw_reset_timeout_ms = mac_config->sw_reset_timeout_ms;
@@ -841,16 +879,22 @@ esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config,
emac->parent.receive = emac_dm9051_receive;
/* create mutex */
emac->spi_lock = xSemaphoreCreateMutex();
MAC_CHECK(emac->spi_lock, "create lock failed", err_lock, NULL);
MAC_CHECK(emac->spi_lock, "create lock failed", err, NULL);
/* create dm9051 task */
BaseType_t xReturned = xTaskCreate(emac_dm9051_task, "dm9051_tsk", mac_config->rx_task_stack_size, emac,
mac_config->rx_task_prio, &emac->rx_task_hdl);
MAC_CHECK(xReturned == pdPASS, "create dm9051 task failed", err_tsk, NULL);
MAC_CHECK(xReturned == pdPASS, "create dm9051 task failed", err, NULL);
return &(emac->parent);
err_tsk:
vSemaphoreDelete(emac->spi_lock);
err_lock:
free(emac);
err:
if (emac) {
if (emac->rx_task_hdl) {
vTaskDelete(emac->rx_task_hdl);
}
if (emac->spi_lock) {
vSemaphoreDelete(emac->spi_lock);
}
free(emac);
}
return ret;
}

View File

@@ -40,7 +40,6 @@ static const char *TAG = "emac_esp32";
} \
} while (0)
#define RX_QUEUE_WAIT_MS (20)
#define PHY_OPERATION_TIMEOUT_US (1000)
typedef struct {
@@ -224,7 +223,16 @@ static esp_err_t emac_esp32_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t *
esp_err_t ret = ESP_OK;
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
MAC_CHECK(buf && length, "can't set buf and length to null", err, ESP_ERR_INVALID_ARG);
*length = emac_hal_receive_frame(&emac->hal, buf, &emac->frames_remain);
uint32_t receive_len = emac_hal_receive_frame(&emac->hal, buf, *length, &emac->frames_remain);
/* we need to check the return value in case the buffer size is not enough */
if (*length < receive_len) {
ESP_LOGE(TAG, "buffer size too small");
/* tell upper layer the size we need */
*length = receive_len;
ret = ESP_ERR_INVALID_SIZE;
goto err;
}
*length = receive_len;
return ESP_OK;
err:
return ret;
@@ -236,21 +244,22 @@ static void emac_esp32_rx_task(void *arg)
uint8_t *buffer = NULL;
uint32_t length = 0;
while (1) {
if (ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(RX_QUEUE_WAIT_MS))) {
do {
buffer = (uint8_t *)malloc(ETH_MAX_PACKET_SIZE);
if (emac_esp32_receive(&emac->parent, buffer, &length) == ESP_OK) {
/* pass the buffer to stack (e.g. TCP/IP layer) */
if (length) {
emac->eth->stack_input(emac->eth, buffer, length);
} else {
free(buffer);
}
// block indefinitely until some task notifies me
ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
do {
length = ETH_MAX_PACKET_SIZE;
buffer = (uint8_t *)malloc(length);
if (emac_esp32_receive(&emac->parent, buffer, &length) == ESP_OK) {
/* pass the buffer to stack (e.g. TCP/IP layer) */
if (length) {
emac->eth->stack_input(emac->eth, buffer, length);
} else {
free(buffer);
}
} while (emac->frames_remain);
}
} else {
free(buffer);
}
} while (emac->frames_remain);
}
vTaskDelete(NULL);
}
@@ -358,43 +367,30 @@ void emac_esp32_isr_handler(void *args)
esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config)
{
esp_eth_mac_t *ret = NULL;
void *descriptors = NULL;
emac_esp32_t *emac = NULL;
MAC_CHECK(config, "can't set mac config to null", err, NULL);
emac_esp32_t *emac = calloc(1, sizeof(emac_esp32_t));
emac = calloc(1, sizeof(emac_esp32_t));
MAC_CHECK(emac, "calloc emac failed", err, NULL);
/* alloc memory for ethernet dma descriptor */
uint32_t desc_size = CONFIG_ETH_DMA_RX_BUFFER_NUM * sizeof(eth_dma_rx_descriptor_t) +
CONFIG_ETH_DMA_TX_BUFFER_NUM * sizeof(eth_dma_tx_descriptor_t);
void *descriptors = heap_caps_calloc(1, desc_size, MALLOC_CAP_DMA);
MAC_CHECK(descriptors, "calloc descriptors failed", err_desc, NULL);
descriptors = heap_caps_calloc(1, desc_size, MALLOC_CAP_DMA);
MAC_CHECK(descriptors, "calloc descriptors failed", err, NULL);
int i = 0;
/* alloc memory for ethernet dma buffer */
for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
emac->rx_buf[i] = heap_caps_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, MALLOC_CAP_DMA);
if (!(emac->rx_buf[i])) {
break;
goto err;
}
}
if (i != CONFIG_ETH_DMA_RX_BUFFER_NUM) {
for (--i; i >= 0; i--) {
free(emac->rx_buf[i]);
}
goto err_buffer;
}
for (i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
emac->tx_buf[i] = heap_caps_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, MALLOC_CAP_DMA);
if (!(emac->tx_buf[i])) {
break;
goto err;
}
}
if (i != CONFIG_ETH_DMA_TX_BUFFER_NUM) {
for (--i; i >= 0; i--) {
free(emac->tx_buf[i]);
}
for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
free(emac->rx_buf[i]);
}
goto err_buffer;
}
/* initialize hal layer driver */
emac_hal_init(&emac->hal, descriptors, emac->rx_buf, emac->tx_buf);
emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms;
@@ -415,26 +411,32 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config)
/* Interrupt configuration */
MAC_CHECK(esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, ESP_INTR_FLAG_IRAM, emac_esp32_isr_handler,
&emac->hal, &(emac->intr_hdl)) == ESP_OK,
"alloc emac interrupt failed", err_intr, NULL);
"alloc emac interrupt failed", err, NULL);
/* create rx task */
BaseType_t xReturned = xTaskCreate(emac_esp32_rx_task, "emac_rx", config->rx_task_stack_size, emac,
config->rx_task_prio, &emac->rx_task_hdl);
MAC_CHECK(xReturned == pdPASS, "create emac_rx task failed", err_task, NULL);
MAC_CHECK(xReturned == pdPASS, "create emac_rx task failed", err, NULL);
return &(emac->parent);
err_task:
esp_intr_free(emac->intr_hdl);
err_intr:
for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
free(emac->tx_buf[i]);
}
for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
free(emac->rx_buf[i]);
}
err_buffer:
free(descriptors);
err_desc:
free(emac);
err:
if (emac) {
if (emac->rx_task_hdl) {
vTaskDelete(emac->rx_task_hdl);
}
if (emac->intr_hdl) {
esp_intr_free(emac->intr_hdl);
}
for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
free(emac->tx_buf[i]);
}
for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
free(emac->rx_buf[i]);
}
free(emac);
}
if (descriptors) {
free(descriptors);
}
return ret;
}

View File

@@ -79,16 +79,55 @@ typedef union {
typedef struct {
esp_eth_phy_t parent;
esp_eth_mediator_t *eth;
const char *name;
uint32_t addr;
uint32_t reset_timeout_ms;
uint32_t autonego_timeout_ms;
eth_link_t link_status;
} phy_dm9051_t;
static esp_err_t dm9051_update_link_duplex_speed(phy_dm9051_t *dm9051)
{
esp_eth_mediator_t *eth = dm9051->eth;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
bmsr_reg_t bmsr;
dscsr_reg_t dscsr;
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
/* check if link status changed */
if (dm9051->link_status != link) {
/* when link up, read negotiation result */
if (link == ETH_LINK_UP) {
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCSR_REG_ADDR, &(dscsr.val)) == ESP_OK,
"read DSCSR failed", err);
if (dscsr.fdx100 || dscsr.hdx100) {
speed = ETH_SPEED_100M;
} else {
speed = ETH_SPEED_10M;
}
if (dscsr.fdx100 || dscsr.fdx10) {
duplex = ETH_DUPLEX_FULL;
} else {
duplex = ETH_DUPLEX_HALF;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK,
"change speed failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK,
"change duplex failed", err);
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK,
"change link failed", err);
dm9051->link_status = link;
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t dm9051_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
PHY_CHECK(eth, "can't set mediator for dm9051 to null", err);
PHY_CHECK(eth, "can't set mediator to null", err);
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
dm9051->eth = eth;
return ESP_OK;
@@ -99,19 +138,8 @@ err:
static esp_err_t dm9051_get_link(esp_eth_phy_t *phy)
{
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
esp_eth_mediator_t *eth = dm9051->eth;
bmsr_reg_t bmsr;
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
if (dm9051->link_status != link) {
if (link == ETH_LINK_UP) {
phy->negotiate(phy);
} else {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
dm9051->link_status = link;
}
}
/* Updata information about link, speed, duplex */
PHY_CHECK(dm9051_update_link_duplex_speed(dm9051) == ESP_OK, "update link duplex speed failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -122,17 +150,22 @@ static esp_err_t dm9051_reset(esp_eth_phy_t *phy)
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
esp_eth_mediator_t *eth = dm9051->eth;
dscr_reg_t dscr;
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)) == ESP_OK, "read DSCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)) == ESP_OK,
"read DSCR failed", err);
dscr.smrst = 1;
PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, dscr.val) == ESP_OK, "write DSCR failed", err);
PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, dscr.val) == ESP_OK,
"write DSCR failed", err);
bmcr_reg_t bmcr = {.reset = 1};
PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
/* Wait for reset complete */
uint32_t to = 0;
for (to = 0; to < dm9051->reset_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)) == ESP_OK, "read DSCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)) == ESP_OK,
"read DSCR failed", err);
if (!bmcr.reset && !dscr.smrst) {
break;
}
@@ -154,15 +187,18 @@ static esp_err_t dm9051_negotiate(esp_eth_phy_t *phy)
.en_auto_nego = 1, /* Auto Negotiation */
.restart_auto_nego = 1 /* Restart Auto Negotiation */
};
PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
/* Wait for auto negotiation complete */
bmsr_reg_t bmsr;
dscsr_reg_t dscsr;
uint32_t to = 0;
for (to = 0; to < dm9051->autonego_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCSR_REG_ADDR, &(dscsr.val)) == ESP_OK, "read DSCSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCSR_REG_ADDR, &(dscsr.val)) == ESP_OK,
"read DSCSR failed", err);
if (bmsr.auto_nego_complete && dscsr.anmb & 0x08) {
break;
}
@@ -171,27 +207,7 @@ static esp_err_t dm9051_negotiate(esp_eth_phy_t *phy)
ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout");
}
/* Updata information about link, speed, duplex */
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCSR_REG_ADDR, &(dscsr.val)) == ESP_OK, "read DSCSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
if (dscsr.fdx100 || dscsr.hdx100) {
speed = ETH_SPEED_100M;
} else {
speed = ETH_SPEED_10M;
}
if (dscsr.fdx100 || dscsr.fdx10) {
duplex = ETH_DUPLEX_FULL;
} else {
duplex = ETH_DUPLEX_HALF;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err);
if (dm9051->link_status != link) {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
dm9051->link_status = link;
}
PHY_CHECK(dm9051_update_link_duplex_speed(dm9051) == ESP_OK, "update link duplex speed failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -202,7 +218,8 @@ static esp_err_t dm9051_pwrctl(esp_eth_phy_t *phy, bool enable)
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
esp_eth_mediator_t *eth = dm9051->eth;
bmcr_reg_t bmcr;
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!enable) {
/* Enable IEEE Power Down Mode */
bmcr.power_down = 1;
@@ -210,8 +227,10 @@ static esp_err_t dm9051_pwrctl(esp_eth_phy_t *phy, bool enable)
/* Disable IEEE Power Down Mode */
bmcr.power_down = 0;
}
PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!enable) {
PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
} else {
@@ -231,7 +250,7 @@ static esp_err_t dm9051_set_addr(esp_eth_phy_t *phy, uint32_t addr)
static esp_err_t dm9051_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
{
PHY_CHECK(addr, "get phy address failed", err);
PHY_CHECK(addr, "addr can't be null", err);
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
*addr = dm9051->addr;
return ESP_OK;
@@ -251,15 +270,18 @@ static esp_err_t dm9051_init(esp_eth_phy_t *phy)
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
esp_eth_mediator_t *eth = dm9051->eth;
/* Power on Ethernet PHY */
PHY_CHECK(dm9051_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err);
PHY_CHECK(dm9051_pwrctl(phy, true) == ESP_OK, "power control failed", err);
/* Reset Ethernet PHY */
PHY_CHECK(dm9051_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err);
PHY_CHECK(dm9051_reset(phy) == ESP_OK, "reset failed", err);
/* Check PHY ID */
phyidr1_reg_t id1;
phyidr2_reg_t id2;
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err);
PHY_CHECK(id1.oui_msb == 0x0181 && id2.oui_lsb == 0x2E && id2.vendor_model == 0x0A, "wrong PHY chip ID", err);
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK,
"read ID1 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK,
"read ID2 failed", err);
PHY_CHECK(id1.oui_msb == 0x0181 && id2.oui_lsb == 0x2E && id2.vendor_model == 0x0A,
"wrong chip ID", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -268,7 +290,7 @@ err:
static esp_err_t dm9051_deinit(esp_eth_phy_t *phy)
{
/* Power off Ethernet PHY */
PHY_CHECK(dm9051_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err);
PHY_CHECK(dm9051_pwrctl(phy, false) == ESP_OK, "power control failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -279,8 +301,7 @@ esp_eth_phy_t *esp_eth_phy_new_dm9051(const eth_phy_config_t *config)
PHY_CHECK(config, "can't set phy config to null", err);
PHY_CHECK(config->phy_addr == 1, "dm9051's phy address can only set to 1", err);
phy_dm9051_t *dm9051 = calloc(1, sizeof(phy_dm9051_t));
PHY_CHECK(dm9051, "calloc dm9051 object failed", err);
dm9051->name = "dm9051";
PHY_CHECK(dm9051, "calloc dm9051 failed", err);
dm9051->addr = config->phy_addr;
dm9051->reset_timeout_ms = config->reset_timeout_ms;
dm9051->link_status = ETH_LINK_DOWN;
@@ -295,7 +316,6 @@ esp_eth_phy_t *esp_eth_phy_new_dm9051(const eth_phy_config_t *config)
dm9051->parent.get_addr = dm9051_get_addr;
dm9051->parent.set_addr = dm9051_set_addr;
dm9051->parent.del = dm9051_del;
return &(dm9051->parent);
err:
return NULL;

View File

@@ -85,16 +85,55 @@ typedef union {
typedef struct {
esp_eth_phy_t parent;
esp_eth_mediator_t *eth;
const char *name;
uint32_t addr;
uint32_t reset_timeout_ms;
uint32_t autonego_timeout_ms;
eth_link_t link_status;
} phy_dp83848_t;
static esp_err_t dp83848_update_link_duplex_speed(phy_dp83848_t *dp83848)
{
esp_eth_mediator_t *eth = dp83848->eth;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
bmsr_reg_t bmsr;
physts_reg_t physts;
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
/* check if link status changed */
if (dp83848->link_status != link) {
/* when link up, read negotiation result */
if (link == ETH_LINK_UP) {
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_STS_REG_ADDR, &(physts.val)) == ESP_OK,
"read PHYSTS failed", err);
if (physts.speed_status) {
speed = ETH_SPEED_10M;
} else {
speed = ETH_SPEED_100M;
}
if (physts.duplex_status) {
duplex = ETH_DUPLEX_FULL;
} else {
duplex = ETH_DUPLEX_HALF;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK,
"change speed failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK,
"change duplex failed", err);
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK,
"change link failed", err);
dp83848->link_status = link;
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t dp83848_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
PHY_CHECK(eth, "can't set mediator for dp83848 to null", err);
PHY_CHECK(eth, "can't set mediator to null", err);
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
dp83848->eth = eth;
return ESP_OK;
@@ -105,19 +144,8 @@ err:
static esp_err_t dp83848_get_link(esp_eth_phy_t *phy)
{
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
esp_eth_mediator_t *eth = dp83848->eth;
bmsr_reg_t bmsr;
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
if (dp83848->link_status != link) {
if (link == ETH_LINK_UP) {
phy->negotiate(phy);
} else {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
dp83848->link_status = link;
}
}
/* Updata information about link, speed, duplex */
PHY_CHECK(dp83848_update_link_duplex_speed(dp83848) == ESP_OK, "update link duplex speed failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -128,17 +156,19 @@ static esp_err_t dp83848_reset(esp_eth_phy_t *phy)
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
esp_eth_mediator_t *eth = dp83848->eth;
bmcr_reg_t bmcr = {.reset = 1};
PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
/* Wait for reset complete */
uint32_t to = 0;
for (to = 0; to < dp83848->reset_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!bmcr.reset) {
break;
}
}
PHY_CHECK(to < dp83848->reset_timeout_ms / 10, "PHY reset timeout", err);
PHY_CHECK(to < dp83848->reset_timeout_ms / 10, "reset timeout", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -155,45 +185,28 @@ static esp_err_t dp83848_negotiate(esp_eth_phy_t *phy)
.en_auto_nego = 1, /* Auto Negotiation */
.restart_auto_nego = 1 /* Restart Auto Negotiation */
};
PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
/* Wait for auto negotiation complete */
bmsr_reg_t bmsr;
physts_reg_t physts;
uint32_t to = 0;
for (to = 0; to < dp83848->autonego_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_STS_REG_ADDR, &(physts.val)) == ESP_OK, "read PHYSTS failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_STS_REG_ADDR, &(physts.val)) == ESP_OK,
"read PHYSTS failed", err);
if (bmsr.auto_nego_complete && physts.auto_nego_complete) {
break;
}
}
/* Auto negotiation failed, maybe no network cable plugged in, so output a warning */
if (to >= dp83848->autonego_timeout_ms / 10) {
ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout");
ESP_LOGW(TAG, "auto negotiation timeout");
}
/* Updata information about link, speed, duplex */
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_STS_REG_ADDR, &(physts.val)) == ESP_OK, "read PHYSTS failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
if (physts.speed_status) {
speed = ETH_SPEED_10M;
} else {
speed = ETH_SPEED_100M;
}
if (physts.duplex_status) {
duplex = ETH_DUPLEX_FULL;
} else {
duplex = ETH_DUPLEX_HALF;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err);
if (dp83848->link_status != link) {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
dp83848->link_status = link;
}
PHY_CHECK(dp83848_update_link_duplex_speed(dp83848) == ESP_OK, "update link duplex speed failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -204,7 +217,8 @@ static esp_err_t dp83848_pwrctl(esp_eth_phy_t *phy, bool enable)
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
esp_eth_mediator_t *eth = dp83848->eth;
bmcr_reg_t bmcr;
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!enable) {
/* Enable IEEE Power Down Mode */
bmcr.power_down = 1;
@@ -212,8 +226,10 @@ static esp_err_t dp83848_pwrctl(esp_eth_phy_t *phy, bool enable)
/* Disable IEEE Power Down Mode */
bmcr.power_down = 0;
}
PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!enable) {
PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
} else {
@@ -233,7 +249,7 @@ static esp_err_t dp83848_set_addr(esp_eth_phy_t *phy, uint32_t addr)
static esp_err_t dp83848_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
{
PHY_CHECK(addr, "get phy address failed", err);
PHY_CHECK(addr, "addr can't be null", err);
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
*addr = dp83848->addr;
return ESP_OK;
@@ -253,15 +269,18 @@ static esp_err_t dp83848_init(esp_eth_phy_t *phy)
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
esp_eth_mediator_t *eth = dp83848->eth;
/* Power on Ethernet PHY */
PHY_CHECK(dp83848_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err);
PHY_CHECK(dp83848_pwrctl(phy, true) == ESP_OK, "power control failed", err);
/* Reset Ethernet PHY */
PHY_CHECK(dp83848_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err);
PHY_CHECK(dp83848_reset(phy) == ESP_OK, "reset failed", err);
/* Check PHY ID */
phyidr1_reg_t id1;
phyidr2_reg_t id2;
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err);
PHY_CHECK(id1.oui_msb == 0x2000 && id2.oui_lsb == 0x17 && id2.vendor_model == 0x09, "wrong PHY chip ID", err);
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK,
"read ID1 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK,
"read ID2 failed", err);
PHY_CHECK(id1.oui_msb == 0x2000 && id2.oui_lsb == 0x17 && id2.vendor_model == 0x09,
"wrong chip ID", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -270,7 +289,7 @@ err:
static esp_err_t dp83848_deinit(esp_eth_phy_t *phy)
{
/* Power off Ethernet PHY */
PHY_CHECK(dp83848_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err);
PHY_CHECK(dp83848_pwrctl(phy, false) == ESP_OK, "power control failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -280,8 +299,7 @@ esp_eth_phy_t *esp_eth_phy_new_dp83848(const eth_phy_config_t *config)
{
PHY_CHECK(config, "can't set phy config to null", err);
phy_dp83848_t *dp83848 = calloc(1, sizeof(phy_dp83848_t));
PHY_CHECK(dp83848, "calloc dp83848 object failed", err);
dp83848->name = "dp83848";
PHY_CHECK(dp83848, "calloc dp83848 failed", err);
dp83848->addr = config->phy_addr;
dp83848->reset_timeout_ms = config->reset_timeout_ms;
dp83848->link_status = ETH_LINK_DOWN;

View File

@@ -102,7 +102,6 @@ typedef union {
typedef struct {
esp_eth_phy_t parent;
esp_eth_mediator_t *eth;
const char *name;
uint32_t addr;
uint32_t reset_timeout_ms;
uint32_t autonego_timeout_ms;
@@ -121,9 +120,60 @@ err:
return ESP_FAIL;
}
static esp_err_t ip101_update_link_duplex_speed(phy_ip101_t *ip101)
{
esp_eth_mediator_t *eth = ip101->eth;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
cssr_reg_t cssr;
bmsr_reg_t bmsr;
PHY_CHECK(ip101_page_select(ip101, 16) == ESP_OK, "select page 16 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
/* check if link status changed */
if (ip101->link_status != link) {
/* when link up, read negotiation result */
if (link == ETH_LINK_UP) {
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_CSSR_REG_ADDR, &(cssr.val)) == ESP_OK,
"read CSSR failed", err);
switch (cssr.op_mode) {
case 1: //10M Half
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_HALF;
break;
case 2: //100M Half
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_HALF;
break;
case 5: //10M Full
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_FULL;
break;
case 6: //100M Full
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_FULL;
break;
default:
break;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK,
"change speed failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK,
"change duplex failed", err);
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK,
"chagne link failed", err);
ip101->link_status = link;
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t ip101_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
PHY_CHECK(eth, "can't set mediator for ip101 to null", err);
PHY_CHECK(eth, "can't set mediator to null", err);
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
ip101->eth = eth;
return ESP_OK;
@@ -134,19 +184,8 @@ err:
static esp_err_t ip101_get_link(esp_eth_phy_t *phy)
{
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
esp_eth_mediator_t *eth = ip101->eth;
bmsr_reg_t bmsr;
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
if (ip101->link_status != link) {
if (link == ETH_LINK_UP) {
phy->negotiate(phy);
} else {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
ip101->link_status = link;
}
}
/* Updata information about link, speed, duplex */
PHY_CHECK(ip101_update_link_duplex_speed(ip101) == ESP_OK, "update link duplex speed failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -157,17 +196,19 @@ static esp_err_t ip101_reset(esp_eth_phy_t *phy)
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
esp_eth_mediator_t *eth = ip101->eth;
bmcr_reg_t bmcr = {.reset = 1};
PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
/* wait for reset complete */
uint32_t to = 0;
uint32_t to = 0;
for (to = 0; to < ip101->reset_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!bmcr.reset) {
break;
}
}
PHY_CHECK(to < ip101->reset_timeout_ms / 10, "PHY reset timeout", err);
PHY_CHECK(to < ip101->reset_timeout_ms / 10, "reset timeout", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -177,65 +218,32 @@ static esp_err_t ip101_negotiate(esp_eth_phy_t *phy)
{
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
esp_eth_mediator_t *eth = ip101->eth;
/* Start auto negotiation */
/* Restart auto negotiation */
bmcr_reg_t bmcr = {
.speed_select = 1, /* 100Mbps */
.duplex_mode = 1, /* Full Duplex */
.en_auto_nego = 1, /* Auto Negotiation */
.restart_auto_nego = 1 /* Restart Auto Negotiation */
};
PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
/* Wait for auto negotiation complete */
bmsr_reg_t bmsr;
uint32_t to = 0;
for (to = 0; to < ip101->autonego_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
if (bmsr.auto_nego_complete) {
break;
}
}
/* Auto negotiation failed, maybe no network cable plugged in, so output a warning */
if (to >= ip101->autonego_timeout_ms / 10) {
ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout");
ESP_LOGW(TAG, "auto negotiation timeout");
}
PHY_CHECK(ip101_page_select(ip101, 16) == ESP_OK, "select page failed", err);
/* Updata information about link, speed, duplex */
cssr_reg_t cssr;
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_CSSR_REG_ADDR, &(cssr.val)) == ESP_OK, "read CSSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
switch (cssr.op_mode) {
case 0: //Link off
link = ETH_LINK_DOWN;
break;
case 1: //10M Half
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_HALF;
break;
case 2: //100M Half
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_HALF;
break;
case 5: //10M Full
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_FULL;
break;
case 6: //100M Full
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_FULL;
break;
default:
break;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err);
if (ip101->link_status != link) {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
ip101->link_status = link;
}
PHY_CHECK(ip101_update_link_duplex_speed(ip101) == ESP_OK, "update link duplex speed failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -246,7 +254,8 @@ static esp_err_t ip101_pwrctl(esp_eth_phy_t *phy, bool enable)
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
esp_eth_mediator_t *eth = ip101->eth;
bmcr_reg_t bmcr;
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!enable) {
/* Enable IEEE Power Down Mode */
bmcr.power_down = 1;
@@ -254,8 +263,10 @@ static esp_err_t ip101_pwrctl(esp_eth_phy_t *phy, bool enable)
/* Disable IEEE Power Down Mode */
bmcr.power_down = 0;
}
PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!enable) {
PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
} else {
@@ -275,7 +286,7 @@ static esp_err_t ip101_set_addr(esp_eth_phy_t *phy, uint32_t addr)
static esp_err_t ip101_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
{
PHY_CHECK(addr, "get phy address failed", err);
PHY_CHECK(addr, "addr can't be null", err);
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
*addr = ip101->addr;
return ESP_OK;
@@ -295,15 +306,15 @@ static esp_err_t ip101_init(esp_eth_phy_t *phy)
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
esp_eth_mediator_t *eth = ip101->eth;
/* Power on Ethernet PHY */
PHY_CHECK(ip101_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err);
PHY_CHECK(ip101_pwrctl(phy, true) == ESP_OK, "power control failed", err);
/* Reset Ethernet PHY */
PHY_CHECK(ip101_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err);
PHY_CHECK(ip101_reset(phy) == ESP_OK, "reset failed", err);
/* Check PHY ID */
phyidr1_reg_t id1;
phyidr2_reg_t id2;
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err);
PHY_CHECK(id1.oui_msb == 0x243 && id2.oui_lsb == 0x3 && id2.vendor_model == 0x5, "wrong PHY chip ID", err);
PHY_CHECK(id1.oui_msb == 0x243 && id2.oui_lsb == 0x3 && id2.vendor_model == 0x5, "wrong chip ID", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -312,7 +323,7 @@ err:
static esp_err_t ip101_deinit(esp_eth_phy_t *phy)
{
/* Power off Ethernet PHY */
PHY_CHECK(ip101_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err);
PHY_CHECK(ip101_pwrctl(phy, false) == ESP_OK, "power control failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -322,8 +333,7 @@ esp_eth_phy_t *esp_eth_phy_new_ip101(const eth_phy_config_t *config)
{
PHY_CHECK(config, "can't set phy config to null", err);
phy_ip101_t *ip101 = calloc(1, sizeof(phy_ip101_t));
PHY_CHECK(ip101, "calloc ip101 object failed", err);
ip101->name = "ip101";
PHY_CHECK(ip101, "calloc ip101 failed", err);
ip101->addr = config->phy_addr;
ip101->reset_timeout_ms = config->reset_timeout_ms;
ip101->link_status = ETH_LINK_DOWN;

View File

@@ -157,16 +157,65 @@ typedef union {
typedef struct {
esp_eth_phy_t parent;
esp_eth_mediator_t *eth;
const char *name;
uint32_t addr;
uint32_t reset_timeout_ms;
uint32_t autonego_timeout_ms;
eth_link_t link_status;
} phy_lan8720_t;
static esp_err_t lan8720_update_link_duplex_speed(phy_lan8720_t *lan8720)
{
esp_eth_mediator_t *eth = lan8720->eth;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
bmsr_reg_t bmsr;
pscsr_reg_t pscsr;
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
/* check if link status changed */
if (lan8720->link_status != link) {
/* when link up, read negotiation result */
if (link == ETH_LINK_UP) {
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_PSCSR_REG_ADDR, &(pscsr.val)) == ESP_OK,
"read PSCSR failed", err);
switch (pscsr.speed_indication) {
case 1: //10Base-T half-duplex
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_HALF;
break;
case 2: //100Base-TX half-duplex
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_HALF;
break;
case 5: //10Base-T full-duplex
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_FULL;
break;
case 6: //100Base-TX full-duplex
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_FULL;
break;
default:
break;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK,
"change speed failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK,
"change duplex failed", err);
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK,
"change link failed", err);
lan8720->link_status = link;
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t lan8720_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
PHY_CHECK(eth, "can't set mediator for lan8720 to null", err);
PHY_CHECK(eth, "can't set mediator to null", err);
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
lan8720->eth = eth;
return ESP_OK;
@@ -177,19 +226,8 @@ err:
static esp_err_t lan8720_get_link(esp_eth_phy_t *phy)
{
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
esp_eth_mediator_t *eth = lan8720->eth;
bmsr_reg_t bmsr;
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
if (lan8720->link_status != link) {
if (link == ETH_LINK_UP) {
phy->negotiate(phy);
} else {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
lan8720->link_status = link;
}
}
/* Updata information about link, speed, duplex */
PHY_CHECK(lan8720_update_link_duplex_speed(lan8720) == ESP_OK, "update link duplex speed failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -200,17 +238,19 @@ static esp_err_t lan8720_reset(esp_eth_phy_t *phy)
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
esp_eth_mediator_t *eth = lan8720->eth;
bmcr_reg_t bmcr = {.reset = 1};
PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
/* wait for reset complete */
uint32_t to = 0;
for (to = 0; to < lan8720->reset_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!bmcr.reset) {
break;
}
}
PHY_CHECK(to < lan8720->reset_timeout_ms / 10, "PHY reset timeout", err);
PHY_CHECK(to < lan8720->reset_timeout_ms / 10, "reset timeout", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -220,7 +260,7 @@ static esp_err_t lan8720_negotiate(esp_eth_phy_t *phy)
{
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
esp_eth_mediator_t *eth = lan8720->eth;
/* Start auto negotiation */
/* Restart auto negotiation */
bmcr_reg_t bmcr = {
.speed_select = 1, /* 100Mbps */
.duplex_mode = 1, /* Full Duplex */
@@ -234,48 +274,20 @@ static esp_err_t lan8720_negotiate(esp_eth_phy_t *phy)
int32_t to = 0;
for (to = 0; to < lan8720->autonego_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_PSCSR_REG_ADDR, &(pscsr.val)) == ESP_OK, "read PSCSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_PSCSR_REG_ADDR, &(pscsr.val)) == ESP_OK,
"read PSCSR failed", err);
if (bmsr.auto_nego_complete && pscsr.auto_nego_done) {
break;
}
}
/* Auto negotiation failed, maybe no network cable plugged in, so output a warning */
if (to >= lan8720->autonego_timeout_ms / 10) {
ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout");
ESP_LOGW(TAG, "auto negotiation timeout");
}
/* Updata information about link, speed, duplex */
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_PSCSR_REG_ADDR, &(pscsr.val)) == ESP_OK, "read PSCSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
switch (pscsr.speed_indication) {
case 1: //10Base-T half-duplex
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_HALF;
break;
case 2: //100Base-TX half-duplex
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_HALF;
break;
case 5: //10Base-T full-duplex
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_FULL;
break;
case 6: //100Base-TX full-duplex
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_FULL;
break;
default:
break;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err);
if (lan8720->link_status != link) {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
lan8720->link_status = link;
}
PHY_CHECK(lan8720_update_link_duplex_speed(lan8720) == ESP_OK, "update link duplex speed failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -286,7 +298,8 @@ static esp_err_t lan8720_pwrctl(esp_eth_phy_t *phy, bool enable)
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
esp_eth_mediator_t *eth = lan8720->eth;
bmcr_reg_t bmcr;
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!enable) {
/* General Power Down Mode */
bmcr.power_down = 1;
@@ -294,8 +307,10 @@ static esp_err_t lan8720_pwrctl(esp_eth_phy_t *phy, bool enable)
/* Normal operation Mode */
bmcr.power_down = 0;
}
PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!enable) {
PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
} else {
@@ -315,7 +330,7 @@ static esp_err_t lan8720_set_addr(esp_eth_phy_t *phy, uint32_t addr)
static esp_err_t lan8720_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
{
PHY_CHECK(addr, "get phy address failed", err);
PHY_CHECK(addr, "addr can't be null", err);
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
*addr = lan8720->addr;
return ESP_OK;
@@ -335,15 +350,17 @@ static esp_err_t lan8720_init(esp_eth_phy_t *phy)
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
esp_eth_mediator_t *eth = lan8720->eth;
/* Power on Ethernet PHY */
PHY_CHECK(lan8720_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err);
PHY_CHECK(lan8720_pwrctl(phy, true) == ESP_OK, "power control failed", err);
/* Reset Ethernet PHY */
PHY_CHECK(lan8720_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err);
PHY_CHECK(lan8720_reset(phy) == ESP_OK, "reset failed", err);
/* Check PHY ID */
phyidr1_reg_t id1;
phyidr2_reg_t id2;
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err);
PHY_CHECK(id1.oui_msb == 0x7 && id2.oui_lsb == 0x30 && id2.vendor_model == 0xF, "wrong PHY chip ID", err);
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK,
"read ID1 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK,
"read ID2 failed", err);
PHY_CHECK(id1.oui_msb == 0x7 && id2.oui_lsb == 0x30 && id2.vendor_model == 0xF, "wrong chip ID", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -352,7 +369,7 @@ err:
static esp_err_t lan8720_deinit(esp_eth_phy_t *phy)
{
/* Power off Ethernet PHY */
PHY_CHECK(lan8720_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err);
PHY_CHECK(lan8720_pwrctl(phy, false) == ESP_OK, "power control failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -362,8 +379,7 @@ esp_eth_phy_t *esp_eth_phy_new_lan8720(const eth_phy_config_t *config)
{
PHY_CHECK(config, "can't set phy config to null", err);
phy_lan8720_t *lan8720 = calloc(1, sizeof(phy_lan8720_t));
PHY_CHECK(lan8720, "calloc lan8720 object failed", err);
lan8720->name = "lan8720";
PHY_CHECK(lan8720, "calloc lan8720 failed", err);
lan8720->addr = config->phy_addr;
lan8720->reset_timeout_ms = config->reset_timeout_ms;
lan8720->link_status = ETH_LINK_DOWN;

View File

@@ -63,7 +63,6 @@ typedef union {
typedef struct {
esp_eth_phy_t parent;
esp_eth_mediator_t *eth;
const char *name;
uint32_t addr;
uint32_t reset_timeout_ms;
uint32_t autonego_timeout_ms;
@@ -82,9 +81,50 @@ err:
return ESP_FAIL;
}
static esp_err_t rtl8201_update_link_duplex_speed(phy_rtl8201_t *rtl8201)
{
esp_eth_mediator_t *eth = rtl8201->eth;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
bmcr_reg_t bmcr;
bmsr_reg_t bmsr;
PHY_CHECK(rtl8201_page_select(rtl8201, 0) == ESP_OK, "select page 0 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
/* check if link status changed */
if (rtl8201->link_status != link) {
/* when link up, read negotiation result */
if (link == ETH_LINK_UP) {
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (bmcr.speed_select) {
speed = ETH_SPEED_100M;
} else {
speed = ETH_SPEED_10M;
}
if (bmcr.duplex_mode) {
duplex = ETH_DUPLEX_FULL;
} else {
duplex = ETH_DUPLEX_HALF;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK,
"change speed failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK,
"change duplex failed", err);
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK,
"change link failed", err);
rtl8201->link_status = link;
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t rtl8201_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
PHY_CHECK(eth, "can't set mediator for rtl8201 to null", err);
PHY_CHECK(eth, "can't set mediator to null", err);
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
rtl8201->eth = eth;
return ESP_OK;
@@ -95,19 +135,8 @@ err:
static esp_err_t rtl8201_get_link(esp_eth_phy_t *phy)
{
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
esp_eth_mediator_t *eth = rtl8201->eth;
bmsr_reg_t bmsr;
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
if (rtl8201->link_status != link) {
if (link == ETH_LINK_UP) {
phy->negotiate(phy);
} else {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
rtl8201->link_status = link;
}
}
/* Updata information about link, speed, duplex */
PHY_CHECK(rtl8201_update_link_duplex_speed(rtl8201) == ESP_OK, "update link duplex speed failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -118,17 +147,19 @@ static esp_err_t rtl8201_reset(esp_eth_phy_t *phy)
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
esp_eth_mediator_t *eth = rtl8201->eth;
bmcr_reg_t bmcr = {.reset = 1};
PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
/* Wait for reset complete */
uint32_t to = 0;
for (to = 0; to < rtl8201->reset_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!bmcr.reset) {
break;
}
}
PHY_CHECK(to < rtl8201->reset_timeout_ms / 10, "PHY reset timeout", err);
PHY_CHECK(to < rtl8201->reset_timeout_ms / 10, "reset timeout", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -138,51 +169,32 @@ static esp_err_t rtl8201_negotiate(esp_eth_phy_t *phy)
{
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
esp_eth_mediator_t *eth = rtl8201->eth;
/* Start auto negotiation */
/* Restart auto negotiation */
bmcr_reg_t bmcr = {
.speed_select = 1, /* 100Mbps */
.duplex_mode = 1, /* Full Duplex */
.en_auto_nego = 1, /* Auto Negotiation */
.restart_auto_nego = 1 /* Restart Auto Negotiation */
};
PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
/* Wait for auto negotiation complete */
bmsr_reg_t bmsr;
uint32_t to = 0;
for (to = 0; to < rtl8201->autonego_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
if (bmsr.auto_nego_complete) {
break;
}
}
/* Auto negotiation failed, maybe no network cable plugged in, so output a warning */
if (to >= rtl8201->autonego_timeout_ms / 10) {
ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout");
ESP_LOGW(TAG, "auto negotiation timeout");
}
PHY_CHECK(rtl8201_page_select(rtl8201, 0) == ESP_OK, "select page failed", err);
/* Updata information about link, speed, duplex */
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
if (bmcr.speed_select) {
speed = ETH_SPEED_100M;
} else {
speed = ETH_SPEED_10M;
}
if (bmcr.duplex_mode) {
duplex = ETH_DUPLEX_FULL;
} else {
duplex = ETH_DUPLEX_HALF;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err);
if (rtl8201->link_status != link) {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
rtl8201->link_status = link;
}
PHY_CHECK(rtl8201_update_link_duplex_speed(rtl8201) == ESP_OK, "update link duplex speed failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -193,7 +205,8 @@ static esp_err_t rtl8201_pwrctl(esp_eth_phy_t *phy, bool enable)
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
esp_eth_mediator_t *eth = rtl8201->eth;
bmcr_reg_t bmcr;
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!enable) {
/* Enable IEEE Power Down Mode */
bmcr.power_down = 1;
@@ -201,8 +214,10 @@ static esp_err_t rtl8201_pwrctl(esp_eth_phy_t *phy, bool enable)
/* Disable IEEE Power Down Mode */
bmcr.power_down = 0;
}
PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!enable) {
PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
} else {
@@ -222,7 +237,7 @@ static esp_err_t rtl8201_set_addr(esp_eth_phy_t *phy, uint32_t addr)
static esp_err_t rtl8201_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
{
PHY_CHECK(addr, "get phy address failed", err);
PHY_CHECK(addr, "addr can't be null", err);
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
*addr = rtl8201->addr;
return ESP_OK;
@@ -242,15 +257,18 @@ static esp_err_t rtl8201_init(esp_eth_phy_t *phy)
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
esp_eth_mediator_t *eth = rtl8201->eth;
/* Power on Ethernet PHY */
PHY_CHECK(rtl8201_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err);
PHY_CHECK(rtl8201_pwrctl(phy, true) == ESP_OK, "power control failed", err);
/* Reset Ethernet PHY */
PHY_CHECK(rtl8201_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err);
PHY_CHECK(rtl8201_reset(phy) == ESP_OK, "reset failed", err);
/* Check PHY ID */
phyidr1_reg_t id1;
phyidr2_reg_t id2;
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err);
PHY_CHECK(id1.oui_msb == 0x1C && id2.oui_lsb == 0x32 && id2.vendor_model == 0x1, "wrong PHY chip ID", err);
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK,
"read ID1 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK,
"read ID2 failed", err);
PHY_CHECK(id1.oui_msb == 0x1C && id2.oui_lsb == 0x32 && id2.vendor_model == 0x1,
"wrong chip ID", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -259,7 +277,7 @@ err:
static esp_err_t rtl8201_deinit(esp_eth_phy_t *phy)
{
/* Power off Ethernet PHY */
PHY_CHECK(rtl8201_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err);
PHY_CHECK(rtl8201_pwrctl(phy, false) == ESP_OK, "power control failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@@ -269,8 +287,7 @@ esp_eth_phy_t *esp_eth_phy_new_rtl8201(const eth_phy_config_t *config)
{
PHY_CHECK(config, "can't set phy config to null", err);
phy_rtl8201_t *rtl8201 = calloc(1, sizeof(phy_rtl8201_t));
PHY_CHECK(rtl8201, "calloc rtl8201 object failed", err);
rtl8201->name = "rtl8201";
PHY_CHECK(rtl8201, "calloc rtl8201 failed", err);
rtl8201->addr = config->phy_addr;
rtl8201->reset_timeout_ms = config->reset_timeout_ms;
rtl8201->link_status = ETH_LINK_DOWN;

View File

@@ -81,7 +81,7 @@ TEST_CASE("esp32 ethernet io test", "[ethernet][test_env=UT_T2_Ethernet]")
uint8_t mac_addr[6];
memset(mac_addr, 0, sizeof(mac_addr));
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr));
ESP_LOGI(TAG, "Ethernet MAC Address: %d:%d:%d:%d:%d:%d",
ESP_LOGI(TAG, "Ethernet MAC Address: %02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
TEST_ASSERT(mac_addr[0] != 0);
/* get PHY address */

View File

@@ -294,6 +294,21 @@ esp_err_t esp_http_client_get_username(esp_http_client_handle_t client, char **v
return ESP_OK;
}
esp_err_t esp_http_client_set_username(esp_http_client_handle_t client, const char *username)
{
if (client == NULL) {
ESP_LOGE(TAG, "client must not be NULL");
return ESP_ERR_INVALID_ARG;
}
if (username == NULL && client->connection_info.username != NULL) {
free(client->connection_info.username);
client->connection_info.username = NULL;
} else if (username != NULL) {
client->connection_info.username = strdup(username);
}
return ESP_OK;
}
esp_err_t esp_http_client_get_password(esp_http_client_handle_t client, char **value)
{
if (client == NULL || value == NULL) {
@@ -304,6 +319,22 @@ esp_err_t esp_http_client_get_password(esp_http_client_handle_t client, char **v
return ESP_OK;
}
esp_err_t esp_http_client_set_password(esp_http_client_handle_t client, char *password)
{
if (client == NULL) {
ESP_LOGE(TAG, "client must not be NULL");
return ESP_ERR_INVALID_ARG;
}
if (password == NULL && client->connection_info.password != NULL) {
memset(client->connection_info.password, 0, strlen(client->connection_info.password));
free(client->connection_info.password);
client->connection_info.password = NULL;
} else if (password != NULL) {
client->connection_info.password = strdup(password);
}
return ESP_OK;
}
static esp_err_t _set_config(esp_http_client_handle_t client, const esp_http_client_config_t *config)
{
client->connection_info.method = config->method;
@@ -660,10 +691,7 @@ esp_err_t esp_http_client_set_url(esp_http_client_handle_t client, const char *u
}
old_port = client->connection_info.port;
// Whether the passed url is absolute or is just a path
bool is_absolute_url = (bool) purl.field_data[UF_HOST].len;
if (is_absolute_url) {
if (purl.field_data[UF_HOST].len) {
http_utils_assign_string(&client->connection_info.host, url + purl.field_data[UF_HOST].off, purl.field_data[UF_HOST].len);
HTTP_MEM_CHECK(TAG, client->connection_info.host, return ESP_ERR_NO_MEM);
}
@@ -720,14 +748,7 @@ esp_err_t esp_http_client_set_url(esp_http_client_handle_t client, const char *u
} else {
return ESP_ERR_NO_MEM;
}
} else if (is_absolute_url) {
// Only reset authentication info if the passed URL is full
free(client->connection_info.username);
free(client->connection_info.password);
client->connection_info.username = NULL;
client->connection_info.password = NULL;
}
}
//Reset path and query if there are no information
if (purl.field_data[UF_PATH].len) {

View File

@@ -264,6 +264,20 @@ esp_err_t esp_http_client_get_header(esp_http_client_handle_t client, const char
*/
esp_err_t esp_http_client_get_username(esp_http_client_handle_t client, char **value);
/**
* @brief Set http request username.
* The value of username parameter will be assigned to username buffer.
* If the username parameter is NULL then username buffer will be freed.
*
* @param[in] client The esp_http_client handle
* @param[in] username The username value
*
* @return
* - ESP_OK
* - ESP_ERR_INVALID_ARG
*/
esp_err_t esp_http_client_set_username(esp_http_client_handle_t client, const char *username);
/**
* @brief Get http request password.
* The address of password buffer will be assigned to value parameter.
@@ -278,6 +292,20 @@ esp_err_t esp_http_client_get_username(esp_http_client_handle_t client, char **v
*/
esp_err_t esp_http_client_get_password(esp_http_client_handle_t client, char **value);
/**
* @brief Set http request password.
* The value of password parameter will be assigned to password buffer.
* If the password parameter is NULL then password buffer will be freed.
*
* @param[in] client The esp_http_client handle
* @param[in] password The password value
*
* @return
* - ESP_OK
* - ESP_ERR_INVALID_ARG
*/
esp_err_t esp_http_client_set_password(esp_http_client_handle_t client, char *password);
/**
* @brief Set http request method
*

View File

@@ -103,10 +103,11 @@ TEST_CASE("Username is unmodified when we change to new path", "[ESP HTTP CLIENT
}
/**
* Test case to test that, the esp_http_client_set_url will reset username and password
* when passing a full URL with username & password missing.
* Test case to test that, the esp_http_client_set_url do not reset the auth credentials
* Explicit APIs esp_http_client_set_username and esp_http_client_set_password are used to change
* the auth credentials
**/
TEST_CASE("Username is reset if new absolute URL doesnot specify username.", "[ESP HTTP CLIENT]")
TEST_CASE("Username and password will not reset if new absolute URL doesnot specify auth credentials.", "[ESP HTTP CLIENT]")
{
esp_http_client_config_t config_with_auth = {
.host = HOST,
@@ -122,8 +123,17 @@ TEST_CASE("Username is reset if new absolute URL doesnot specify username.", "[E
TEST_ASSERT_NOT_NULL(value);
TEST_ASSERT_EQUAL_STRING(USERNAME, value);
esp_http_client_set_url(client, "http://" HOST "/get");
esp_http_client_set_username(client, value);
esp_http_client_set_password(client, value);
//checks if username is set or not
r = esp_http_client_get_username(client, &value);
TEST_ASSERT_EQUAL(ESP_OK, r);
TEST_ASSERT_NULL(value);
//If username is set then value should not be NULL
TEST_ASSERT_NOT_NULL(value);
//checks if password is set or not
r = esp_http_client_get_password(client, &value);
TEST_ASSERT_EQUAL(ESP_OK, r);
//If password is set then value should not be NULL
TEST_ASSERT_NOT_NULL(value);
esp_http_client_cleanup(client);
}

View File

@@ -39,7 +39,6 @@ static const char *TAG = "WEBSOCKET_CLIENT";
#define WEBSOCKET_NETWORK_TIMEOUT_MS (10*1000)
#define WEBSOCKET_PING_TIMEOUT_MS (10*1000)
#define WEBSOCKET_EVENT_QUEUE_SIZE (1)
#define WEBSOCKET_SEND_EVENT_TIMEOUT_MS (1000/portTICK_RATE_MS)
#define ESP_WS_CLIENT_MEM_CHECK(TAG, a, action) if (!(a)) { \
ESP_LOGE(TAG,"%s:%d (%s): %s", __FILE__, __LINE__, __FUNCTION__, "Memory exhausted"); \
@@ -63,6 +62,7 @@ typedef struct {
bool auto_reconnect;
void *user_context;
int network_timeout_ms;
char *subprotocol;
} websocket_config_storage_t;
typedef enum {
@@ -111,10 +111,10 @@ static esp_err_t esp_websocket_client_dispatch_event(esp_websocket_client_handle
WEBSOCKET_EVENTS, event,
&event_data,
sizeof(esp_websocket_event_data_t),
WEBSOCKET_SEND_EVENT_TIMEOUT_MS)) != ESP_OK) {
portMAX_DELAY)) != ESP_OK) {
return err;
}
return esp_event_loop_run(client->event_handle, WEBSOCKET_SEND_EVENT_TIMEOUT_MS);
return esp_event_loop_run(client->event_handle, 0);
}
static esp_err_t esp_websocket_client_abort_connection(esp_websocket_client_handle_t client)
@@ -172,6 +172,11 @@ static esp_err_t esp_websocket_client_set_config(esp_websocket_client_handle_t c
cfg->path = strdup(config->path);
ESP_WS_CLIENT_MEM_CHECK(TAG, cfg->path, return ESP_ERR_NO_MEM);
}
if (config->subprotocol) {
free(cfg->subprotocol);
cfg->subprotocol = strdup(config->subprotocol);
ESP_WS_CLIENT_MEM_CHECK(TAG, cfg->subprotocol, return ESP_ERR_NO_MEM);
}
cfg->network_timeout_ms = WEBSOCKET_NETWORK_TIMEOUT_MS;
cfg->user_context = config->user_context;
@@ -199,12 +204,23 @@ static esp_err_t esp_websocket_client_destroy_config(esp_websocket_client_handle
free(cfg->scheme);
free(cfg->username);
free(cfg->password);
free(cfg->subprotocol);
memset(cfg, 0, sizeof(websocket_config_storage_t));
free(client->config);
client->config = NULL;
return ESP_OK;
}
static void set_websocket_transport_optional_settings(esp_websocket_client_handle_t client, esp_transport_handle_t trans)
{
if (trans && client->config->path) {
esp_transport_ws_set_path(trans, client->config->path);
}
if (trans && client->config->subprotocol) {
esp_transport_ws_set_subprotocol(trans, client->config->subprotocol);
}
}
esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_client_config_t *config)
{
esp_websocket_client_handle_t client = calloc(1, sizeof(struct esp_websocket_client));
@@ -224,6 +240,9 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
client->lock = xSemaphoreCreateMutex();
ESP_WS_CLIENT_MEM_CHECK(TAG, client->lock, goto _websocket_init_fail);
client->config = calloc(1, sizeof(websocket_config_storage_t));
ESP_WS_CLIENT_MEM_CHECK(TAG, client->config, goto _websocket_init_fail);
client->transport_list = esp_transport_list_init();
ESP_WS_CLIENT_MEM_CHECK(TAG, client->transport_list, goto _websocket_init_fail);
@@ -259,14 +278,11 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
esp_transport_set_default_port(wss, WEBSOCKET_SSL_DEFAULT_PORT);
esp_transport_list_add(client->transport_list, wss, "wss");
if (config->transport == WEBSOCKET_TRANSPORT_OVER_TCP) {
if (config->transport == WEBSOCKET_TRANSPORT_OVER_SSL) {
asprintf(&client->config->scheme, "wss");
ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail);
}
client->config = calloc(1, sizeof(websocket_config_storage_t));
ESP_WS_CLIENT_MEM_CHECK(TAG, client->config, goto _websocket_init_fail);
if (config->uri) {
if (esp_websocket_client_set_uri(client, config->uri) != ESP_OK) {
ESP_LOGE(TAG, "Invalid uri");
@@ -284,6 +300,9 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->scheme, goto _websocket_init_fail);
}
set_websocket_transport_optional_settings(client, esp_transport_list_get_transport(client->transport_list, "ws"));
set_websocket_transport_optional_settings(client, esp_transport_list_get_transport(client->transport_list, "wss"));
client->keepalive_tick_ms = _tick_get_ms();
client->reconnect_tick_ms = _tick_get_ms();
client->ping_tick_ms = _tick_get_ms();
@@ -362,19 +381,17 @@ esp_err_t esp_websocket_client_set_uri(esp_websocket_client_handle_t client, con
}
if (puri.field_data[UF_PATH].len) {
if (puri.field_data[UF_PATH].len || puri.field_data[UF_QUERY].len) {
free(client->config->path);
asprintf(&client->config->path, "%.*s", puri.field_data[UF_PATH].len, uri + puri.field_data[UF_PATH].off);
if (puri.field_data[UF_QUERY].len == 0) {
asprintf(&client->config->path, "%.*s", puri.field_data[UF_PATH].len, uri + puri.field_data[UF_PATH].off);
} else if (puri.field_data[UF_PATH].len == 0) {
asprintf(&client->config->path, "/?%.*s", puri.field_data[UF_QUERY].len, uri + puri.field_data[UF_QUERY].off);
} else {
asprintf(&client->config->path, "%.*s?%.*s", puri.field_data[UF_PATH].len, uri + puri.field_data[UF_PATH].off,
puri.field_data[UF_QUERY].len, uri + puri.field_data[UF_QUERY].off);
}
ESP_WS_CLIENT_MEM_CHECK(TAG, client->config->path, return ESP_ERR_NO_MEM);
esp_transport_handle_t trans = esp_transport_list_get_transport(client->transport_list, "ws");
if (trans) {
esp_transport_ws_set_path(trans, client->config->path);
}
trans = esp_transport_list_get_transport(client->transport_list, "wss");
if (trans) {
esp_transport_ws_set_path(trans, client->config->path);
}
}
if (puri.field_data[UF_PORT].off) {
client->config->port = strtol((const char*)(uri + puri.field_data[UF_PORT].off), NULL, 10);

View File

@@ -91,6 +91,7 @@ typedef struct {
int buffer_size; /*!< Websocket buffer size */
const char *cert_pem; /*!< SSL Certification, PEM format as string, if the client requires to verify server */
esp_websocket_transport_t transport; /*!< Websocket transport type, see `esp_websocket_transport_t */
char *subprotocol; /*!< Websocket subprotocol */
} esp_websocket_client_config_t;
/**

View File

@@ -330,7 +330,7 @@ esp_err_t esp_wifi_restore(void);
* @return
* - ESP_OK: succeed
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init
* - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start
* - ESP_ERR_WIFI_NOT_STARTED: WiFi is not started by esp_wifi_start
* - ESP_ERR_WIFI_CONN: WiFi internal error, station or soft-AP control block wrong
* - ESP_ERR_WIFI_SSID: SSID of AP which station connects is invalid
*/

View File

@@ -0,0 +1,212 @@
#include "unity.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "test_utils.h"
#include "freertos/event_groups.h"
#define GOT_IP_EVENT 0x00000001
#define DISCONNECT_EVENT 0x00000002
#define EVENT_HANDLER_FLAG_DO_NOT_AUTO_RECONNECT 0x00000001
#define EMPH_STR(s) "****** "s" ******"
static const char* TAG = "test_wifi_init";
static uint32_t wifi_event_handler_flag;
static EventGroupHandle_t wifi_events;
static void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
{
printf("wifi ev_handle_called.\n");
switch(event_id) {
case WIFI_EVENT_STA_START:
ESP_LOGI(TAG, "WIFI_EVENT_STA_START");
break;
case WIFI_EVENT_STA_DISCONNECTED:
ESP_LOGI(TAG, "WIFI_EVENT_STA_DISCONNECTED");
if (! (EVENT_HANDLER_FLAG_DO_NOT_AUTO_RECONNECT & wifi_event_handler_flag) ) {
TEST_ESP_OK(esp_wifi_connect());
}
if (wifi_events) {
xEventGroupSetBits(wifi_events, DISCONNECT_EVENT);
}
break;
default:
break;
}
return;
}
static void ip_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
{
ip_event_got_ip_t *event;
printf("ip ev_handle_called.\n");
switch(event_id) {
case IP_EVENT_STA_GOT_IP:
event = (ip_event_got_ip_t*)event_data;
ESP_LOGI(TAG, "IP_EVENT_STA_GOT_IP");
ESP_LOGI(TAG, "got ip:%s\n", ip4addr_ntoa(&event->ip_info.ip));
if (wifi_events) {
xEventGroupSetBits(wifi_events, GOT_IP_EVENT);
}
break;
default:
break;
}
return;
}
static esp_err_t event_init(void)
{
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, &ip_event_handler, NULL));
return ESP_OK;
}
static void wifi_driver_can_start_on_APP_CPU_task(void* arg)
{
SemaphoreHandle_t *sema = (SemaphoreHandle_t *) arg;
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
//init nvs
ESP_LOGI(TAG, EMPH_STR("nvs_flash_init"));
esp_err_t r = nvs_flash_init();
if (r == ESP_ERR_NVS_NO_FREE_PAGES || r == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_LOGI(TAG, EMPH_STR("no free pages or NFS version mismatch, erase.."));
TEST_ESP_OK(nvs_flash_erase());
r = nvs_flash_init();
}
TEST_ESP_OK(r);
//init event loop
ESP_LOGI(TAG, EMPH_STR("event_init"));
event_init();
unity_reset_leak_checks();
ESP_LOGI(TAG, EMPH_STR("esp_wifi_init"));
TEST_ESP_OK(esp_wifi_init(&cfg));
ESP_LOGI(TAG, EMPH_STR("esp_wifi_deinit..."));
TEST_ESP_OK(esp_wifi_deinit());
ESP_LOGI(TAG, EMPH_STR("nvs_flash_deinit..."));
nvs_flash_deinit();
ESP_LOGI(TAG, "test passed...");
xSemaphoreGive(*sema);
vTaskDelete(NULL);
}
TEST_CASE("wifi driver can start on APP CPU", "[wifi_init]")
{
TaskHandle_t th;
SemaphoreHandle_t sema = xSemaphoreCreateBinary();
printf("Creating tasks\n");
#ifndef CONFIG_FREERTOS_UNICORE
xTaskCreatePinnedToCore(wifi_driver_can_start_on_APP_CPU_task, "wifi_driver_can_start_on_APP_CPU_task", 2048*2, &sema, 3, &th, 1);
#else
xTaskCreate(wifi_driver_can_start_on_APP_CPU_task, "wifi_driver_can_start_on_APP_CPU_task", 2048*2, &sema, 3, &th);
#endif
xSemaphoreTake(sema, portMAX_DELAY);
vSemaphoreDelete(sema);
sema = NULL;
TEST_IGNORE_MESSAGE("this test case is ignored due to the event_loop.");
}
static void wifi_start_stop_task(void* arg)
{
SemaphoreHandle_t *sema = (SemaphoreHandle_t *) arg;
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
//init nvs
ESP_LOGI(TAG, EMPH_STR("nvs_flash_init"));
esp_err_t r = nvs_flash_init();
if (r == ESP_ERR_NVS_NO_FREE_PAGES || r == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_LOGI(TAG, EMPH_STR("no free pages or NFS version mismatch, erase.."));
TEST_ESP_OK(nvs_flash_erase());
r = nvs_flash_init();
}
TEST_ESP_OK(r);
//init tcpip
ESP_LOGI(TAG, EMPH_STR("tcpip_adapter_init"));
tcpip_adapter_init();
//init event loop
ESP_LOGI(TAG, EMPH_STR("event_init"));
event_init();
unity_reset_leak_checks();
ESP_LOGI(TAG, EMPH_STR("esp_wifi_init"));
TEST_ASSERT(esp_wifi_init(&cfg) == ESP_OK);
ESP_LOGI(TAG, EMPH_STR("esp_wifi_start"));
TEST_ASSERT(esp_wifi_start() == ESP_OK);
ESP_LOGI(TAG, EMPH_STR("esp_wifi_stop"));
TEST_ASSERT(esp_wifi_stop() == ESP_OK);
ESP_LOGI(TAG, EMPH_STR("esp_wifi_stop"));
TEST_ASSERT(esp_wifi_stop() == ESP_OK);
ESP_LOGI(TAG, EMPH_STR("esp_wifi_deinit"));
TEST_ASSERT(esp_wifi_deinit() == ESP_OK);
ESP_LOGI(TAG, EMPH_STR("nvs_flash_deinit..."));
nvs_flash_deinit();
ESP_LOGI(TAG, "test passed...");
xSemaphoreGive(*sema);
vTaskDelete(NULL);
}
TEST_CASE("Calling esp_wifi_stop() with start", "[wifi_init]")
{
TaskHandle_t th;
SemaphoreHandle_t sema = xSemaphoreCreateBinary();
printf("Creating tasks\n");
#ifndef CONFIG_FREERTOS_UNICORE
xTaskCreatePinnedToCore(wifi_start_stop_task, "wifi_start_stop_task", 2048*2, &sema, 3, &th, 0);
#else
xTaskCreate(wifi_start_stop_task, "wifi_start_stop_task", 2048*2, &sema, 3, &th);
#endif
xSemaphoreTake(sema, portMAX_DELAY);
vSemaphoreDelete(sema);
sema = NULL;
TEST_IGNORE_MESSAGE("this test case is ignored due to the critical memory leak of tcpip_adapter and event_loop.");
}
static void wifi_stop_task(void* arg)
{
SemaphoreHandle_t *sema = (SemaphoreHandle_t *) arg;
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
//init nvs
ESP_LOGI(TAG, EMPH_STR("nvs_flash_init"));
esp_err_t r = nvs_flash_init();
if (r == ESP_ERR_NVS_NO_FREE_PAGES || r == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_LOGI(TAG, EMPH_STR("no free pages or NFS version mismatch, erase.."));
TEST_ESP_OK(nvs_flash_erase());
r = nvs_flash_init();
}
TEST_ESP_OK(r);
//init event loop
ESP_LOGI(TAG, EMPH_STR("event_init"));
event_init();
unity_reset_leak_checks();
ESP_LOGI(TAG, EMPH_STR("esp_wifi_init"));
TEST_ASSERT(esp_wifi_init(&cfg) == ESP_OK);
ESP_LOGI(TAG, EMPH_STR("esp_wifi_stop"));
TEST_ASSERT(esp_wifi_stop() == ESP_OK);
ESP_LOGI(TAG, EMPH_STR("esp_wifi_stop"));
TEST_ASSERT(esp_wifi_stop() == ESP_OK);
ESP_LOGI(TAG, EMPH_STR("esp_wifi_deinit"));
TEST_ASSERT(esp_wifi_deinit() == ESP_OK);
ESP_LOGI(TAG, EMPH_STR("nvs_flash_deinit..."));
nvs_flash_deinit();
ESP_LOGI(TAG, "test passed...");
xSemaphoreGive(*sema);
vTaskDelete(NULL);
}
TEST_CASE("Calling esp_wifi_stop() without start", "[wifi_init]")
{
TaskHandle_t th;
SemaphoreHandle_t sema = xSemaphoreCreateBinary();
printf("Creating tasks\n");
#ifndef CONFIG_FREERTOS_UNICORE
xTaskCreatePinnedToCore(wifi_stop_task, "wifi_stop_task", 2048*2, &sema, 3, &th, 0);
#else
xTaskCreate(wifi_stop_task, "wifi_stop_task", 2048*2, &sema, 3, &th);
#endif
xSemaphoreTake(sema, portMAX_DELAY);
vSemaphoreDelete(sema);
sema = NULL;
TEST_IGNORE_MESSAGE("this test case is ignored due to the event_loop.");
}

View File

@@ -0,0 +1,18 @@
# Note: we can't expand these environment variables in the main IDF CMake build,
# because we want to expand them at flashing time not at CMake runtime (so they can change
# without needing a CMake re-run)
set(ESPPORT $ENV{ESPPORT})
if(NOT ESPPORT)
message("Note: ${TOOL} will search for a serial port. To specify a port, set the ESPPORT environment variable.")
else()
set(port_arg "-p ${ESPPORT}")
endif()
set(ESPBAUD $ENV{ESPBAUD})
if(NOT ESPBAUD)
message("Note: ${TOOL} will attempt to set baud rate automatically. "
"To specify a baud rate, set the ESPBAUD environment variable.")
else()
set(baud_arg "-b ${ESPBAUD}")
endif()

View File

@@ -142,13 +142,34 @@ function(esptool_py_custom_target target_name flasher_filename dependencies)
-D IDF_PATH="${idf_path}"
-D ESPTOOLPY="${ESPTOOLPY}"
-D ESPTOOL_ARGS="write_flash;@flash_${flasher_filename}_args"
-D ESPTOOL_WORKING_DIR="${build_dir}"
-D WORKING_DIRECTORY="${build_dir}"
-P run_esptool.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
USES_TERMINAL
)
endfunction()
add_custom_target(erase_flash
COMMAND ${CMAKE_COMMAND}
-D IDF_PATH="${idf_path}"
-D ESPTOOLPY="${ESPTOOLPY}"
-D ESPTOOL_ARGS="erase_flash"
-P run_esptool.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
USES_TERMINAL
)
add_custom_target(monitor
COMMAND ${CMAKE_COMMAND}
-D IDF_PATH="${idf_path}"
-D IDF_MONITOR="${idf_path}/tools/idf_monitor.py"
-D ELF_FILE="${elf}"
-D WORKING_DIRECTORY="${build_dir}"
-P run_idf_monitor.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
USES_TERMINAL
)
esptool_py_custom_target(flash project "app;partition_table;bootloader")
esptool_py_custom_target(app-flash app "app")

View File

@@ -0,0 +1,15 @@
if(NOT IDF_PATH)
message(FATAL_ERROR "IDF_PATH not set.")
endif()
include("${IDF_PATH}/tools/cmake/utilities.cmake")
spaces2list(CMD)
execute_process(COMMAND ${CMD}
WORKING_DIRECTORY "${WORKING_DIRECTORY}"
RESULT_VARIABLE result
)
if(${result})
# No way to have CMake silently fail, unfortunately
message(FATAL_ERROR "${TOOL} failed")
endif()

View File

@@ -8,39 +8,14 @@
#
cmake_minimum_required(VERSION 3.5)
if(NOT IDF_PATH OR NOT ESPTOOLPY OR NOT ESPTOOL_ARGS OR NOT ESPTOOL_WORKING_DIR)
message(FATAL_ERROR "IDF_PATH, ESPTOOLPY, ESPTOOL_ARGS, and ESPTOOL_WORKING_DIR must "
"be specified on the CMake command line. For direct esptool execution, it is "
"strongly recommended to run esptool.py directly.")
set(TOOL "esptool.py")
if(NOT ESPTOOLPY OR NOT ESPTOOL_ARGS)
message(FATAL_ERROR "ESPTOOLPY and ESPTOOL_ARGS must "
"be specified on the CMake command line. For direct execution, it is "
"strongly recommended to run ${TOOL} directly.")
endif()
# Note: we can't expand these environment variables in the main IDF CMake build,
# because we want to expand them at flashing time not at CMake runtime (so they can change
# without needing a CMake re-run)
set(ESPPORT $ENV{ESPPORT})
if(NOT ESPPORT)
message("Note: esptool.py will search for a serial port. To specify a port, set the ESPPORT environment variable.")
else()
set(port_arg "-p ${ESPPORT}")
endif()
set(ESPBAUD $ENV{ESPBAUD})
if(NOT ESPBAUD)
message("Note: Using default baud rate 460800. To modify, set ESPBAUD environment variable.")
set(ESPBAUD 460800)
endif()
include("${IDF_PATH}/tools/cmake/utilities.cmake")
set(cmd "${ESPTOOLPY} ${port_arg} -b ${ESPBAUD} ${ESPTOOL_ARGS}")
spaces2list(cmd)
execute_process(COMMAND ${cmd}
WORKING_DIRECTORY "${ESPTOOL_WORKING_DIR}"
RESULT_VARIABLE result
)
if(${result})
# No way to have CMake silently fail, unfortunately
message(FATAL_ERROR "esptool.py failed")
endif()
include("${CMAKE_CURRENT_LIST_DIR}/get_port_args.cmake")
set(CMD "${ESPTOOLPY} ${port_arg} ${baud_arg} ${ESPTOOL_ARGS}")
include("${CMAKE_CURRENT_LIST_DIR}/run_cmd.cmake")

View File

@@ -0,0 +1,21 @@
# A CMake script to run idf_monitor from within ninja or make
# or another cmake-based build runner
#
# (Needed to expand environment variables, for backwards compatibility.)
#
# It is recommended to NOT USE this CMake script if you have the option of
# running idf_monitor.py directly. This script exists only for use inside CMake builds.
#
cmake_minimum_required(VERSION 3.5)
set(TOOL "idf_monitor.py")
if(NOT IDF_MONITOR OR NOT ELF_FILE)
message(FATAL_ERROR "IDF_MONITOR and ELF_FILE must "
"be specified on the CMake command line. For direct execution, it is "
"strongly recommended to run ${TOOL} directly.")
endif()
include("${CMAKE_CURRENT_LIST_DIR}/get_port_args.cmake")
set(CMD "${IDF_MONITOR} ${port_arg} ${baud_arg} ${ELF_FILE}")
include("${CMAKE_CURRENT_LIST_DIR}/run_cmd.cmake")

View File

@@ -1962,7 +1962,7 @@ BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClea
*
* \ingroup TaskNotifications
*/
#define xTaskNotifyGive( xTaskToNotify ) xTaskNotify( ( xTaskToNotify ), 0, eIncrement );
#define xTaskNotifyGive( xTaskToNotify ) xTaskNotify( ( xTaskToNotify ), 0, eIncrement )
/**
* Simplified macro for sending task notification from ISR.

View File

@@ -22,6 +22,10 @@
void mdns_debug_packet(const uint8_t * data, size_t len);
#endif
// Internal size of IPv6 address is defined here as size of AAAA record in mdns packet
// since the ip6_addr_t is defined in lwip and depends on using IPv6 zones
#define _MDNS_SIZEOF_IP6_ADDR (MDNS_ANSWER_AAAA_SIZE)
static const char * MDNS_DEFAULT_DOMAIN = "local";
static const char * MDNS_SUB_STR = "_sub";
@@ -734,11 +738,11 @@ static uint16_t _mdns_append_aaaa_record(uint8_t * packet, uint16_t * index, uin
uint16_t data_len_location = *index - 2;
if ((*index + 15) >= MDNS_MAX_PACKET_SIZE) {
if ((*index + MDNS_ANSWER_AAAA_SIZE) > MDNS_MAX_PACKET_SIZE) {
return 0;
}
part_length = sizeof(ip6_addr_t);
part_length = MDNS_ANSWER_AAAA_SIZE;
memcpy(packet + *index, ipv6, part_length);
*index += part_length;
_mdns_set_u16(packet, data_len_location, part_length);
@@ -817,7 +821,7 @@ static bool _ipv6_address_is_zero(ip6_addr_t ip6)
{
uint8_t i;
uint8_t * data = (uint8_t *)ip6.addr;
for (i=0; i<16; i++) {
for (i=0; i<_MDNS_SIZEOF_IP6_ADDR; i++) {
if (data[i]) {
return false;
}
@@ -2185,7 +2189,7 @@ static int _mdns_check_aaaa_collision(ip6_addr_t * ip, tcpip_adapter_if_t tcpip_
if (tcpip_adapter_get_ip6_linklocal(tcpip_if, &if_ip6)) {
return 1;//they win
}
int ret = memcmp((uint8_t*)&if_ip6.addr, (uint8_t*)ip->addr, sizeof(ip6_addr_t));
int ret = memcmp((uint8_t*)&if_ip6.addr, (uint8_t*)ip->addr, _MDNS_SIZEOF_IP6_ADDR);
if (ret > 0) {
return -1;//we win
} else if (ret < 0) {
@@ -2197,7 +2201,7 @@ static int _mdns_check_aaaa_collision(ip6_addr_t * ip, tcpip_adapter_if_t tcpip_
if (tcpip_adapter_get_ip6_linklocal(other_if, &other_ip6)) {
return 1;//IPv6 not active! They win
}
if (memcmp((uint8_t*)&other_ip6.addr, (uint8_t*)ip->addr, sizeof(ip6_addr_t))) {
if (memcmp((uint8_t*)&other_ip6.addr, (uint8_t*)ip->addr, _MDNS_SIZEOF_IP6_ADDR)) {
return 1;//IPv6 not ours! They win
}
_mdns_dup_interface(tcpip_if);
@@ -2898,7 +2902,7 @@ void mdns_parse_packet(mdns_rx_packet_t * packet)
} else if (type == MDNS_TYPE_AAAA) {//ipv6
ip_addr_t ip6;
ip6.type = IPADDR_TYPE_V6;
memcpy(ip6.u_addr.ip6.addr, data_ptr, 16);
memcpy(ip6.u_addr.ip6.addr, data_ptr, MDNS_ANSWER_AAAA_SIZE);
if (search_result) {
//check for more applicable searches (PTR & A/AAAA at the same time)
while (search_result) {
@@ -4944,7 +4948,7 @@ void mdns_debug_packet(const uint8_t * data, size_t len)
_mdns_dbg_printf("\n");
} else if (type == MDNS_TYPE_AAAA) {
ip6_addr_t ip6;
memcpy(&ip6, data_ptr, sizeof(ip6_addr_t));
memcpy(&ip6, data_ptr, MDNS_ANSWER_AAAA_SIZE);
_mdns_dbg_printf(IPV6STR "\n", IPV62STR(ip6));
} else if (type == MDNS_TYPE_A) {
ip4_addr_t ip;

View File

@@ -52,6 +52,7 @@
#define MDNS_ANSWER_AAAA 0x10
#define MDNS_ANSWER_NSEC 0x20
#define MDNS_ANSWER_SDPTR 0x80
#define MDNS_ANSWER_AAAA_SIZE 16
#define MDNS_SERVICE_PORT 5353 // UDP port that the server runs on
#define MDNS_SERVICE_STACK_DEPTH 4096 // Stack size for the service thread

View File

@@ -232,19 +232,6 @@ static void start_measure(int64_t* sys_time, int64_t* real_time)
*sys_time = (int64_t)tv_time.tv_sec * 1000000L + tv_time.tv_usec;
}
static void end_measure(int64_t* sys_time, int64_t* real_time)
{
struct timeval tv_time;
int64_t t1, t2;
do {
t1 = esp_timer_get_time();
gettimeofday(&tv_time, NULL);
t2 = esp_timer_get_time();
} while (t2 - t1 > 40);
*real_time = t2;
*sys_time = (int64_t)tv_time.tv_sec * 1000000L + tv_time.tv_usec;
}
static int64_t calc_correction(const char* tag, int64_t* sys_time, int64_t* real_time)
{
int64_t dt_real_time_us = real_time[1] - real_time[0];
@@ -273,23 +260,22 @@ static void measure_time_task(void *pvParameters)
start_measure(&main_sys_time_us[0], &main_real_time_us[0]);
{
int64_t real_time_us[2];
int64_t sys_time_us[2];
int64_t delay_us = 2 * 1000000; // 2 sec
start_measure(&sys_time_us[0], &real_time_us[0]);
int64_t real_time_us[2] = { main_real_time_us[0], 0};
int64_t sys_time_us[2] = { main_sys_time_us[0], 0};
// although exit flag is set in another task, checking (exit_flag == false) is safe
while (exit_flag == false) {
ets_delay_us(delay_us);
ets_delay_us(2 * 1000000); // 2 sec
end_measure(&sys_time_us[1], &real_time_us[1]);
start_measure(&sys_time_us[1], &real_time_us[1]);
result_adjtime_correction_us[1] += calc_correction("measure", sys_time_us, real_time_us);
sys_time_us[0] = sys_time_us[1];
real_time_us[0] = real_time_us[1];
}
main_sys_time_us[1] = sys_time_us[1];
main_real_time_us[1] = real_time_us[1];
}
end_measure(&main_sys_time_us[1], &main_real_time_us[1]);
result_adjtime_correction_us[0] = calc_correction("main", main_sys_time_us, main_real_time_us);
int64_t delta_us = result_adjtime_correction_us[0] - result_adjtime_correction_us[1];
printf("\nresult of adjtime correction: %lli us, %lli us. delta = %lli us\n", result_adjtime_correction_us[0], result_adjtime_correction_us[1], delta_us);

View File

@@ -280,8 +280,11 @@ enum state
{ s_dead = 1 /* important that this is > 0 */
, s_start_req_or_res
, s_res_or_resp_I /* for ICY URIs */
, s_res_or_resp_H
, s_start_res
, s_res_I /* for ICY URIs */
, s_res_IC /* for ICY URIs */
, s_res_H
, s_res_HT
, s_res_HTT
@@ -728,6 +731,10 @@ reexecute:
if (ch == 'H') {
UPDATE_STATE(s_res_or_resp_H);
CALLBACK_NOTIFY(message_begin);
} else if (ch == 'I') {
UPDATE_STATE(s_res_or_resp_I);
CALLBACK_NOTIFY(message_begin);
} else {
parser->type = HTTP_REQUEST;
@@ -738,6 +745,13 @@ reexecute:
break;
}
case s_res_or_resp_I: /* ICY URI case */
if (ch == 'C') {
parser->type = HTTP_RESPONSE;
UPDATE_STATE(s_res_IC);
}
break;
case s_res_or_resp_H:
if (ch == 'T') {
parser->type = HTTP_RESPONSE;
@@ -764,7 +778,9 @@ reexecute:
case 'H':
UPDATE_STATE(s_res_H);
break;
case 'I': /* ICY URI */
UPDATE_STATE(s_res_I);
break;
case CR:
case LF:
break;
@@ -777,6 +793,15 @@ reexecute:
CALLBACK_NOTIFY(message_begin);
break;
}
case s_res_I:
STRICT_CHECK(ch != 'C');
UPDATE_STATE(s_res_IC);
break;
case s_res_IC:
STRICT_CHECK(ch != 'Y');
UPDATE_STATE(s_res_http_minor);
break;
case s_res_H:
STRICT_CHECK(ch != 'T');

View File

@@ -482,7 +482,7 @@ void emac_hal_transmit_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t len
hal->dma_regs->dmatxpolldemand = 0;
}
uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t *frames_remain)
uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t size, uint32_t *frames_remain)
{
eth_dma_rx_descriptor_t *desc_iter = NULL;
eth_dma_rx_descriptor_t *first_desc = NULL;
@@ -501,6 +501,12 @@ uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t
if (desc_iter->RDES0.LastDescriptor) {
/* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */
len = desc_iter->RDES0.FrameLength - ETH_CRC_LENGTH;
/* check if the buffer can store the whole frame */
if (len > size) {
/* return the real size that we want */
/* user need to compare the return value to the size they prepared when this function returned */
return len;
}
/* update unhandled frame count */
frame_count++;
}

View File

@@ -380,7 +380,7 @@ uint32_t emac_hal_get_tx_desc_owner(emac_hal_context_t *hal);
void emac_hal_transmit_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t length);
uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t *frames_remain);
uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t size, uint32_t *frames_remain);
void emac_hal_isr(void *arg);

View File

@@ -21,7 +21,7 @@
#include "esp_log.h"
#include "esp_heap_caps.h"
#include "hal/spi_types.h"
#include "driver/spi_common.h"
#include "driver/spi_common_internal.h"
#include "esp_flash_internal.h"
__attribute__((unused)) static const char TAG[] = "spi_flash";

View File

@@ -6,7 +6,7 @@
#include <unity.h>
#include "esp_flash.h"
#include "driver/spi_common.h"
#include "driver/spi_common_internal.h"
#include "esp_flash_spi_init.h"
#include <esp_attr.h>
#include "esp_log.h"
@@ -14,7 +14,6 @@
#include <test_utils.h>
#include "unity.h"
#include "driver/spi_common.h"
#include "driver/gpio.h"
#include "soc/io_mux_reg.h"

View File

@@ -43,7 +43,6 @@ void esp_transport_ws_set_path(esp_transport_handle_t t, const char *path);
*/
esp_err_t esp_transport_ws_set_subprotocol(esp_transport_handle_t t, const char *sub_protocol);
#ifdef __cplusplus
}
#endif

View File

@@ -188,18 +188,17 @@ static int _ws_write(esp_transport_handle_t t, int opcode, int mask_flag, const
ws_header[header_len++] = (uint8_t)((len >> 8) & 0xFF);
ws_header[header_len++] = (uint8_t)((len >> 0) & 0xFF);
}
if (len) {
if (mask_flag) {
mask = &ws_header[header_len];
getrandom(ws_header + header_len, 4, 0);
header_len += 4;
for (i = 0; i < len; ++i) {
buffer[i] = (buffer[i] ^ mask[i % 4]);
}
if (mask_flag) {
mask = &ws_header[header_len];
getrandom(ws_header + header_len, 4, 0);
header_len += 4;
for (i = 0; i < len; ++i) {
buffer[i] = (buffer[i] ^ mask[i % 4]);
}
}
if (esp_transport_write(ws->parent, ws_header, header_len, timeout_ms) != header_len) {
ESP_LOGE(TAG, "Error write header");
return -1;
@@ -224,7 +223,7 @@ static int ws_write(esp_transport_handle_t t, const char *b, int len, int timeou
{
if (len == 0) {
ESP_LOGD(TAG, "Write PING message");
return _ws_write(t, WS_OPCODE_PING | WS_FIN, 0, NULL, 0, timeout_ms);
return _ws_write(t, WS_OPCODE_PING | WS_FIN, WS_MASK, NULL, 0, timeout_ms);
}
return _ws_write(t, WS_OPCODE_BINARY | WS_FIN, WS_MASK, b, len, timeout_ms);
}
@@ -282,7 +281,7 @@ static int ws_read(esp_transport_handle_t t, char *buffer, int len, int timeout_
}
// Then receive and process payload
if ((rlen = esp_transport_read(ws->parent, buffer, payload_len, timeout_ms)) <= 0) {
if (payload_len != 0 && (rlen = esp_transport_read(ws->parent, buffer, payload_len, timeout_ms)) <= 0) {
ESP_LOGE(TAG, "Error read data");
return rlen;
}

View File

@@ -16,17 +16,26 @@
#include "utils/common.h"
#include "utils/wpa_debug.h"
static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len, int uppercase)
static inline int
_wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len,
int uppercase, int whitespace)
{
size_t i;
char *pos = buf, *end = buf + buf_size;
int ret;
static const char *fmt_upper = "%02X";
static const char *fmt_lower = "%02x";
static const char *fmt_upper_ws = "%02X ";
static const char *fmt_lower_ws = "%02x ";
const char *fmt = uppercase ? (whitespace ? fmt_upper_ws : fmt_upper) :
(whitespace ? fmt_lower_ws : fmt_lower);
if (buf_size == 0)
return 0;
for (i = 0; i < len; i++) {
ret = snprintf(pos, end - pos, uppercase? "%02X":"%02x", data[i]);
ret = snprintf(pos, end - pos, fmt, data[i]);
if (ret < 0 || ret >= end - pos) {
end[-1] = '\0';
return pos - buf;
@@ -39,25 +48,31 @@ static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, size_t len)
{
return _wpa_snprintf_hex(buf, buf_size, data, len, 1);
return _wpa_snprintf_hex(buf, buf_size, data, len, 1, 0);
}
int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len)
{
return _wpa_snprintf_hex(buf, buf_size, data, len, 0);
return _wpa_snprintf_hex(buf, buf_size, data, len, 0, 0);
}
#ifdef DEBUG_PRINT
void wpa_dump_mem(char* desc, uint8_t *addr, uint16_t len)
{
char output[50];
wpa_printf(MSG_DEBUG, "%s\n", desc);
if (addr){
uint16_t i=0;
for (i=0; i<len; i++){
if (i%16==0) wpa_printf(MSG_DEBUG, "\n");
wpa_printf(MSG_DEBUG, "%02x ", addr[i]);
for (i = 0; i < len / 16; i++) {
_wpa_snprintf_hex(output, 50, addr + i * 16, 16, 0, 1);
wpa_printf(MSG_DEBUG, "%s", output);
}
if (len % 16) {
int bytes_printed = (len / 16) * 16;
_wpa_snprintf_hex(output, 50, addr + bytes_printed,
len - bytes_printed, 0, 1);
wpa_printf(MSG_DEBUG, "%s", output);
}
wpa_printf(MSG_DEBUG, "\n");
}
}
@@ -74,21 +89,26 @@ void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)
{
#ifdef DEBUG_PRINT
size_t i;
char output[50];
if (level < MSG_MSGDUMP)
return;
wpa_printf(MSG_DEBUG, "%s - hexdump(len=%lu):\n", title, (unsigned long) len);
wpa_printf(MSG_DEBUG, "%s - hexdump(len=%lu):", title, (unsigned long) len);
if (buf == NULL) {
wpa_printf(MSG_DEBUG, " [NULL]\n");
wpa_printf(MSG_DEBUG, " [NULL]");
} else {
for (i = 0; i < len; i++) {
wpa_printf(MSG_DEBUG, " %02x", buf[i]);
if((i+1) % 16 == 0)
wpa_printf(MSG_DEBUG, "\n");
}
for (i = 0; i < len / 16; i++) {
_wpa_snprintf_hex(output, 50, buf + i * 16, 16, 0, 1);
wpa_printf(MSG_DEBUG, "%s", output);
}
if (len % 16) {
int bytes_printed = (len / 16) * 16;
_wpa_snprintf_hex(output, 50, buf + bytes_printed,
len - bytes_printed, 0, 1);
wpa_printf(MSG_DEBUG, "%s", output);
}
}
wpa_printf(MSG_DEBUG, "\n");
#endif
}

View File

@@ -0,0 +1,63 @@
#Diagram demonstrating reading and returning an item in a No-Split/Allow-Split ring buffer
#Buffer of 128 bytes, with 4 items of 16, 20, 8 and 24 bytes. First 3 items are read and returned
packetdiag ring_buffer_send_acquire_complete {
node_width = 6
node_height = 24
default_fontsize = 12
colwidth = 128
#Initial
0-7: 8 [color = lightblue];
8-23: 16 Available [color = lightyellow];
24-127: Free
#Acquire item 1, 2, 3
128-135: 8 [color = lightblue];
136-151: 16 Available [color = lightyellow];
152-179: 20 Acquired [color = lightgrey];
180-195: 8 Acquired [color = lightgrey];
196-227: 24 Acquired [color = lightgrey];
228-255: 28 Free
#Complete item 2
256-263: 8 [color = lightblue];
264-279: 16 Available [color = lightyellow];
280-307: 20 Acquired [color = lightgrey];
308-315: 8 [color = pink];
316-323: 8 Completed [color = pink];
324-355: 24 Acquired [color = lightgrey];
356-383: 28 Free
#Complete item 3
384-391: 8 [color = lightblue];
392-407: 16 Available [color = lightyellow];
408-435: 20 Acquired [color = lightgrey];
436-443: 8 [color = pink];
444-451: 8 Completed [color = pink];
452-459: 8 [color = pink];
460-483: 24 Completed [color = pink];
484-511: 28 Free
#Complete item 1
512-519: 8 [color = lightblue];
520-535: 16 Available [color = lightyellow];
536-543: 8 [color = pink];
544-563: 20 Completed [color = pink];
564-571: 8 [color = pink];
572-579: 8 Completed [color = pink];
580-587: 8 [color = pink];
588-611: 24 Completed [color = pink];
612-639: 28 Free
#Return item 3
640-647: 8 [color = lightblue];
648-663: 16 Available [color = lightyellow];
664-671: 8 [color = lightblue];
672-691: 20 Available [color = lightyellow];
692-699: 8 [color = lightblue];
700-707: 8 Available [color = lightyellow];
708-715: 8 [color = lightblue];
716-739: 24 Available [color = lightyellow];
740-767: 28 Free
}

View File

@@ -1168,7 +1168,7 @@ can be used with CMake commands that support generator expressions.
.. code-block:: none
idf_component_set_property(property val [APPEND])
idf_component_set_property(component property val [APPEND])
Set a specified *component*'s :ref:`component property<cmake-component-properties>`, *property* with value *val*. Specifying *APPEND* will append the specified value to the current
value of the property. If the property does not previously exist or it is currently empty, the specified value becomes

View File

@@ -40,6 +40,8 @@ For easy interaction with IDF Monitor, use the keyboard shortcuts given in the t
+-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| - Ctrl+H (or H) | Display all keyboard shortcuts | |
+-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| - Ctrl+X (or X) | Exit the program | |
+-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
Any keys pressed, other than ``Ctrl-]`` and ``Ctrl-T``, will be sent through the serial port.

View File

@@ -23,14 +23,17 @@ Ring Buffers
The ESP-IDF FreeRTOS ring buffer is a strictly FIFO buffer that supports arbitrarily sized items.
Ring buffers are a more memory efficient alternative to FreeRTOS queues in situations where the
size of items is variable. The capacity of a ring buffer is not measured by the number of items
it can store, but rather by the amount of memory used for storing items. Items are sent to
ring buffers by copy, however for efficiency reasons **items are retrieved by reference**. As a
result, all retrieved items **must also be returned** in order for them to be removed from
the ring buffer completely. The ring buffers are split into the three following types:
it can store, but rather by the amount of memory used for storing items. You may apply for a
piece of memory on the ring buffer to send an item, or just use the API to copy your data and send
(according to the send API you call). For efficiency reasons,
**items are always retrieved from the ring buffer by reference**. As a result, all retrieved
items *must also be returned* in order for them to be removed from the ring buffer completely.
The ring buffers are split into the three following types:
**No-Split** buffers will guarantee that an item is stored in contiguous memory and will not
**No-Split** buffers will guarantee that an item is stored in contiguous memory and will not
attempt to split an item under any circumstances. Use no-split buffers when items must occupy
contiguous memory.
contiguous memory. *Only this buffer type allows you getting the data item address and writting
to the item by yourself.*
**Allow-Split** buffers will allow an item to be split when wrapping around if doing so will allow
the item to be stored. Allow-split buffers are more memory efficient than no-split buffers but
@@ -42,7 +45,8 @@ do not need to be maintained (e.g. a byte stream).
.. note::
No-split/allow-split buffers will always store items at 32-bit aligned addresses. Therefore when
retrieving an item, the item pointer is guaranteed to be 32-bit aligned.
retrieving an item, the item pointer is guaranteed to be 32-bit aligned. This is useful
especially when you need to send some data to the DMA.
.. note::
Each item stored in no-split/allow-split buffers will **require an additional 8 bytes for a header**.
@@ -76,6 +80,46 @@ and :cpp:func:`xRingbufferSend` to create a ring buffer then send an item to it.
printf("Failed to send item\n");
}
The following example demonstrates the usage of :cpp:func:`xRingbufferSendAcquire` and
:cpp:func:`xRingbufferSendComplete` instead of :cpp:func:`xRingbufferSend` to apply for the
memory on the ring buffer (of type `RINGBUF_TYPE_NOSPLIT`) and then send an item to it. This way
adds one more step, but allows getting the address of the memory to write to, and writing to the
memory yourself.
.. code-block:: c
#include "freertos/ringbuf.h"
#include "soc/lldesc.h"
typedef struct {
lldesc_t dma_desc;
uint8_t buf[1];
} dma_item_t;
#define DMA_ITEM_SIZE(N) (sizeof(lldesc_t)+(((N)+3)&(~3)))
...
//Retrieve space for DMA descriptor and corresponding data buffer
//This has to be done with SendAcquire, or the address may be different when copy
dma_item_t item;
UBaseType_t res = xRingbufferSendAcquire(buf_handle,
&item, DMA_ITEM_SIZE(buffer_size), pdMS_TO_TICKS(1000));
if (res != pdTRUE) {
printf("Failed to acquire memory for item\n");
}
item->dma_desc = (lldesc_t) {
.size = buffer_size,
.length = buffer_size,
.eof = 0,
.owner = 1,
.buf = &item->buf,
};
//Actually send to the ring buffer for consumer to use
res = xRingbufferSendComplete(buf_handle, &item);
if (res != pdTRUE) {
printf("Failed to send item\n");
}
The following example demonstrates retrieving and returning an item from a **no-split ring buffer**
using :cpp:func:`xRingbufferReceive` and :cpp:func:`vRingbufferReturnItem`
@@ -83,7 +127,7 @@ using :cpp:func:`xRingbufferReceive` and :cpp:func:`vRingbufferReturnItem`
.. code-block:: c
...
//Receive an item from no-split ring buffer
size_t item_size;
char *item = (char *)xRingbufferReceive(buf_handle, &item_size, pdMS_TO_TICKS(1000));
@@ -162,23 +206,23 @@ using :cpp:func:`xRingbufferReceiveUpTo` and :cpp:func:`vRingbufferReturnItem`
For ISR safe versions of the functions used above, call :cpp:func:`xRingbufferSendFromISR`, :cpp:func:`xRingbufferReceiveFromISR`,
:cpp:func:`xRingbufferReceiveSplitFromISR`, :cpp:func:`xRingbufferReceiveUpToFromISR`, and :cpp:func:`vRingbufferReturnItemFromISR`
:cpp:func:`xRingbufferReceiveSplitFromISR`, :cpp:func:`xRingbufferReceiveUpToFromISR`, and :cpp:func:`vRingbufferReturnItemFromISR`
Sending to Ring Buffer
^^^^^^^^^^^^^^^^^^^^^^
The following diagrams illustrate the differences between no-split/allow-split buffers
and byte buffers with regards to sending items/data. The diagrams assume that three
The following diagrams illustrate the differences between no-split/allow-split buffers
and byte buffers with regards to sending items/data. The diagrams assume that three
items of sizes **18, 3, and 27 bytes** are sent respectively to a **buffer of 128 bytes**.
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_send_non_byte_buf.diag
:caption: Sending items to no-split/allow-split ring buffers
:align: center
For no-split/allow-split buffers, a header of 8 bytes precedes every data item. Furthermore, the space
For no-split/allow-split buffers, a header of 8 bytes precedes every data item. Furthermore, the space
occupied by each item is **rounded up to the nearest 32-bit aligned size** in order to maintain overall
32-bit alignment. However the true size of the item is recorded inside the header which will be
32-bit alignment. However the true size of the item is recorded inside the header which will be
returned when the item is retrieved.
Referring to the diagram above, the 18, 3, and 27 byte items are **rounded up to 20, 4, and 28 bytes**
@@ -188,12 +232,42 @@ respectively. An 8 byte header is then added in front of each item.
:caption: Sending items to byte buffers
:align: center
Byte buffers treat data as a sequence of bytes and does not incur any overhead
Byte buffers treat data as a sequence of bytes and does not incur any overhead
(no headers). As a result, all data sent to a byte buffer is merged into a single item.
Referring to the diagram above, the 18, 3, and 27 byte items are sequentially written to the
byte buffer and **merged into a single item of 48 bytes**.
Using SendAcquire and SendComplete
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Items in no-split buffers are acquired (by SendAcquire) in strict FIFO order and must be sent to
the buffer by SendComplete for the data to be accessible by the consumer. Multiple items can be
sent or acquired without calling SendComplete, and the items do not necessarily need to be
completed in the order they were acquired. However the receiving of data items must occur in FIFO
order, therefore not calling SendComplete the earliest acquired item will prevent the subsequent
items from being received.
The following diagrams illustrate what will happen when SendAcquire/SendComplete don't happen in
the same order. At the beginning, there is already an data item of 16 bytes sent to the ring
buffer. Then SendAcquire is called to acquire space of 20, 8, 24 bytes on the ring buffer.
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_send_acquire_complete.diag
:caption: SendAcquire/SendComplete items in no-split ring buffers
:align: center
After that, we fill (use) the buffers, and send them to the ring buffer by SendComplete in the
order of 8, 24, 20. When 8 bytes and 24 bytes data are sent, the consumer still can only get the
16 bytes data item. Due to the usage if 20 bytes item is not complete, it's not available, nor
the following data items.
When the 20 bytes item is finally completed, all the 3 data items can be received now, in the
order of 20, 8, 24 bytes, right after the 16 bytes item existing in the buffer at the beginning.
Allow-split/byte buffers do not allow using SendAcquire/SendComplete since acquired buffers are
required to be complete (not wrapped).
Wrap around
^^^^^^^^^^^
@@ -207,15 +281,15 @@ with **56 bytes of free space that wraps around** and a sent item of **28 bytes*
No-split buffers will **only store an item in continuous free space and will not split
an item under any circumstances**. When the free space at the tail of the buffer is insufficient
to completely store the item and its header, the free space at the tail will be **marked as dummy data**.
to completely store the item and its header, the free space at the tail will be **marked as dummy data**.
The buffer will then wrap around and store the item in the free space at the head of the buffer.
Referring to the diagram above, the 16 bytes of free space at the tail of the buffer is
Referring to the diagram above, the 16 bytes of free space at the tail of the buffer is
insufficient to store the 28 byte item. Therefore the 16 bytes is marked as dummy data and
the item is written to the free space at the head of the buffer instead.
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_wrap_allow_split.diag
:caption: Wrap around in allow-split buffers
:caption: Wrap around in allow-split buffers
:align: center
Allow-split buffers will attempt to **split the item into two parts** when the free space at the tail
@@ -232,17 +306,17 @@ as two parts to the buffer.
parts of a split item in a thread safe manner.
.. packetdiag:: ../../../_static/diagrams/ring-buffer/ring_buffer_wrap_byte_buf.diag
:caption: Wrap around in byte buffers
:caption: Wrap around in byte buffers
:align: center
Byte buffers will **store as much data as possible into the free space at the tail of buffer**. The remaining
Byte buffers will **store as much data as possible into the free space at the tail of buffer**. The remaining
data will then be stored in the free space at the head of the buffer. No overhead is incurred when wrapping
around in byte buffers.
Referring to the diagram above, the 16 bytes of free space at the tail of the buffer is insufficient to
completely store the 28 bytes of data. Therefore the 16 bytes of free space is filled with data, and the
remaining 12 bytes are written to the free space at the head of the buffer. The buffer now contains
data in two separate continuous parts, and each part continuous will be treated as a separate item by the
data in two separate continuous parts, and each part continuous will be treated as a separate item by the
byte buffer.
Retrieving/Returning
@@ -255,10 +329,10 @@ byte buffers in retrieving and returning data.
:caption: Retrieving/Returning items in no-split/allow-split ring buffers
:align: center
Items in no-split/allow-split buffers are **retrieved in strict FIFO order** and **must be returned**
for the occupied space to be freed. Multiple items can be retrieved before returning, and the items
Items in no-split/allow-split buffers are **retrieved in strict FIFO order** and **must be returned**
for the occupied space to be freed. Multiple items can be retrieved before returning, and the items
do not necessarily need to be returned in the order they were retrieved. However the freeing of space
must occur in FIFO order, therefore not returning the earliest retrieved item will prevent the space
must occur in FIFO order, therefore not returning the earliest retrieved item will prevent the space
of subsequent items from being freed.
Referring to the diagram above, the **16, 20, and 8 byte items are retrieved in FIFO order**. However the items
@@ -270,13 +344,13 @@ are not returned in they were retrieved (20, 8, 16). As such, the space is not f
:align: center
Byte buffers **do not allow multiple retrievals before returning** (every retrieval must be followed by a return
before another retrieval is permitted). When using :cpp:func:`xRingbufferReceive` or
before another retrieval is permitted). When using :cpp:func:`xRingbufferReceive` or
:cpp:func:`xRingbufferReceiveFromISR`, all continuous stored data will be retrieved. :cpp:func:`xRingbufferReceiveUpTo`
or :cpp:func:`xRingbufferReceiveUpToFromISR` can be used to restrict the maximum number of bytes retrieved. Since
every retrieval must be followed by a return, the space will be freed as soon as the data is returned.
Referring to the diagram above, the 38 bytes of continuous stored data at the tail of the buffer is retrieved,
returned, and freed. The next call to :cpp:func:`xRingbufferReceive` or :cpp:func:`xRingbufferReceiveFromISR`
Referring to the diagram above, the 38 bytes of continuous stored data at the tail of the buffer is retrieved,
returned, and freed. The next call to :cpp:func:`xRingbufferReceive` or :cpp:func:`xRingbufferReceiveFromISR`
then wraps around and does the same to the 30 bytes of continuous stored data at the head of the buffer.
Ring Buffers with Queue Sets
@@ -331,7 +405,7 @@ The :cpp:func:`xRingbufferCreateStatic` can be used to create ring buffers with
- The ring buffer's data structure of type :cpp:type:`StaticRingbuffer_t`
- The ring buffer's storage area of size ``xBufferSize``. Note that ``xBufferSize`` must be 32-bit aligned for no-split/allow-split buffers.
The manner in which these blocks are allocated will depend on the users requirements (e.g. all blocks being statically declared, or dynamically allocated with specific capabilities such as external RAM).
The manner in which these blocks are allocated will depend on the users requirements (e.g. all blocks being statically declared, or dynamically allocated with specific capabilities such as external RAM).
.. note::
The :ref:`CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION` option must be enabled in `menuconfig` for statically allocated ring buffers to be available.
@@ -375,20 +449,20 @@ Ring Buffer API Reference
.. note::
Ideally, ring buffers can be used with multiple tasks in an SMP fashion where the **highest
priority task will always be serviced first.** However due to the usage of binary semaphores
in the ring buffer's underlying implementation, priority inversion may occur under very
in the ring buffer's underlying implementation, priority inversion may occur under very
specific circumstances.
The ring buffer governs sending by a binary semaphore which is given whenever space is
The ring buffer governs sending by a binary semaphore which is given whenever space is
freed on the ring buffer. The highest priority task waiting to send will repeatedly take
the semaphore until sufficient free space becomes available or until it times out. Ideally
this should prevent any lower priority tasks from being serviced as the semaphore should
always be given to the highest priority task.
However in between iterations of acquiring the semaphore, there is a **gap in the critical
section** which may permit another task (on the other core or with an even higher priority) to
section** which may permit another task (on the other core or with an even higher priority) to
free some space on the ring buffer and as a result give the semaphore. Therefore the semaphore
will be given before the highest priority task can re-acquire the semaphore. This will result
in the **semaphore being acquired by the second highest priority task** waiting to send, hence
in the **semaphore being acquired by the second highest priority task** waiting to send, hence
causing priority inversion.
This side effect will not affect ring buffer performance drastically given if the number
@@ -403,9 +477,9 @@ Ring Buffer API Reference
Hooks
-----
FreeRTOS consists of Idle Hooks and Tick Hooks which allow for application
specific functionality to be added to the Idle Task and Tick Interrupt.
ESP-IDF provides its own Idle and Tick Hook API in addition to the hooks
FreeRTOS consists of Idle Hooks and Tick Hooks which allow for application
specific functionality to be added to the Idle Task and Tick Interrupt.
ESP-IDF provides its own Idle and Tick Hook API in addition to the hooks
provided by Vanilla FreeRTOS. ESP-IDF hooks have the added benefit of
being run time configurable and asymmetrical.
@@ -416,9 +490,9 @@ Idle and Tick Hooks in vanilla FreeRTOS are implemented by the user
defining the functions ``vApplicationIdleHook()`` and ``vApplicationTickHook()``
respectively somewhere in the application. Vanilla FreeRTOS will run the user
defined Idle Hook and Tick Hook on every iteration of the Idle Task and Tick
Interrupt respectively.
Interrupt respectively.
Vanilla FreeRTOS hooks are referred to as **Legacy Hooks** in ESP-IDF FreeRTOS.
Vanilla FreeRTOS hooks are referred to as **Legacy Hooks** in ESP-IDF FreeRTOS.
To enable legacy hooks, :ref:`CONFIG_FREERTOS_LEGACY_HOOKS` should be enabled
in :doc:`project configuration menu </api-reference/kconfig>`.
@@ -433,9 +507,9 @@ Due to the the dual core nature of the ESP32, it may be necessary for some
applications to have separate hooks for each core. Furthermore, it may
be necessary for the Idle Tasks or Tick Interrupts to execute multiple hooks
that are configurable at run time. Therefore the ESP-IDF provides it's own hooks
API in addition to the legacy hooks provided by Vanilla FreeRTOS.
API in addition to the legacy hooks provided by Vanilla FreeRTOS.
The ESP-IDF tick/idle hooks are registered at run time, and each tick/idle hook
The ESP-IDF tick/idle hooks are registered at run time, and each tick/idle hook
must be registered to a specific CPU. When the idle task runs/tick Interrupt
occurs on a particular CPU, the CPU will run each of its registered idle/tick hooks
in turn.

View File

@@ -2,7 +2,7 @@ Espressif IoT Development Framework Style Guide
===============================================
About this guide
About This Guide
----------------
Purpose of this style guide is to encourage use of common coding practices within the ESP-IDF.
@@ -13,7 +13,7 @@ We try to keep rules simple enough, which means that they can not cover all pote
When doing modifications to third-party code used in ESP-IDF, follow the way that particular project is written. That will help propose useful changes for merging into upstream project.
C code formatting
C Code Formatting
-----------------
Indentation
@@ -21,7 +21,7 @@ Indentation
Use 4 spaces for each indentation level. Don't use tabs for indentation. Configure the editor to emit 4 spaces each time you press tab key.
Vertical space
Vertical Space
^^^^^^^^^^^^^^
Place one empty line between functions. Don't begin or end a function with an empty line.
@@ -43,7 +43,9 @@ Place one empty line between functions. Don't begin or end a function with an em
}
}
Horizontal space
The maximum line length is 120 characters as long as it doesn't seriously affect the readability.
Horizontal Space
^^^^^^^^^^^^^^^^
Always add single space after conditional and loop keywords::
@@ -173,7 +175,7 @@ If you accidentally have some commits in your branch that add LF endings, you ca
For updating a single commit, it's possible to run ``dos2unix FILENAME`` and then run ``git commit --amend``
Formatting your code
Formatting Your Code
^^^^^^^^^^^^^^^^^^^^
You can use ``astyle`` program to format your code according to the above recommendations.
@@ -185,6 +187,106 @@ To re-format a file, run::
tools/format.sh components/my_component/file.c
C++ Code Formatting
-------------------
The same rules as for C apply. Where they are not enough, apply the following rules.
File Naming
^^^^^^^^^^^^
C++ Header files have the extension ``.h``. C++ source files have the extension ``.cpp``, which is important for the compiler to distiguish them from normal C source files.
Naming
^^^^^^
* **Class and struct** names shall be written in ``CamelCase`` with a capital letter as beginning. Member variables and methods shall be in ``snake_case``.
* **Namespaces** shall be in lower ``snake_case``.
* **Templates** are specified in the line above the function declaration.
Member Order in Classes
^^^^^^^^^^^^^^^^^^^^^^^
First put the public members, then the protected, then private ones. Omit public, protected or private sections without any members.
Spacing
^^^^^^^
* Don't indent inside namespaces.
* Put ``public``, ``protected`` and ``private`` labels at the same indentation level as the corresponding ``class`` label.
Simple Example
^^^^^^^^^^^^^^^
::
// file spaceship.h
#ifndef SPACESHIP_H_
#define SPACESHIP_H_
#include <cstdlib>
namespace spaceships {
class SpaceShip {
public:
SpaceShip(size_t crew);
size_t get_crew_size() const;
private:
const size_t crew;
};
class SpaceShuttle : public SpaceShip {
public:
SpaceShuttle();
};
class Sojuz : public SpaceShip {
public:
Sojuz();
};
template <typename T>
class CargoShip {
public:
CargoShip(const T &cargo);
private:
T cargo;
};
} // namespace spaceships
#endif // SPACESHIP_H_
// file spaceship.cpp
#include "spaceship.h"
namespace spaceships {
// Putting the curly braces in the same line for constructors is OK if it only initializes
// values in the initializer list
SpaceShip::SpaceShip(size_t crew) : crew(crew) { }
size_t SpaceShip::get_crew_size() const
{
return crew;
}
SpaceShuttle::SpaceShuttle() : SpaceShip(7)
{
// doing further initialization
}
Sojuz::Sojuz() : SpaceShip(3)
{
// doing further initialization
}
template <typename T>
CargoShip<T>::CargoShip(const T &cargo) : cargo(cargo) { }
} // namespace spaceships
CMake Code Style
----------------
@@ -198,7 +300,7 @@ CMake Code Style
- For globally scoped variables, use uppercase (``WITH_UNDERSCORES``).
- Otherwise follow the defaults of the cmake-lint_ project.
Configuring the code style for a project using EditorConfig
Configuring the Code Style for a Project Using EditorConfig
-----------------------------------------------------------
EditorConfig helps developers define and maintain consistent coding styles between different editors and IDEs. The EditorConfig project consists of a file format for defining coding styles and a collection of text editor plugins that enable editors to read the file format and adhere to defined styles. EditorConfig files are easily readable and they work nicely with version control systems.
@@ -206,7 +308,7 @@ EditorConfig helps developers define and maintain consistent coding styles betwe
For more information, see `EditorConfig <http://editorconfig.org>`_ Website.
Documenting code
Documenting Code
----------------
Please see the guide here: :doc:`documenting-code`.
@@ -230,7 +332,7 @@ Structure
To be written.
Language features
Language Features
-----------------
To be written.

View File

@@ -20,6 +20,10 @@ https://dl.espressif.com/dl/esp32_win32_msys2_environment_and_toolchain-20190611
Unzip the zip file to ``C:\`` (or some other location, but this guide assumes ``C:\``) and it will create an ``msys32`` directory with a pre-prepared environment.
.. important::
If another toolchain location is used (different than the default `C:\msys32`), please ensure that the path where the all-in-one toolchain gets unzipped is a plain ASCII, contains no spaces, symlinks or accents.
Check it Out
============

View File

@@ -1,3 +0,0 @@
:orphan:
.. Remove this file when the Chinese translation of getting started guide is updated

View File

@@ -1,73 +0,0 @@
在用户配置文件中添加 IDF_PATH 和 idf.py PATH
==========================================================================================================
:link_to_translation:`en:[英文]`
使用基于 CMake 的构建系统和 idf.py 工具,用户需修改两处系统环境变量:
- ``IDF_PATH`` 需设置为含有 ESP-IDF 目录的路径
- 系统 ``PATH`` 变量需包括含有 ``idf.py`` 工具 (属于 ESP-IDF 一部分)的目录
为确保系统重启后仍保存之前的变量设置,请参照以下说明将变量设置添加到用户配置文件中。
.. note:: 使用 IDE 工具的情况下,你可以选择在 IDE 项目环境中设置环境变量,而不使用如下命令行。
.. note:: 如果你从未用过 ``idf.py`` 命令行工具,而是直接运行 cmake 或通过 IDE 工具运行 cmake则无需设置 ``PATH`` 变量,只需设置 ``IDF_PATH`` 变量。不过,你也可以两个都设置。
.. note:: 如果你只用过 ``idf.py`` 命令行工具,从未直接运行 cmake 或通过 IDE 工具运行 cmake则无需设置 ``IDF_PATH`` 变量。``idf.py`` 会搜索自身包含的目录,如果没有发现 ``IDF_PATH``,则会自行进行有关设置。
.. _add-paths-to-profile-windows:
Windows 操作系统
-----------------------------------
在 Windows 10 操作系统下设置环境变量,用户应在开始菜单下搜索 "Edit Environment Variables"。
在较早版本的 Windows 操作系统下设置环境变量,用户应打开系统控制面板,选择“高级”,找到环境变量按钮。
你可以为本台电脑上的“所有用户”或“当前用户”设置环境变量,这取决于其他用户是否也需要使用 ESP-IDF。
- 点击 ``New...`` (新建... 添加名为 ``IDF_PATH`` 的新系统变量,具体设置为包含 ESP-IDF 的目录,例如,``C:\Users\user-name\esp\esp-idf``
- 找到 ``Path`` 环境变量,双击进行编辑。在末尾添加 ``;%IDF_PATH%\tools``,这样你就可以通过 Windows 命令窗口运行 ``idf.py`` 等其他工具了。
如果你在安装 ESP32 硬件开发的软件环境时,从 :ref:`get-started-setup-path` 小节跳到了这里,请返回 :ref:`get-started-start-project` 小节开始阅读。
.. _add-idf_path-to-profile-linux-macos:
Linux 和 MacOS 操作系统
------------------------------------
要设置 ``IDF_PATH``,并在 PATH 中添加 ``idf.py``,请将以下两行代码添加至你的 ``~/.profile`` 文件中::
export IDF_PATH=~/esp/esp-idf
export PATH="$IDF_PATH/tools:$PATH"
.. note::
``~/.profile`` 表示在你的电脑用户主目录中,后缀为 ``.profile`` 的文件。(``~`` 为 shell 中的缩写)。
请退出,并重新登录使更改生效。
.. note::
并非所有 shell 都使用 ``.profile``,但是如果同时存在 ``/bin/bash````.bash_profile``,请更新此配置文件。如果存在 ``zsh``,请更新 ``.zprofile``。其他 shell 可能使用其他配置文件(详询有关 shell 的文档)。
运行以下命令来检查 ``IDF_PATH`` 设置是否正确::
printenv IDF_PATH
此处应打印出此前在 ``~/.profile`` 文件中输入(或手动设置)的路径。
为确认 ``idf.py`` 目前是否在 ``PATH`` 中,你可以运行以下命令::
which idf.py
这里,应打印出类似 ``${IDF_PATH}/tools/idf.py`` 的路径。
如果不想修改 ``IDF_PATH````PATH``,你可以在每次重启或退出后在终端中手动输入::
export IDF_PATH=~/esp/esp-idf
export PATH="$IDF_PATH/tools:$PATH"
如果你在安装 ESP32 硬件开发的软件环境时,从 :ref:`get-started-setup-path` 小节跳到了这里,请返回 :ref:`get-started-start-project` 小节开始阅读。

View File

@@ -4,6 +4,8 @@ Eclipse IDE 创建和烧录指南
:link_to_translation:`en:[English]`
有关基于 CMake-based 构建系统和 Eclipse CDT进行 Eclipse 设置的相关文档即将发布
ESP-IDF V4.0 将默认采用基于 CMake 的编译系统
.. _eclipse.org: https://www.eclipse.org/
对此,我们还推出了针对 CMake 编译系统的新 ESP-IDF Eclipse 插件。具体操作,请见 `ESP-IDF Eclipse 插件 <https://github.com/espressif/idf-eclipse-plugin/blob/master/README.md>`
如您仍需要对传统 GNU Make 编译系统的 Eclipse 支持,请前往 :doc:`传统 GNU Make 编译系统入门指南 </get-started-legacy/index>`,查看 :doc:`使用 Eclipse IDE 进行编译与烧录 </get-started-legacy/eclipse-setup>` 章节。

View File

@@ -1,22 +1,20 @@
*******************
快速入门CMake
*******************
***********
快速入门
***********
:link_to_translation:`en:[English]`
本文档旨在指导用户搭建 ESP32 硬件开发的软件环境,
通过一个简单的示例展示如何使用 ESP-IDF (Espressif IoT Development Framework) 配置菜单,并编译、下载固件至 ESP32 开发板等步骤。
本文档旨在指导用户搭建 ESP32 硬件开发的软件环境,通过一个简单的示例展示如何使用 ESP-IDF (Espressif IoT Development Framework) 配置菜单,并编译、下载固件至 ESP32 开发板等步骤。
.. include:: /_build/inc/version-note.inc
概述
====
============
ESP32 SoC 芯片支持以下功能:
* 2.4 GHz Wi-Fi
* 蓝牙 4.2 标准
* 蓝牙 4.2
* 高性能双核
* 超低功耗协处理器
* 多种外设
@@ -26,18 +24,18 @@ ESP32 采用 40 nm 工艺制成,具有最佳的功耗性能、射频性能、
乐鑫为用户提供完整的软、硬件资源,进行 ESP32 硬件设备的开发。其中,乐鑫的软件开发环境 ESP-IDF 旨在协助用户快速开发物联网 (IoT) 应用,可满足用户对 Wi-Fi、蓝牙、低功耗等方面的要求。
准备工作
========
=============
硬件:
* 一款 **ESP32** 开发板
* **USB 数据线** USB A/Micro USB B
* **USB 数据线** (A 转 Micro-B)
* PCWindows、Linux 或 Mac OS
软件:
* 设置 **工具链**,用于编译 ESP32 代码;
* **编译工具** —— CMake 和 Ninja 编译工具,用于编译 ESP32 **应用程序**
* **编译工具** —— CMake 和 Ninja 编译工具,用于编译 ESP32 **应用程序**
* 获取 **ESP-IDF** 软件开发框架。该框架已经基本包含 ESP32 使用的 API软件库和源代码和运行 **工具链** 的脚本;
* 安装 C 语言编程(**工程**)的 **文本编辑器**,例如 `Eclipse <https://www.eclipse.org/>`_
@@ -51,7 +49,7 @@ ESP32 采用 40 nm 工艺制成,具有最佳的功耗性能、射频性能、
开发板简介
==========
===========================
请点击下方连接,了解有关具体开发板的详细信息。
@@ -67,17 +65,17 @@ ESP32 采用 40 nm 工艺制成,具有最佳的功耗性能、射频性能、
.. _get-started-step-by-step:
详细安装步骤
==============
=========================
请根据下方详细步骤,完成安装过程。
设置开发环境
~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* :ref:`get-started-setup-toolchain`
* :ref:`get-started-get-prerequisites` :doc:`Windows <windows-setup>`:doc:`Linux <linux-setup>`:doc:`macOS <macos-setup>`
* :ref:`get-started-get-esp-idf`
* :ref:`get-started-setup-path`
* :ref:`get-started-get-packages`
* :ref:`get-started-set-up-tools`
* :ref:`get-started-set-up-env`
创建您的第一个工程
~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -90,14 +88,12 @@ ESP32 采用 40 nm 工艺制成,具有最佳的功耗性能、射频性能、
* :ref:`get-started-build-monitor`
.. _get-started-setup-toolchain:
.. _get-started-get-prerequisites:
第一步:设置工具链
====================
第一步:安装准备
=============================
工具链指一套用于编译代码和应用程序的程序。
为了加快开发进度,您可以直接使用乐鑫提供的预制工具链。请根据您的操作系统,点击下方对应的链接,并按照链接中的指导进行安装。
在正式开始创建工程前,请先完成工具的安装,具体步骤见下:
.. toctree::
:hidden:
@@ -125,27 +121,22 @@ ESP32 采用 40 nm 工艺制成,具有最佳的功耗性能、射频性能、
.. _Linux: ../get-started/linux-setup.html
.. _Mac OS: ../get-started/macos-setup.html
.. _get-started-get-esp-idf:
第二步:获取 ESP-IDF
=================================
在围绕 ESP32 构建应用程序之前,请先获取乐鑫提供的软件库文件 `ESP-IDF 仓库 <https://github.com/espressif/esp-idf>`_
获取 ESP-IDF 的本地副本:打开终端,切换到您要保存 ESP-IDF 的工作目录,使用 ``git clone`` 命令克隆远程仓库。针对不同操作系统的详细步骤,请见下文。
.. note::
在本文档中Linux 和 MacOS 操作系统中 ESP-IDF 的默认安装路径为 ``~/esp``Windows 操作系统的默认路径为 ``%userprofile%\esp``。您也可以将 ESP-IDF 安装在任何其他路径下但请注意在使用命令行时进行相应替换。注意ESP-IDF 不支持带有空格的路径。
此外, 您也可以根据自身经验和实际需求,对环境进行个性化设置,而非使用预制工具链。此时,请前往 :ref:`工具链的个性化设置<get-started-customized-setup>` 章节获取更多信息。
.. _get-started-get-esp-idf:
.. _get-started-set-up-tools:
第二步:获取 ESP-IDF
===========================
除了工具链,您还需要供 ESP32 使用的 API软件库和源代码具体请见 `ESP-IDF 仓库 <https://github.com/espressif/esp-idf>`_。
请将 ESP-IDF 下载到您的本地。
获取本地副本:打开终端,切换到你要存放 ESP-IDF 的工作目录,使用 ``git clone`` 命令克隆远程仓库。
Linux 和 MacOS 操作系统
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
打开终端,后运行以下命令:
@@ -156,71 +147,103 @@ ESP-IDF 将下载至 ``~/esp/esp-idf``。
请前往 :doc:`/versions`,查看 ESP-IDF 不同版本的具体适用场景。
Windows 操作系统
~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. note::
较早版本 ESP-IDF 使用了 **MSYS2 bash 终端** 命令行。目前,基于 CMake 的编译系统可使用常见的 **Windows 命令窗口**,即本指南中使用的终端。
请注意,如果您使用基于 bash 的终端或 PowerShell 终端,一些命令语法将与下面描述有所不同。
打开命令提示符,后运行以下命令:
.. include:: /_build/inc/git-clone-windows.inc
ESP-IDF 将下载至 ``%userprofile%\esp\esp-idf``
除了安装必要工具外,第一步中介绍的 :ref:`get-started-windows-tools-installer` 也能同时下载 ESP-IDF 本地副本。
请前往 :doc:`/versions`,查看 ESP-IDF 不同版本的具体适用场景。
.. include:: /_build/inc/git-clone-notes.inc
除了使用 ESP-IDF 工具安装器,您也可以参考 :ref:`指南 <get-esp-idf-windows-command-line>` 手动下载 ESP-IDF。
.. note::
.. _get-started-set-up-tools:
在克隆远程仓库时,不要忘记加上 ``--recursive`` 选项。否则,请接着运行以下命令,获取所有子模块: ::
cd esp-idf
git submodule update --init
.. _get-started-setup-path:
.. _get-started-set-up-env:
第三步:设置环境变量
===========================
请在您的 PC 上设置以下环境变量,否则无法编译工程。
- ``IDF_PATH`` 应设置为 ESP-IDF 根目录的路径。
- ``PATH`` 应包括同一 ``IDF_PATH`` 目录下的 ``tools`` 目录路径。
您可以在每次重启会话时手动设置,也可以在用户配置中进行永久设置,具体请前往 :doc:`add-idf_path-to-profile` 章节,查看 :ref:`Windows <add-paths-to-profile-windows>`:ref:`Linux 及 MacOS <add-idf_path-to-profile-linux-macos>` 操作系统的具体设置方式。
.. _get-started-get-packages:
第四步:安装 Python 软件包
第三步:设置工具
=================================
ESP-IDF 所需的 Python 软件包位于 ``IDF_PATH/requirements.txt`` 中。您可以运行以下命令进行安装: ::
除了 ESP-IDF 本身,您还需要安装 ESP-IDF 使用的各种工具比如编译器、调试器、Python 包等。
python -m pip install --user -r $IDF_PATH/requirements.txt
Windows 操作系统
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. note::
请根据第一步中对 Windows (:ref:`get-started-windows-tools-installer`) 的介绍,安装所有必需工具。
请注意查询您所使用的 Python 解释器的版本(运行命令 ``python --version``),并根据查询结果将上方命令中的 ``python`` 替换为 ``python2``, ``python2.7``,例如
除了使用 ESP-IDF 工具安装器,您也可以通过 **命令提示符** 窗口手动安装这些工具。具体步骤见下
``python2.7 -m pip install --user -r $IDF_PATH/requirements.txt``
.. code-block:: batch
cd %userprofile%\esp\esp-idf
install.bat
或使用 Windows PowerShell
.. code-block:: powershell
cd ~/esp/esp-idf
./install.ps1
Linux 和 MacOS 操作系统
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: bash
cd ~/esp/esp-idf
./install.sh
自定义工具安装路径
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
本步骤中介绍的脚本将 ESP-IDF 所需的编译工具默认安装在用户根文件夹中,即 Linux 和 MacOS 系统中的 ``$HOME/.espressif`` 和 Windows 系统的 ``%USERPROFILE%\.espressif``。此外,您可以可以将工具安装到其他目录中,但请在运行安装脚本前,重新设置环境变量 ``IDF_TOOLS_PATH``。注意,请确保您的用户已经具备了读写该路径的权限。
如果修改了 ``IDF_TOOLS_PATH`` 变量,请确保该变量在每次执行“安装脚本” (``install.bat````install.ps1````install.sh``) 和导出脚本 (``export.bat````export.ps1````export.sh``) 均保持一致。
.. _get-started-set-up-env:
第四步:设置环境变量
=======================================
此时,您刚刚安装的工具尚未添加至 PATH 环境变量,无法通过“命令窗口”使用这些工具。因此,必须设置一些环境变量,这可以通过 ESP-IDF 提供的另一个脚本完成。
Windows 操作系统
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Windows 安装器(:ref:`get-started-windows-tools-installer` )可在“开始”菜单创建一个 "ESP-IDF Command Prompt" 快捷方式。该快捷方式可以打开命令提示符窗口,并设置所有环境变量。您可以点击该快捷方式,然后继续下一步。
此外,如果您希望在当下命令提示符窗口使用 ESP-IDF请使用下方代码
.. code-block:: batch
%userprofile%\esp\esp-idf\export.bat
或使用 Windows PowerShell
.. code-block:: powershell
.$HOME/esp/esp-idf/export.ps1
Linux 和 MacOS 操作系统
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
请在您需要运行 ESP-IDF 的“命令提示符”窗口运行以下命令:
.. code-block:: bash
. $HOME/esp/esp-idf/export.sh
注意,命令开始的 "." 与路径之间应有一个空格!
此外,您也可以将这行代码增加至您的 ``.profile````.bash_profile`` 脚本中,这样您就可以在任何命令窗口使用 ESP-IDF 工具了。
.. _get-started-start-project:
第五步:开始创建工程
=======================
========================================
现在,您可以开始准备开发 ESP32 应用程序了。您可以从 ESP-IDF 中 :idf:`examples` 目录下的 :example:`get-started/hello_world` 工程开始。
:example:`get-started/hello_world` 复制至您本地的 ``~/esp`` 目录下:
Linux 和 MacOS 操作系统
~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: bash
@@ -228,7 +251,7 @@ Linux 和 MacOS 操作系统
cp -r $IDF_PATH/examples/get-started/hello_world .
Windows 操作系统
~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: batch
@@ -244,7 +267,7 @@ ESP-IDF 的 :idf:`examples` 目录下有一系列示例工程,都可以按照
.. _get-started-connect:
第六步:连接设备
======================
==========================================
现在,请将您的 ESP32 开发板连接到 PC并查看开发板使用的串口。
@@ -264,34 +287,28 @@ ESP-IDF 的 :idf:`examples` 目录下有一系列示例工程,都可以按照
.. _get-started-configure:
第七步:配置
=================
=========================
请进入 :ref:`get-started-start-project` 中提到的 ``hello_world`` 目录,并运行工程配置工具 ``menuconfig``
Linux 和 MacOS 操作系统
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: bash
cd ~/esp/hello_world
idf.py menuconfig
如果您的默认 Python 版本为 3.0 以上,可能需要运行 ``python2 idf.py``
如果您的默认 Python 版本为 3.0 以上,可能需要运行 ``python2 $(which idf.py) menuconfig``
Windows 操作系统
~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: batch
cd %userprofile%\esp\hello_world
idf.py menuconfig
Python 2.7 安装程序将尝试配置 Windows``.py`` 文件与 Python 2 关联起来。如果其他程序(比如 Visual Studio Python 工具)曾关联了其他版本 Python``idf.py`` 可能无法正常运行(文件将在 Visual Studio 中打开)。这种情况下,您可以选择每次都运行一遍 ``C:\Python27\python idf.py``,或更改 Windows 的 ``.py`` 关联文件设置。
.. note::
如果出现 ``idf.py not found无法找到 idf.py`` 错误,请确保 ``PATH`` 环境变量设置无误,具体请参考 :ref:`get-started-setup-path`。如果 ``tools`` 目录下没有 ``idf.py`` 文件,请确保 CMake 预览的分支正确无误,具体请参考 :ref:`get-started-get-esp-idf`
如果之前的步骤都正确,则会显示下面的菜单:
.. figure:: ../../_static/project-configuration.png
@@ -299,17 +316,17 @@ Python 2.7 安装程序将尝试配置 Windows将 ``.py`` 文件与 Python 2
:alt: 工程配置 — 主窗口
:figclass: align-center
工程配置 — 主窗口
工程配置 — 主窗口
``menuconfig`` 工具的常见操作见下。
* ``上下箭头``:移动
* 上下箭头:移动
* ``回车``:进入子菜单
* ``ESC 键``:返回上级菜单或退出
* ``英文问号``:调出帮助菜单(退出帮助菜单,请按回车键)。
* ``空格````Y 键````N 键``使能/禁用 ``[*]`` 配置选项
* ``英文问号``:调出有关高亮选项的帮助菜单
* ``/ 键``:寻找配置项目
* ``空格````Y 键``:选择 ``[*]`` 配置选项;``N 键``:禁用 ``[*]`` 配置选项
* ``英文问号`` (查询配置选项):调出有关选项的帮助菜单
* ``/ 键``:寻找配置工程
.. attention::
@@ -318,7 +335,7 @@ Python 2.7 安装程序将尝试配置 Windows将 ``.py`` 文件与 Python 2
.. _get-started-build:
第八步:编译工程
==================
=========================
请使用以下命令,编译烧录工程:::
@@ -328,23 +345,23 @@ Python 2.7 安装程序将尝试配置 Windows将 ``.py`` 文件与 Python 2
.. code-block:: none
$ idf.py build
Running cmake in directory /path/to/hello_world/build
Executing "cmake -G Ninja --warn-uninitialized /path/to/hello_world"...
Warn about uninitialized values.
-- Found Git: /usr/bin/git (found version "2.17.0")
-- Building empty aws_iot component due to configuration
-- Component names: ...
-- Component paths: ...
... (more lines of build system output)
[527/527] Generating hello-world.bin
esptool.py v2.3.1
Project build complete. To flash, run this command:
../../../components/esptool_py/esptool/esptool.py -p (PORT) -b 921600 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x10000 build/hello-world.bin build 0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin
or run 'idf.py -p PORT flash'
$ idf.py build
Running cmake in directory /path/to/hello_world/build
Executing "cmake -G Ninja --warn-uninitialized /path/to/hello_world"...
Warn about uninitialized values.
-- Found Git:/usr/bin/git (found version "2.17.0")
-- Building empty aws_iot component due to configuration
-- Component names: ...
-- Component paths: ...
... (more lines of build system output)
[527/527] Generating hello-world.bin
esptool.py v2.3.1
Project build complete. To flash, run this command:
../../../components/esptool_py/esptool/esptool.py -p (PORT) -b 921600 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x10000 build/hello-world.bin build 0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin
or run 'idf.py -p PORT flash'
如果一切正常,编译完成后将生成 .bin 文件。
@@ -352,15 +369,15 @@ Python 2.7 安装程序将尝试配置 Windows将 ``.py`` 文件与 Python 2
.. _get-started-flash:
第九步:烧录到设备
====================
=============================
请使用以下命令,将刚刚生成的二进制文件烧录至您的 ESP32 开发板: ::
请使用以下命令,将刚刚生成的二进制文件烧录至您的 ESP32 开发板:
idf.py -p PORT [-b BAUD] flash
``idf.py -p PORT [-b BAUD] flash``
请将 PORT 替换为 ESP32 开发板的串口名称,具体可见 :ref:`get-started-connect`
您还可以将 BAUD 替换为您希望的烧录波特率。默认波特率为 ``460800``
您还可以将 BAUD 替换为您希望的烧录波特率。默认波特率为 ``460800``
更多有关 idf.py 参数的详情,请见 :ref:`idf.py`
@@ -409,11 +426,11 @@ Python 2.7 安装程序将尝试配置 Windows将 ``.py`` 文件与 Python 2
.. _get-started-build-monitor:
第十步:监视器
==================
======================
您可以使用 ``make monitor`` 命令,监视 “hello_world” 的运行情况。注意,不要忘记将 PORT 替换为您的串口名称。
运行该命令后,:doc:`IDF 监视器 <../api-guides/tools/idf-monitor>` 应用程序将启动: ::
运行该命令后,:doc:`IDF 监视器 <../api-guides/tools/idf-monitor>` 应用程序将启动:::
$ idf.py -p /dev/ttyUSB0 monitor
Running idf_monitor in directory [...]/esp/hello_world/build
@@ -440,17 +457,17 @@ Python 2.7 安装程序将尝试配置 Windows将 ``.py`` 文件与 Python 2
您可使用快捷键 ``Ctrl+]``,退出 IDF 监视器。
如果 IDF 监视器在烧录后很快发生错误,或打印信息全是乱码(见下),很有可能是因为您的开发板用了 26 MHz 晶振,而 ESP-IDF 默认支持大多数开发板使用的 40 MHz 晶振。
如果 IDF 监视器在烧录后很快发生错误,或打印信息全是乱码(见下),很有可能是因为您的开发板用了 26 MHz 晶振,而 ESP-IDF 默认支持大多数开发板使用的 40 MHz 晶振。
.. figure:: ../../_static/get-started-garbled-output.png
:align: center
:alt: 乱码输出
:figclass: align-center
此时,您:
此时,您可以
1. 退出监视器。
2. 打开 :ref:`menuconfig <get-started-configure>`
2. 打开 :ref:`menuconfig <get-started-configure>`
3. 进入 ``Component config`` --> ``ESP32-specific`` --> ``Main XTAL frequency`` 进行配置,将 :ref:`CONFIG_ESP32_XTAL_FREQ_SEL` 设置为 26 MHz。
4. 然后,请重新 :ref:`编译和烧录 <get-started-flash>` 应用程序。
@@ -458,7 +475,7 @@ Python 2.7 安装程序将尝试配置 Windows将 ``.py`` 文件与 Python 2
您也可以运行以下命令,一次性执行构建、烧录和监视过程:
``idf.py -p PORT flash monitor``
``idf.py -p PORT flash monitor``
此外,
@@ -470,21 +487,22 @@ Python 2.7 安装程序将尝试配置 Windows将 ``.py`` 文件与 Python 2
现在,您可以尝试一些其他 :idf:`examples`,或者直接开发自己的应用程序。
更新 ESP-IDF
=================
================
乐鑫会不时推出更新版本的 ESP-IDF修复 bug 或提出新的特性。因此,您在使用时,也应注意更新您本地的版本。最简单的方法是:直接删除您本地的 ``esp-idf`` 文件夹,然后按照 :ref:`get-started-get-esp-idf` 中的指示,重新完成克隆。
如果您希望将 ESP-IDF 克隆到新的路径下,请务必 :doc:`重新设置 IDF_PATH <add-idf_path-to-profile>`。否则,工具链将无法找到 ESP-IDF。
此外,您可以仅更新变更部分。具体方式,请前往 :ref:`更新 <updating>` 章节查看。
注意,更新完成后,请执行 ``install.sh`` Windows 系统中为 ``install.bat``)脚本,避免新版 ESP-IDF 所需的工具也有所更新。具体请参考 :ref:`get-started-set-up-tools`
一旦重新安装好工具,请使用“导出脚本”更新环境,具体请参考 :ref:`get-started-set-up-env`
相关文档
===========
=================
.. toctree::
:maxdepth: 1
add-idf_path-to-profile
establish-serial-connection
eclipse-setup
../api-guides/tools/idf-monitor

View File

@@ -4,7 +4,7 @@
:link_to_translation:`en:[English]`
除了从乐鑫官网直接下载已编译好的二进制工具链外,还可以按照本文介绍,从头开始设置自己的工具链。如需快速使用已编译好的二进制工具链,可回到 :doc:`linux-setup` 章节。
除了从乐鑫官网直接下载已编译好的二进制工具链外,还可以按照本文介绍,从头开始设置自己的工具链。如需快速使用已编译好的二进制工具链,可回到 :doc:`linux-setup` 章节。
安装准备
=====================
@@ -23,39 +23,38 @@
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-click python2-cryptography python2-future python2-pyparsing python2-pyelftools cmake ninja ccache
.. note::
使用 ESP-IDF 需要 CMake 3.5 或以上版本。较早版本的 Linux 可能需要升级才能向后移植仓库,或安装 "cmake3" 软件包,而不是安装 "cmake"。
从源代码编译工具链
=================================
- 安装依赖:
安装依赖
- CentOS 7::
- CentOS 7::
sudo yum install gawk gperf grep gettext ncurses-devel python python-devel automake bison flex texinfo help2man libtool make
sudo yum install gawk gperf grep gettext ncurses-devel python python-devel automake bison flex texinfo help2man libtool make
- Ubuntu pre-16.04::
- Ubuntu pre-16.04::
sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool make
sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool make
- Ubuntu 16.04 以上::
- Ubuntu 16.04 以上 ::
sudo apt-get install gawk gperf grep gettext python python-dev automake bison flex texinfo help2man libtool libtool-bin make
sudo apt-get install gawk gperf grep gettext python python-dev automake bison flex texinfo help2man libtool libtool-bin make
- Debian 9::
- Debian 9::
sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool libtool-bin make
sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool libtool-bin make
- Arch::
- Arch::
TODO
TODO
创建工作目录,并进入该目录::
mkdir -p ~/esp
cd ~/esp
mkdir -p ~/esp
cd ~/esp
下载并编译 ``crosstool-NG``
@@ -67,7 +66,7 @@
./ct-ng build
chmod -R u+w builds/xtensa-esp32-elf
编译得到的工具链会被保存到 ``~/esp/crosstool-NG/builds/xtensa-esp32-elf``。请按照 :ref:`标准设置指南 <setup-linux-toolchain-add-it-to-path>` 的介绍,将工具链添加到 ``PATH``
编译得到的工具链会被保存到 ``~/esp/crosstool-NG/builds/xtensa-esp32-elf``。请按照 :ref:`标准设置指南 <setup-linux-toolchain-add-it-to-path-legacy>` 的介绍,将工具链添加到 ``PATH``
后续步骤

View File

@@ -1,10 +1,10 @@
*******************************************************************
*********************************************
Linux 平台工具链的标准设置
*******************************************************************
*********************************************
:link_to_translation:`en:[英文]`
:link_to_translation:`en:[English]`
安装前提
安装准备
=====================
编译 ESP-IDF 需要以下软件包:
@@ -15,94 +15,41 @@ Linux 平台工具链的标准设置
- Ubuntu 和 Debian::
sudo apt-get install git wget libncurses-dev flex bison gperf python python-click python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache
sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-click python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache
- Arch::
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-click python2-cryptography python2-future python2-pyparsing python2-pyelftools cmake ninja ccache
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pip python2-pyserial python2-click python2-cryptography python2-future python2-pyparsing python2-pyelftools cmake ninja ccache
.. note::
使用 ESP-IDF 需要 CMake 3.5 或以上版本。较早版本的 Linux 可能需要升级才能向后移植仓库,或安装 "cmake3" 软件包,而不是安装 "cmake"。
工具链的设置
=========================
.. include:: /_build/inc/download-links.inc
Linux 版的 ESP32 工具链可以从 Espressif 的网站下载:
- 64 位 Linux
|download_link_linux64|
- 32 位 Linux
|download_link_linux32|
1. 下载完成后,将它解压到 ``~/esp`` 目录:
- for 64-bit Linux:
.. include:: /_build/inc/unpack-code-linux64.inc
- for 32-bit Linux:
.. include:: /_build/inc/unpack-code-linux32.inc
.. _setup-linux-toolchain-add-it-to-path:
2. 工具链将会被解压到 ``~/esp/xtensa-esp32-elf/`` 目录。
要使用工具链,你还需要在 ``~/.profile`` 文件中更新环境变量 ``PATH``。要使 ``xtensa-esp32-elf`` 在所有的终端会话中都有效,需要将下面这一行代码添加到你的 ``~/.profile`` 文件中:::
export PATH="$HOME/esp/xtensa-esp32-elf/bin:$PATH"
或者,你也可以给上面的命令创建一个别名。这样做的好处是,你仅在需要时才获取工具链,将下面这行代码添加到 ``~/.profile`` 文件中即可::
alias get_esp32='export PATH="$HOME/esp/xtensa-esp32-elf/bin:$PATH"'
然后,当你需要使用工具链时,在命令行输入 ``get_esp32``,然后工具链会自动添加到你的 ``PATH`` 中。
.. note::
如果将 ``/bin/bash`` 设置为登录 shell且同时存在 ``.bash_profile````.profile``,则更新 ``.bash_profile``
3. 退出并重新登录以使 ``.profile`` 更改生效。运行以下命令来检查 ``PATH`` 设置是否正确::
printenv PATH
检查字符串的开头是否包含类似的工具链路径::
$ printenv PATH
/home/user-name/esp/xtensa-esp32-elf/bin:/home/user-name/bin:/home/user-name/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
除了 ``/home/user-name``,应该有具体的安装的主路径。
其他提示
===============
权限问题 /dev/ttyUSB0
----------------------------------------------
------------------------------------------------------------
使用某些 Linux 版本向 ESP32 烧写固件时,可能会出现 ``Failed to open port /dev/ttyUSB0`` 错误消息。此时,可以将当前用户增加至 :ref:` Linux Dialout 组 <linux-dialout-group>`
使用某些 Linux 版本向 ESP32 烧写固件时,可能会出现 ``Failed to open port /dev/ttyUSB0`` 错误消息。此时,可以将当前用户增加至 :ref:` Linux Dialout 组 <linux-dialout-group>`
Arch Linux 用户
--------------------------------
ncurses 5 依赖项
--------------------
Arch Linux 运行预编译的 gdb (xtensa-esp32-elf-gdb) 需要 ncurses 5是 Arch 使用的是 ncurses 6。
在 Linux 运行预编译的 gdb (xtensa-esp32-elf-gdb) 需要 ncurses 5一些较新版本默认只提供 ncurses 6。
`AUR`_ 中存在向下兼容的库文件,可用于本地和 lib32 的配置:
请查看对应版本信息,确认是否存在可用的 ncurses 5。此外您也可以使用 crosstool-NG 编译一个链接到 ncurses 6 的 gdb。
Arch Linux 用户可在 AUR_ 中获得 native 和 lib32 配置的 ncurses 5 库:
- https://aur.archlinux.org/packages/ncurses5-compat-libs/
- https://aur.archlinux.org/packages/lib32-ncurses5-compat-libs/
在安装这些软件包之前,可能需要将作者的公钥添加到的密钥环中,具体见上方链接中的 "Comments" 部分的介绍
或者,你也可以使用 crosstool-NG 编译一个链接到 ncurses 6 的 gdb。
在安装这些软件包之前,可能需要将作者的公钥添加到的密钥环中,具体参考上方的“注释”部分
后续步骤
================
==========
后续开发环境设置,请参考 :ref:`get-started-get-esp-idf` 节。
继续设置开发环境,请前往 :ref:`get-started-get-esp-idf` 节。
相关文档
@@ -115,3 +62,4 @@ Arch Linux 用户
.. _AUR: https://wiki.archlinux.org/index.php/Arch_User_Repository

View File

@@ -1,86 +1,87 @@
*********************************************************************
从零开始设置 Mac OS 环境下的工具链
*********************************************************************
***********************************************
从零开始设置 MacOS 环境下的工具链
***********************************************
:link_to_translation:`en:[英文]`
:link_to_translation:`en:[English]`
软件包管理器
======================
===============
从零开始设置工具链,需要安装 MacPorts_ 或 homebrew_ 包管理器。或者,也可以直接 :doc:`下载预编译的工具链 <macos-setup>`
从零开始设置工具链,需要安装 MacPorts_ 或 homebrew_ 软件包管理器。或者,也可以直接 :doc:`下载预编译的工具链 <macos-setup>`
MacPorts_ 需要安装完整的 XCode 软件,而 homebrew_ 只需要安装 XCode 命令行工具即可。
MacPorts 需要完整的 XCode 软件,而 homebrew 只需要安装 XCode 命令行工具即可。
.. _homebrew: https://brew.sh/
.. _MacPorts: https://www.macports.org/install.php
.. _homebrew: https://brew.sh/
.. _MacPorts: https://www.macports.org/install.php
请参考 :ref:`工具链自定义设置 <get-started-customized-setup>` 章节,查看在哪些情景下需要从头开始设置工具链。
请参考 :ref:`工具链自定义设置 <get-started-customized-setup>` 章节,查看可能需要从头开始设置工具链的情况
准备工作
============================
安装准备
=====================
- 安装 pip::
sudo easy_install pip
sudo easy_install pip
- 安装 pyserial::
pip install --user pyserial
pip install --user pyserial
- 安装 CMake 和 Ninja 编译工具:
- 若使用 HomeBrew可以运行::
- 若有 HomeBrew可以运行::
brew install cmake ninja
brew install cmake ninja
- 若使用 MacPorts可以运行::
- 若有 MacPorts可以运行::
sudo port install cmake ninja
sudo port install cmake ninja
从源代码编译工具链
========================================
=================================
- 相关安装
安装依赖项:
- 对于 MacPorts::
- 对于 MacPorts::
sudo port install gsed gawk binutils gperf grep gettext wget libtool autoconf automake make
sudo port install gsed gawk binutils gperf grep gettext wget libtool autoconf automake make
- 对于 homebrew::
- 对于 homebrew::
brew install gnu-sed gawk binutils gperftools gettext wget help2man libtool autoconf automake make
brew install gnu-sed gawk binutils gperftools gettext wget help2man libtool autoconf automake make
创建一个文件系统镜像(区分大小写)::
hdiutil create ~/esp/crosstool.dmg -volname "ctng" -size 10g -fs "Case-sensitive HFS+"
hdiutil create ~/esp/crosstool.dmg -volname "ctng" -size 10g -fs "Case-sensitive HFS+"
挂载::
hdiutil mount ~/esp/crosstool.dmg
hdiutil mount ~/esp/crosstool.dmg
创建指向工作目录的符号链接::
创建指向工作目录的符号链接::
mkdir -p ~/esp
ln -s /Volumes/ctng ~/esp/ctng-volume
mkdir -p ~/esp
ln -s /Volumes/ctng ~/esp/ctng-volume
前往新创建的目录::
前往新创建的目录 ::
cd ~/esp/ctng-volume
cd ~/esp/ctng-volume
下载 ``crosstool-NG``,并开始编译:
下载并编译 ``crosstool-NG``
.. include:: /_build/inc/scratch-build-code.inc
编译工具链::
编译工具链::
./ct-ng xtensa-esp32-elf
./ct-ng build
chmod -R u+w builds/xtensa-esp32-elf
./ct-ng xtensa-esp32-elf
./ct-ng build
chmod -R u+w builds/xtensa-esp32-elf
编译的工具链将保存在 ``~/esp/ctng-volume/crosstool-NG/builds/xtensa-esp32-elf``根据 :ref:`Mac OS 下设置环境变量的标准方法 <setup-macos-toolchain-add-it-to-path>` 中的介绍,将工具链添加到 ``PATH``
编译得到的工具链会被保存到 ``~/esp/ctng-volume/crosstool-NG/builds/xtensa-esp32-elf``使用工具链前,请将 ``~/esp/ctng-volume/crosstool-NG/builds/xtensa-esp32-elf/bin`` 添加至 ``PATH`` 环境变量
后续步骤
=================
==========
继续设置开发环境,请前往 :ref:`get-started-get-esp-idf` 章节。
继续设置开发环境,请前往 :ref:`获取 ESP-IDF <get-started-get-esp-idf>` 章节。

View File

@@ -1,8 +1,8 @@
******************************************************************
Mac OS 上安装 ESP32 工具链
******************************************************************
**********************************************
MacOS 平台工具链的标准设置
**********************************************
:link_to_translation:`en:[英文]`
:link_to_translation:`en:[English]`
安装准备
=====================
@@ -19,64 +19,30 @@ ESP-IDF 将使用 Mac OS 上默认安装的 Python 版本。
- 安装 CMake 和 Ninja 编译工具:
- 若有 HomeBrew_可以运行::
- 若有 HomeBrew_可以运行::
brew install cmake ninja
brew install cmake ninja
- 若有 MacPorts_可以运行::
- 若有 MacPorts_可以运行::
sudo port install cmake ninja
sudo port install cmake ninja
- 若以上均不适用,请访问 CMake_ 和 Ninja_ 主页,查询有关 Mac OS 平台的下载安装问题。
- 若以上均不适用,请访问 CMake_ 和 Ninja_ 主页,查询有关 Mac OS 平台的下载安装问题。
- 强烈建议同时安装 ccache_ 以达到更快的编译速度。如有 HomeBrew_可通过 MacPorts_ 上的 ``brew install ccache````sudo port install ccache`` 完成安装。
- 强烈建议同时安装 ccache_ 以获得更快的编译速度。如有 HomeBrew_可通过 MacPorts_ 上的 ``brew install ccache````sudo port install ccache`` 完成安装。
.. note::
如您在上述任何步骤中遇到以下错误::
如在任一步骤中出现以下报错信息::
``xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun``
你需要安装 XCode 命令行工具才能继续,具体可运行 ``xcode-select --install`` 进行安装。
安装工具链
======================
.. include:: /_build/inc/download-links.inc
下载 MacOS 版本的 ESP32 工具链,请前往乐鑫官网:
|download_link_osx|
完成下载后,请在 ``~/esp`` 目录下进行解压:
.. include:: /_build/inc/unpack-code-osx.inc
.. _setup-macos-toolchain-add-it-to-path:
此后,该工具链将解压至 ``~/esp/xtensa-esp32-elf/`` 目录。
为了开始使用工具链,你必须更新 ``~/.profile`` 文件中的 ``PATH`` 环境变量。为了让所有终端都可以使用 ``xtensa-esp32-elf``,请将下方命令增加至你的 ``~/.profile`` 文件:::
export PATH=$HOME/esp/xtensa-esp32-elf/bin:$PATH
此外,你可以为以上命令增加一个别名。这样,你就可以仅在有需要时获取工具链。具体方式是在 ``~/.profile`` 文件中增加下方命令::
alias get_esp32="export PATH=$HOME/esp/xtensa-esp32-elf/bin:$PATH"
此时,你可以直接输入 ``get_esp32`` 命令,即可将工具链添加至你的 ``PATH``
注意,这里需要退出并重新登陆,``.profile`` 更改才会生效。
此外,你可以使用以下命令,验证 ``PATH`` 是否设置正确::
printenv PATH
``xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at:/Library/Developer/CommandLineTools/usr/bin/xcrun``
则必须安装 XCode 命令行工具,具体可运行 ``xcode-select --install``。
后续步骤
=================
==========
前往 :ref:`get-started-get-esp-idf`,完成接下来的开发环境配置
继续设置开发环境,请前往 :ref:`get-started-get-esp-idf` 章节
相关文档
=================
@@ -91,3 +57,4 @@ ESP-IDF 将使用 Mac OS 上默认安装的 Python 版本。
.. _ccache: https://ccache.samba.org/
.. _homebrew: https://brew.sh/
.. _MacPorts: https://www.macports.org/install.php

View File

@@ -1,17 +1,17 @@
.. _get-started-customized-setup:
*********************************************************
工具链自定义设置
*********************************************************
*************************************
工具链自定义设置
*************************************
:link_to_translation:`en:[英文]`
:link_to_translation:`en:[English]`
除了从乐鑫官网(请见 :ref:`get-started-setup-toolchain`)下载二进制工具链外,还可以自行编译工具链。
除了从乐鑫官网(请见 :ref:`get-started-set-up-tools`)下载二进制工具链外,还可以自行编译工具链。
果没有特别需求,建议直接使用我们提供的预编译二进制工具链。不过,你也可能也会由于以下原因,编译你自己的工具链:
无特殊需求,建议直接使用我们提供的预编译二进制工具链。不过,您可以在以下情况考虑自行编译工具链:
- 需要定制工具链编译配置
- 使用其他 GCC 版本(如 4.8.5
- 需要使用其他 GCC 版本(如 4.8.5
- 需要破解 gcc、newlib 或 libstdc++
- 有相关兴趣或时间充裕
- 不信任从网站下载的 bin 文件
@@ -19,9 +19,10 @@
如需自行编译工具链,请查看以下文档:
.. toctree::
:maxdepth: 1
:maxdepth: 1
windows-setup-scratch
linux-setup-scratch
macos-setup-scratch
windows-setup-scratch
linux-setup-scratch
macos-setup-scratch

View File

@@ -1,72 +1,99 @@
******************************************************************
********************************************
从零开始设置 Windows 环境下的工具链
******************************************************************
********************************************
:link_to_translation:`en:[英文]`
:link_to_translation:`en:[English]`
本文就如何运行基于 CMake 构建系统中的 :doc:`ESP-IDF 工具安装器 <windows-setup>` 进行逐步详细说明。手动安装所有工具能更好地控制整个安装流程,同时也方便高阶用户进行自定义安装。
除了使用 :doc:`ESP-IDF 工具安装器 <windows-setup>`,用户也可以手动设置 Windows 环境下的工具链,这也是本文的主要内容。手动安装工具可以更好地控制安装流程,同时也方便高阶用户进行自定义安装。
使用 ESP-IDF 工具安装器对工具链及其他工具进行快速标准设置,请参照 :doc:`windows-setup`
.. note::
基于 GNU Make 的构建系统要求 Windows 兼容 MSYS2_ Unix基于 CMake 的构建系统则无此要求。
.. _get-esp-idf-windows-command-line:
获取 ESP-IDF
=================
.. note::
基于 GNU Make 的构建系统要求 Windows 兼容 `MSYS2`_ Unix。基于 CMake 的构建系统则无此要求。
较早版本 ESP-IDF 使用了 **MSYS2 bash 终端** 命令行。目前,基于 CMake 的编译系统可使用常见的 **Windows 命令窗口**,即本指南中使用的终端。
请注意,如果您使用基于 bash 的终端或 PowerShell 终端,一些命令语法将与下面描述有所不同。
打开命令提示符,运行以下命令:
.. include:: /_build/inc/git-clone-windows.inc
ESP-IDF 将下载至 ``%userprofile%\esp\esp-idf``
请前往 :doc:`/versions`,查看 ESP-IDF 不同版本的具体适用场景。
.. include:: /_build/inc/git-clone-notes.inc
.. note::
在克隆远程仓库时,不要忘记加上 ``--recursive`` 选项。否则,请接着运行以下命令,获取所有子模块 ::
cd esp-idf
git submodule update --init
工具
=====
cmake
^^^^^
cmake 工具
^^^^^^^^^^
下载最新发布的 Windows 平台稳定版 `CMake`_并运行安装器。
当安装器询问安装选项时,选择 "Add CMake to the system PATH for all users"(为所有用户的系统路径添加 CMake或 "Add CMake to the system PATH for the current user"(为当前用户的系统路径添加 CMake
当安装器询问安装选项时,选择 "Add CMake to the system PATH for all users"(为所有用户的系统路径添加 CMake或 "Add CMake to the system PATH for the current user"(为当前用户的系统路径添加 CMake
Ninja 编译工具
^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. note::
Ninja 目前仅为 64 位版本 Windows 提供 bin 文件。也可以通过其他编译工具使用 CMake 和 ``idf.py``,如适用于 32 位 Windows 的 mingw-make但是目前暂无关于此工具的说明文档。
目前,Ninja 仅提供支持 64 位 Windows 版本的 bin 文件。也可以配合其他编译工具在 32 位 Windows 版本中使用 CMake 和 ``idf.py`` ,比如 mingw-make但是目前暂无关于此工具的说明文档。
从(`下载页面 <ninja-dl>`_)下载最新发布的 Windows 平台稳定版 `ninja`_。
从(`下载页面 <ninja-dl_>`_)下载最新发布的 Windows 平台稳定版 ninja_。
适用于 Windows 平台的 Ninja 下载文件是一个 .zip 文件,包含一个 ``ninja.exe`` 文件。将其解压到目录,并 `添加到的路径 <add-directory-windows-path>`_ (或者选择你的路径中已有目录)。
适用于 Windows 平台的 Ninja 下载文件是一个 .zip 文件,包含一个 ``ninja.exe`` 文件。您需要将该文件解压到目录,并 :ref:`添加到的路径 <add-directory-windows-path>` (或者选择路径中已有目录)。
Python 2.x
^^^^^^^^^^
下载并运行适用于 Windows 安装器的最新版 `Python`_ 2.7。
下载并运行适用于 Windows 安装器的最新版 Python_ 2.7。
Python 安装的“自定义”那一步提供了一份选项列表,最后一个选项是 "Add python.exe to Path"(添加 python.exe 到路径中),更改该选项,选择 "Will be installed"(将会安装)。
Python 安装的“自定义”菜单可为您提供一系列选项,最后一项为 "Add python.exe to Path"(添加 python.exe 到路径中)。请将该选项更改到 "Will be installed"(将会安装)。
Python 安装完成后,打开 Windows 开始菜单下的 Command Prompt,并运行以下命令::
Python 安装完成后, Windows 开始菜单中打开“命令提示符”窗口,并运行以下命令::
pip install --user pyserial
pip install --user pyserial
适用于 IDF 的 MConf
^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^^^^^^^^
`kconfig-frontends 发布页面 <mconf-idf>`_ 下载配置工具 mconf-idf。此为 ``mconf`` 配置工具,可针对 ESP-IDF 进行一些自定义操作。
`kconfig-frontends releases page`_ 下载配置工具 mconf-idf。此为 ``mconf`` 配置工具,可针对 ESP-IDF 进行少量自定义操作。
你需将此工具解压到目录,然后 `添加到的路径 <add-directory-windows-path>`_
将此工具解压到目录,:ref:`添加到的路径 <add-directory-windows-path>`
工具链设置
===============
.. include:: /_build/inc/download-links.inc
下载预编译的 Windows 平台工具链:
下载预编译的 Windows 工具链:
|download_link_win32|
解压压缩包文件到 ``C:\Program Files`` (或其他地址)。压缩包文件包含 ``xtensa-esp32-elf`` 目录。
解压压缩包文件到 ``C:\Program Files`` (或其他位置)。压缩包文件包含一个 ``xtensa-esp32-elf`` 目录。
然后,将该目录下的子目录 ``bin`` `添加到的路径 <add-directory-windows-path>`_。例如,``C:\Program Files\xtensa-esp32-elf\bin``
然后,将该目录下的 ``bin`` 子目录 :ref:`添加到的路径 <add-directory-windows-path>`。例如,``C:\Program Files\xtensa-esp32-elf\bin``
.. note::
如果你已安装 MSYS2 环境(适用 "GNU Make" 构建系统),你可以跳过下载那一步,直接添加目录 ``C:\msys32\opt\xtensa-esp32-elf\bin`` 到路径,因为 MSYS2 环境已包含工具链。
如果您已安装 MSYS2 环境(适用 "GNU Make" 编译系统),则可以跳过下载那一步,直接添加目录 ``C:\msys32\opt\xtensa-esp32-elf\bin`` 到路径,因为 MSYS2 环境已包含工具链。
.. _add-directory-windows-path:
@@ -74,19 +101,24 @@ Python 安装完成后,打开 Windows 开始菜单下的 Command Prompt
添加目录到路径
========================
添加任何新目录到你的 Windows Path 环境变量:
Windows 环境下,向 Path 环境变量增加任何新目录,请
打开系统控制面板,找到环境变量对话框(对于 Windows 10,则在高级系统设置中查找对话框)。
打开系统控制面板找到环境变量对话框Windows 10 用户请前往“高级系统设置”)。
双击 ``Path`` 变量(选择用户系统路径,这取决于是否希望其他用户路径中也存在该目录)。在最后数值那里新添 ``;<new value>``
双击 ``Path`` 变量(选择用户”或“系统路径”,具体取决于是否希望其他用户路径中也存在该目录)。在最后数值那里新添 ``;<new value>``
后续步骤
================
==========
继续设置开发环境,请参照 :ref:`get-started-get-esp-idf`
继续设置开发环境,请前往 :ref:`get-started-get-esp-idf` 章节
.. _cmake: https://cmake.org/download/
.. _ninja: https://ninja-build.org/
.. _ninja-dl: https://github.com/ninja-build/ninja/releases
.. _Python: https://www.python.org/downloads/windows/
.. _MSYS2: https://msys2.github.io/
.. _kconfig-frontends releases page: https://github.com/espressif/kconfig-frontends/releases
.. _Stable version: https://docs.espressif.com/projects/esp-idf/zh_CN/stable/

View File

@@ -1,3 +1,41 @@
:orphan:
*************************************************
在 Windows 环境下更新 ESP-IDF 工具
*************************************************
.. _get-started-install_bat-windows:
使用脚本安装 ESP-IDF 工具
====================================
请从 Windows “命令提示符”窗口,切换至 ESP-IDF 的安装目录。然后运行::
install.bat
对于 Powershell请切换至 ESP-IDF 的安装目录。然后运行::
install.ps1
该命令可下载安装 ESP-IDF 所需的工具。如您已经安装了某个版本的工具,则该命令将无效。
该工具的下载安装位置由 ESP-IDF 工具安装器的设置决定,默认情况下为: ``C:\Users\username\.espressif``
.. _get-started-export_bat-windows:
使用“导出脚本”将 ESP-IDF 工具添加至 PATH
=================================================================================
ESP-IDF 工具安装器将在“开始菜单”为 “ESP-IDF 命令提示符” 创建快捷方式。点击该快捷方式可打开 Windows 命令提示符窗口,您可在该窗口使用所有已安装的工具。
有些情况下,您正在使用的 ESP-IDF 版本可能并未创建命令提示符快捷方式,此时您可以根据下方步骤将 ESP-IDF 工具添加至 PATH。
首先,请打开需要使用 ESP-IDF 的命令提示符窗口,切换至 ESP-IDF 的安装路径,然后执行 ``export.bat``::
cd %userprofile%\esp\esp-idf
export.bat
对于 Powershell 用户,请同样切换至 ESP-IDF 的安装路径,然后执行 ``export.ps1``::
cd ~/esp/esp-idf
export.ps1
运行完成后,您就可以通过命令提示符使用 ESP-IDF 工具了。
.. Remove this file when the Chinese translation of getting started guide is updated

View File

@@ -1,54 +1,52 @@
**********************************************************
***********************************************
Windows 平台工具链的标准设置
**********************************************************
***********************************************
:link_to_translation:`en:[英文]`
:link_to_translation:`en:[English]`
.. note::
基于 CMake 的构建系统仅支持 64 位版本 Windows。
目前,基于 CMake 的构建系统仅支持 64 位 Windows 版本。32 位 Windows 版本的用户可根据 :doc:`传统 GNU Make 构建系统<../get-started-legacy/windows-setup>` 中的介绍进行操作
引言
概述
============
ESP-IDF 需要安装必要的工具,以编译 ESP32 固件,包括Git交叉编译器,以及 CMake 构建工具。本文将对这些工具一一说明
ESP-IDF 需要安装一些必备工具,才能围绕 ESP32 构建固件,包括 Python、Git交叉编译器、menuconfig 工具、CMake和 Ninja 编译工具等
入门指南中,我们通过命令提示符进行有关操作。不过,安装 ESP-IDF 后还可以使用 :doc:`Eclipse <eclipse-setup>` 或支持 CMake 的图形化工具 IDE。
入门指南中,我们通过 **命令提示符** 进行有关操作。不过,您在安装 ESP-IDF 后还可以使用 :doc:`Eclipse <eclipse-setup>`其他支持 CMake 的图形化工具 IDE。
https://dl.espressif.com/dl/esp32_win32_msys2_environment_and_toolchain-20190611.zip
.. note::
较早 ESP-IDF 版本使用 :doc:`传统 GNU Make 编译系统<../get-started-legacy/windows-setup>` 和 MSYS2_ Unix 兼容环境。但如今已非必需,用户可直接通过 Windows 命令提示符使用 ESP-IDF。
.. _get-started-windows-tools-installer:
ESP-IDF 工具安装器
=======================
安装 ESP-IDF 必备工具最简易的方式是下载 ESP-IDF 工具安装器,地址如下:
安装 ESP-IDF 必备工具最简易的方式是下载 ESP-IDF 工具安装器,地址如下:
https://dl.espressif.com/dl/esp-idf-tools-setup-1.2.exe
https://dl.espressif.com/dl/esp-idf-tools-setup-2.0.exe
安装器会自动安装 ESP32 Xtensa gcc 工具链,Ninja_ 编译工具,以及名为 mconf-idf_ 配置工具。此外,如果你的电脑还未安装有关 CMake_ 和 Python_ 2.7 的安装器,它还可以下载和运行与之对应的安装器。
安装器可为您安装所需的交叉编译器、OpenOCD、cmake_ 和 Ninja_ 编译工具,以及一款 mconf-idf_ 配置工具。此外,本安装器还可在有需要时下载、运行 Python_ 3.7 `Git For Windows` 的安装器。
安装器默认更新 Windows ``Path`` 环境变量,因而上述工具也可在其他环境中运行。如果禁止该选项,则需自行设置 ESP-IDF 所使用的环境(终端或所选 IDE并配置正确的路径。
安装器还可用于下载任意 ESP-IDF 发布版本。
请注意,此安装器仅针对 ESP-IDF 工具包,并不包括 ESP-IDF。
使用命令提示符
========================
安装 Git
==============
在后续步骤中,我们将使用 Windows 的命令提示符进行操作。
ESP-IDF 工具安装器并不会安装 Git因为快速入门指南默认你将以命令行的模式使用它。你可以通过 `Git For Windows`_ 下载和安装 Windows 平台的命令行 Git 工具(包括 "Git Bash" 终端)
ESP-IDF 工具安装器可在“开始”菜单中,创建一个打开 ESP-IDF 命令提示符窗口的快捷方式。本快捷方式可以打开 Windows 命令提示符(即 cmd.exe并运行 ``export.bat`` 脚本以设置各环境变量(比如 ``PATH````IDF_PATH`` 等)。此外,您可还以通过 Windows 命令提示符使用各种已经安装的工具
如果你想使用其他图形化 Git 客户端,如 `Github Desktop` 你可以自行安装,但需要对本《入门指南》中相应的 Git 命令进行转换,以便用于你所选的 Git 客户端。
注意,本快捷方式仅适用 ESP-IDF 工具安装器中指定的 ESP-IDF 路径。如果您的电脑上存在多个 ESP-IDF比如您需要不同的 ESP-IDF 版本)需要使用快捷方式,您可以:
使用终端
================
1. 为 ESP-IDF 工具安装器创建的快捷方式创建一个副本,并将新快捷方式的“当前路径”指定为您希望使用的 ESP-IDF 路径。
在本《入门指南》接下来的步骤说明中,我们将使用终端命令提示符进行有关操作。你也可以使用任何其他形式的命令提示符:
- 比如Windows 开始菜单下内置的命令提示符。本文档中的所有 Windows 命令行指令均为 Windows 命令提示符中所使用的 "batch" 命令。
- 你还可以使用 `Git for Windows`_ 中的 "Git Bash" 终端,其所使用的 "bash" 命令提示符语法与 Mac OS 或 Linux 的既定语法相同。安装此终端后,你可以在开始菜单下找到命令提示符窗口。
- 如果你已安装 MSYS2_ (通过 ESP-IDF 之前版本),你还可以使用 MSYS 终端。
2. 运行 ``cmd.exe``,并更新至您希望使用的 ESP-IDF 目录,然后运行 ``export.bat``。注意,这种方法要求 ``PATH`` 中存在 Python 和 Git。如果您在使用时遇到有关“找不到 Python 或 Git” 的错误信息,请使用第一种方法。
后续步骤
==========
要继续设置开发环境,请参照 :ref:`get-started-get-esp-idf`
当 ESP-IDF 工具安装器安装完成后,则开发环境设置也到此结束。后续开发步骤,请前往 :ref:`get-started-start-project` 查看
相关文档
=================
@@ -59,7 +57,7 @@ ESP-IDF 工具安装器并不会安装 Git因为快速入门指南默认你
:maxdepth: 1
windows-setup-scratch
windows-setup-update
.. _MSYS2: https://msys2.github.io/
.. _cmake: https://cmake.org/download/
@@ -68,3 +66,4 @@ ESP-IDF 工具安装器并不会安装 Git因为快速入门指南默认你
.. _Git for Windows: https://gitforwindows.org/
.. _mconf-idf: https://github.com/espressif/kconfig-frontends/releases/
.. _Github Desktop: https://desktop.github.com/

View File

@@ -1,6 +1,6 @@
# Override some defaults so BT stack is enabled
# by default in this example
CONFIG_BT_ENABLED=y
CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y
CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY=
CONFIG_BTDM_CONTROLLER_MODE_BTDM=
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=
CONFIG_BTDM_CTRL_MODE_BTDM=

View File

@@ -150,12 +150,12 @@ static void gen_onoff_set_unack_handler(esp_ble_mesh_model_t *model,
uint8_t prev_onoff;
esp_err_t err;
ESP_LOGI(TAG, "%s, addr 0x%02x onoff 0x%02x", __func__, model->element->element_addr, led->current);
prev_onoff = led->previous;
led->current = data[0];
remote_onoff = led->current;
ESP_LOGI(TAG, "%s, addr 0x%04x onoff 0x%02x", __func__, model->element->element_addr, led->current);
board_led_operation(led->pin, led->current);
/* If Generic OnOff state is changed, and the publish address of Generic OnOff Server
@@ -181,12 +181,12 @@ static void gen_onoff_set_handler(esp_ble_mesh_model_t *model,
uint8_t prev_onoff, send_data;
esp_err_t err;
ESP_LOGI(TAG, "%s, addr 0x%02x onoff 0x%02x", __func__, model->element->element_addr, led->current);
prev_onoff = led->previous;
led->current = data[0];
remote_onoff = led->current;
ESP_LOGI(TAG, "%s, addr 0x%04x onoff 0x%02x", __func__, model->element->element_addr, led->current);
board_led_operation(led->pin, led->current);
send_data = led->current;

View File

@@ -1,20 +1,20 @@
# Override some defaults so BT stack is enabled
# by default in this example
CONFIG_BT_ENABLED=y
CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y
CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY=
CONFIG_BTDM_CONTROLLER_MODE_BTDM=
CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=n
CONFIG_BLE_SCAN_DUPLICATE=y
CONFIG_SCAN_DUPLICATE_TYPE=2
CONFIG_SCAN_DUPLICATE_BY_ADV_DATA_AND_DEVICE_ADDR=y
CONFIG_DUPLICATE_SCAN_CACHE_SIZE=200
CONFIG_BLE_MESH_SCAN_DUPLICATE_EN=y
CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE=200
CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED=y
CONFIG_BLE_ADV_REPORT_FLOW_CONTROL_SUPPORTED=y
CONFIG_GATTS_ENABLE=y
CONFIG_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=
CONFIG_BTDM_CTRL_MODE_BTDM=
CONFIG_BTDM_MODEM_SLEEP=n
CONFIG_BTDM_BLE_SCAN_DUPL=y
CONFIG_BTDM_SCAN_DUPL_TYPE=2
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE=200
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
CONFIG_BTDM_MESH_DUPL_SCAN_CACHE_SIZE=200
CONFIG_BTDM_CTRL_FULL_SCAN_SUPPORTED=y
CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP=y
CONFIG_BT_GATTS_ENABLE=y
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
CONFIG_BLE_MESH=y
CONFIG_BLE_MESH_HCI_5_0=y
CONFIG_BLE_MESH_USE_DUPLICATE_SCAN=y
@@ -44,4 +44,4 @@ CONFIG_BLE_MESH_LOW_POWER=
CONFIG_BLE_MESH_FRIEND=
CONFIG_BLE_MESH_CFG_CLI=
CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y
CONFIG_BTU_TASK_STACK_SIZE=4512
CONFIG_BT_BTU_TASK_STACK_SIZE=4512

View File

@@ -1,23 +1,23 @@
# Override some defaults so BT stack is enabled
# by default in this example
CONFIG_CONSOLE_UART_BAUDRATE=921600
CONFIG_ESP_CONSOLE_UART_BAUDRATE=921600
CONFIG_ESPTOOLPY_BAUD_921600B=y
CONFIG_MONITOR_BAUD_921600B=y
CONFIG_ESPTOOLPY_MONITOR_BAUD_921600B=y
CONFIG_BT_ENABLED=y
CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y
CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY=
CONFIG_BTDM_CONTROLLER_MODE_BTDM=
CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=n
CONFIG_BLE_SCAN_DUPLICATE=y
CONFIG_SCAN_DUPLICATE_TYPE=2
CONFIG_SCAN_DUPLICATE_BY_ADV_DATA_AND_DEVICE_ADDR=y
CONFIG_DUPLICATE_SCAN_CACHE_SIZE=200
CONFIG_BLE_MESH_SCAN_DUPLICATE_EN=y
CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE=200
CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED=y
CONFIG_BLE_ADV_REPORT_FLOW_CONTROL_SUPPORTED=y
CONFIG_GATTS_ENABLE=y
CONFIG_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=
CONFIG_BTDM_CTRL_MODE_BTDM=
CONFIG_BTDM_MODEM_SLEEP=n
CONFIG_BTDM_BLE_SCAN_DUPL=y
CONFIG_BTDM_SCAN_DUPL_TYPE=2
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE=200
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
CONFIG_BTDM_MESH_DUPL_SCAN_CACHE_SIZE=200
CONFIG_BTDM_CTRL_FULL_SCAN_SUPPORTED=y
CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP=y
CONFIG_BT_GATTS_ENABLE=y
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
CONFIG_BLE_MESH=y
CONFIG_BLE_MESH_HCI_5_0=y
CONFIG_BLE_MESH_USE_DUPLICATE_SCAN=y
@@ -45,4 +45,4 @@ CONFIG_BLE_MESH_RELAY=y
CONFIG_BLE_MESH_LOW_POWER=
CONFIG_BLE_MESH_FRIEND=
CONFIG_BLE_MESH_CFG_CLI=y
CONFIG_BTU_TASK_STACK_SIZE=4512
CONFIG_BT_BTU_TASK_STACK_SIZE=4512

View File

@@ -1,18 +1,18 @@
# Override some defaults so BT stack is enabled
# by default in this example
CONFIG_BT_ENABLED=y
CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y
CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY=
CONFIG_BTDM_CONTROLLER_MODE_BTDM=
CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=n
CONFIG_BLE_SCAN_DUPLICATE=y
CONFIG_SCAN_DUPLICATE_TYPE=2
CONFIG_SCAN_DUPLICATE_BY_ADV_DATA_AND_DEVICE_ADDR=y
CONFIG_DUPLICATE_SCAN_CACHE_SIZE=200
CONFIG_BLE_MESH_SCAN_DUPLICATE_EN=y
CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE=200
CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED=y
CONFIG_BLE_ADV_REPORT_FLOW_CONTROL_SUPPORTED=y
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=
CONFIG_BTDM_CTRL_MODE_BTDM=
CONFIG_BTDM_MODEM_SLEEP=n
CONFIG_BTDM_BLE_SCAN_DUPL=y
CONFIG_BTDM_SCAN_DUPL_TYPE=2
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE=200
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
CONFIG_BTDM_MESH_DUPL_SCAN_CACHE_SIZE=200
CONFIG_BTDM_CTRL_FULL_SCAN_SUPPORTED=y
CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP=y
CONFIG_BLE_MESH=y
CONFIG_BLE_MESH_HCI_5_0=y
CONFIG_BLE_MESH_USE_DUPLICATE_SCAN=y
@@ -37,6 +37,6 @@ CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=6
CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=1
CONFIG_BLE_MESH_RX_SDU_MAX=384
CONFIG_BLE_MESH_TX_SEG_MAX=32
CONFIG_BTU_TASK_STACK_SIZE=4512
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
CONFIG_BLE_MESH_CFG_CLI=y
CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y
CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y

View File

@@ -1,18 +1,18 @@
# Override some defaults so BT stack is enabled
# by default in this example
CONFIG_BT_ENABLED=y
CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y
CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY=
CONFIG_BTDM_CONTROLLER_MODE_BTDM=
CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=n
CONFIG_BLE_SCAN_DUPLICATE=y
CONFIG_SCAN_DUPLICATE_TYPE=2
CONFIG_SCAN_DUPLICATE_BY_ADV_DATA_AND_DEVICE_ADDR=y
CONFIG_DUPLICATE_SCAN_CACHE_SIZE=200
CONFIG_BLE_MESH_SCAN_DUPLICATE_EN=y
CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE=200
CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED=y
CONFIG_BLE_ADV_REPORT_FLOW_CONTROL_SUPPORTED=y
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=
CONFIG_BTDM_CTRL_MODE_BTDM=
CONFIG_BTDM_MODEM_SLEEP=n
CONFIG_BTDM_BLE_SCAN_DUPL=y
CONFIG_BTDM_SCAN_DUPL_TYPE=2
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE=200
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
CONFIG_BTDM_MESH_DUPL_SCAN_CACHE_SIZE=200
CONFIG_BTDM_CTRL_FULL_SCAN_SUPPORTED=y
CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP=y
CONFIG_BLE_MESH=y
CONFIG_BLE_MESH_HCI_5_0=y
CONFIG_BLE_MESH_USE_DUPLICATE_SCAN=y
@@ -32,7 +32,7 @@ CONFIG_BLE_MESH_GATT_PROXY=y
CONFIG_BLE_MESH_RELAY=y
CONFIG_BLE_MESH_LOW_POWER=
CONFIG_BLE_MESH_FRIEND=
CONFIG_BTU_TASK_STACK_SIZE=4512
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
CONFIG_BLE_MESH_CFG_CLI=y
CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y
CONFIG_BLE_MESH_ADV_BUF_COUNT=100
@@ -42,4 +42,4 @@ CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10
CONFIG_BLE_MESH_RX_SDU_MAX=384
CONFIG_BLE_MESH_TX_SEG_MAX=32
CONFIG_BLE_MESH_NO_LOG=n
CONFIG_BLE_MESH_STACK_TRACE_LEVEL=1
CONFIG_BLE_MESH_STACK_TRACE_LEVEL=1

View File

@@ -1,20 +1,20 @@
# Override some defaults so BT stack is enabled
# by default in this example
CONFIG_BT_ENABLED=y
CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y
CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY=
CONFIG_BTDM_CONTROLLER_MODE_BTDM=
CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=n
CONFIG_BLE_SCAN_DUPLICATE=y
CONFIG_SCAN_DUPLICATE_TYPE=2
CONFIG_SCAN_DUPLICATE_BY_ADV_DATA_AND_DEVICE_ADDR=y
CONFIG_DUPLICATE_SCAN_CACHE_SIZE=200
CONFIG_BLE_MESH_SCAN_DUPLICATE_EN=y
CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE=200
CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED=y
CONFIG_BLE_ADV_REPORT_FLOW_CONTROL_SUPPORTED=y
CONFIG_GATTS_ENABLE=y
CONFIG_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=
CONFIG_BTDM_CTRL_MODE_BTDM=
CONFIG_BTDM_MODEM_SLEEP=n
CONFIG_BTDM_BLE_SCAN_DUPL=y
CONFIG_BTDM_SCAN_DUPL_TYPE=2
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE=200
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
CONFIG_BTDM_MESH_DUPL_SCAN_CACHE_SIZE=200
CONFIG_BTDM_CTRL_FULL_SCAN_SUPPORTED=y
CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP=y
CONFIG_BT_GATTS_ENABLE=y
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
CONFIG_BLE_MESH=y
CONFIG_BLE_MESH_HCI_5_0=y
CONFIG_BLE_MESH_USE_DUPLICATE_SCAN=y
@@ -40,7 +40,7 @@ CONFIG_BLE_MESH_GATT_PROXY=y
CONFIG_BLE_MESH_RELAY=y
CONFIG_BLE_MESH_LOW_POWER=
CONFIG_BLE_MESH_FRIEND=
CONFIG_BTU_TASK_STACK_SIZE=4512
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
CONFIG_BLE_MESH_CFG_CLI=y
CONFIG_BLE_MESH_CRPL=60
CONFIG_BLE_MESH_MSG_CACHE_SIZE=60
@@ -50,4 +50,4 @@ CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10
CONFIG_BLE_MESH_RX_SDU_MAX=384
CONFIG_BLE_MESH_TX_SEG_MAX=32
CONFIG_BLE_MESH_NO_LOG=n
CONFIG_BLE_MESH_STACK_TRACE_LEVEL=0
CONFIG_BLE_MESH_STACK_TRACE_LEVEL=0

View File

@@ -146,11 +146,11 @@ static void gen_onoff_set_unack_handler(esp_ble_mesh_model_t *model,
uint8_t prev_onoff;
esp_err_t err;
ESP_LOGI(TAG, "%s, addr 0x%02x onoff 0x%02x", __func__, model->element->element_addr, led->current);
prev_onoff = led->previous;
led->current = data[0];
ESP_LOGI(TAG, "%s, addr 0x%04x onoff 0x%02x", __func__, model->element->element_addr, led->current);
board_led_operation(led->pin, led->current);
/* If Generic OnOff state is changed, and the publish address of Generic OnOff Server
@@ -175,11 +175,11 @@ static void gen_onoff_set_handler(esp_ble_mesh_model_t *model,
uint8_t prev_onoff, send_data;
esp_err_t err;
ESP_LOGI(TAG, "%s, addr 0x%02x onoff 0x%02x", __func__, model->element->element_addr, led->current);
prev_onoff = led->previous;
led->current = data[0];
ESP_LOGI(TAG, "%s, addr 0x%04x onoff 0x%02x", __func__, model->element->element_addr, led->current);
board_led_operation(led->pin, led->current);
send_data = led->current;

View File

@@ -1,20 +1,20 @@
# Override some defaults so BT stack is enabled
# by default in this example
CONFIG_BT_ENABLED=y
CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y
CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY=
CONFIG_BTDM_CONTROLLER_MODE_BTDM=
CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=n
CONFIG_BLE_SCAN_DUPLICATE=y
CONFIG_SCAN_DUPLICATE_TYPE=2
CONFIG_SCAN_DUPLICATE_BY_ADV_DATA_AND_DEVICE_ADDR=y
CONFIG_DUPLICATE_SCAN_CACHE_SIZE=200
CONFIG_BLE_MESH_SCAN_DUPLICATE_EN=y
CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE=200
CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED=y
CONFIG_BLE_ADV_REPORT_FLOW_CONTROL_SUPPORTED=y
CONFIG_GATTS_ENABLE=y
CONFIG_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=
CONFIG_BTDM_CTRL_MODE_BTDM=
CONFIG_BTDM_MODEM_SLEEP=n
CONFIG_BTDM_BLE_SCAN_DUPL=y
CONFIG_BTDM_SCAN_DUPL_TYPE=2
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE=200
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
CONFIG_BTDM_MESH_DUPL_SCAN_CACHE_SIZE=200
CONFIG_BTDM_CTRL_FULL_SCAN_SUPPORTED=y
CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP=y
CONFIG_BT_GATTS_ENABLE=y
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
CONFIG_BLE_MESH=y
CONFIG_BLE_MESH_HCI_5_0=y
CONFIG_BLE_MESH_USE_DUPLICATE_SCAN=y
@@ -42,4 +42,4 @@ CONFIG_BLE_MESH_RELAY=y
CONFIG_BLE_MESH_LOW_POWER=
CONFIG_BLE_MESH_FRIEND=
CONFIG_BLE_MESH_CFG_CLI=y
CONFIG_BTU_TASK_STACK_SIZE=4512
CONFIG_BT_BTU_TASK_STACK_SIZE=4512

View File

@@ -1,18 +1,18 @@
# Override some defaults so BT stack is enabled
# by default in this example
CONFIG_BT_ENABLED=y
CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y
CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY=
CONFIG_BTDM_CONTROLLER_MODE_BTDM=
CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=n
CONFIG_BLE_SCAN_DUPLICATE=y
CONFIG_SCAN_DUPLICATE_TYPE=2
CONFIG_SCAN_DUPLICATE_BY_ADV_DATA_AND_DEVICE_ADDR=y
CONFIG_DUPLICATE_SCAN_CACHE_SIZE=200
CONFIG_BLE_MESH_SCAN_DUPLICATE_EN=y
CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE=200
CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED=y
CONFIG_BLE_ADV_REPORT_FLOW_CONTROL_SUPPORTED=y
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=
CONFIG_BTDM_CTRL_MODE_BTDM=
CONFIG_BTDM_MODEM_SLEEP=n
CONFIG_BTDM_BLE_SCAN_DUPL=y
CONFIG_BTDM_SCAN_DUPL_TYPE=2
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE=200
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
CONFIG_BTDM_MESH_DUPL_SCAN_CACHE_SIZE=200
CONFIG_BTDM_CTRL_FULL_SCAN_SUPPORTED=y
CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP=y
CONFIG_BLE_MESH=y
CONFIG_BLE_MESH_HCI_5_0=y
CONFIG_BLE_MESH_USE_DUPLICATE_SCAN=y
@@ -37,6 +37,6 @@ CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=6
CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=6
CONFIG_BLE_MESH_RX_SDU_MAX=384
CONFIG_BLE_MESH_TX_SEG_MAX=32
CONFIG_BTU_TASK_STACK_SIZE=4512
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
CONFIG_BLE_MESH_CFG_CLI=y
CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y
CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y

View File

@@ -20,7 +20,7 @@ CONFIG_BLE_MESH_GATT_PROXY=y
CONFIG_BLE_MESH_RELAY=y
CONFIG_BLE_MESH_LOW_POWER=
CONFIG_BLE_MESH_FRIEND=
CONFIG_BTU_TASK_STACK_SIZE=4512
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
CONFIG_BLE_MESH_CFG_CLI=y
CONFIG_BLE_MESH_CRPL=60
CONFIG_BLE_MESH_MSG_CACHE_SIZE=60
@@ -30,4 +30,4 @@ CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10
CONFIG_BLE_MESH_RX_SDU_MAX=384
CONFIG_BLE_MESH_TX_SEG_MAX=32
CONFIG_BLE_MESH_NO_LOG=n
CONFIG_BLE_MESH_STACK_TRACE_LEVEL=0
CONFIG_BLE_MESH_STACK_TRACE_LEVEL=0

View File

@@ -5,20 +5,20 @@ CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240
CONFIG_MEMMAP_SMP=y
CONFIG_BT_ENABLED=y
CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y
CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY=
CONFIG_BTDM_CONTROLLER_MODE_BTDM=
CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=n
CONFIG_BLE_SCAN_DUPLICATE=y
CONFIG_SCAN_DUPLICATE_TYPE=2
CONFIG_SCAN_DUPLICATE_BY_ADV_DATA_AND_DEVICE_ADDR=y
CONFIG_DUPLICATE_SCAN_CACHE_SIZE=200
CONFIG_BLE_MESH_SCAN_DUPLICATE_EN=y
CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE=200
CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED=y
CONFIG_BLE_ADV_REPORT_FLOW_CONTROL_SUPPORTED=y
CONFIG_GATTS_ENABLE=y
CONFIG_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=
CONFIG_BTDM_CTRL_MODE_BTDM=
CONFIG_BTDM_MODEM_SLEEP=n
CONFIG_BTDM_BLE_SCAN_DUPL=y
CONFIG_BTDM_SCAN_DUPL_TYPE=2
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE=200
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
CONFIG_BTDM_MESH_DUPL_SCAN_CACHE_SIZE=200
CONFIG_BTDM_CTRL_FULL_SCAN_SUPPORTED=y
CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP=y
CONFIG_BT_GATTS_ENABLE=y
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
CONFIG_BLE_MESH=y
CONFIG_BLE_MESH_HCI_5_0=y
CONFIG_BLE_MESH_USE_DUPLICATE_SCAN=y
@@ -40,7 +40,7 @@ CONFIG_BLE_MESH_GATT_PROXY=y
CONFIG_BLE_MESH_RELAY=y
CONFIG_BLE_MESH_LOW_POWER=
CONFIG_BLE_MESH_FRIEND=
CONFIG_BTU_TASK_STACK_SIZE=4512
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
CONFIG_BLE_MESH_CFG_CLI=y
CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y
CONFIG_BLE_MESH_CRPL=60
@@ -53,7 +53,7 @@ CONFIG_BLE_MESH_TX_SEG_MAX=32
CONFIG_BLE_MESH_NO_LOG=n
CONFIG_BLE_MESH_STACK_TRACE_LEVEL=0
CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=4096
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=4096
CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=16
CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=64
@@ -66,19 +66,19 @@ CONFIG_ESP32_WIFI_RX_BA_WIN=32
CONFIG_FREERTOS_UNICORE=
CONFIG_FREERTOS_HZ=1000
CONFIG_INT_WDT=
CONFIG_TASK_WDT=
CONFIG_ESP_INT_WDT=
CONFIG_ESP_TASK_WDT=
CONFIG_TCP_SND_BUF_DEFAULT=65534
CONFIG_TCP_WND_DEFAULT=65534
CONFIG_TCP_RECVMBOX_SIZE=64
CONFIG_UDP_RECVMBOX_SIZE=64
CONFIG_TCPIP_RECVMBOX_SIZE=64
CONFIG_LWIP_TCP_SND_BUF_DEFAULT=65534
CONFIG_LWIP_TCP_WND_DEFAULT=65534
CONFIG_LWIP_TCP_RECVMBOX_SIZE=64
CONFIG_LWIP_UDP_RECVMBOX_SIZE=64
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=64
CONFIG_LWIP_ETHARP_TRUST_IP_MAC=
CONFIG_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_40M=y
CONFIG_LWIP_IRAM_OPTIMIZATION=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y

View File

@@ -75,6 +75,7 @@ esp_err_t example_connect(void)
}
s_connect_event_group = xEventGroupCreate();
start();
ESP_ERROR_CHECK(esp_register_shutdown_handler(&stop));
xEventGroupWaitBits(s_connect_event_group, CONNECTED_BITS, true, true, portMAX_DELAY);
ESP_LOGI(TAG, "Connected to %s", s_connection_name);
ESP_LOGI(TAG, "IPv4 address: " IPSTR, IP2STR(&s_ip_addr));
@@ -103,7 +104,11 @@ static void on_wifi_disconnect(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
ESP_LOGI(TAG, "Wi-Fi disconnected, trying to reconnect...");
ESP_ERROR_CHECK(esp_wifi_connect());
esp_err_t err = esp_wifi_connect();
if (err == ESP_ERR_WIFI_NOT_STARTED) {
return;
}
ESP_ERROR_CHECK(err);
}
#ifdef CONFIG_EXAMPLE_CONNECT_IPV6
@@ -151,7 +156,11 @@ static void stop(void)
ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_GOT_IP6, &on_got_ipv6));
ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, &on_wifi_connect));
#endif
ESP_ERROR_CHECK(esp_wifi_stop());
esp_err_t err = esp_wifi_stop();
if (err == ESP_ERR_WIFI_NOT_INIT) {
return;
}
ESP_ERROR_CHECK(err);
ESP_ERROR_CHECK(esp_wifi_deinit());
}
#endif // CONFIG_EXAMPLE_CONNECT_WIFI

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