Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
/*
* This file is part of DroneBridge:https://github.com/DroneBridge/ESP32
*
* Copyright 2025 Wolfgang Christl
*
* 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.
*
*/
#include "db_parameters.h"
#include <esp_log.h>
#include <esp_wifi_types_generic.h>
#include <string.h>
#include <lwip/sockets.h>
#define TAG "DB_PARAM"
#define DB_PARAM_PRINT_LINE_BUFFER_SIZE 128U
/**
* Steps to add new parameters.
* 1. Add new parameter as db_parameter_t below
* 2. Add new parameter to db_params array
* 3. Increase DB_PARAM_TOTAL_NUM
* 4. Increase DB_MAV_PARAM_CNT if parameter is available via MAVLink (non-string parameter)
* 5. Make parameter available globally by adding extern definition into db_parameters.h
* 6. Create an optional macro in db_parameters.h to make the parameter value easy accessible
*/
/**
* Introduced and used for settings change only since changing DB_WIFI_MODE directly while system is live will
* eventually lead to crashes. Stores the new Wi-Fi mode and will be written to the settings. This means it will
* become active after reboot.
*/
uint8_t DB_RADIO_MODE_DESIGNATED = DB_WIFI_MODE_AP; // initially assign the same value as DB_RADIO_MODE
/* ---------- String based parameters - not available via MAVLink ---------- */
db_parameter_t db_param_ssid, db_param_pass, db_param_espnow_link_secret, db_param_wifi_ap_ip, db_param_wifi_sta_ip, db_param_wifi_sta_gw,
db_param_wifi_sta_netmask, db_param_udp_client_ip, db_param_wifi_hostname = {0};
/* ---------- From here with increasing param_index all parameters that are also available via MAVLink ---------- */
/**
* never change this value while the ESP32 is running, will likely lead to a crash.
* Assign it during startup when received from storage. Can therefore only be changed via reboot and DB_WIFI_MODE_DESIGNATED
*/
db_parameter_t db_param_radio_mode = {
.db_name = "esp32_mode",
.type = UINT8,
.mav_t = {
.param_name = "SYS_ESP32_MODE",
.param_index = 0,
.param_type = MAV_PARAM_TYPE_UINT8,
},
.value = {
.db_param_u8 = {
.value = DB_WIFI_MODE_AP,
.default_value = DB_WIFI_MODE_AP,
.min = DB_WIFI_MODE_AP,
.max = DB_WIFI_MODE_END,
}
}
};
/**
* Radio channel in WiFi AP and ESP-NOW mode
*/
db_parameter_t db_param_channel = {
.db_name = "wifi_chan",
.type = UINT8,
.mav_t = {
.param_name = "WIFI_AP_CHANNEL",
.param_index = 1,
.param_type = MAV_PARAM_TYPE_UINT8,
},
.value = {
.db_param_u8 = {
.value = 6,
.default_value = 6,
.min = 1,
.max = 13,
}
}
};
/**
* Allow the usage of 802.11bgn mode
* disabled: only 802.11b support for client mode - set to true: 802.11b/g/n/ax mode support.
* ax only when chip supports it.
*/
db_parameter_t db_param_wifi_en_gn = {
.db_name = "wifi_en_gn",
.type = UINT8,
.mav_t = {
.param_name = "WIFI_EN_GN",
.param_index = 2,
.param_type = MAV_PARAM_TYPE_UINT8,
},
.value = {
.db_param_u8 = {
.value = false,
.default_value = false,
.min = false,
.max = true,
}
}
};
/**
* Set to 1 to use external antenna. Set to 0 to enable onboard antenna - board must have antenna switch
* Official ESP32C6 board supports this option.
*/
db_parameter_t db_param_radio_ant_ext = {
.db_name = "ant_use_ext",
.type = UINT8,
.mav_t = {
.param_name = "RADIO_EN_EXT_ANT",
.param_index = 3,
.param_type = MAV_PARAM_TYPE_UINT8,
},
.value = {
.db_param_u8 = {
.value = false,
.default_value = false,
.min = false,
.max = true,
}
}
};
/**
* UART baud rate
*/
db_parameter_t db_param_baud = {
.db_name = "baud",
.type = INT32,
.mav_t = {
.param_name = "SERIAL_BAUD",
.param_index = 4,
.param_type = MAV_PARAM_TYPE_INT32,
},
.value = {
.db_param_i32 = {
.value = DB_DEFAULT_UART_BAUD_RATE,
.default_value = DB_DEFAULT_UART_BAUD_RATE,
.min = 1200,
.max = 5000000,
}
}
};
/**
* TX GPIO number of the UART
*/
db_parameter_t db_param_gpio_tx = {
.db_name = "gpio_tx",
.type = UINT8,
.mav_t = {
.param_name = "SERIAL_TX_PIN",
.param_index = 5,
.param_type = MAV_PARAM_TYPE_UINT8,
},
.value = {
.db_param_u8 = {
.value = DB_DEFAULT_UART_TX_PIN,
.default_value = DB_DEFAULT_UART_TX_PIN,
.min = 0,
.max = SOC_GPIO_IN_RANGE_MAX,
}
}
};
/**
* RX GPIO number of the UART
*/
db_parameter_t db_param_gpio_rx = {
.db_name = "gpio_rx",
.type = UINT8,
.mav_t = {
.param_name = "SERIAL_RX_PIN",
.param_index = 6,
.param_type = MAV_PARAM_TYPE_UINT8,
},
.value = {
.db_param_u8 = {
.value = DB_DEFAULT_UART_RX_PIN,
.default_value = DB_DEFAULT_UART_RX_PIN,
.min = 0,
.max = SOC_GPIO_IN_RANGE_MAX,
}
}
};
/**
* RTS GPIO number of the UART. Set to same value as CTS GPIO to disable flow control.
*/
db_parameter_t db_param_gpio_rts = {
.db_name = "gpio_rts",
.type = UINT8,
.mav_t = {
.param_name = "SERIAL_RTS_PIN",
.param_index = 7,
.param_type = MAV_PARAM_TYPE_UINT8,
},
.value = {
.db_param_u8 = {
.value = DB_DEFAULT_UART_RTS_PIN,
.default_value = DB_DEFAULT_UART_RTS_PIN,
.min = 0,
.max = SOC_GPIO_IN_RANGE_MAX,
}
}
};
/**
* CTS GPIO number of the UART. Set to same value as RTS GPIO to disable flow control.
*/
db_parameter_t db_param_gpio_cts = {
.db_name = "gpio_cts",
.type = UINT8,
.mav_t = {
.param_name = "SERIAL_CTS_PIN",
.param_index = 8,
.param_type = MAV_PARAM_TYPE_UINT8,
},
.value = {
.db_param_u8 = {
.value = DB_DEFAULT_UART_CTS_PIN,
.default_value = DB_DEFAULT_UART_CTS_PIN,
.min = 0,
.max = SOC_GPIO_IN_RANGE_MAX,
}
}
};
/**
* I really don't know. Maybe some sort of timeout. Just leave it at the defaults.
*/
db_parameter_t db_param_gpio_rts_thresh = {
.db_name = "rts_thresh",
.type = UINT8,
.mav_t = {
.param_name = "SERIAL_RTS_THRES",
.param_index = 9,
.param_type = MAV_PARAM_TYPE_UINT8,
},
.value = {
.db_param_u8 = {
.value = 127,
.default_value = 127,
.min = 0,
.max = 127,
}
}
};
/**
* Sets the parser for the serial port
*/
db_parameter_t db_param_proto = {
.db_name = "proto",
.type = UINT8,
.mav_t = {
.param_name = "SERIAL_TEL_PROTO",
.param_index = 10,
.param_type = MAV_PARAM_TYPE_UINT8,
},
.value = {
.db_param_u8 = {
.value = DB_SERIAL_PROTOCOL_MAVLINK,
.default_value = DB_SERIAL_PROTOCOL_MAVLINK,
.min = DB_SERIAL_PROTOCOL_MSPLTM,
.max = DB_SERIAL_PROTOCOL_TRANSPARENT,
}
}
};
/**
* Maximum packet size via ESP-NOW or WiFi in transparent or mavlink mode. Caped to 250 bytes-HEADER in ESP-NOW mode.
*/
db_parameter_t db_param_serial_pack_size = {
.db_name = "trans_pack_size",
.type = UINT16,
.mav_t = {
.param_name = "SERIAL_PACK_SIZE",
.param_index = 11,
.param_type = MAV_PARAM_TYPE_UINT16,
},
.value = {
.db_param_u16 = {
.value = 576,
.default_value = 576,
.min = 16,
.max = DB_SERIAL_PACK_SIZE_MAX,
}
}
};
/**
* Serial read timeout [ms] for transparent and MAVLink mode, after that the packet will be sent over the air even when
* the max. packet size was not reached.
*/
db_parameter_t db_param_serial_read_timeout = {
.db_name = "serial_timeout",
.type = UINT16,
.mav_t = {
.param_name = "SERIAL_T_OUT_MS",
.param_index = 12,
.param_type = MAV_PARAM_TYPE_UINT16,
},
.value = {
.db_param_u16 = {
.value = 20,
.default_value = 20,
.min = 1,
.max = UINT16_MAX,
}
}
};
/**
* Number of LTM frames per packet
*/
db_parameter_t db_param_ltm_per_packet = {
.db_name = "ltm_per_packet",
.type = UINT8,
.mav_t = {
.param_name = "SERIAL_LTM_PACK",
.param_index = 13,
.param_type = MAV_PARAM_TYPE_UINT8,
},
.value = {
.db_param_u8 = {
.value = 2,
.default_value = 2,
.min = 1,
.max = MAX_LTM_FRAMES_IN_BUFFER,
}
}
};
/**
* Detects armed state from MAVLink & LTM stream and disables radio when autopilot reports armed state.
*/
db_parameter_t db_param_dis_radio_armed = {
.db_name = "radio_dis_onarm",
.type = UINT8,
.mav_t = {
.param_name = "RADIO_DIS_ON_ARM",
.param_index = 14,
.param_type = MAV_PARAM_TYPE_UINT8,
},
.value = {
.db_param_u8 = {
.value = false,
.default_value = false,
.min = false,
.max = true,
}
}
};
/**
* Port for db_param_udp_client_ip
*/
db_parameter_t db_param_udp_client_port = {
.db_name = "udp_client_port",
.type = UINT16,
.mav_t = {
.param_name = "WIFI_UDP_CPORT",
.param_index = 15,
.param_type = MAV_PARAM_TYPE_UINT16,
},
.value = {
.db_param_u16 = {
.value = 0,
.default_value = 0,
.min = 0,
.max = UINT16_MAX,
}
}
};
/**
* Format/Unit of the reported RSSI as part of MAVLink RADIO STATUS message.
* If set to true (1) the RSSI will be reported as dBm (QGC)
* If set to false (0) the RSSI will be calculated as a value from 0 to 100 (MissionPlanner)
*/
db_parameter_t db_param_rssi_dbm = {
.db_name = "rep_rssi_dbm",
.type = UINT8,
.mav_t = {
.param_name = "RADIO_RSSI_DBM",
.param_index = 16,
.param_type = MAV_PARAM_TYPE_UINT8,
},
.value = {
.db_param_u8 = {
.value = true,
.default_value = true,
.min = false,
.max = true,
}
}
};
/**
* Enables delivery of authenticated MAVLink traffic from other ESP-NOW AIR units to the local flight controller.
*/
db_parameter_t db_param_espnow_air2air = {
.db_name = "espnow_air2air",
.type = UINT8,
.mav_t = {
.param_name = "ESPNOW_AIR2AIR",
.param_index = 17,
.param_type = MAV_PARAM_TYPE_UINT8,
},
.value = {
.db_param_u8 = {
.value = false,
.default_value = false,
.min = false,
.max = true,
}
}
};
/**
* Array containing all references to the DB parameters assigned with db_param_init_parameters()
*/
db_parameter_t *db_params[DB_PARAM_TOTAL_NUM] = {NULL};
/**
* Leaks memory. Only call during init of the parameters.
* Inits a string parameter with the supplied values and ranges.
* @param db_name NVM & web interface name/identifier
* @param mav_param_name MAVLink parameter name
* @param default_value Default value
* @param min_val_len minimum length of the string (used for validation)
* @param max_val_len maximum length of the string (used for memory allocation and validation)
* @return The inited string parameter
*/
db_parameter_t db_param_init_str_param(char *db_name, char *mav_param_name, const char *default_value,
uint8_t min_val_len, uint8_t max_val_len) {
db_parameter_t db_str_param = {
.db_name = "",
.type = STRING,
.mav_t = {
.param_name = "",
.param_index = -1,
.param_type = MAV_PARAM_TYPE_ENUM_END, // no string support so far
},
.value = {
.db_param_str = {
.min_len = min_val_len,
.max_len = max_val_len,
}
}
};
strncpy((char *) db_str_param.db_name, db_name, DB_PARAM_NAME_MAXLEN-1);
uint mav_param_name_str_len = strlen(mav_param_name);
if (mav_param_name_str_len < DB_PARAM_MAX_MAV_PARAM_NAME_LEN) {
// normal case - param name and string terminator fit into allocated memory
strncpy((char *) db_str_param.mav_t.param_name, mav_param_name, DB_PARAM_MAX_MAV_PARAM_NAME_LEN - 1);
} else {
// mav param name is allowed to be 16 chars long - it is valid without a string terminator if len = 16
// copy the first 16 chars of string without a string terminator
memcpy((char *) db_str_param.mav_t.param_name, mav_param_name, DB_PARAM_MAX_MAV_PARAM_NAME_LEN);
}
db_str_param.value.db_param_str.default_value = (uint8_t *) strdup(default_value);
db_str_param.value.db_param_str.value = malloc(max_val_len);
if (db_str_param.value.db_param_str.value == NULL) {
ESP_LOGE(TAG, "Error allocating %i bytes for string parameter %s", max_val_len, db_name);
} else {
// all good - init value to default value
strncpy((char *) db_str_param.value.db_param_str.value, (char *) db_str_param.value.db_param_str.default_value, max_val_len);
// Ensure null termination, especially if default_value is >= max_val_len. For password this might not be necessary
db_str_param.value.db_param_str.value[max_val_len - 1] = '\0';
ESP_LOGD(TAG, "Initialized value for %s%s", db_name,
strcmp(db_name, "wifi_pass") == 0 || strcmp(db_name, "espnow_secret") == 0 ? " [redacted]" :
(char*)db_str_param.value.db_param_str.value);
}
return db_str_param;
}
/**
* Initializes the parameters used for storing user settings. All parameters are collected in an array.
* Leaks memory. Only call once during startup!
* Add new parameters here!
*/
void db_param_init_parameters() {
// Wi-Fi AP SSID name OR Wi-Fi AP SSID name to connect to in Wi-Fi client mode
db_param_ssid = db_param_init_str_param("ssid", "SYS_SSID", "DroneBridge for ESP32", 1, MAX_SSID_LEN);
// Password for Wi-Fi connections & ESP-NOW encryption.
db_param_pass = db_param_init_str_param("wifi_pass", "SYS_PASS", "dronebridge", 7, 64);
// Optional generated ESP-NOW secret. An empty value keeps legacy ESP-NOW pairs on wifi_pass.
db_param_espnow_link_secret = db_param_init_str_param("espnow_secret", "SYS_ESPNOWPASS", "", 0, 44);
// IPv4 of the Wi-Fi access point when in Wi-Fi AP mode
db_param_wifi_ap_ip = db_param_init_str_param("ap_ip", "WIFI_AP_IP", "192.168.2.1", 8, IP4ADDR_STRLEN_MAX);
// User can specify static IP when in Wi-Fi client mode. If this is empty use auto IP.
db_param_wifi_sta_ip = db_param_init_str_param("ip_sta", "WIFI_STA_IP", "", 0, IP4ADDR_STRLEN_MAX);
// If db_param_wifi_sta_ip is set then this must be set to the gateway IP
db_param_wifi_sta_gw = db_param_init_str_param("ip_sta_gw", "WIFI_STA_GW", "", 0, IP4ADDR_STRLEN_MAX);
// If db_param_wifi_sta_ip is set: Netmask when settings static IP in Wi-Fi client mode
db_param_wifi_sta_netmask = db_param_init_str_param("ip_sta_netmsk", "WIFI_STA_NETM", "", 0, IP4ADDR_STRLEN_MAX);
// Users can add custom UDP client targets. This is the IP of the first target added. Only the first one is saved to NVM.
db_param_udp_client_ip = db_param_init_str_param("udp_client_ip", "WIFI_UDP_IP", "", 0, IP4ADDR_STRLEN_MAX);
// Specifies the hostname. Used in Wi-Fi ap & client mode.
db_param_wifi_hostname = db_param_init_str_param("wifi_hostname", "WIFI_HOSTNAME", CONFIG_LWIP_LOCAL_HOSTNAME, 1, 32);
db_parameter_t *db_params_l[] = {
&db_param_ssid,
&db_param_pass,
&db_param_espnow_link_secret,
&db_param_wifi_ap_ip,
&db_param_wifi_sta_ip,
&db_param_wifi_sta_gw,
&db_param_wifi_sta_netmask,
&db_param_udp_client_ip,
&db_param_wifi_hostname,
&db_param_radio_mode,
&db_param_channel,
&db_param_wifi_en_gn,
&db_param_radio_ant_ext,
&db_param_baud,
&db_param_gpio_tx,
&db_param_gpio_rx,
&db_param_gpio_rts,
&db_param_gpio_cts,
&db_param_gpio_rts_thresh,
&db_param_proto,
&db_param_serial_pack_size,
&db_param_serial_read_timeout,
&db_param_ltm_per_packet,
&db_param_dis_radio_armed,
&db_param_udp_client_port,
&db_param_rssi_dbm,
&db_param_espnow_air2air
};
memcpy(db_params, db_params_l, sizeof(db_params_l));
}
/**
* Sets the value of the supplied the parameter to its default value
* @param db_parameter The parameter to reset to default
*/
void db_param_set_to_default(db_parameter_t *db_parameter) {
switch (db_parameter->type) {
case STRING:
strncpy((char *) db_parameter->value.db_param_str.value,
(char *) db_parameter->value.db_param_str.default_value,
db_parameter->value.db_param_str.max_len);
db_parameter->value.db_param_str.value[db_parameter->value.db_param_str.max_len - 1] = '\0';
break;
case UINT8:
db_parameter->value.db_param_u8.value = db_parameter->value.db_param_u8.default_value;
break;
case UINT16:
db_parameter->value.db_param_u16.value = db_parameter->value.db_param_u16.default_value;
break;
case INT32:
db_parameter->value.db_param_i32.value = db_parameter->value.db_param_i32.default_value;
break;
default:
ESP_LOGE(TAG, "db_param_set_to_default() -> db_parameter.type unknown!");
break;
}
}
/**
* Helper function to reset all known parameters to their defaults. Parameter must be part of db_params array
*/
void db_param_reset_all() {
for (int i = 0; i < sizeof(db_params) / sizeof(db_params[0]); i++) {
db_param_set_to_default(db_params[i]);
}
}
/**
* Formats one parameter value into a bounded, redacted diagnostic line.
*
* @param parameter Parameter to format.
* @param line_buffer Destination buffer for one complete line.
* @param line_buffer_size Capacity of line_buffer in bytes.
* @param line_length Receives the line length excluding the terminator.
* @return true when the complete line fit in line_buffer, otherwise false.
*/
static bool db_param_format_value_line(const db_parameter_t *parameter, uint8_t *line_buffer,
const size_t line_buffer_size, size_t *line_length) {
if (parameter == NULL || line_buffer == NULL || line_length == NULL || line_buffer_size == 0U) {
return false;
}
int written = -1;
switch (parameter->type) {
case STRING:
if (strcmp((char *) parameter->db_name, (char *) db_param_pass.db_name) == 0 ||
strcmp((char *) parameter->db_name, (char *) db_param_espnow_link_secret.db_name) == 0) {
written = snprintf((char *) line_buffer, line_buffer_size, "\t%s: [redacted]\n",
(char *) parameter->db_name);
} else {
written = snprintf((char *) line_buffer, line_buffer_size, "\t%s: %s\n", (char *) parameter->db_name,
(char *) parameter->value.db_param_str.value);
}
break;
case UINT8:
written = snprintf((char *) line_buffer, line_buffer_size, "\t%s: %i\n", (char *) parameter->db_name,
parameter->value.db_param_u8.value);
break;
case UINT16:
written = snprintf((char *) line_buffer, line_buffer_size, "\t%s: %i\n", (char *) parameter->db_name,
parameter->value.db_param_u16.value);
break;
case INT32:
written = snprintf((char *) line_buffer, line_buffer_size, "\t%s: %li\n", (char *) parameter->db_name,
parameter->value.db_param_i32.value);
break;
default:
ESP_LOGE(TAG, "db_param_format_value_line() -> db_parameter.type unknown!");
return false;
}
if (written < 0 || (size_t) written >= line_buffer_size) {
ESP_LOGE(TAG, "Parameter log line does not fit for %s", (char *) parameter->db_name);
return false;
}
*line_length = (size_t) written;
return true;
}
/**
* Streams all parameter values as independently bounded, redacted diagnostic lines.
*
* @param output_callback Callback that consumes every formatted parameter line.
* @param context Caller-owned context passed to output_callback.
* @return true when every parameter was emitted, otherwise false.
*/
bool db_param_stream_values(const db_param_output_callback_t output_callback, void *context) {
if (output_callback == NULL) {
return false;
}
uint8_t line_buffer[DB_PARAM_PRINT_LINE_BUFFER_SIZE] = {0};
for (int i = 0; i < sizeof(db_params) / sizeof(db_params[0]); i++) {
size_t line_length = 0U;
if (!db_param_format_value_line(db_params[i], line_buffer, sizeof(line_buffer), &line_length) ||
!output_callback(line_buffer, line_length, context)) {
return false;
}
}
return true;
}
/**
* Writes all parameter values to the ESP log without exposing sensitive values.
*/
static bool db_param_log_value_line(const uint8_t *line, const size_t line_length, void *context) {
(void) context;
if (line == NULL || line_length == 0U) {
return false;
}
ESP_LOGI(TAG, "%.*s", (int) (line_length - 1U), (const char *) line);
return true;
}
/**
* Logs all parameter values using bounded per-parameter formatting.
*/
void db_param_log_values() {
if (!db_param_stream_values(db_param_log_value_line, NULL)) {
ESP_LOGE(TAG, "Unable to print all parameter values");
}
}
/**
* Helper function to read a string from the NVS based on a key. Handles errors accordingly and print result to console
* @param my_handle nvs_handle to use
* @param key NVS key as string with max length NVS_KEY_NAME_MAX_SIZE-1
* @param dst Destination for the read value
*/
void db_read_str_nvs(nvs_handle_t my_handle, db_parameter_t *db_param) {
size_t required_size = 0;
// First call to get size
esp_err_t err = nvs_get_str(my_handle, (char *) db_param->db_name, NULL, &required_size);
if (err == ESP_OK) {
if (required_size > db_param->value.db_param_str.max_len) {
ESP_LOGW(TAG, "NVS string for %s too long (%d > %d), using default.",
(char *) db_param->db_name, required_size, db_param->value.db_param_str.max_len);
db_param_set_to_default(db_param); // Use default if stored value too big
} else if (required_size == 0) {
// Handle case where key exists but string is empty (e.g., saved empty password)
ESP_LOGI(TAG, "NVS string for %s is empty, using default.", (char *) db_param->db_name);
db_param_set_to_default(db_param);
} else {
// Read the actual value
err = nvs_get_str(my_handle, (char *) db_param->db_name, (char *)db_param->value.db_param_str.value, &required_size);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error (%s) reading string %s from NVS! Using default.", esp_err_to_name(err), (char *) db_param->db_name);
db_param_set_to_default(db_param);
} else {
if (strcmp((char *) db_param->db_name, (char *) db_param_pass.db_name) == 0 ||
strcmp((char *) db_param->db_name, (char *) db_param_espnow_link_secret.db_name) == 0) {
ESP_LOGD(TAG, "Read %s from NVS: [redacted]", (char *) db_param->db_name);
} else {
ESP_LOGD(TAG, "Read %s from NVS: '%s'", (char *) db_param->db_name,
(char *) db_param->value.db_param_str.value);
}
}
}
} else if (err == ESP_ERR_NVS_NOT_FOUND) {
if (strcmp((char *) db_param->db_name, (char *) db_param_espnow_link_secret.db_name) == 0) {
ESP_LOGD(TAG, "Optional ESP-NOW link secret not found in NVS, using legacy fallback.");
} else {
ESP_LOGI(TAG, "Parameter %s not found in NVS, using default.", (char *) db_param->db_name);
}
db_param_set_to_default(db_param); // Apply the default value
} else {
ESP_LOGE(TAG, "Error (%s) checking NVS for %s! Using default.", esp_err_to_name(err), (char *) db_param->db_name);
db_param_set_to_default(db_param); // Also use default on other errors
}
}
/**
* Updates all parameters with their values from the NVM.
* Parameters must be part of db_params array
* Checks validity of read parameter and if not valid assigns default value to it.
* @param nvs_handle Opened Namespace of the NVM partition. This is the handle.
*/
void db_param_read_all_params_nvs(const nvs_handle_t *nvs_handle) {
for (int i = 0; i < sizeof(db_params) / sizeof(db_params[0]); i++) {
switch (db_params[i]->type) {
case STRING:
db_read_str_nvs(*nvs_handle, db_params[i]);
if (!db_param_is_valid_str((char *) db_params[i]->value.db_param_str.value, db_params[i])) {
// read parameter is not valid - overwrite NVS value with default value
strncpy((char *) db_params[i]->value.db_param_str.value,
(char *) db_params[i]->value.db_param_str.default_value,
db_params[i]->value.db_param_str.max_len);
ESP_LOGW(TAG, "Read invalid parameter %s from NVS, setting to default value %s",
db_params[i]->db_name, db_params[i]->value.db_param_str.default_value);
}
break;
case UINT8:
{
const esp_err_t read_result = nvs_get_u8(*nvs_handle, (char *) db_params[i]->db_name,
&db_params[i]->value.db_param_u8.value);
if (read_result == ESP_ERR_NVS_NOT_FOUND) {
ESP_LOGI(TAG, "Parameter %s not found in NVS, using default.", db_params[i]->db_name);
break;
}
if (read_result != ESP_OK) {
ESP_LOGW(TAG, "Unable to read parameter %s from NVS: %s. Using default.",
db_params[i]->db_name, esp_err_to_name(read_result));
db_params[i]->value.db_param_u8.value = db_params[i]->value.db_param_u8.default_value;
break;
}
if (!db_param_is_valid_u8(db_params[i]->value.db_param_u8.value, db_params[i])) {
// read parameter is not valid - overwrite NVS value with default value
db_params[i]->value.db_param_u8.value = db_params[i]->value.db_param_u8.default_value;
ESP_LOGW(TAG, "Read invalid parameter %s from NVS, setting to default value %i",
db_params[i]->db_name, db_params[i]->value.db_param_u8.default_value);
}
break;
}
case UINT16:
{
const esp_err_t read_result = nvs_get_u16(*nvs_handle, (char *) db_params[i]->db_name,
&db_params[i]->value.db_param_u16.value);
if (read_result == ESP_ERR_NVS_NOT_FOUND) {
ESP_LOGI(TAG, "Parameter %s not found in NVS, using default.", db_params[i]->db_name);
break;
}
if (read_result != ESP_OK) {
ESP_LOGW(TAG, "Unable to read parameter %s from NVS: %s. Using default.",
db_params[i]->db_name, esp_err_to_name(read_result));
db_params[i]->value.db_param_u16.value = db_params[i]->value.db_param_u16.default_value;
break;
}
if (!db_param_is_valid_u16(db_params[i]->value.db_param_u16.value, db_params[i])) {
// read parameter is not valid - overwrite NVS value with default value
db_params[i]->value.db_param_u16.value = db_params[i]->value.db_param_u16.default_value;
ESP_LOGW(TAG, "Read invalid parameter %s from NVS, setting to default value %i",
db_params[i]->db_name, db_params[i]->value.db_param_u16.default_value);
}
break;
}
case INT32:
{
const esp_err_t read_result = nvs_get_i32(*nvs_handle, (char *) db_params[i]->db_name,
&db_params[i]->value.db_param_i32.value);
if (read_result == ESP_ERR_NVS_NOT_FOUND) {
ESP_LOGI(TAG, "Parameter %s not found in NVS, using default.", db_params[i]->db_name);
break;
}
if (read_result != ESP_OK) {
ESP_LOGW(TAG, "Unable to read parameter %s from NVS: %s. Using default.",
db_params[i]->db_name, esp_err_to_name(read_result));
db_params[i]->value.db_param_i32.value = db_params[i]->value.db_param_i32.default_value;
break;
}
if (!db_param_is_valid_i32(db_params[i]->value.db_param_i32.value, db_params[i])) {
// read parameter is not valid - overwrite NVS value with default value
db_params[i]->value.db_param_i32.value = db_params[i]->value.db_param_i32.default_value;
ESP_LOGW(TAG, "Read invalid parameter %s from NVS, setting to default value %li",
db_params[i]->db_name, db_params[i]->value.db_param_i32.default_value);
}
break;
}
default:
ESP_LOGE(TAG, "db_param_read_all_params_to_nvs() -> db_parameter.type unknown!");
break;
}
}
}
/**
* Writes all parameters with their values to the NVM. Makes an exception for the mode.
* Here DB_RADIO_MODE_DESIGNATED is saved instead.
* Parameters must be part of db_params array
* @param nvs_handle Opened Namespace of the NVM partition. This is the handle.
*/
void db_param_write_all_params_nvs(const nvs_handle_t *nvs_handle) {
for (int i = 0; i < sizeof(db_params) / sizeof(db_params[0]); i++) {
switch (db_params[i]->type) {
case STRING:
ESP_ERROR_CHECK(nvs_set_str(*nvs_handle, (char *) db_params[i]->db_name,
(char *) db_params[i]->value.db_param_str.value));
break;
case UINT8:
if (strcmp((char *) db_params[i]->db_name, (char *) db_param_radio_mode.db_name) == 0) {
// This is different. User writes the desired mode into DB_RADIO_MODE_DESIGNATED and does not overwrite the value
ESP_ERROR_CHECK(nvs_set_u8(*nvs_handle, (char *) db_params[i]->db_name, DB_RADIO_MODE_DESIGNATED));
} else {
ESP_ERROR_CHECK(
nvs_set_u8(*nvs_handle, (char *) db_params[i]->db_name,
db_params[i]->value.db_param_u8.value));
}
break;
case UINT16:
ESP_ERROR_CHECK(nvs_set_u16(*nvs_handle, (char *) db_params[i]->db_name,
db_params[i]->value.db_param_u16.value));
break;
case INT32:
ESP_ERROR_CHECK(nvs_set_i32(*nvs_handle, (char *) db_params[i]->db_name,
db_params[i]->value.db_param_i32.value));
break;
default:
ESP_LOGE(TAG, "db_param_write_all_params_to_nvs() -> db_parameter.type unknown!");
break;
}
}
}
/**
* Parses the provided json for all known parameters. Applies all recognized parameter values to local storage.
* Checks if parameter values are within the valid range. Otherwise, reject by not applying the new value.
* Does not save them to NVM!
* @param root_obj JSON that contains a single layer with the parameters to change.
*/
void db_param_read_all_params_json(const cJSON *root_obj) {
for (int i = 0; i < sizeof(db_params) / sizeof(db_params[0]); i++) {
cJSON *jobject = cJSON_GetObjectItem(root_obj, (char *) db_params[i]->db_name);
switch (db_params[i]->type) {
case STRING:
if (jobject) {
if (!cJSON_IsNull(jobject)) {
db_param_is_valid_assign_str(jobject->valuestring, db_params[i]);
} else {
// received empty string
db_params[i]->value.db_param_str.value[0] = '\0';
}
} else {
// do nothing - param was not found in the json
}
break;
case UINT8:
if (jobject) {
db_param_is_valid_assign_u8(jobject->valueint, db_params[i]);
} else {
// do nothing - param was not found in the json
}
break;
case UINT16:
if (jobject) {
db_param_is_valid_assign_u16(jobject->valueint, db_params[i]);
} else {
// do nothing - param was not found in the json
}
break;
case INT32:
if (jobject) {
db_param_is_valid_assign_i32(jobject->valueint, db_params[i]);
} else {
// do nothing - param was not found in the json
}
break;
default:
ESP_LOGE(TAG, "db_param_write_all_params_to_nvs() -> db_parameter.type unknown!");
break;
}
}
}
/**
* Writes all known parameters to a supplied cJSON.
* @param root_obj A cJSON object that will be filled with all known parameters
*/
void db_param_write_all_params_json(cJSON *root_obj) {
for (int i = 0; i < sizeof(db_params) / sizeof(db_params[0]); i++) {
switch (db_params[i]->type) {
case STRING:
cJSON_AddStringToObject(root_obj, (char *) db_params[i]->db_name,
(char *) db_params[i]->value.db_param_str.value);
break;
case UINT8:
cJSON_AddNumberToObject(root_obj, (char *) db_params[i]->db_name,
db_params[i]->value.db_param_u8.value);
break;
case UINT16:
cJSON_AddNumberToObject(root_obj, (char *) db_params[i]->db_name,
db_params[i]->value.db_param_u16.value);
break;
case INT32:
cJSON_AddNumberToObject(root_obj, (char *) db_params[i]->db_name,
db_params[i]->value.db_param_i32.value);
break;
default:
ESP_LOGE(TAG, "db_param_write_all_params_json() -> db_parameter.type unknown!");
break;
}
}
}
/**
* Checks if the supplied IPv4 string is representing a valid IPv4 address.
* @param ipaddress IPv4 string
* @return true if valid IPv4 string was supplied
*/
bool is_valid_ip4(const char *ipaddress) {
struct sockaddr_in sa;
const int result = inet_pton(AF_INET, ipaddress, &(sa.sin_addr));
return result != 0;
}
/**
* Checks if string is valid for assignment to the target_param.
* @param new_string_value The string to be set as value
* @param target_param The target parameter
* @return true if valid or false if not
*/
bool db_param_is_valid_str(char *new_string_value, db_parameter_t *target_param) {
// ToDo: Add IPv4 check for strings via custom validation function in db_parameter_t
if (new_string_value != NULL) {
const size_t string_len = strlen(new_string_value);
if (target_param->value.db_param_str.max_len > 0 &&
string_len < target_param->value.db_param_str.max_len &&
string_len >= target_param->value.db_param_str.min_len) {
return true;
}
}
return false;
};
/**
* Checks if uint8 is valid for assignment to the target_param.
* @param new_u8_value The u8 to be set as value
* @param target_param The target parameter
* @return true if valid or false if not
*/
bool db_param_is_valid_u8(const uint8_t new_u8_value, db_parameter_t *target_param) {
if (new_u8_value <= target_param->value.db_param_u8.max && new_u8_value >= target_param->value.db_param_u8.min) {
return true;
} else { return false; }
}
/**
* Checks if uint16 is valid for assignment to the target_param.
* @param new_u16_value The u16 to be set as value
* @param target_param The target parameter
* @return true if valid or false if not
*/
bool db_param_is_valid_u16(const uint16_t new_u16_value, db_parameter_t *target_param) {
if (new_u16_value <= target_param->value.db_param_u16.max && new_u16_value >= target_param->value.db_param_u16.min) {
return true;
} else { return false; }
}
/**
* Checks if int32 is valid for assignment to the target_param.
* @param new_i32_value The i32 to be set as value
* @param target_param The target parameter
* @return true if valid or false if not
*/
bool db_param_is_valid_i32(const int32_t new_i32_value, db_parameter_t *target_param) {
if (new_i32_value <= target_param->value.db_param_i32.max && new_i32_value >= target_param->value.db_param_i32.min) {
return true;
} else { return false; }
}
/**
* Checks if string is valid for assignment to the target_param. If valid assigns the new value to the parameter
* @param new_string_value The new string to be checked and assigned
* @param target_param The internal db parameter to be assigned with the new value
* @return true when valid and assigned - else false
*/
bool db_param_is_valid_assign_str(char *new_string_value, db_parameter_t *target_param) {
if (db_param_is_valid_str(new_string_value, target_param)) {
strlcpy((char *) target_param->value.db_param_str.value,
new_string_value,
target_param->value.db_param_str.max_len);
return true;
} else {
// new value is not valid - do not assign
ESP_LOGE(TAG, "db_param_is_valid_assign_str(): Invalid string length (%i-%i) or NULL for param %s",
target_param->value.db_param_str.min_len, target_param->value.db_param_str.max_len,
(char *) target_param->db_name);
return false;
}
}
/**
* Checks if u8 is valid for assignment to the target_param. If valid assigns the new value to the parameter
* @param new_u8_value The new u8 to be checked and assigned
* @param target_param The internal db parameter to be assigned with the new value
* @return true when valid and assigned - else false
*/
bool db_param_is_valid_assign_u8(const uint8_t new_u8_value, db_parameter_t *target_param) {
if (db_param_is_valid_u8(new_u8_value, target_param)) {
if (strcmp((char *) target_param->db_name, (char *) db_param_radio_mode.db_name) == 0) {
// Special case check: Do not directly change DB_WIFI_MODE since it is not safe and constantly
// processed by other tasks. Save settings and reboot will assign DB_RADIO_MODE_DESIGNATED to DB_WIFI_MODE
DB_RADIO_MODE_DESIGNATED = new_u8_value;
} else {
target_param->value.db_param_u8.value = new_u8_value; // accept value and assign
}
return true;
}
// new value is not valid
ESP_LOGE(
TAG, "db_param_is_valid_assign_u8(): Value %i is out of valid range (%i-%i) for param %s",
new_u8_value, target_param->value.db_param_u8.max, target_param->value.db_param_u8.min,
(char *) target_param->db_name);
return false;
}
/**
* Checks if u16 is valid for assignment to the target_param. If valid assigns the new value to the parameter
* @param new_u16_value The new u16 to be checked and assigned
* @param target_param The internal db parameter to be assigned with the new value
* @return true when valid and assigned - else false
*/
bool db_param_is_valid_assign_u16(const uint16_t new_u16_value, db_parameter_t *target_param) {
if (db_param_is_valid_u16(new_u16_value, target_param)) {
target_param->value.db_param_u16.value = new_u16_value; // accept value and assign
return true;
}
// new value is not valid
ESP_LOGE(
TAG, "db_param_is_valid_assign_u16(): Value %i is out of valid range (%i-%i) for param %s",
new_u16_value, target_param->value.db_param_u16.max, target_param->value.db_param_u16.min,
(char *) target_param->db_name);
return false;
}
/**
* Checks if i32 is valid for assignment to the target_param. If valid assigns the new value to the parameter
* @param new_i32_value The new i32 to be checked and assigned
* @param target_param The internal db parameter to be assigned with the new value
* @return true when valid and assigned - else false
*/
bool db_param_is_valid_assign_i32(const int32_t new_i32_value, db_parameter_t *target_param) {
if (db_param_is_valid_i32(new_i32_value, target_param)) {
target_param->value.db_param_i32.value = new_i32_value; // accept value and assign
return true;
}
// new value is not valid
ESP_LOGE(
TAG, "db_param_is_valid_assign_i32(): Value %li is out of valid range (%li-%li) for param %s",
new_i32_value, target_param->value.db_param_i32.max, target_param->value.db_param_i32.min,
(char *) target_param->db_name);
return false;
}
ed1b9ef89This file is pinned to the selected release. Download the original to open it in your design tool.