move embedded tutorials out of protocol tree

This commit is contained in:
Sergio R. Caprile committed 2026-10-07 16:10:28 -03:00
1 parent 338756d0b0
commit 8fc5651044
287 files changed
+720 -267

No files matched your search

@@ -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.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(mongoose-esp32-example)
+38
View File
@@ -0,0 +1,38 @@
THISDIR = $(realpath $(CURDIR))
ROOTDIR = $(realpath $(CURDIR)/../../../..)
DOCKER ?= docker run --rm $(DA) -v $(ROOTDIR):$(ROOTDIR) -w $(THISDIR) espressif/idf
CMD ?= idf.py build
PORT ?= /dev/ttyUSB0
all: example
example:
true
build: Makefile $(wildcard main/*)
$(DOCKER) $(CMD)
flash:
flash: CMD = idf.py flash
flash: DA = --device $(PORT)
flash: build
.PHONY: build
dashboard.hex: build
esputil mkhex \
0x8000 build/partition_table/partition-table.bin \
0x1000 build/bootloader/bootloader.bin \
0x100000 build/mongoose-esp32-example.bin > $@
flash2: dashboard.hex
esputil -p $(PORT) -b 921600 -fp 0x220 flash dashboard.hex
esputil -p $(PORT) monitor
ESPTOOL ?= esptool.py
flash3:
cd build && $(ESPTOOL) --chip esp32 -p $(PORT) -b 460800 --before=default_reset --after=hard_reset write_flash --flash_mode dio --flash_freq 40m --flash_size 2MB 0x8000 partition_table/partition-table.bin 0x1000 bootloader/bootloader.bin 0x100000 mongoose-esp32-example.bin
clean:
test -d build && $(DOCKER) rm -rf build sdkconfig || true
@@ -0,0 +1 @@
See detailed tutorial at https://mongoose.ws/tutorials/esp32/device-dashboard
@@ -0,0 +1,7 @@
idf_component_register(SRCS "main.c"
"wifi.c"
"net.c"
"packed_fs.c"
"mongoose.c")
component_compile_options(-DHTTP_URL="http://0.0.0.0:80")
component_compile_options(-DHTTPS_URL="https://0.0.0.0:443")
@@ -0,0 +1,272 @@
// Copyright (c) 2020 Cesanta Software Limited
// All rights reserved
#include "mongoose.h"
#include "net.h"
#define WIFI_SSID "YOUR_WIFI_NETWORK_NAME" // SET THIS!
#define WIFI_PASS "YOUR_WIFI_PASSWORD" // SET THIS!
void app_main(void) {
// Setup wifi. This function is implemented in wifi.c
// It blocks until connected to the configured WiFi network
void wifi_init(const char *ssid, const char *pass);
wifi_init(WIFI_SSID, WIFI_PASS);
// Connected to WiFi, now start HTTP server
struct mg_mgr mgr;
mg_log_set(MG_LL_DEBUG); // Set log level
mg_mgr_init(&mgr);
MG_INFO(("Mongoose version : v%s", MG_VERSION));
MG_INFO(("Listening on : %s", HTTP_URL));
#if MG_ENABLE_MBEDTLS
MG_INFO(("Listening on : %s", HTTPS_URL));
#endif
web_init(&mgr);
for (;;) mg_mgr_poll(&mgr, 1000); // Infinite event loop
}
#if MG_OTA == MG_OTA_CUSTOM
enum {
MG_OTA_UNAVAILABLE = 0, // No OTA information is present
MG_OTA_FIRST_BOOT = 1, // Device booting the first time after the OTA
MG_OTA_UNCOMMITTED = 2, // Ditto, but marking us for the rollback
MG_OTA_COMMITTED = 3 // The firmware is good
};
enum { MG_FIRMWARE_CURRENT = 0, MG_FIRMWARE_PREVIOUS = 1 };
void *mg_flash_start(void) {
return NULL;
}
size_t mg_flash_size(void) {
return 0;
}
size_t mg_flash_sector_size(void) {
return 0;
}
size_t mg_flash_write_align(void) {
return 0;
}
int mg_flash_bank(void) {
return 0;
}
bool mg_flash_erase(void *location) {
(void) location;
return false;
}
bool mg_flash_swap_bank(void) {
return true;
}
bool mg_flash_write(void *addr, const void *buf, size_t len) {
(void) addr, (void) buf, (void) len;
return false;
}
void mg_device_reset(void) {
esp_restart();
}
#include "esp_app_format.h"
#include "esp_ota_ops.h"
static size_t s_size = 0; // Firmware size to flash. In-progress indicator
static bool rx_checked = false; // Whether firmware being received has been checked as valid
const esp_partition_t * update_partition = NULL; // The partition the update is being applied to
esp_ota_handle_t update_handle = 0; // Handle of the current update process
const esp_partition_t * get_partition_from_fw(int fw) {
if (MG_FIRMWARE_CURRENT == fw) {
return esp_ota_get_running_partition();
}
const esp_partition_t * p = esp_ota_get_last_invalid_partition();
if (NULL == p) {
p = esp_ota_get_next_update_partition(NULL);
}
return p;
}
// Returns true if the data buffer contains the header of a valid firmware
const size_t fw_size_required = sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t);
bool check_fw_header(const void* buf, size_t len) {
// Ensure we have received enough data to do the check
if (len < fw_size_required) {
MG_ERROR(("Insufficient data to check firmware header - %d bytes, require %d bytes", len, fw_size_required));
return false;
}
// Check the magic word of the received firmare
esp_app_desc_t* rx_app_info = (esp_app_desc_t*)(((char*)buf) + sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t));
if (ESP_APP_DESC_MAGIC_WORD != rx_app_info->magic_word) {
MG_ERROR(("Invalid app - invalid magic word"));
return false;
}
MG_INFO(("Received firmware: %s %s", rx_app_info->project_name, rx_app_info->version));
// Get the name/version of the running firmware
const esp_partition_t *current = esp_ota_get_running_partition();
esp_app_desc_t curr_app_info;
esp_err_t res = esp_ota_get_partition_description(current, &curr_app_info);
if (ESP_OK != res) {
MG_ERROR(("Unable to get name/version of running firmware"));
return false;
}
MG_INFO(("Running firmware: %s %s", curr_app_info.project_name, curr_app_info.version));
// Check the name of the new firmware is the same as the old firmware
if (memcmp(curr_app_info.project_name, rx_app_info->project_name, sizeof(curr_app_info.project_name)) != 0) {
MG_ERROR(("Firmware name is different. Wrong firmware uploaded! Current %s Uploaded %s", curr_app_info.project_name, rx_app_info->project_name));
return false;
}
// Check the version of the new firmware is different from the old firmware
if (memcmp(curr_app_info.version, rx_app_info->version, sizeof(curr_app_info.version)) == 0) {
MG_ERROR(("Firmware version is the same. Wrong firmware uploaded! Current %s, Uploaded %s", curr_app_info.version, rx_app_info->version));
//return false;
}
return true;
}
size_t mg_ota_size(int fw) {
const esp_partition_t *p = get_partition_from_fw(fw);
if (NULL == p) {
return 0;
}
return p->size;
}
bool mg_ota_begin(size_t new_firmware_size) {
rx_checked = false;
if (s_size) {
MG_ERROR(("OTA already in progress. Call mg_ota_end()"));
return false;
}
int partition_size = mg_ota_size(MG_FIRMWARE_PREVIOUS);
if (new_firmware_size > partition_size) {
MG_ERROR(("Firmware %lu bytes, max %lu", new_firmware_size, partition_size));
return false;
}
update_partition = esp_ota_get_next_update_partition(NULL);
if (NULL == update_partition) {
MG_ERROR(("esp_ota_get_next_update_partition returned NULL"));
return false;
}
esp_err_t res = esp_ota_begin(update_partition, OTA_WITH_SEQUENTIAL_WRITES, &update_handle);
if (res != ESP_OK) {
esp_ota_abort(update_handle);
MG_ERROR(("esp_ota_begin failed (%s)", esp_err_to_name(res)));
return false;
}
s_size = new_firmware_size;
MG_INFO(("Starting OTA, firmware size %lu", s_size));
return true;
}
bool mg_ota_write(const void *buf, size_t len) {
if (s_size == 0) {
MG_ERROR(("OTA is not started, call mg_ota_begin()"));
return false;
}
if (!rx_checked) {
if (!check_fw_header(buf, len)) {
return false;
}
rx_checked = true;
}
esp_err_t res = esp_ota_write(update_handle, buf, len);
if (res != ESP_OK) {
esp_ota_abort(update_handle);
MG_ERROR(("esp_ota_write FAILED (%s)", esp_err_to_name(res)));
return false;
}
return true;
}
bool mg_ota_end(void) {
if (0 == s_size) {
MG_INFO(("Finishing OTA: fail"));
return false;
}
s_size = 0;
esp_err_t err = esp_ota_end(update_handle);
if (err != ESP_OK) {
MG_ERROR(("esp_ota_end failed (%s)!", esp_err_to_name(err)));
return false;
}
err = esp_ota_set_boot_partition(update_partition);
if (err != ESP_OK) {
MG_ERROR(("esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err)));
return false;
}
return true;
}
bool mg_ota_commit(void) {
esp_ota_mark_app_valid_cancel_rollback();
return true;
}
bool mg_ota_rollback(void) {
if(esp_ota_check_rollback_is_possible()) {
esp_ota_mark_app_invalid_rollback_and_reboot();
return true;
}
MG_ERROR(("Rollback NOT possible"));
return false;
}
int mg_ota_status(int fw) {
const esp_partition_t *p = get_partition_from_fw(fw);
if (NULL == p) {
return 0;
}
int status = MG_OTA_UNAVAILABLE;
esp_ota_img_states_t img_state = ESP_OTA_IMG_UNDEFINED;
esp_err_t res = esp_ota_get_state_partition(p, &img_state);
if (ESP_OK == res) {
if (ESP_OTA_IMG_VALID == img_state) {
status = MG_OTA_COMMITTED;
} else if (ESP_OTA_IMG_UNDEFINED == img_state) {
status = MG_OTA_UNCOMMITTED;
} else if (ESP_OTA_IMG_INVALID == img_state) {
status = MG_OTA_UNAVAILABLE;
} else if (ESP_OTA_IMG_ABORTED == img_state) {
status = MG_OTA_UNAVAILABLE;
} else if (ESP_OTA_IMG_NEW == img_state) {
status = MG_OTA_FIRST_BOOT;
} else if (ESP_OTA_IMG_PENDING_VERIFY == img_state) {
status = MG_OTA_UNCOMMITTED;
}
}
return status;
}
uint32_t mg_ota_crc32(int fw) {
(void) fw;
return 0;
}
uint32_t mg_ota_timestamp(int fw) {
const esp_partition_t *p = get_partition_from_fw(fw);
esp_app_desc_t app;
esp_err_t res = esp_ota_get_partition_description(p, &app);
if (ESP_OK != res)
{
return 0;
}
struct tm datetime = {};
if (NULL == strptime(app.date, "%b %d %Y", &datetime))
{
return 0;
}
if (NULL == strptime(app.time, "%H:%M:%S", &datetime))
{
return 0;
}
return mktime(&datetime);
}
#endif
+1
View File
@@ -0,0 +1 @@
../../../../mongoose.c
+1
View File
@@ -0,0 +1 @@
../../../../mongoose.h
@@ -0,0 +1,4 @@
#define MG_ARCH MG_ARCH_ESP32
#define MG_TLS MG_TLS_NONE // change to 'MG_TLS_MBED' to enable TLS
#define MG_OTA MG_OTA_CUSTOM
+1
View File
@@ -0,0 +1 @@
../../../http/device-dashboard/net.c
+1
View File
@@ -0,0 +1 @@
../../../http/device-dashboard/net.h
+1
View File
@@ -0,0 +1 @@
../../../http/device-dashboard/packed_fs.c
@@ -0,0 +1,104 @@
// Code taken from the ESP32 IDF WiFi station Example
#include <string.h>
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "freertos/task.h"
#include "nvs_flash.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "mongoose.h"
static EventGroupHandle_t s_wifi_event_group;
/* The event group allows multiple bits for each event, but we only care about
* two events:
* - we are connected to the AP with an IP
* - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
static int s_retry_num = 0;
static void event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data) {
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_base == WIFI_EVENT &&
event_id == WIFI_EVENT_STA_DISCONNECTED) {
if (s_retry_num < 10) {
esp_wifi_connect();
s_retry_num++;
MG_INFO(("retry to connect to the AP"));
} else {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
MG_ERROR(("connect to the AP fail"));
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
MG_INFO(("IP ADDRESS:" IPSTR, IP2STR(&event->ip_info.ip)));
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}
void wifi_init(const char *ssid, const char *pass) {
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_ERROR_CHECK(ret);
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;
ESP_ERROR_CHECK(esp_event_handler_instance_register(
WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(
IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &instance_got_ip));
wifi_config_t c = {.sta = {.threshold = {.authmode = WIFI_AUTH_WPA2_PSK},
.pmf_cfg = {.capable = true, .required = false}}};
snprintf((char *) c.sta.ssid, sizeof(c.sta.ssid), "%s", ssid);
snprintf((char *) c.sta.password, sizeof(c.sta.password), "%s", pass);
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &c));
ESP_ERROR_CHECK(esp_wifi_start());
MG_DEBUG(("wifi_init_sta finished."));
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
pdFALSE, pdFALSE, portMAX_DELAY);
if (bits & WIFI_CONNECTED_BIT) {
MG_INFO(("connected to ap SSID:%s password:%s", ssid, pass));
} else if (bits & WIFI_FAIL_BIT) {
MG_ERROR(("Failed to connect to SSID:%s, password:%s", ssid, pass));
} else {
MG_ERROR(("UNEXPECTED EVENT"));
}
/* The event will not be processed after unregister */
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(
IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(
WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
vEventGroupDelete(s_wifi_event_group);
}
@@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, , 0x6000
otadata, data, ota, , 0x2000,
phy_init, data, phy, , 0x1000,
ota_0, app, ota_0, , 948K,
ota_1, app, ota_1, , 948K,
1 # Name, Type, SubType, Offset, Size, Flags
2 nvs, data, nvs, , 0x6000
3 otadata, data, ota, , 0x2000,
4 phy_init, data, phy, , 0x1000,
5 ota_0, app, ota_0, , 948K,
6 ota_1, app, ota_1, , 948K,
@@ -0,0 +1,5 @@
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y
#CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
@@ -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.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(mongoose-esp32-example)
+32
View File
@@ -0,0 +1,32 @@
CWD = $(realpath $(CURDIR))
MNT = $(realpath $(CURDIR)/../../../..)
PORT ?= /dev/ttyUSB0
CMD ?= build
all: example
example:
true
build: Makefile $(wildcard main/*)
docker run --rm $(DA) -v $(MNT):$(MNT) -w $(CWD) espressif/idf idf.py $(CMD)
flash:
flash: CMD = flash
flash: DA = --device $(PORT)
flash: build
.PHONY: build
bridge.hex: build
esputil mkhex \
0x8000 build/partition_table/partition-table.bin \
0x1000 build/bootloader/bootloader.bin \
0x100000 build/mongoose-esp32-example.bin > $@
flash2: bridge.hex
esputil -p $(PORT) -b 921600 -fp 0x220 flash bridge.hex
esputil -p $(PORT) monitor
clean:
rm -rf build
+41
View File
@@ -0,0 +1,41 @@
# A UART to network bridge for ESP32
![](../../uart-bridge/screenshots/dashboard.png)
- See detailed tutorial at https://mongoose.ws/tutorials/esp32/uart-bridge/
## Flash pre-built firmware
You can flash a pre-built firmware to the ESP32 device using the following
instructions:
1. Connect your ESP32 device to the workstation. It should be accessible
via a serial port
2. Download and unzip ESP32 flashing tool from https://mongoose.ws/downloads/esputil.zip
3. Download a prebuilt firmware https://mongoose.ws/downloads/uart-bridge.hex into the unzipped directory
4. Start command prompt (or terminal on Mac/Linux). Run `cd
PATH/TO/esputil` to go into the unzipped `esputil/` directory. After that, run
the following command (change `COMPORT` to the board's serial port):
| OS | Command |
| ------- | ------- |
| Windows | <pre><code class="language-bash">.\windows\esputil -p COMPORT flash uart-bridge.hex</code></pre>|
| Linux | <pre><code class="language-bash">./linux/esputil -p COMPORT flash uart-bridge.hex</pre> |
| MacOS | <pre><code class="language-bash">./macos/esputil -p COMPORT flash uart-bridge.hex</code></pre> |
Next step is to monitor and follow the instructions.
```sh
esputil -p COMPORT monitor
```
Note: if monitor command shows constant restarts, the flash parameters
settings can be wrong. Reflash your device with `-fp ...` flash parameters
settings. For example, WROOM-32 based boards use `-fp 0x220`:
```sh
esputil -p COMPORT -fp 0x220 flash uart-bridge.hex
```
For more on possible options for flash parameters, see
https://github.com/cpq/esputil#flash-parameters
@@ -0,0 +1,8 @@
idf_component_register(SRCS "main.c"
"wifi.c"
"uart.c"
"cli.c"
"net.c"
"packed_fs.c"
"mongoose.c")
component_compile_options(-DUART_API_IMPLEMENTED=1)
+94
View File
@@ -0,0 +1,94 @@
#include "main.h"
static void cli_wifi(const char *ssid, const char *pass) {
if (wifi_init(ssid, pass)) {
mg_file_printf(&mg_fs_posix, WIFI_FILE, "{%m:%m,%m:%m}\n", mg_print_esc, 0,
"ssid", mg_print_esc, 0, ssid, mg_print_esc, 0, "pass",
mg_print_esc, 0, pass);
MG_INFO(("Reboot now"));
}
}
static void cli_ls(void) {
DIR *dirp = opendir(FS_ROOT);
struct dirent *dp;
if (dirp == NULL) {
MG_ERROR(("Cannot open FS: %d", errno));
} else {
while ((dp = readdir(dirp)) != NULL) {
/* Do not show current and parent dirs */
if (strcmp((const char *) dp->d_name, ".") == 0 ||
strcmp((const char *) dp->d_name, "..") == 0) {
continue;
} else {
printf("%s\n", dp->d_name);
}
}
closedir(dirp);
}
}
static void cli_cat(const char *fname) {
char path[MG_PATH_MAX];
snprintf(path, sizeof(path), "%s/%s", FS_ROOT, fname);
FILE *fp = fopen(path, "r");
if (fp != NULL) {
int ch;
while ((ch = fgetc(fp)) != EOF) putchar(ch);
fclose(fp);
}
}
static void cli_rm(const char *fname) {
char path[100];
snprintf(path, sizeof(path), "%s/%s", FS_ROOT, fname);
remove(path);
}
static struct mg_iobuf in;
void cli(uint8_t input_byte) {
if (input_byte == 0 || input_byte == 0xff) return;
if (in.len >= 128) in.len = 0;
mg_iobuf_add(&in, in.len, &input_byte, sizeof(input_byte));
if (input_byte == '\n') {
const char *arrow = "---";
char buf0[10], buf1[50], buf2[250];
in.buf[in.len] = '\0';
buf0[0] = buf1[0] = buf2[0] = '\0';
sscanf((char *) in.buf, "%9s %49s %249[^\r\n]", buf0, buf1, buf2);
printf("%s CLI command: '%s'\n", arrow, buf0);
if (strcmp(buf0, "reboot") == 0) {
esp_restart();
} else if (strcmp(buf0, "ls") == 0) {
cli_ls();
} else if (strcmp(buf0, "cat") == 0) {
cli_cat(buf1);
} else if (strcmp(buf0, "rm") == 0) {
cli_rm(buf1);
} else if (strcmp(buf0, "reboot") == 0) {
esp_restart();
} else if (strcmp(buf0, "ll") == 0) {
mg_log_set(atoi(buf1));
} else if (strcmp(buf0, "wifi") == 0) {
cli_wifi(buf1, buf2);
} else {
printf("%s %s\n", arrow, "Unknown command. Usage:");
printf("%s %s\n", arrow, " set NAME VALUE");
printf("%s %s\n", arrow, " rm FILENAME");
printf("%s %s\n", arrow, " cat FILENAME");
printf("%s %s\n", arrow, " ls");
printf("%s %s\n", arrow, " reboot");
printf("%s %s\n", arrow, " wifi WIFI_NET WIFI_PASS");
}
printf("%s %s\n", arrow, "CLI output end");
in.len = 0;
}
}
void cli_init(void) {
mg_iobuf_init(&in, 0, 32);
}
+50
View File
@@ -0,0 +1,50 @@
// Copyright (c) 2020 Cesanta Software Limited
// All rights reserved
#include "main.h"
const char *s_listening_url = "http://0.0.0.0:80";
struct mg_str config_read(void) {
return mg_file_read(&mg_fs_posix, FS_ROOT "/config.json");
}
void config_write(struct mg_str config) {
mg_file_write(&mg_fs_posix, FS_ROOT "/config.json", config.buf, config.len);
}
void app_main(void) {
// Mount filesystem
esp_vfs_spiffs_conf_t conf = {
.base_path = FS_ROOT, .max_files = 20, .format_if_mount_failed = true};
int res = esp_vfs_spiffs_register(&conf);
MG_INFO(("FS at %s initialised, status: %d", conf.base_path, res));
// Try to connect to wifi by using saved WiFi credentials
struct mg_str json = mg_file_read(&mg_fs_posix, WIFI_FILE);
if (json.buf != NULL) {
char *ssid = mg_json_get_str(json, "$.ssid");
char *pass = mg_json_get_str(json, "$.pass");
while (!wifi_init(ssid, pass)) (void) 0;
mg_free(ssid);
mg_free(pass);
mg_free((void *) json.buf);
} else {
// If WiFi is not configured, run CLI until configured
MG_INFO(("WiFi is not configured, running CLI. Press enter"));
cli_init();
for (;;) {
uint8_t ch = getchar();
cli(ch);
usleep(10000);
}
}
// Connected to WiFi, now start HTTP server
struct mg_mgr mgr;
mg_mgr_init(&mgr);
mg_log_set(MG_LL_DEBUG); // Set log level
MG_INFO(("Mongoose v%s on %s", MG_VERSION, s_listening_url));
mg_http_listen(&mgr, s_listening_url, uart_bridge_fn, NULL);
for (;;) mg_mgr_poll(&mgr, 10); // Infinite event loop
}
+18
View File
@@ -0,0 +1,18 @@
#pragma once
#include "mongoose.h"
#include "driver/gpio.h"
#include "driver/uart.h"
#include "esp_spiffs.h"
#include "freertos/FreeRTOS.h"
#define FS_ROOT "/spiffs"
#define WIFI_FILE FS_ROOT "/wifi.json"
#define UART_NO 1
void uart_bridge_fn(struct mg_connection *, int, void *);
int uart_read(void *buf, size_t len);
bool wifi_init(const char *ssid, const char *pass);
void cli(uint8_t ch);
void cli_init(void);
+1
View File
@@ -0,0 +1 @@
../../../../mongoose.c
+1
View File
@@ -0,0 +1 @@
../../../../mongoose.h
@@ -0,0 +1,2 @@
#define MG_ARCH MG_ARCH_ESP32
+1
View File
@@ -0,0 +1 @@
../../../http/uart-bridge/net.c
+1
View File
@@ -0,0 +1 @@
../../../http/uart-bridge/packed_fs.c
+49
View File
@@ -0,0 +1,49 @@
#include "main.h"
#include "esp_idf_version.h" // < 3.3 not supported, sadly
int uart_close(int no) {
return uart_driver_delete(no);
}
int uart_open(int no, int rx, int tx, int cts, int rts, int baud) {
uart_config_t uart_config = {
.baud_rate = baud,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = cts > 0 && rts > 0 ? UART_HW_FLOWCTRL_CTS_RTS
: cts > 0 ? UART_HW_FLOWCTRL_CTS
: rts > 0 ? UART_HW_FLOWCTRL_RTS
: UART_HW_FLOWCTRL_DISABLE,
};
int e1 = uart_param_config(no, &uart_config);
int e2 = uart_set_pin(no, tx, rx, rts, cts);
int e3 =
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 5)
uart_driver_install(no, UART_HW_FIFO_LEN(no) * 2, UART_HW_FIFO_LEN(no) * 2, 0, NULL, 0);
#else
uart_driver_install(no, UART_FIFO_LEN * 2, UART_FIFO_LEN * 2, 0, NULL, 0);
#endif
MG_INFO(("%d: %d/%d/%d, %d %d %d", no, rx, tx, baud, e1, e2, e3));
if (e1 != ESP_OK || e2 != ESP_OK || e3 != ESP_OK) return -1;
return no;
}
void uart_init(int tx, int rx, int baud) {
uart_open(UART_NO, rx, tx, -1, -1, baud);
}
int uart_read(void *buf, size_t len) {
size_t x = 0;
int no = UART_NO;
if (uart_get_buffered_data_len(no, &x) != ESP_OK || x == 0) return 0;
int n = uart_read_bytes(no, buf, len, 10 / portTICK_PERIOD_MS);
MG_DEBUG(("%d bytes: [%.*s]", n, n, (char *) buf));
return n;
}
int uart_write(const void *buf, int len) {
int no = UART_NO;
MG_DEBUG(("%d bytes: [%.*s]", len, len, (char *) buf));
return uart_write_bytes(no, (const char *) buf, len);
}
+108
View File
@@ -0,0 +1,108 @@
// Code taken from the ESP32 IDF WiFi station Example
#include <string.h>
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "freertos/task.h"
#include "nvs_flash.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "mongoose.h"
static EventGroupHandle_t s_wifi_event_group;
/* The event group allows multiple bits for each event, but we only care about
* two events:
* - we are connected to the AP with an IP
* - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
static int s_retry_num = 0;
static void event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data) {
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_base == WIFI_EVENT &&
event_id == WIFI_EVENT_STA_DISCONNECTED) {
if (s_retry_num < 3) {
esp_wifi_connect();
s_retry_num++;
MG_INFO(("retry to connect to the AP"));
} else {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
MG_ERROR(("connect to the AP fail"));
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
MG_INFO(("IP ADDRESS: " IPSTR ". Go to:", IP2STR(&event->ip_info.ip)));
MG_INFO(("http://" IPSTR, IP2STR(&event->ip_info.ip)));
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}
bool wifi_init(const char *ssid, const char *pass) {
bool result = false;
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_ERROR_CHECK(ret);
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;
ESP_ERROR_CHECK(esp_event_handler_instance_register(
WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(
IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &instance_got_ip));
wifi_config_t c = {.sta = {.threshold = {.authmode = WIFI_AUTH_WPA2_PSK},
.pmf_cfg = {.capable = true, .required = false}}};
snprintf((char *) c.sta.ssid, sizeof(c.sta.ssid), "%s", ssid);
snprintf((char *) c.sta.password, sizeof(c.sta.password), "%s", pass);
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &c));
ESP_ERROR_CHECK(esp_wifi_start());
MG_DEBUG(("wifi_init_sta finished."));
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
pdFALSE, pdFALSE, portMAX_DELAY);
if (bits & WIFI_CONNECTED_BIT) {
MG_INFO(("connected to ap SSID:%s", ssid));
result = true;
} else if (bits & WIFI_FAIL_BIT) {
MG_ERROR(("Failed to connect to SSID:%s, password:%s", ssid, pass));
} else {
MG_ERROR(("UNEXPECTED EVENT"));
}
/* The event will not be processed after unregister */
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(
IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(
WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
vEventGroupDelete(s_wifi_event_group);
return result;
}
View File
Whitespace-only changes.
@@ -0,0 +1,5 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
storage, data, spiffs, 0x10000, 0x10000,
factory, app, factory, 0x100000, 1M,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x6000
3 phy_init data phy 0xf000 0x1000
4 storage data spiffs 0x10000 0x10000
5 factory app factory 0x100000 1M
@@ -0,0 +1,4 @@
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
#CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192