Initial WiFi commit.
This commit is contained in:
commit
5afbef0177
|
@ -0,0 +1,6 @@
|
||||||
|
# The following lines of boilerplate have to be in your project's
|
||||||
|
# CMakeLists in this exact order for cmake to work correctly
|
||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(dht_temp)
|
|
@ -0,0 +1,50 @@
|
||||||
|
# Hello World Example
|
||||||
|
|
||||||
|
Starts a FreeRTOS task to print "Hello World".
|
||||||
|
|
||||||
|
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||||
|
|
||||||
|
## How to use example
|
||||||
|
|
||||||
|
Follow detailed instructions provided specifically for this example.
|
||||||
|
|
||||||
|
Select the instructions depending on Espressif chip installed on your development board:
|
||||||
|
|
||||||
|
- [ESP32 Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/stable/get-started/index.html)
|
||||||
|
- [ESP32-S2 Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/get-started/index.html)
|
||||||
|
|
||||||
|
|
||||||
|
## Example folder contents
|
||||||
|
|
||||||
|
The project **hello_world** contains one source file in C language [hello_world_main.c](main/hello_world_main.c). The file is located in folder [main](main).
|
||||||
|
|
||||||
|
ESP-IDF projects are built using CMake. The project build configuration is contained in `CMakeLists.txt` files that provide set of directives and instructions describing the project's source files and targets (executable, library, or both).
|
||||||
|
|
||||||
|
Below is short explanation of remaining files in the project folder.
|
||||||
|
|
||||||
|
```
|
||||||
|
├── CMakeLists.txt
|
||||||
|
├── pytest_hello_world.py Python script used for automated testing
|
||||||
|
├── main
|
||||||
|
│ ├── CMakeLists.txt
|
||||||
|
│ └── hello_world_main.c
|
||||||
|
└── README.md This is the file you are currently reading
|
||||||
|
```
|
||||||
|
|
||||||
|
For more information on structure and contents of ESP-IDF projects, please refer to Section [Build System](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html) of the ESP-IDF Programming Guide.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
* Program upload failure
|
||||||
|
|
||||||
|
* Hardware connection is not correct: run `idf.py -p PORT monitor`, and reboot your board to see if there are any output logs.
|
||||||
|
* The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again.
|
||||||
|
|
||||||
|
## Technical support and feedback
|
||||||
|
|
||||||
|
Please use the following feedback channels:
|
||||||
|
|
||||||
|
* For technical queries, go to the [esp32.com](https://esp32.com/) forum
|
||||||
|
* For a feature request or bug report, create a [GitHub issue](https://github.com/espressif/esp-idf/issues)
|
||||||
|
|
||||||
|
We will get back to you as soon as possible.
|
|
@ -0,0 +1,9 @@
|
||||||
|
idf_component_register(
|
||||||
|
SRCS
|
||||||
|
"app_wifi.c"
|
||||||
|
"main.c"
|
||||||
|
"aht10/aht10.c"
|
||||||
|
INCLUDE_DIRS
|
||||||
|
"include"
|
||||||
|
"aht10"
|
||||||
|
)
|
|
@ -0,0 +1,20 @@
|
||||||
|
menu "Application Configuration"
|
||||||
|
|
||||||
|
config APP_WIFI_SSID
|
||||||
|
string "WiFi SSID"
|
||||||
|
default "myssid"
|
||||||
|
help
|
||||||
|
SSID (network name) for the application to connect to.
|
||||||
|
|
||||||
|
config APP_WIFI_PASSWORD
|
||||||
|
string "WiFi Password"
|
||||||
|
default "mypassword"
|
||||||
|
help
|
||||||
|
WiFi password (WPA or WPA2) for the application to use.
|
||||||
|
|
||||||
|
config APP_MAXIMUM_RETRY
|
||||||
|
int "Maximum retry"
|
||||||
|
default 5
|
||||||
|
help
|
||||||
|
Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent.
|
||||||
|
endmenu
|
|
@ -0,0 +1,134 @@
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/* Private header */
|
||||||
|
#include "aht10.h"
|
||||||
|
|
||||||
|
#define AHT10_STATUS_CALIBRATED_MASK (1U << 3U)
|
||||||
|
#define AHT10_STATUS_BUSY_MASK (1U << 7U)
|
||||||
|
|
||||||
|
#define AHT10_ERROR_CHECK(x) \
|
||||||
|
if (x != AHT10_OK) return AHT10_FAIL
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t status;
|
||||||
|
uint32_t temperature;
|
||||||
|
uint32_t humidity;
|
||||||
|
} aht10_raw_t;
|
||||||
|
|
||||||
|
static aht10_ret_t aht10_software_reset(aht10_t *aht) {
|
||||||
|
/* Reset and initialize device */
|
||||||
|
|
||||||
|
uint8_t tx_data[3] = {0xBA};
|
||||||
|
|
||||||
|
aht10_xfer_desc_t xfer = {
|
||||||
|
.tx_data = tx_data,
|
||||||
|
.tx_size = 1U,
|
||||||
|
.rx_data = NULL,
|
||||||
|
.rx_size = 0U,
|
||||||
|
};
|
||||||
|
|
||||||
|
AHT10_ERROR_CHECK(aht->cb.xfer(aht->user_data, &xfer));
|
||||||
|
|
||||||
|
AHT10_ERROR_CHECK(aht->cb.delay(aht->user_data, 20));
|
||||||
|
|
||||||
|
tx_data[0] = 0xE1;
|
||||||
|
tx_data[1] = 0x08;
|
||||||
|
tx_data[2] = 0x00;
|
||||||
|
|
||||||
|
xfer.tx_size = 3U;
|
||||||
|
|
||||||
|
AHT10_ERROR_CHECK(aht->cb.xfer(aht->user_data, &xfer));
|
||||||
|
|
||||||
|
return AHT10_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static aht10_ret_t aht10_start_measurement(aht10_t *aht) {
|
||||||
|
/* Start measurement */
|
||||||
|
|
||||||
|
uint8_t tx_data[3] = {0xAC, 0x33, 0x00};
|
||||||
|
|
||||||
|
aht10_xfer_desc_t xfer = {
|
||||||
|
.tx_data = tx_data,
|
||||||
|
.tx_size = 3U,
|
||||||
|
.rx_data = NULL,
|
||||||
|
.rx_size = 0U,
|
||||||
|
};
|
||||||
|
|
||||||
|
AHT10_ERROR_CHECK(aht->cb.xfer(aht->user_data, &xfer));
|
||||||
|
|
||||||
|
return AHT10_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static aht10_ret_t aht10_read_result(aht10_t *aht, aht10_raw_t *raw) {
|
||||||
|
/* Read conversion result */
|
||||||
|
|
||||||
|
uint8_t tx_data[] = {0x71};
|
||||||
|
uint8_t rx_data[6];
|
||||||
|
|
||||||
|
aht10_xfer_desc_t xfer = {
|
||||||
|
.tx_data = tx_data,
|
||||||
|
.tx_size = 1U,
|
||||||
|
.rx_data = rx_data,
|
||||||
|
.rx_size = 6U,
|
||||||
|
};
|
||||||
|
|
||||||
|
AHT10_ERROR_CHECK(aht->cb.xfer(aht->user_data, &xfer));
|
||||||
|
|
||||||
|
raw->humidity = rx_data[1] << 12U;
|
||||||
|
raw->humidity |= rx_data[2] << 4U;
|
||||||
|
raw->humidity |= rx_data[3] >> 4U;
|
||||||
|
|
||||||
|
raw->temperature = (rx_data[3] & 0x0FU) << 16U;
|
||||||
|
raw->temperature |= rx_data[4] << 8U;
|
||||||
|
raw->temperature |= rx_data[5];
|
||||||
|
|
||||||
|
raw->status = rx_data[0];
|
||||||
|
|
||||||
|
return AHT10_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
aht10_ret_t aht10_init(aht10_t *aht) {
|
||||||
|
/* Check if we need initialization */
|
||||||
|
|
||||||
|
/* Delay 40ms after POR */
|
||||||
|
AHT10_ERROR_CHECK(aht->cb.delay(aht->user_data, 40));
|
||||||
|
|
||||||
|
aht10_raw_t raw;
|
||||||
|
|
||||||
|
/* Check 0x71 status byte, if uncalibrated then reset and calibrate it. */
|
||||||
|
AHT10_ERROR_CHECK(aht10_read_result(aht, &raw));
|
||||||
|
if ((raw.status & AHT10_STATUS_CALIBRATED_MASK) == 0) {
|
||||||
|
AHT10_ERROR_CHECK(aht10_software_reset(aht));
|
||||||
|
}
|
||||||
|
|
||||||
|
return AHT10_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
aht10_ret_t aht10_measure(aht10_t *aht, aht10_result_t *result) {
|
||||||
|
/* Start a measurement and read back result... */
|
||||||
|
|
||||||
|
AHT10_ERROR_CHECK(aht10_start_measurement(aht));
|
||||||
|
|
||||||
|
AHT10_ERROR_CHECK(aht->cb.delay(aht->user_data, 80));
|
||||||
|
|
||||||
|
aht10_raw_t raw;
|
||||||
|
|
||||||
|
uint8_t max_retries = 5U;
|
||||||
|
|
||||||
|
do {
|
||||||
|
AHT10_ERROR_CHECK(aht10_read_result(aht, &raw));
|
||||||
|
max_retries--;
|
||||||
|
if (max_retries == 0) {
|
||||||
|
return AHT10_FAIL;
|
||||||
|
}
|
||||||
|
#ifndef AHT10_SKIP_BUSY_CHECK
|
||||||
|
} while (raw.status & AHT10_STATUS_BUSY_MASK);
|
||||||
|
#else
|
||||||
|
} while (0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
result->temperature = ((double)raw.temperature * 200.0 / 1048576.0) - 50.0;
|
||||||
|
result->humidity = (double)raw.humidity * 100.0 / 1048576.0;
|
||||||
|
|
||||||
|
return AHT10_OK;
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef AHT10_H
|
||||||
|
#define AHT10_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define AHT10_SKIP_BUSY_CHECK
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
AHT10_OK,
|
||||||
|
AHT10_FAIL,
|
||||||
|
} aht10_ret_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t *tx_data;
|
||||||
|
uint8_t *rx_data;
|
||||||
|
uint16_t tx_size;
|
||||||
|
uint16_t rx_size;
|
||||||
|
} aht10_xfer_desc_t;
|
||||||
|
|
||||||
|
typedef aht10_ret_t (*aht10_i2c_xfer_t)(void *pdev, aht10_xfer_desc_t *xfer);
|
||||||
|
typedef aht10_ret_t (*aht10_delay_t)(void *pdev, uint32_t delay_msec);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
double temperature;
|
||||||
|
double humidity;
|
||||||
|
} aht10_result_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
aht10_i2c_xfer_t xfer;
|
||||||
|
aht10_delay_t delay;
|
||||||
|
} aht10_cb_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
aht10_cb_t cb;
|
||||||
|
void *user_data;
|
||||||
|
} aht10_t;
|
||||||
|
|
||||||
|
aht10_ret_t aht10_init(aht10_t *aht);
|
||||||
|
aht10_ret_t aht10_measure(aht10_t *aht, aht10_result_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,93 @@
|
||||||
|
/* ESP drivers */
|
||||||
|
#include "esp_event.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_system.h"
|
||||||
|
#include "esp_wifi.h"
|
||||||
|
|
||||||
|
/* FreeRTOS */
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/event_groups.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
|
||||||
|
/* App specific */
|
||||||
|
#include "app_wifi.h"
|
||||||
|
|
||||||
|
#define APP_LOG_TAG "APP_WIFI"
|
||||||
|
|
||||||
|
EventGroupHandle_t g_app_wifi_event_group;
|
||||||
|
|
||||||
|
static uint8_t s_retries = 0U;
|
||||||
|
|
||||||
|
static void app_wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
|
||||||
|
|
||||||
|
esp_err_t app_wifi_init(void) {
|
||||||
|
g_app_wifi_event_group = xEventGroupCreate();
|
||||||
|
if (g_app_wifi_event_group == NULL) {
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(esp_netif_init());
|
||||||
|
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||||
|
esp_netif_create_default_wifi_sta();
|
||||||
|
|
||||||
|
wifi_init_config_t wifi_init_cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_cfg));
|
||||||
|
|
||||||
|
esp_event_handler_instance_t inst_any_id;
|
||||||
|
esp_event_handler_instance_t inst_got_ip;
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(
|
||||||
|
esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, app_wifi_event_handler, NULL, &inst_any_id));
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(
|
||||||
|
esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, app_wifi_event_handler, NULL, &inst_got_ip));
|
||||||
|
|
||||||
|
wifi_config_t wifi_config = {
|
||||||
|
.sta =
|
||||||
|
{
|
||||||
|
.ssid = CONFIG_APP_WIFI_SSID,
|
||||||
|
.password = CONFIG_APP_WIFI_PASSWORD,
|
||||||
|
.threshold.authmode = WIFI_AUTH_WPA2_PSK,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_start());
|
||||||
|
|
||||||
|
ESP_LOGI(APP_LOG_TAG, "WiFi initialized, heap free: %d.", esp_get_free_heap_size());
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void app_wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) {
|
||||||
|
/* Event handler */
|
||||||
|
|
||||||
|
if (event_base == WIFI_EVENT) {
|
||||||
|
if (event_id == WIFI_EVENT_STA_START) {
|
||||||
|
esp_wifi_connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||||
|
if (s_retries < CONFIG_APP_MAXIMUM_RETRY) {
|
||||||
|
esp_wifi_connect();
|
||||||
|
s_retries++;
|
||||||
|
|
||||||
|
ESP_LOGI(APP_LOG_TAG, "Connection lost, retrying #%d/%d...", s_retries, CONFIG_APP_MAXIMUM_RETRY);
|
||||||
|
} else {
|
||||||
|
xEventGroupSetBits(g_app_wifi_event_group, APP_WIFI_EVENT_GROUP_EVENT_FAILED);
|
||||||
|
|
||||||
|
ESP_LOGW(APP_LOG_TAG, "Connection lost, maximum retries reached.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(event_base == IP_EVENT) {
|
||||||
|
if(event_id == IP_EVENT_STA_GOT_IP) {
|
||||||
|
xEventGroupSetBits(g_app_wifi_event_group, APP_WIFI_EVENT_GROUP_EVENT_CONNECTED);
|
||||||
|
s_retries = 0U;
|
||||||
|
|
||||||
|
ip_event_got_ip_t *event = event_data;
|
||||||
|
|
||||||
|
ESP_LOGI(APP_LOG_TAG, "Connected, IP address: "IPSTR, IP2STR(&event->ip_info.ip));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef APP_WIFI_H
|
||||||
|
#define APP_WIFI_H
|
||||||
|
|
||||||
|
/* ESP drivers */
|
||||||
|
#include "esp_system.h"
|
||||||
|
|
||||||
|
/* FreeRTOS */
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/event_groups.h"
|
||||||
|
|
||||||
|
#define APP_WIFI_EVENT_GROUP_EVENT_CONNECTED (1 << 0U)
|
||||||
|
#define APP_WIFI_EVENT_GROUP_EVENT_FAILED (1 << 1U)
|
||||||
|
|
||||||
|
extern EventGroupHandle_t g_app_wifi_event_group;
|
||||||
|
|
||||||
|
esp_err_t app_wifi_init(void);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: CC0-1.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* ESP drivers */
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
|
/* FreeRTOS */
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
|
||||||
|
/* NVS */
|
||||||
|
#include "nvs_flash.h"
|
||||||
|
|
||||||
|
/* Config */
|
||||||
|
#include "app_wifi.h"
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
|
#define APP_LOG_TAG "MAIN"
|
||||||
|
|
||||||
|
void app_main(void) {
|
||||||
|
printf("Hello world!\n");
|
||||||
|
|
||||||
|
esp_err_t ret = nvs_flash_init();
|
||||||
|
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||||
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||||
|
|
||||||
|
ret = nvs_flash_init();
|
||||||
|
|
||||||
|
ESP_LOGW(APP_LOG_TAG, "NVS content corrupted or outdated, cleared.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(ret);
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(app_wifi_init());
|
||||||
|
|
||||||
|
EventBits_t bits = xEventGroupWaitBits(g_app_wifi_event_group,
|
||||||
|
APP_WIFI_EVENT_GROUP_EVENT_CONNECTED | APP_WIFI_EVENT_GROUP_EVENT_FAILED,
|
||||||
|
pdFALSE, pdFALSE, portMAX_DELAY);
|
||||||
|
|
||||||
|
if (bits & APP_WIFI_EVENT_GROUP_EVENT_FAILED) {
|
||||||
|
/* ?? */
|
||||||
|
}
|
||||||
|
|
||||||
|
vTaskSuspend(NULL);
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
# ESP-IDF Partition Table
|
||||||
|
# Name, Type, SubType, Offset, Size, Flags
|
||||||
|
nvs, data, nvs, 0x9000, 0x6000,
|
||||||
|
phy_init, data, phy, 0xf000, 0x1000,
|
||||||
|
factory, app, factory, 0x10000, 3M,
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||||
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from pytest_embedded_idf.dut import IdfDut
|
||||||
|
from pytest_embedded_qemu.dut import QemuDut
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.supported_targets
|
||||||
|
@pytest.mark.generic
|
||||||
|
def test_hello_world(dut: IdfDut, log_minimum_free_heap_size: Callable[..., None]) -> None:
|
||||||
|
dut.expect('Hello world!')
|
||||||
|
log_minimum_free_heap_size()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.esp32 # we only support qemu on esp32 for now
|
||||||
|
@pytest.mark.host_test
|
||||||
|
@pytest.mark.qemu
|
||||||
|
def test_hello_world_host(dut: QemuDut) -> None:
|
||||||
|
dut.expect('Hello world!')
|
|
@ -0,0 +1,7 @@
|
||||||
|
# Minimum flash size set to 4MB
|
||||||
|
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||||
|
|
||||||
|
# Use custom partition table, 3MB application.
|
||||||
|
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||||
|
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||||
|
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue