Compare commits
10 Commits
81a8da24a0
...
53bea4eb04
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
53bea4eb04 | ||
|
|
5c55d8da9b | ||
|
|
ffb56936f1 | ||
|
|
a0601c16fa | ||
|
|
40a2b3765c | ||
|
|
d46cb252fb | ||
|
|
012d28ae14 | ||
|
|
2ac5d30490 | ||
|
|
095a52fea7 | ||
|
|
039c29a39d |
@@ -13,4 +13,6 @@
|
||||
<storageModule moduleId="org.eclipse.cdt.core.pathentry">
|
||||
<pathentry excluding="**/CMakeFiles/**" kind="out" path="build"/>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
|
||||
</cproject>
|
||||
9
.externalToolBuilders/OTA SC-F001.launch
Normal file
9
.externalToolBuilders/OTA SC-F001.launch
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
|
||||
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="false"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/SC-F001/ota_deploy.bat}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/SC-F001}"/>
|
||||
</launchConfiguration>
|
||||
10
.project
10
.project
@@ -11,6 +11,16 @@
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
|
||||
<triggers>full,incremental,</triggers>
|
||||
<arguments>
|
||||
<dictionary>
|
||||
<key>LaunchConfigHandle</key>
|
||||
<value><project>/.externalToolBuilders/OTA SC-F001.launch</value>
|
||||
</dictionary>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.cdt.core.cnature</nature>
|
||||
|
||||
6
.settings/org.eclipse.cdt.core.prefs
Normal file
6
.settings/org.eclipse.cdt.core.prefs
Normal file
@@ -0,0 +1,6 @@
|
||||
doxygen/doxygen_new_line_after_brief=true
|
||||
doxygen/doxygen_use_brief_tag=false
|
||||
doxygen/doxygen_use_javadoc_tags=true
|
||||
doxygen/doxygen_use_pre_tag=false
|
||||
doxygen/doxygen_use_structural_commands=false
|
||||
eclipse.preferences.version=1
|
||||
@@ -3,4 +3,4 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(app-template)
|
||||
project(SC-F001)
|
||||
|
||||
13
README.md
13
README.md
@@ -1,11 +1,4 @@
|
||||
ESP-IDF template app
|
||||
====================
|
||||
SC-F001
|
||||
=======
|
||||
|
||||
This is a template application to be used with [Espressif IoT Development Framework](https://github.com/espressif/esp-idf).
|
||||
|
||||
Please check [ESP-IDF docs](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for getting started instructions.
|
||||
|
||||
*Code in this repository is in the Public Domain (or CC0 licensed, at your option.)
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.*
|
||||
Firmware for SC-B001
|
||||
@@ -1,6 +1,6 @@
|
||||
dependencies:
|
||||
esp-idf-lib/esp_idf_lib_helpers:
|
||||
component_hash: a8049b1e609679fb54b2d57b0399dd29c4d1fda09a797edac9926f7810aa5703
|
||||
component_hash: 689853bb8993434f9556af0f2816e808bf77b5d22100144b21f3519993daf237
|
||||
dependencies: []
|
||||
source:
|
||||
registry_url: https://components.espressif.com
|
||||
@@ -16,9 +16,9 @@ dependencies:
|
||||
- esp32p4
|
||||
- esp32s2
|
||||
- esp32s3
|
||||
version: 1.3.10
|
||||
version: 1.4.0
|
||||
esp-idf-lib/i2cdev:
|
||||
component_hash: 11c08f9e1a7d346b5dd763196dc2567cf2209ae49042402c2c2d296624601c14
|
||||
component_hash: 4f3838b2e68ab2b77fd43737139fa97dd0243b46af7b4a04588c67ff6b275ba1
|
||||
dependencies:
|
||||
- name: esp-idf-lib/esp_idf_lib_helpers
|
||||
registry_url: https://components.espressif.com
|
||||
@@ -38,7 +38,7 @@ dependencies:
|
||||
- esp32p4
|
||||
- esp32s2
|
||||
- esp32s3
|
||||
version: 2.0.8
|
||||
version: 2.1.0
|
||||
esp-idf-lib/tca95x5:
|
||||
component_hash: 4bbdbd82828cf1fd5c03fd07e3ea2cb0f36daf16cb3ac7219d1e5decb9ec04ee
|
||||
dependencies:
|
||||
@@ -65,6 +65,16 @@ dependencies:
|
||||
- esp32s2
|
||||
- esp32s3
|
||||
version: 1.0.7
|
||||
espressif/mdns:
|
||||
component_hash: 29e47564b1a7ee778135e17fbbf2a2773f71c97ebabfe626c8eda7c958a7ad16
|
||||
dependencies:
|
||||
- name: idf
|
||||
require: private
|
||||
version: '>=5.0'
|
||||
source:
|
||||
registry_url: https://components.espressif.com/
|
||||
type: service
|
||||
version: 1.9.1
|
||||
idf:
|
||||
source:
|
||||
type: idf
|
||||
@@ -81,8 +91,9 @@ dependencies:
|
||||
version: 1.20.3
|
||||
direct_dependencies:
|
||||
- esp-idf-lib/tca95x5
|
||||
- espressif/mdns
|
||||
- idf
|
||||
- joltwallet/littlefs
|
||||
manifest_hash: b32a1e2b2eb19ff5cd4984c921bf3a1bcd9c1546566ee977021d2d4bf4b3de31
|
||||
manifest_hash: c3a20310a8ecc5e8e0221a7589abf8d2e372eb48f06d6b6fbb3fbf5f48a61aaf
|
||||
target: esp32
|
||||
version: 2.0.0
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
# See the build system documentation in IDF programming guide
|
||||
# for more information about component CMakeLists.txt files.
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/version.cmake)
|
||||
|
||||
idf_component_register(
|
||||
SRCS main.c i2c.c rtc.c storage.c uart_comms.c control_fsm.c power_mgmt.c rf_433.c rtc.c sensors.c solar.c webserver.c # list the source files of this component
|
||||
INCLUDE_DIRS # optional, add here public include directories
|
||||
SRCS main.c i2c.c rtc.c storage.c uart_comms.c control_fsm.c power_mgmt.c rf_433.c rtc.c sensors.c solar.c webserver.c simple_dns_server.c # list the source files of this component
|
||||
INCLUDE_DIRS "." "${CMAKE_BINARY_DIR}"
|
||||
PRIV_INCLUDE_DIRS # optional, add here private include directories
|
||||
REQUIRES # optional, list the public requirements (component names)
|
||||
PRIV_REQUIRES # optional, list the private requirements
|
||||
|
||||
REQUIRES driver esp_http_server esp_netif lwip json esp_timer esp_adc app_update esp_wifi nvs_flash mdns # optional, list the public requirements (component names)
|
||||
# esp_https_server
|
||||
PRIV_REQUIRES # optional, list the private requirements
|
||||
#EMBED_TXTFILES servercert.pem prvtkey.pem
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "control_fsm.h"
|
||||
#include "esp_task_wdt.h"
|
||||
#include "esp_timer.h"
|
||||
#include "i2c.h"
|
||||
#include "power_mgmt.h"
|
||||
#include "rtc_wdt.h"
|
||||
#include "driver/gpio.h"
|
||||
@@ -18,6 +19,9 @@
|
||||
|
||||
#define TRANSITION_DELAY_US 1000000
|
||||
|
||||
#define CALIBRATE_JACK_MAX_TIME 3000000
|
||||
#define CALIBRATE_DRIVE_MAX_TIME 6000000
|
||||
|
||||
#define TAG "FSM"
|
||||
|
||||
static QueueHandle_t fsm_cmd_queue = NULL;
|
||||
@@ -35,10 +39,19 @@ bridge_t bridge_map[] = {
|
||||
|
||||
bool relay_states[8] = {false};
|
||||
int64_t override_times[8] = {-1};
|
||||
int64_t override_cooldown[8] = {-1};
|
||||
bool enabled = false;
|
||||
|
||||
|
||||
RTC_DATA_ATTR float remaining_distance = 0.0f;
|
||||
float fsm_get_remaining_distance(void) { return remaining_distance; }
|
||||
void fsm_set_remaining_distance(float x) { remaining_distance = x;}
|
||||
|
||||
// Track the starting encoder count for the current move
|
||||
static int32_t move_start_encoder = 0;
|
||||
|
||||
// Track total jack up time to use for jack down duration
|
||||
static int64_t jack_up_total_time = 0;
|
||||
|
||||
volatile fsm_state_t current_state = STATE_IDLE;
|
||||
volatile int64_t current_time = 0;
|
||||
@@ -48,9 +61,16 @@ void setRelay(int8_t relay, bool state) {
|
||||
relay_states[relay] = state;
|
||||
}
|
||||
|
||||
bool isRunning() {
|
||||
for (int i=0;i<8;i++) {
|
||||
if (relay_states[i]) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void driveRelays() {
|
||||
uint8_t state = 0x00;
|
||||
relay_states[0] = (current_time / 1000000) % 2;
|
||||
//relay_states[0] = (current_time / 1000000) % 2; // for testing purposes
|
||||
|
||||
for (uint8_t i=0; i<8; i++) {
|
||||
// if we command and efuse permits it set the relay
|
||||
@@ -60,7 +80,7 @@ void driveRelays() {
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "RELAY STATE: %x", state);
|
||||
//ESP_LOGI(TAG, "RELAY STATE: %x", state);
|
||||
i2c_set_relays(state);
|
||||
}
|
||||
|
||||
@@ -70,8 +90,8 @@ fsm_state_t fsm_get_state() {
|
||||
return current_state;
|
||||
}
|
||||
|
||||
static uint64_t timer_end = 0;
|
||||
static uint64_t timer_start = 0;
|
||||
static int64_t timer_end = 0;
|
||||
static int64_t timer_start = 0;
|
||||
static inline void set_timer(uint64_t us) {
|
||||
timer_end = current_time + us;
|
||||
timer_start = current_time;
|
||||
@@ -79,8 +99,14 @@ static inline void set_timer(uint64_t us) {
|
||||
static inline bool timer_done() { return current_time >= timer_end; }
|
||||
|
||||
void pulseOverride(relay_t relay) {
|
||||
if (current_state == STATE_IDLE)
|
||||
override_times[relay] = current_time + get_param_value_t(PARAM_RF_PULSE_LENGTH).u64;
|
||||
if (current_state == STATE_IDLE) {
|
||||
// Check if this relay is in cooldown
|
||||
if (override_cooldown[relay] > current_time) {
|
||||
// Still cooling down, ignore the command
|
||||
return;
|
||||
}
|
||||
override_times[relay] = current_time + get_param_value_t(PARAM_RF_PULSE_LENGTH).u32;
|
||||
}
|
||||
}
|
||||
|
||||
/*void fsm_begin_auto_move() {
|
||||
@@ -89,6 +115,12 @@ void pulseOverride(relay_t relay) {
|
||||
set_timer(TRANSITION_DELAY_US);
|
||||
}*/
|
||||
|
||||
int64_t fsm_cal_t, fsm_cal_e;
|
||||
float fsm_cal_val;
|
||||
void fsm_set_cal_val(float v) {fsm_cal_val = v;}
|
||||
int64_t fsm_get_cal_t(){return fsm_cal_t;}
|
||||
int64_t fsm_get_cal_e(){return fsm_cal_e;}
|
||||
|
||||
void fsm_request(fsm_cmd_t cmd)
|
||||
{
|
||||
if (fsm_cmd_queue != NULL)
|
||||
@@ -99,6 +131,7 @@ int8_t fsm_get_current_progress(int8_t denominator) {
|
||||
int8_t x = 0;
|
||||
switch (current_state) {
|
||||
case STATE_DRIVE:
|
||||
case STATE_JACK_UP_START:
|
||||
case STATE_JACK_UP:
|
||||
case STATE_JACK_DOWN:
|
||||
case STATE_MOVE_START_DELAY:
|
||||
@@ -120,15 +153,15 @@ int8_t fsm_get_current_progress(int8_t denominator) {
|
||||
}
|
||||
|
||||
|
||||
#define JACK_TIME get_param_value_t(PARAM_JACK_MSPI ).u32 * 1000 * get_param_value_t(PARAM_JACK_DIST ).u8
|
||||
#define DRIVE_TIME get_param_value_t(PARAM_DRIVE_MSPF).u32 * 1000 * get_param_value_t(PARAM_DRIVE_DIST).u8
|
||||
#define DRIVE_DIST get_param_value_t(PARAM_DRIVE_TPDF).u32 / 10 * get_param_value_t(PARAM_DRIVE_DIST).u8
|
||||
#define JACK_TIME get_param_value_t(PARAM_JACK_KT).f32 * get_param_value_t(PARAM_JACK_DIST ).f32
|
||||
#define DRIVE_TIME get_param_value_t(PARAM_DRIVE_KT).f32 * get_param_value_t(PARAM_DRIVE_DIST).f32
|
||||
#define DRIVE_DIST get_param_value_t(PARAM_DRIVE_KE).f32 * get_param_value_t(PARAM_DRIVE_DIST).f32
|
||||
|
||||
void control_task(void *param) {
|
||||
esp_task_wdt_add(NULL);
|
||||
|
||||
TickType_t xLastWakeTime = xTaskGetTickCount();
|
||||
const TickType_t xFrequency = pdMS_TO_TICKS(50);
|
||||
const TickType_t xFrequency = pdMS_TO_TICKS(20);
|
||||
enabled = true;
|
||||
|
||||
|
||||
@@ -141,8 +174,16 @@ void control_task(void *param) {
|
||||
switch (cmd) {
|
||||
case FSM_CMD_START:
|
||||
if (current_state == STATE_IDLE) {
|
||||
current_state = STATE_MOVE_START_DELAY;
|
||||
set_timer(TRANSITION_DELAY_US);
|
||||
// Check if we have remaining distance before starting
|
||||
if (remaining_distance > 0.0f
|
||||
&& !efuse_is_tripped(BRIDGE_DRIVE)
|
||||
&& !efuse_is_tripped(BRIDGE_JACK)
|
||||
&& !efuse_is_tripped(BRIDGE_AUX)) {
|
||||
current_state = STATE_MOVE_START_DELAY;
|
||||
set_timer(TRANSITION_DELAY_US);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Cannot start move: no remaining distance (%.2f)", remaining_distance);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FSM_CMD_STOP:
|
||||
@@ -158,6 +199,68 @@ void control_task(void *param) {
|
||||
case FSM_CMD_SHUTDOWN:
|
||||
enabled = false;
|
||||
break;
|
||||
|
||||
case FSM_CMD_CALIBRATE_JACK_PREP:
|
||||
ESP_LOGI(TAG, "FSM_CMD_CALIBRATE_JACK_PREP");
|
||||
if (current_state == STATE_IDLE) {
|
||||
current_state = STATE_CALIBRATE_JACK_DELAY;
|
||||
}
|
||||
break;
|
||||
|
||||
case FSM_CMD_CALIBRATE_JACK_START:
|
||||
ESP_LOGI(TAG, "FSM_CMD_CALIBRATE_JACK_START");
|
||||
if (current_state == STATE_CALIBRATE_JACK_DELAY) {
|
||||
current_state = STATE_CALIBRATE_JACK_MOVE;
|
||||
set_timer(CALIBRATE_JACK_MAX_TIME);
|
||||
}
|
||||
break;
|
||||
case FSM_CMD_CALIBRATE_JACK_END:
|
||||
ESP_LOGI(TAG, "FSM_CMD_CALIBRATE_JACK_END");
|
||||
if (current_state == STATE_CALIBRATE_JACK_MOVE) {
|
||||
fsm_cal_t = current_time - timer_start;
|
||||
current_state = STATE_IDLE;
|
||||
}
|
||||
break;
|
||||
case FSM_CMD_CALIBRATE_JACK_FINISH:
|
||||
set_param_value_t(PARAM_JACK_KT,
|
||||
(param_value_t){.f32 = fsm_cal_t / fsm_cal_val});
|
||||
ESP_LOGI(TAG, "FSM_CMD_CALIBRATE_JACK_FINISH -> %f", get_param_value_t(PARAM_JACK_KT).f32);
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case FSM_CMD_CALIBRATE_DRIVE_PREP:
|
||||
ESP_LOGI(TAG, "FSM_CMD_CALIBRATE_DRIVE_PREP");
|
||||
if (current_state == STATE_IDLE) {
|
||||
current_state = STATE_CALIBRATE_DRIVE_DELAY;
|
||||
}
|
||||
break;
|
||||
|
||||
case FSM_CMD_CALIBRATE_DRIVE_START:
|
||||
ESP_LOGI(TAG, "FSM_CMD_CALIBRATE_DRIVE_START");
|
||||
if (current_state == STATE_CALIBRATE_DRIVE_DELAY) {
|
||||
current_state = STATE_CALIBRATE_DRIVE_MOVE;
|
||||
set_timer(CALIBRATE_DRIVE_MAX_TIME);
|
||||
set_sensor_counter(SENSOR_DRIVE, 0);
|
||||
}
|
||||
break;
|
||||
case FSM_CMD_CALIBRATE_DRIVE_END:
|
||||
ESP_LOGI(TAG, "FSM_CMD_CALIBRATE_DRIVE_END");
|
||||
if (current_state == STATE_CALIBRATE_DRIVE_MOVE) {
|
||||
fsm_cal_t = current_time - timer_start;
|
||||
fsm_cal_e = get_sensor_counter(SENSOR_DRIVE);
|
||||
current_state = STATE_IDLE;
|
||||
}
|
||||
break;
|
||||
case FSM_CMD_CALIBRATE_DRIVE_FINISH:
|
||||
set_param_value_t(PARAM_DRIVE_KT,
|
||||
(param_value_t){.f32 = fsm_cal_t / fsm_cal_val});
|
||||
set_param_value_t(PARAM_DRIVE_KE,
|
||||
(param_value_t){.f32 = fsm_cal_e / fsm_cal_val});
|
||||
ESP_LOGI(TAG, "FSM_CMD_CALIBRATE_DRIVE_FINISH -> %f / %f",
|
||||
get_param_value_t(PARAM_DRIVE_KT).f32,
|
||||
get_param_value_t(PARAM_DRIVE_KE).f32);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,51 +271,181 @@ void control_task(void *param) {
|
||||
// State transitions
|
||||
switch (current_state) {
|
||||
case STATE_IDLE:
|
||||
break;
|
||||
//ESP_LOGI("FSM", "IDLE @ %lld", current_time);
|
||||
for (uint8_t i = 0; i < N_RELAYS; ++i) {
|
||||
//ESP_LOGI("FSM", "t[%d] %lld", i, override_times[i]);
|
||||
bool active = override_times[i] > current_time;
|
||||
if (active) rtc_reset_shutdown_timer();
|
||||
|
||||
// Current limiting for manual jack down override (RELAY_B2)
|
||||
if (i == RELAY_B2 && active) {
|
||||
int64_t elapsed = current_time - (override_times[i] - get_param_value_t(PARAM_RF_PULSE_LENGTH).u32);
|
||||
int64_t delay = get_param_value_t(PARAM_EFUSE_INRUSH_US).u32;
|
||||
|
||||
// After inrush delay, check for current spike
|
||||
if (elapsed > delay) {
|
||||
float current = get_bridge_A(BRIDGE_JACK);
|
||||
float threshold = get_param_value_t(PARAM_JACK_I_DOWN).f32;
|
||||
|
||||
if (current > threshold) {
|
||||
// Current spike detected - stop jacking down and start cooldown
|
||||
override_times[i] = -1;
|
||||
override_cooldown[i] = current_time + get_param_value_t(PARAM_EFUSE_TCOOL).u32;
|
||||
active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// prohibit movement past jack limit switch
|
||||
//if (i == BRIDGE_JACK*2+(bridge_polarities[BRIDGE_JACK]>0?0:1) && get_sensor(SENSOR_JACK))
|
||||
// setRelay(i, false);
|
||||
//else
|
||||
setRelay(i, active);
|
||||
//if (active) ESP_LOGI("FSM", "RUN CHANNEL %d (%lld %c %lld)", i, (long long) override_times[i], active ? '>':'<', (long long) current_time);
|
||||
|
||||
}
|
||||
break;
|
||||
case STATE_MOVE_START_DELAY:
|
||||
if (timer_done()) {
|
||||
current_state = STATE_JACK_UP;
|
||||
set_timer(JACK_TIME);
|
||||
current_state = STATE_JACK_UP_START;
|
||||
set_timer(JACK_TIME / 2); // First phase is half of total jack time
|
||||
jack_up_total_time = 0; // Reset jack up time tracker
|
||||
}
|
||||
break;
|
||||
case STATE_JACK_UP_START:
|
||||
{
|
||||
// Track elapsed time
|
||||
int64_t elapsed = current_time - timer_start;
|
||||
jack_up_total_time = elapsed;
|
||||
|
||||
// Get current sensing parameters
|
||||
int64_t delay = get_param_value_t(PARAM_EFUSE_INRUSH_US).u32;
|
||||
float current = get_bridge_A(BRIDGE_JACK);
|
||||
float threshold = get_param_value_t(PARAM_JACK_I_UP).f32;
|
||||
|
||||
// After inrush delay, check for current spike OR half-time timeout
|
||||
if (elapsed > delay) {
|
||||
if (current > threshold || timer_done()) {
|
||||
ESP_LOGI(TAG, "START->UP BY CURRENT");
|
||||
current_state = STATE_JACK_UP;
|
||||
set_timer(JACK_TIME); // Second phase is also half of total jack time
|
||||
}
|
||||
}
|
||||
|
||||
// E-fuse trip should still cause undo
|
||||
if (efuse_is_tripped(BRIDGE_JACK)) {
|
||||
ESP_LOGI(TAG, "START->UP BY TIME");
|
||||
current_state = STATE_UNDO_JACK_START;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STATE_JACK_UP:
|
||||
if (timer_done()) {
|
||||
current_state = STATE_DRIVE_START_DELAY;
|
||||
set_timer(TRANSITION_DELAY_US);
|
||||
}
|
||||
if (efuse_is_tripped(BRIDGE_JACK)) {
|
||||
current_state = STATE_UNDO_JACK_START;
|
||||
{
|
||||
if (timer_done() || efuse_is_tripped(BRIDGE_JACK)) {
|
||||
// Track total time including first phase
|
||||
jack_up_total_time += current_time - timer_start;
|
||||
current_state = STATE_DRIVE_START_DELAY;
|
||||
set_timer(TRANSITION_DELAY_US);
|
||||
}
|
||||
if (efuse_is_tripped(BRIDGE_JACK)) {
|
||||
ESP_LOGE(TAG, "JACK TRIPPED EFUSE");
|
||||
current_state = STATE_UNDO_JACK_START;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STATE_DRIVE_START_DELAY:
|
||||
if (timer_done()) {
|
||||
current_state = STATE_DRIVE;
|
||||
set_timer(DRIVE_TIME);
|
||||
// Set the encoder counter to track remaining distance in this move
|
||||
set_sensor_counter(SENSOR_DRIVE, -DRIVE_DIST);
|
||||
// Record starting encoder position AFTER setting it
|
||||
move_start_encoder = get_sensor_counter(SENSOR_DRIVE);
|
||||
ESP_LOGI(TAG, "STATE_DRIVE starting: encoder=%ld, remaining_distance=%.2f, DRIVE_DIST=%.2f",
|
||||
(long)move_start_encoder, remaining_distance, DRIVE_DIST);
|
||||
}
|
||||
break;
|
||||
case STATE_DRIVE:
|
||||
if (timer_done() || get_sensor_counter(SENSOR_DRIVE) > 0) {
|
||||
current_state = STATE_DRIVE_END_DELAY;
|
||||
set_timer(TRANSITION_DELAY_US);
|
||||
}
|
||||
if (efuse_is_tripped(BRIDGE_DRIVE)) {
|
||||
current_state = STATE_UNDO_JACK_START;
|
||||
{
|
||||
int32_t current_encoder = get_sensor_counter(SENSOR_DRIVE);
|
||||
int32_t ticks_traveled = current_encoder - move_start_encoder;
|
||||
float ke = get_param_value_t(PARAM_DRIVE_KE).f32;
|
||||
float distance_traveled = ticks_traveled / ke;
|
||||
|
||||
ESP_LOGI(TAG, "STATE_DRIVE: current_encoder=%ld, move_start=%ld, ticks=%ld, ke=%.2f, dist_traveled=%.2f, remaining=%.2f",
|
||||
(long)current_encoder, (long)move_start_encoder, (long)ticks_traveled,
|
||||
ke, distance_traveled, remaining_distance);
|
||||
|
||||
// Check if we'll exceed remaining distance with a full move
|
||||
bool will_exceed = distance_traveled >= remaining_distance;
|
||||
|
||||
// Stop if timer expires OR encoder target reached OR we've used up remaining distance
|
||||
if (timer_done() || current_encoder > 0 || will_exceed) {
|
||||
ESP_LOGI(TAG, "Drive stopping: timer_done=%d, encoder>0=%d, will_exceed=%d",
|
||||
timer_done(), current_encoder > 0, will_exceed);
|
||||
|
||||
// Update remaining distance based on actual travel
|
||||
float old_remaining = remaining_distance;
|
||||
if (will_exceed) {
|
||||
ESP_LOGI(TAG, "Move stopped early - reached remaining distance limit (%.2f)", remaining_distance);
|
||||
remaining_distance = 0.0f;
|
||||
} else {
|
||||
remaining_distance -= distance_traveled;
|
||||
if (remaining_distance < 0.0f) remaining_distance = 0.0f;
|
||||
}
|
||||
ESP_LOGI(TAG, "Drive complete: traveled %.2f, old_remaining %.2f, new_remaining %.2f",
|
||||
distance_traveled, old_remaining, remaining_distance);
|
||||
|
||||
current_state = STATE_DRIVE_END_DELAY;
|
||||
set_timer(TRANSITION_DELAY_US);
|
||||
}
|
||||
|
||||
if (efuse_is_tripped(BRIDGE_DRIVE)) {
|
||||
float old_remaining = remaining_distance;
|
||||
// Update remaining distance even on fault
|
||||
remaining_distance -= distance_traveled;
|
||||
if (remaining_distance < 0.0f) remaining_distance = 0.0f;
|
||||
ESP_LOGW(TAG, "Drive fault: traveled %.2f, old_remaining %.2f, new_remaining %.2f",
|
||||
distance_traveled, old_remaining, remaining_distance);
|
||||
current_state = STATE_UNDO_JACK_START;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STATE_DRIVE_END_DELAY:
|
||||
if (timer_done()) {
|
||||
current_state = STATE_JACK_DOWN;
|
||||
set_timer(JACK_TIME);
|
||||
set_timer(jack_up_total_time); // Use the tracked jack up time
|
||||
}
|
||||
break;
|
||||
case STATE_JACK_DOWN:
|
||||
if (timer_done() || get_sensor(SENSOR_JACK)) {
|
||||
current_state = STATE_IDLE;
|
||||
}
|
||||
|
||||
// assume we hit something hard and should stop
|
||||
if (efuse_is_tripped(BRIDGE_JACK)) {
|
||||
current_state = STATE_IDLE;
|
||||
{
|
||||
// Get current sensing parameters
|
||||
int64_t delay = get_param_value_t(PARAM_EFUSE_INRUSH_US).u32;
|
||||
int64_t elapsed = current_time - timer_start;
|
||||
|
||||
// After inrush delay, check for current spike
|
||||
if (elapsed > delay) {
|
||||
float current = get_bridge_A(BRIDGE_JACK);
|
||||
float threshold = get_param_value_t(PARAM_JACK_I_DOWN).f32;
|
||||
|
||||
if (current > threshold) {
|
||||
ESP_LOGI(TAG, "DOWN->IDLE BY CURRENT");
|
||||
// Current spike detected - we've hit the ground
|
||||
current_state = STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Timeout - finished jacking down
|
||||
if (timer_done()) {
|
||||
ESP_LOGI(TAG, "DOWN->IDLE BY TIME");
|
||||
current_state = STATE_IDLE;
|
||||
}
|
||||
|
||||
// E-fuse trip - assume we hit something hard
|
||||
if (efuse_is_tripped(BRIDGE_JACK)) {
|
||||
current_state = STATE_IDLE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -225,7 +458,7 @@ void control_task(void *param) {
|
||||
}
|
||||
break;
|
||||
case STATE_UNDO_JACK:
|
||||
if (timer_done() || get_sensor(SENSOR_JACK)) {
|
||||
if (timer_done()){ // || get_sensor(SENSOR_JACK)) {
|
||||
current_state = STATE_IDLE;
|
||||
}
|
||||
|
||||
@@ -234,33 +467,79 @@ void control_task(void *param) {
|
||||
current_state = STATE_IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case STATE_CALIBRATE_JACK_DELAY:
|
||||
// no way out of this except a command
|
||||
break;
|
||||
case STATE_CALIBRATE_JACK_MOVE:
|
||||
if (timer_done()) {
|
||||
ESP_LOGI(TAG, "STATE_CALIBRATE_JACK_END");
|
||||
current_state = STATE_IDLE;
|
||||
fsm_cal_t = current_time - timer_start;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case STATE_CALIBRATE_DRIVE_DELAY:
|
||||
// no way out of this except a command
|
||||
break;
|
||||
case STATE_CALIBRATE_DRIVE_MOVE:
|
||||
if (timer_done()) {
|
||||
ESP_LOGI(TAG, "STATE_CALIBRATE_DRIVE_END");
|
||||
current_state = STATE_IDLE;
|
||||
fsm_cal_t = current_time - timer_start;
|
||||
fsm_cal_e = get_sensor_counter(SENSOR_DRIVE);
|
||||
}
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
||||
int64_t elapsed_t = (current_time-timer_start);
|
||||
int64_t total_t = (timer_end-timer_start);
|
||||
int32_t ticks = get_sensor_counter(SENSOR_DRIVE);
|
||||
//int64_t elapsed_t = (current_time-timer_start);
|
||||
//int64_t total_t = (timer_end-timer_start);
|
||||
//int32_t ticks = get_sensor_counter(SENSOR_DRIVE);
|
||||
//ESP_LOGI("FSM", "[%d] %lld / %lld ms, %ld ticks", current_state, (long long) elapsed_t, (long long) total_t, (long) ticks);
|
||||
|
||||
// Output control
|
||||
switch (current_state) {
|
||||
case STATE_IDLE:
|
||||
//ESP_LOGI("FSM", "IDLE @ %lld", current_time);
|
||||
for (uint8_t i = 0; i < N_RELAYS; ++i) {
|
||||
//ESP_LOGI("FSM", "t[%d] %lld", i, override_times[i]);
|
||||
bool active = override_times[i] > current_time;
|
||||
if (active) reset_shutdown_timer();
|
||||
|
||||
// prohibit movement past jack limit switch
|
||||
//if (i == BRIDGE_JACK*2+(bridge_polarities[BRIDGE_JACK]>0?0:1) && get_sensor(SENSOR_JACK))
|
||||
// setRelay(i, false);
|
||||
//else
|
||||
setRelay(i, active);
|
||||
//if (active) ESP_LOGI("FSM", "RUN CHANNEL %d (%lld %c %lld)", i, (long long) override_times[i], active ? '>':'<', (long long) current_time);
|
||||
|
||||
}
|
||||
break;
|
||||
//ESP_LOGI("FSM", "IDLE @ %lld", current_time);
|
||||
for (uint8_t i = 0; i < N_RELAYS; ++i) {
|
||||
//ESP_LOGI("FSM", "t[%d] %lld", i, override_times[i]);
|
||||
bool active = override_times[i] > current_time;
|
||||
if (active) rtc_reset_shutdown_timer();
|
||||
|
||||
// Current limiting for manual jack down override (RELAY_B2)
|
||||
if (i == RELAY_B2 && active) {
|
||||
int64_t elapsed = current_time - (override_times[i] - get_param_value_t(PARAM_RF_PULSE_LENGTH).u32);
|
||||
int64_t delay = get_param_value_t(PARAM_EFUSE_INRUSH_US).u32;
|
||||
|
||||
// After inrush delay, check for current spike
|
||||
if (elapsed > delay) {
|
||||
float current = get_bridge_A(BRIDGE_JACK);
|
||||
float threshold = get_param_value_t(PARAM_JACK_I_DOWN).f32;
|
||||
|
||||
if (current > threshold) {
|
||||
// Current spike detected - stop jacking down
|
||||
override_times[i] = -1;
|
||||
active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// prohibit movement past jack limit switch
|
||||
//if (i == BRIDGE_JACK*2+(bridge_polarities[BRIDGE_JACK]>0?0:1) && get_sensor(SENSOR_JACK))
|
||||
// setRelay(i, false);
|
||||
//else
|
||||
setRelay(i, active);
|
||||
//if (active) ESP_LOGI("FSM", "RUN CHANNEL %d (%lld %c %lld)", i, (long long) override_times[i], active ? '>':'<', (long long) current_time);
|
||||
|
||||
}
|
||||
break;
|
||||
case STATE_CALIBRATE_JACK_MOVE:
|
||||
case STATE_JACK_UP_START:
|
||||
case STATE_JACK_UP:
|
||||
// jack up and fluff
|
||||
setRelay(RELAY_A1, false);
|
||||
@@ -270,8 +549,9 @@ void control_task(void *param) {
|
||||
setRelay(RELAY_B2, false);
|
||||
|
||||
setRelay(RELAY_A3, true);
|
||||
reset_shutdown_timer();
|
||||
rtc_reset_shutdown_timer();
|
||||
break;
|
||||
case STATE_CALIBRATE_DRIVE_MOVE:
|
||||
case STATE_DRIVE:
|
||||
// drive and fluff
|
||||
setRelay(RELAY_A1, true);
|
||||
@@ -281,7 +561,7 @@ void control_task(void *param) {
|
||||
setRelay(RELAY_B2, false);
|
||||
|
||||
setRelay(RELAY_A3, true);
|
||||
reset_shutdown_timer();
|
||||
rtc_reset_shutdown_timer();
|
||||
break;
|
||||
case STATE_UNDO_JACK:
|
||||
case STATE_JACK_DOWN:
|
||||
@@ -293,7 +573,7 @@ void control_task(void *param) {
|
||||
setRelay(RELAY_B2, true);
|
||||
|
||||
setRelay(RELAY_A3, true);
|
||||
reset_shutdown_timer();
|
||||
rtc_reset_shutdown_timer();
|
||||
break;
|
||||
case STATE_UNDO_JACK_START:
|
||||
case STATE_DRIVE_START_DELAY:
|
||||
@@ -306,8 +586,9 @@ void control_task(void *param) {
|
||||
setRelay(RELAY_B2, false);
|
||||
|
||||
setRelay(RELAY_A3, true);
|
||||
reset_shutdown_timer();
|
||||
rtc_reset_shutdown_timer();
|
||||
break;
|
||||
case STATE_CALIBRATE_JACK_DELAY:
|
||||
default:
|
||||
// invalid state; turn all relays off
|
||||
setRelay(RELAY_A1, false);
|
||||
|
||||
@@ -7,18 +7,40 @@
|
||||
#include "freertos/queue.h"
|
||||
|
||||
|
||||
typedef enum { FSM_CMD_START, FSM_CMD_STOP, FSM_CMD_UNDO, FSM_CMD_SHUTDOWN} fsm_cmd_t;
|
||||
typedef enum {
|
||||
FSM_CMD_START,
|
||||
FSM_CMD_STOP,
|
||||
FSM_CMD_UNDO,
|
||||
FSM_CMD_SHUTDOWN,
|
||||
|
||||
FSM_CMD_CALIBRATE_JACK_PREP,
|
||||
FSM_CMD_CALIBRATE_JACK_START,
|
||||
FSM_CMD_CALIBRATE_JACK_END,
|
||||
FSM_CMD_CALIBRATE_JACK_FINISH,
|
||||
|
||||
FSM_CMD_CALIBRATE_DRIVE_PREP,
|
||||
FSM_CMD_CALIBRATE_DRIVE_START,
|
||||
FSM_CMD_CALIBRATE_DRIVE_END,
|
||||
FSM_CMD_CALIBRATE_DRIVE_FINISH
|
||||
} fsm_cmd_t;
|
||||
|
||||
typedef enum {
|
||||
STATE_IDLE = 0,
|
||||
STATE_MOVE_START_DELAY = 1,
|
||||
STATE_JACK_UP = 2,
|
||||
STATE_DRIVE_START_DELAY = 3,
|
||||
STATE_DRIVE = 4,
|
||||
STATE_DRIVE_END_DELAY = 5,
|
||||
STATE_JACK_DOWN = 6,
|
||||
STATE_UNDO_JACK = 7,
|
||||
STATE_UNDO_JACK_START = 8,
|
||||
STATE_MOVE_START_DELAY,
|
||||
STATE_JACK_UP_START,
|
||||
STATE_JACK_UP,
|
||||
STATE_DRIVE_START_DELAY,
|
||||
STATE_DRIVE,
|
||||
STATE_DRIVE_END_DELAY,
|
||||
STATE_JACK_DOWN,
|
||||
STATE_UNDO_JACK,
|
||||
STATE_UNDO_JACK_START,
|
||||
|
||||
STATE_CALIBRATE_JACK_DELAY,
|
||||
STATE_CALIBRATE_JACK_MOVE,
|
||||
|
||||
STATE_CALIBRATE_DRIVE_DELAY,
|
||||
STATE_CALIBRATE_DRIVE_MOVE
|
||||
} fsm_state_t;
|
||||
|
||||
typedef enum {
|
||||
@@ -46,8 +68,17 @@ void pulseOverride(relay_t relay/*, int64_t pulse*/);
|
||||
esp_err_t fsm_init();
|
||||
esp_err_t fsm_stop();
|
||||
|
||||
bool isRunning();
|
||||
|
||||
void fsm_set_cal_val(float v);
|
||||
int64_t fsm_get_cal_t();
|
||||
int64_t fsm_get_cal_e();
|
||||
void fsm_request(fsm_cmd_t cmd);
|
||||
|
||||
|
||||
float fsm_get_remaining_distance(void);
|
||||
void fsm_set_remaining_distance(float x);
|
||||
|
||||
//void fsm_begin_auto_move();
|
||||
|
||||
int8_t fsm_get_current_progress(int8_t remainder);
|
||||
|
||||
@@ -169,4 +169,7 @@ int64_t i2c_get_button_ms(uint8_t btn) {
|
||||
|
||||
uint64_t now = esp_timer_get_time() / 1000;
|
||||
return now - last_change_time[btn];
|
||||
}
|
||||
int64_t i2c_get_button_us(uint8_t btn) {
|
||||
return i2c_get_button_ms(btn)*1000;
|
||||
}
|
||||
@@ -19,6 +19,7 @@ bool i2c_get_button_released(uint8_t button);
|
||||
bool i2c_get_button_state(uint8_t button);
|
||||
bool i2c_get_button_repeat(uint8_t btn);
|
||||
int8_t i2c_get_button_repeats(uint8_t btn);
|
||||
int64_t i2c_get_button_us(uint8_t btn);
|
||||
int64_t i2c_get_button_ms(uint8_t btn);
|
||||
|
||||
#endif // I2C_H_
|
||||
@@ -1,5 +1,6 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/mdns: "*"
|
||||
joltwallet/littlefs: "==1.20.3"
|
||||
esp-idf-lib/tca95x5: "*"
|
||||
## Required IDF version
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
187
main/main.c
187
main/main.c
@@ -12,35 +12,35 @@
|
||||
#include "solar.h"
|
||||
#include "rf_433.h"
|
||||
#include "webserver.h"
|
||||
#include "version.h"
|
||||
|
||||
#define TAG "MAIN"
|
||||
|
||||
|
||||
int64_t last_log_time = 0;
|
||||
esp_err_t send_log() {
|
||||
|
||||
// >Hqfffflccc
|
||||
char entry[LOG_ENTRY_SIZE] = {0};
|
||||
entry[0] = LOG_ENTRY_SIZE;
|
||||
|
||||
// Pack 64-bit timestamp into bytes 1-8
|
||||
uint64_t be_timestamp = htobe64(rtc_time_ms());
|
||||
uint64_t be_timestamp = rtc_get_ms();
|
||||
memcpy(&entry[1], &be_timestamp, 8);
|
||||
|
||||
// Pack 32-bit voltages/currents into bytes 9-24
|
||||
float be_voltage = htobe32(get_battery_V());
|
||||
float be_voltage = get_battery_V();
|
||||
memcpy(&entry[9], &be_voltage, 4);
|
||||
float be_current1 = htobe32(get_bridge_A(BRIDGE_DRIVE));
|
||||
float be_current1 = get_bridge_A(BRIDGE_DRIVE);
|
||||
memcpy(&entry[13], &be_current1, 4);
|
||||
float be_current2 = htobe32(get_bridge_A(BRIDGE_JACK));
|
||||
float be_current2 = get_bridge_A(BRIDGE_JACK);
|
||||
memcpy(&entry[17], &be_current2, 4);
|
||||
float be_current3 = htobe32(get_bridge_A(BRIDGE_AUX));
|
||||
float be_current3 = get_bridge_A(BRIDGE_AUX);
|
||||
memcpy(&entry[21], &be_current3, 4);
|
||||
|
||||
int32_t be_counter = htobe32(get_sensor_counter(SENSOR_DRIVE));
|
||||
int32_t be_counter = get_sensor_counter(SENSOR_DRIVE);
|
||||
memcpy(&entry[25], &be_counter, 4);
|
||||
|
||||
entry[29] = get_sensor(SENSOR_DRIVE);
|
||||
entry[30] = get_sensor(SENSOR_JACK);
|
||||
entry[29] = get_sensor(SENSOR_SAFETY);
|
||||
entry[30] = get_sensor(SENSOR_DRIVE);
|
||||
entry[31] = fsm_get_state();
|
||||
|
||||
last_log_time = esp_timer_get_time();
|
||||
@@ -54,6 +54,7 @@ typedef enum {
|
||||
LED_STATE_ERROR,
|
||||
LED_STATE_AWAKE,
|
||||
LED_STATE_CANCELLING,
|
||||
LED_STATE_ERRORED,
|
||||
LED_STATE_START1,
|
||||
LED_STATE_START2,
|
||||
LED_STATE_START3,
|
||||
@@ -62,17 +63,19 @@ typedef enum {
|
||||
} led_state_t;
|
||||
|
||||
void driveLEDs(led_state_t state) {
|
||||
uint8_t patterns[4][12] = {
|
||||
uint8_t patterns[5][12] = {
|
||||
{1,3,7,6,4,0},
|
||||
{7,0},
|
||||
{0b101,0b001},
|
||||
{1,1,1,1,1,1, 1,1,1,3},
|
||||
{4,2}
|
||||
{4,2},
|
||||
{0b001, 0b101},
|
||||
};
|
||||
switch(state) {
|
||||
case LED_STATE_DRIVING:
|
||||
i2c_set_led1(patterns[state][(esp_timer_get_time()/100000) % 6]);
|
||||
break;
|
||||
case LED_STATE_ERROR:
|
||||
//ESP_LOGE(TAG, "SOME SORT OF ERROR");
|
||||
i2c_set_led1(patterns[state][(esp_timer_get_time()/1000000) % 2]);
|
||||
break;
|
||||
case LED_STATE_AWAKE:
|
||||
@@ -82,44 +85,106 @@ void driveLEDs(led_state_t state) {
|
||||
i2c_set_led1(patterns[state][(esp_timer_get_time()/200000) % 2]);
|
||||
break;
|
||||
|
||||
case LED_STATE_ERRORED:
|
||||
i2c_set_led1(patterns[state][(esp_timer_get_time()/200000) % 2]);
|
||||
break;
|
||||
|
||||
case LED_STATE_BOOTING:
|
||||
i2c_set_led1(1);
|
||||
i2c_set_led1(0b001);
|
||||
break;
|
||||
|
||||
case LED_STATE_START1:
|
||||
i2c_set_led1(0);
|
||||
i2c_set_led1(0b000);
|
||||
break;
|
||||
case LED_STATE_START2:
|
||||
i2c_set_led1(1);
|
||||
i2c_set_led1(0b001);
|
||||
break;
|
||||
case LED_STATE_START3:
|
||||
i2c_set_led1(3);
|
||||
i2c_set_led1(0b011);
|
||||
break;
|
||||
case LED_STATE_START4:
|
||||
i2c_set_led1(7);
|
||||
i2c_set_led1(0b111);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RTC_DATA_ATTR bool first_boot = true;
|
||||
|
||||
void app_main(void) {
|
||||
esp_task_wdt_add(NULL);
|
||||
|
||||
// Say hello; turn on the lights
|
||||
esp_sleep_wakeup_cause_t cause = rtc_wakeup_cause();
|
||||
if (rtc_xtal_init() != ESP_OK) ESP_LOGE(TAG, "RTC FAILED");
|
||||
|
||||
// Say hello; turn on the lights
|
||||
esp_sleep_wakeup_cause_t cause = rtc_wakeup_cause();
|
||||
if (i2c_init() != ESP_OK) ESP_LOGE(TAG, "I2C FAILED");
|
||||
i2c_set_relays(0);
|
||||
driveLEDs(LED_STATE_BOOTING);
|
||||
|
||||
// Every boot we load parameters and monitor solar, no matter what
|
||||
ESP_LOGI(TAG, "Firmware: %s", FIRMWARE_STRING);
|
||||
ESP_LOGI(TAG, "Version: %s", FIRMWARE_VERSION);
|
||||
ESP_LOGI(TAG, "Branch: %s", FIRMWARE_BRANCH);
|
||||
ESP_LOGI(TAG, "Built: %s", BUILD_DATE);
|
||||
|
||||
|
||||
// Check for factory reset condition: Cold boot + button held
|
||||
// This is a cold boot (power-on or hard reset)
|
||||
// Check if button is being held (pin is LOW)
|
||||
if (first_boot && gpio_get_level(GPIO_NUM_13) == 0) {
|
||||
ESP_LOGW(TAG, "FACTORY RESET TRIGGERED - Button held on cold boot");
|
||||
|
||||
// Flash LED pattern to indicate factory reset
|
||||
for (int i = 0; i < 10; i++) {
|
||||
i2c_set_led1(0b111);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
i2c_set_led1(0b000);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
}
|
||||
|
||||
// Initialize minimal components needed for factory reset
|
||||
if (storage_init() != ESP_OK) ESP_LOGE(TAG, "STORAGE FAILED");
|
||||
|
||||
// Perform factory reset
|
||||
esp_err_t reset_err = factory_reset();
|
||||
if (reset_err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Factory reset completed successfully");
|
||||
// Flash success pattern
|
||||
for (int i = 0; i < 5; i++) {
|
||||
i2c_set_led1(0b010);
|
||||
vTaskDelay(pdMS_TO_TICKS(200));
|
||||
i2c_set_led1(0b000);
|
||||
vTaskDelay(pdMS_TO_TICKS(200));
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Factory reset failed!");
|
||||
// Flash error pattern
|
||||
for (int i = 0; i < 5; i++) {
|
||||
i2c_set_led1(0b100);
|
||||
vTaskDelay(pdMS_TO_TICKS(200));
|
||||
i2c_set_led1(0b000);
|
||||
vTaskDelay(pdMS_TO_TICKS(200));
|
||||
}
|
||||
}
|
||||
|
||||
// Reboot the system
|
||||
ESP_LOGI(TAG, "Rebooting system...");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
first_boot = false;
|
||||
|
||||
// Every boot we load parameters and monitor solar, no matter what
|
||||
if (adc_init() != ESP_OK) ESP_LOGE(TAG, "ADC FAILED");
|
||||
if (rtc_xtal_init() != ESP_OK) ESP_LOGE(TAG, "RTC FAILED");
|
||||
if (storage_init() != ESP_OK) ESP_LOGE(TAG, "STORAGE FAILED");
|
||||
if (log_init() != ESP_OK) ESP_LOGE(TAG, "LOG FAILED");
|
||||
if (run_solar_fsm() != ESP_OK) ESP_LOGE(TAG, "SOLAR FAILED");
|
||||
if (solar_run_fsm() != ESP_OK) ESP_LOGE(TAG, "SOLAR FAILED");
|
||||
// TODO: Do a 12V check and enter deep sleep if there's a problem
|
||||
|
||||
|
||||
send_log();
|
||||
|
||||
//write_dummy_log_1();
|
||||
|
||||
// Check wake reasons
|
||||
// If button held, we stay #woke
|
||||
@@ -133,13 +198,13 @@ void app_main(void) {
|
||||
} else */if (cause == ESP_SLEEP_WAKEUP_EXT0) {
|
||||
ESP_LOGI("MAIN", "Woke from button press");
|
||||
} else {
|
||||
if (!alarm_tripped()) {
|
||||
if (!rtc_alarm_tripped()) {
|
||||
//enter_deep_sleep();
|
||||
}
|
||||
}
|
||||
|
||||
/*** FULL BOOT ***/
|
||||
if (uart_init() != ESP_OK) ESP_LOGE(TAG, "UART FAILED");
|
||||
//if (uart_init() != ESP_OK) ESP_LOGE(TAG, "UART FAILED");
|
||||
if (power_init() != ESP_OK) ESP_LOGE(TAG, "POWER FAILED");
|
||||
if (rf_433_init() != ESP_OK) ESP_LOGE(TAG, "RF FAILED");
|
||||
if (fsm_init() != ESP_OK) ESP_LOGE(TAG, "FSM FAILED");
|
||||
@@ -147,9 +212,14 @@ void app_main(void) {
|
||||
if (webserver_init() != ESP_OK) ESP_LOGE(TAG, "WEBSERVER FAILED");
|
||||
|
||||
/*** MAIN LOOP ***/
|
||||
|
||||
TickType_t xLastWakeTime = xTaskGetTickCount();
|
||||
const TickType_t xFrequency = pdMS_TO_TICKS(100);
|
||||
const TickType_t xFrequency = pdMS_TO_TICKS(50);
|
||||
|
||||
/*while(true) {
|
||||
ESP_LOGI(TAG, "TICK");
|
||||
vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(1000));
|
||||
esp_task_wdt_reset();
|
||||
}*/
|
||||
|
||||
while(true) {
|
||||
vTaskDelayUntil(&xLastWakeTime, xFrequency);
|
||||
@@ -157,12 +227,12 @@ void app_main(void) {
|
||||
i2c_poll_buttons();
|
||||
|
||||
if (i2c_get_button_state(0))
|
||||
reset_shutdown_timer();
|
||||
rtc_reset_shutdown_timer();
|
||||
|
||||
switch (fsm_get_state()) {
|
||||
case STATE_IDLE:
|
||||
// LED cue for user
|
||||
if (i2c_get_button_ms(0) > 1600){
|
||||
if (i2c_get_button_ms(0) > 1600){
|
||||
driveLEDs(LED_STATE_START4);
|
||||
} else if (i2c_get_button_ms(0) > 1100){
|
||||
driveLEDs(LED_STATE_START3);
|
||||
@@ -171,11 +241,20 @@ void app_main(void) {
|
||||
} else if (i2c_get_button_ms(0) > 100){
|
||||
driveLEDs(LED_STATE_START1);
|
||||
} else{
|
||||
driveLEDs(LED_STATE_AWAKE);
|
||||
if (
|
||||
rtc_is_set() &&
|
||||
!efuse_is_tripped(BRIDGE_JACK) &&
|
||||
!efuse_is_tripped(BRIDGE_AUX) &&
|
||||
!efuse_is_tripped(BRIDGE_DRIVE)
|
||||
) {
|
||||
driveLEDs(LED_STATE_AWAKE);
|
||||
} else {
|
||||
driveLEDs(LED_STATE_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
// when not actively moving we log at a low frequency
|
||||
if (esp_timer_get_time() > last_log_time + DEEP_SLEEP_US)
|
||||
if (isRunning() || (esp_timer_get_time() > last_log_time + DEEP_SLEEP_US))
|
||||
send_log();
|
||||
|
||||
if(i2c_get_button_ms(0) > 2100)
|
||||
@@ -183,7 +262,7 @@ void app_main(void) {
|
||||
break;
|
||||
case STATE_UNDO_JACK:
|
||||
case STATE_UNDO_JACK_START:
|
||||
// assume it's running
|
||||
// it's running the jack, but undoing
|
||||
send_log();
|
||||
driveLEDs(LED_STATE_CANCELLING);
|
||||
if (i2c_get_button_tripped(0)) {
|
||||
@@ -192,12 +271,34 @@ void app_main(void) {
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_CALIBRATE_JACK_DELAY:
|
||||
send_log();
|
||||
if (i2c_get_button_tripped(0))
|
||||
fsm_request(FSM_CMD_CALIBRATE_JACK_START);
|
||||
break;
|
||||
case STATE_CALIBRATE_JACK_MOVE:
|
||||
send_log();
|
||||
if (i2c_get_button_tripped(0))
|
||||
fsm_request(FSM_CMD_CALIBRATE_JACK_END);
|
||||
break;
|
||||
|
||||
|
||||
case STATE_CALIBRATE_DRIVE_DELAY:
|
||||
send_log();
|
||||
if (i2c_get_button_tripped(0))
|
||||
fsm_request(FSM_CMD_CALIBRATE_DRIVE_START);
|
||||
break;
|
||||
case STATE_CALIBRATE_DRIVE_MOVE:
|
||||
send_log();
|
||||
if (i2c_get_button_tripped(0))
|
||||
fsm_request(FSM_CMD_CALIBRATE_DRIVE_END);
|
||||
break;
|
||||
|
||||
default:
|
||||
// assume it's running in every other case
|
||||
// it's running in every other case
|
||||
send_log();
|
||||
driveLEDs(LED_STATE_DRIVING);
|
||||
if (i2c_get_button_tripped(0)) {
|
||||
ESP_LOGI(TAG, "CTRL + Z PLZ!");
|
||||
fsm_request(FSM_CMD_UNDO);
|
||||
}
|
||||
break;
|
||||
@@ -206,24 +307,14 @@ void app_main(void) {
|
||||
|
||||
|
||||
|
||||
if (alarm_tripped()) {
|
||||
if (rtc_alarm_tripped()) {
|
||||
fsm_request(FSM_CMD_START);
|
||||
set_next_alarm();
|
||||
rtc_schedule_next_alarm();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*ESP_LOGI(TAG, "VOLTAGE: %2.3f | CURRENTS: %+2.8f %+2.8f %+2.8f",
|
||||
get_battery_V(),
|
||||
get_bridge_A(BRIDGE_DRIVE),
|
||||
get_bridge_A(BRIDGE_JACK),
|
||||
get_bridge_A(BRIDGE_AUX));*/
|
||||
|
||||
|
||||
|
||||
run_solar_fsm();
|
||||
solar_run_fsm();
|
||||
|
||||
//check_shutdown_timer();
|
||||
rtc_check_shutdown_timer();
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
}
|
||||
@@ -63,6 +63,9 @@ typedef struct {
|
||||
float heat;
|
||||
bool tripped;
|
||||
int64_t trip_time;
|
||||
|
||||
// Inrush tolerance tracking
|
||||
int64_t inrush_start_time; // When instantaneous overcurrent first detected (0 = not in overcurrent)
|
||||
} isens_channel_t;
|
||||
static isens_channel_t isens[N_BRIDGES] = {0};
|
||||
|
||||
@@ -82,7 +85,7 @@ esp_err_t adc_init() {
|
||||
|
||||
// Configure all channels
|
||||
adc_oneshot_chan_cfg_t chan_cfg = {
|
||||
.atten = ADC_ATTEN_DB_11,
|
||||
.atten = ADC_ATTEN_DB_12,
|
||||
.bitwidth = ADC_BITWIDTH_12,
|
||||
};
|
||||
|
||||
@@ -94,7 +97,7 @@ esp_err_t adc_init() {
|
||||
// Line fitting calibration (modern scheme)
|
||||
adc_cali_line_fitting_config_t cali_cfg = {
|
||||
.unit_id = ADC_UNIT_1,
|
||||
.atten = ADC_ATTEN_DB_11,
|
||||
.atten = ADC_ATTEN_DB_12,
|
||||
.bitwidth = ADC_BITWIDTH_12,
|
||||
};
|
||||
ESP_ERROR_CHECK(adc_cali_create_scheme_line_fitting(&cali_cfg, &adc_cali_handle));
|
||||
@@ -112,7 +115,7 @@ float get_raw_battery_voltage(void) {
|
||||
!= ESP_OK) { return NAN; }
|
||||
|
||||
// Voltage divider: 150kohm to 1Mohm -> gain = 1.15 -> scale = 1150/150
|
||||
return voltage_mv * 0.00766666666; // same as / 1000.0 * 1150.0 / 150.0;
|
||||
return voltage_mv * get_param_value_t(PARAM_V_SENS_K).f32 + get_param_value_t(PARAM_V_SENS_OFFSET).f32; // same as / 1000.0 * 1150.0 / 150.0;
|
||||
}
|
||||
|
||||
esp_err_t process_battery_voltage(void)
|
||||
@@ -125,12 +128,13 @@ esp_err_t process_battery_voltage(void)
|
||||
} else {
|
||||
float alpha = get_param_value_t(PARAM_ADC_ALPHA_BATTERY).f32;
|
||||
if (isnan(raw)) {
|
||||
ESP_LOGI(TAG, "RAW BATTERY IS NAN");
|
||||
//ESP_LOGI(TAG, "RAW BATTERY IS NAN");
|
||||
} else {
|
||||
if (isnan(ema_battery) || isnan(alpha))
|
||||
if (isnan(ema_battery) || isnan(alpha)) {
|
||||
ema_battery = raw;
|
||||
else
|
||||
} else {
|
||||
ema_battery = alpha * (float)raw + (1.0f - alpha) * ema_battery;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +178,7 @@ esp_err_t process_bridge_current(bridge_t bridge) {
|
||||
break;
|
||||
case BRIDGE_DRIVE:
|
||||
// ACS37220LEZATR-100B3 is 100A capable and 13.2 mV/A
|
||||
raw_a = (voltage_mv - 1650.0f) / 13.2f;
|
||||
raw_a = -(voltage_mv - 1650.0f) / 13.2f;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -184,13 +188,14 @@ esp_err_t process_bridge_current(bridge_t bridge) {
|
||||
} else {
|
||||
float alpha = get_param_value_t(PARAM_ADC_ALPHA_ISENS).f32;
|
||||
if (isnan(raw_a)) {
|
||||
ESP_LOGI(TAG, "RAW BATTERY IS NAN");
|
||||
//ESP_LOGI(TAG, "RAW BATTERY IS NAN");
|
||||
channel->ema_current = NAN;
|
||||
} else {
|
||||
if (isnan(ema_battery) || isnan(alpha))
|
||||
if (isnan(ema_battery) || isnan(alpha)) {
|
||||
channel->ema_current = raw_a;
|
||||
else
|
||||
} else {
|
||||
channel->ema_current = alpha * raw_a + (1.0f - alpha) * channel->ema_current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,13 +211,14 @@ esp_err_t process_bridge_current(bridge_t bridge) {
|
||||
} else {
|
||||
float alpha = get_param_value_t(PARAM_ADC_ALPHA_IAZ).f32;
|
||||
if (isnan(raw_a)) {
|
||||
ESP_LOGI(TAG, "RAW BATTERY IS NAN");
|
||||
//ESP_LOGI(TAG, "RAW BATTERY IS NAN");
|
||||
} else {
|
||||
if (isnan(ema_battery) || isnan(alpha))
|
||||
if (isnan(ema_battery) || isnan(alpha)) {
|
||||
channel->az_offset = channel->ema_current;
|
||||
else
|
||||
} else {
|
||||
channel->az_offset = alpha * channel->ema_current +
|
||||
(1.0f - alpha) * channel->az_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -244,12 +250,26 @@ esp_err_t process_bridge_current(bridge_t bridge) {
|
||||
// Normalize the current as a fraction of rated current
|
||||
float I_norm = fabsf(channel->current / I_nominal);
|
||||
|
||||
// Instant trip on extreme overcurrent
|
||||
// Instant trip on extreme overcurrent - but with inrush tolerance
|
||||
if (I_norm >= get_param_value_t(PARAM_EFUSE_KINST).f32) {
|
||||
channel->tripped = true;
|
||||
channel->trip_time = now;
|
||||
ESP_LOGI(TAG, "FUSE TRIP: Inom: %+.5f HEAT:%+2.5f", I_norm, channel->heat);
|
||||
return ESP_OK; // no more processing, if we're over, we're over
|
||||
// Start tracking if this is the first time we've seen overcurrent
|
||||
if (channel->inrush_start_time == 0) {
|
||||
channel->inrush_start_time = now;
|
||||
}
|
||||
|
||||
// Check if overcurrent has persisted long enough
|
||||
int64_t inrush_duration = now - channel->inrush_start_time;
|
||||
if (inrush_duration >= get_param_value_t(PARAM_EFUSE_INRUSH_US).u32) {
|
||||
channel->tripped = true;
|
||||
channel->trip_time = now;
|
||||
channel->inrush_start_time = 0; // Reset for next time
|
||||
//ESP_LOGI(TAG, "FUSE TRIP: Inom: %+.5f HEAT:%+2.5f", I_norm, channel->heat);
|
||||
return ESP_OK; // no more processing, if we're over, we're over
|
||||
}
|
||||
// Still in overcurrent but within inrush tolerance window - don't trip yet
|
||||
} else {
|
||||
// Current dropped below threshold - reset inrush timer
|
||||
channel->inrush_start_time = 0;
|
||||
}
|
||||
|
||||
// Accumulate heat
|
||||
@@ -275,13 +295,13 @@ esp_err_t process_bridge_current(bridge_t bridge) {
|
||||
// And enough time has passed
|
||||
// Go ahead and reset the e-fuse
|
||||
} else if (channel->tripped &&
|
||||
(now - channel->trip_time) > get_param_value_t(PARAM_EFUSE_TCOOL).i64) {
|
||||
(now - channel->trip_time) > get_param_value_t(PARAM_EFUSE_TCOOL).u32) {
|
||||
channel->tripped = false;
|
||||
// channel.heat = 0.0f // I think we should wait for the e-fuse to catch up
|
||||
}
|
||||
|
||||
if (bridge == BRIDGE_DRIVE)
|
||||
ESP_LOGI(TAG, "FUSE: Inom: %+.5f HEAT:%+2.5f", I_norm, channel->heat);
|
||||
//if (bridge == BRIDGE_JACK)
|
||||
//ESP_LOGI(TAG, "FUSE: raw_a: %+.4f cur: %+.4f Inorm: %+.5f HEAT:%+2.5f", raw_a, channel->current, I_norm, channel->heat);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -1,546 +0,0 @@
|
||||
/*
|
||||
* power_mgmt.c
|
||||
*
|
||||
* 1 kHz power-management task:
|
||||
* • Samples all three H-bridge current sensors (DRIVE, AUX, JACK)
|
||||
* • Samples battery voltage (BAT)
|
||||
* • Applies EMA filtering on every channel
|
||||
* • Updates shared volatile globals for the control FSM
|
||||
* • Handles over-current spike protection
|
||||
*
|
||||
* Updated to modern ESP-IDF ADC API (line fitting)
|
||||
* All variables now defined locally
|
||||
*
|
||||
* Created on: Nov 10, 2025
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "driver/rtc_io.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_task_wdt.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_adc/adc_oneshot.h"
|
||||
#include "esp_adc/adc_cali.h"
|
||||
#include "esp_adc/adc_cali_scheme.h"
|
||||
#include "esp_timer.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "control_fsm.h"
|
||||
#include "soc/rtc_io_reg.h"
|
||||
#include "power_mgmt.h"
|
||||
|
||||
#include "storage.h"
|
||||
#include "rtc.h"
|
||||
|
||||
// === GPIO Pin Definitions ===
|
||||
#define PIN_V_ISENS1 ADC_CHANNEL_0 // GPIO36 / VP
|
||||
#define PIN_V_ISENS2 ADC_CHANNEL_6 // GPIO34
|
||||
#define PIN_V_ISENS3 ADC_CHANNEL_7 // GPIO35
|
||||
#define PIN_V_BATTERY ADC_CHANNEL_3 // GPIO39 / VN
|
||||
#define PIN_V_SENS_BAT PIN_V_BATTERY
|
||||
|
||||
#define PIN_CHG_BULK GPIO_NUM_26
|
||||
|
||||
#define AUTOZERO_THRESH 2000.0f // mA
|
||||
|
||||
|
||||
typedef enum {
|
||||
CHG_T_LOWBAT = 0,
|
||||
CHG_T_BULK = 1,
|
||||
CHG_T_STEADY = 2,
|
||||
} charge_timer_t;
|
||||
|
||||
#define N_CHG_TIMERS 3
|
||||
RTC_DATA_ATTR charge_state_t current_charge_state = CHG_STATE_BULK;
|
||||
RTC_DATA_ATTR int64_t charge_timers[N_CHG_TIMERS] = {-1};
|
||||
|
||||
int64_t now;
|
||||
|
||||
charge_state_t get_charging_state() { return current_charge_state; }
|
||||
|
||||
void setTimerN(charge_timer_t i, int64_t sec) {
|
||||
// set the timer for <sec> in the future if it's currently less than now
|
||||
if (charge_timers[i] < now) {
|
||||
charge_timers[i] = now + sec;
|
||||
ESP_LOGI("BAT", "Set timer[%d] +%lld", i, (long long)sec);
|
||||
}
|
||||
}
|
||||
|
||||
void resetTimerN(charge_timer_t i) {
|
||||
charge_timers[i] = -1;
|
||||
}
|
||||
void resetBatTimers() {
|
||||
for (uint8_t i=0; i<N_CHG_TIMERS; i++)
|
||||
resetTimerN(i);
|
||||
}
|
||||
|
||||
bool getTimerN(charge_timer_t i) {
|
||||
if (charge_timers[i] < 0) return false;
|
||||
return system_rtc_get_raw_time() > charge_timers[i];
|
||||
}
|
||||
|
||||
#define BULK_CHARGE_S 20 //2*60*60
|
||||
#define FLOAT_STEADY_S 10 //30*60
|
||||
#define LOW_DETECT_S 10 //5*60
|
||||
|
||||
#define STEADY_MV 13000
|
||||
#define LOW_MV 12800
|
||||
|
||||
void run_charge_fsm() {
|
||||
now = system_rtc_get_raw_time();
|
||||
|
||||
//ESP_LOGI("BAT", "FSM STATE %d", current_charge_state);
|
||||
|
||||
if (rtc_is_set()) {
|
||||
switch(current_charge_state) {
|
||||
case CHG_STATE_BULK:
|
||||
// turn off bulk charging and go to float when time is up
|
||||
if (getTimerN(CHG_T_BULK)) {
|
||||
ESP_LOGI("BAT", "BULK -> FLOAT");
|
||||
current_charge_state = CHG_STATE_FLOAT;
|
||||
}
|
||||
break;
|
||||
|
||||
case CHG_STATE_FLOAT:
|
||||
if (getTimerN(CHG_T_STEADY)) {
|
||||
ESP_LOGI("BAT", "FLOAT -> OFF");
|
||||
current_charge_state = CHG_STATE_OFF;
|
||||
}
|
||||
if (get_battery_mV() > STEADY_MV) {
|
||||
setTimerN(CHG_T_STEADY, FLOAT_STEADY_S);
|
||||
} else {
|
||||
resetTimerN(CHG_T_STEADY);
|
||||
}
|
||||
// NO break; !! float should also kick into bulk with same triggers
|
||||
case CHG_STATE_OFF:
|
||||
|
||||
// after 5 minutes of low-ish battery go into bulk charge
|
||||
if (getTimerN(CHG_T_LOWBAT)) {
|
||||
ESP_LOGI("BAT", " -> BULK");
|
||||
current_charge_state = CHG_STATE_BULK;
|
||||
setTimerN(CHG_T_BULK, BULK_CHARGE_S);
|
||||
}
|
||||
if (get_battery_mV() < LOW_MV) {
|
||||
setTimerN(CHG_T_LOWBAT, LOW_DETECT_S);
|
||||
} else {
|
||||
resetTimerN(CHG_T_LOWBAT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
//ESP_LOGI("BAT", " -> BULK");
|
||||
current_charge_state = CHG_STATE_BULK;
|
||||
}
|
||||
|
||||
//rtc_gpio_hold_dis(PIN_CHG_BULK);
|
||||
//rtc_gpio_hold_dis(PIN_CHG_DISABLE);
|
||||
switch(current_charge_state) {
|
||||
case CHG_STATE_BULK:
|
||||
gpio_set_level(PIN_CHG_BULK, 1);
|
||||
//ESP_LOGI("BAT", "BULK");
|
||||
break;
|
||||
case CHG_STATE_FLOAT:
|
||||
gpio_set_level(PIN_CHG_BULK, 0);
|
||||
//ESP_LOGI("BAT", "FLOAT");
|
||||
break;
|
||||
case CHG_STATE_OFF:
|
||||
gpio_set_level(PIN_CHG_BULK, 0);
|
||||
//ESP_LOGI("BAT", "OFF");
|
||||
break;
|
||||
}
|
||||
//rtc_gpio_hold_en(PIN_CHG_BULK);
|
||||
//rtc_gpio_hold_en(PIN_CHG_DISABLE);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
bool enabled; // Auto-zero active for this channel
|
||||
float threshold_ma; // Max current to consider "zero" (mA)
|
||||
float learned_offset_mv; // Accumulated zero offset (mV)
|
||||
bool initialized; // First valid zero established
|
||||
} autozero_t;
|
||||
static autozero_t autozero[N_BRIDGES] = {0};
|
||||
|
||||
// === E-Fuse (Software Breaker) Configuration ===
|
||||
static const char* currentLimits_A[N_BRIDGES] = {
|
||||
[BRIDGE_DRIVE] = "efuse_drive_A", //40000,
|
||||
[BRIDGE_AUX] = "efuse_aux_A", // 5000,
|
||||
[BRIDGE_JACK] = "efuse_jack_A" // 10000
|
||||
};
|
||||
static const float i2t_thresholds[N_BRIDGES] = { // A^2*s (tunable per bridge if needed)
|
||||
[BRIDGE_DRIVE] = 6.0f,
|
||||
[BRIDGE_AUX] = 6.0f,
|
||||
[BRIDGE_JACK] = 6.0f
|
||||
};
|
||||
static const float i_instant[N_BRIDGES] = { // Instant trip multiplier of I_rated
|
||||
[BRIDGE_DRIVE] = 15.0f,
|
||||
[BRIDGE_AUX] = 15.0f,
|
||||
[BRIDGE_JACK] = 15.0f
|
||||
};
|
||||
static const float cool_rate[N_BRIDGES] = { // Cooling constant (1/s)
|
||||
[BRIDGE_DRIVE] = 0.008f,
|
||||
[BRIDGE_AUX] = 0.008f,
|
||||
[BRIDGE_JACK] = 0.008f
|
||||
};
|
||||
static const int32_t cooldown_ms[N_BRIDGES] = { // Auto-reset delay after trip
|
||||
[BRIDGE_DRIVE] = 5000,
|
||||
[BRIDGE_AUX] = 5000,
|
||||
[BRIDGE_JACK] = 5000
|
||||
};
|
||||
|
||||
static float efuse_heat[N_BRIDGES] = {0};
|
||||
static uint64_t efuse_trip_time[N_BRIDGES] = {0}; // Timestamp when tripped
|
||||
static bool efuse_tripped[N_BRIDGES] = {false};
|
||||
|
||||
// === ADC Handles ===
|
||||
static adc_oneshot_unit_handle_t adc1_handle = NULL;
|
||||
static adc_cali_handle_t adc_cali_handle = NULL;
|
||||
|
||||
// === EMA Filter State ===
|
||||
#define EMA_ALPHA_CURRENT 0.5f
|
||||
#define EMA_ALPHA_BATTERY 0.05f
|
||||
|
||||
static float ema_current[N_BRIDGES] = {0};
|
||||
static bool ema_init[N_BRIDGES] = {false};
|
||||
|
||||
static float ema_battery = 0.0f;
|
||||
static bool ema_battery_init = false;
|
||||
|
||||
// === Shared Volatile Outputs ===
|
||||
volatile int32_t bridgeCurrents_mA[N_BRIDGES] = {0};
|
||||
volatile int32_t batteryVoltage_mV = 0;
|
||||
|
||||
// === ADC Initialization ===
|
||||
static esp_err_t adc_init(void) {
|
||||
if (adc1_handle != NULL) {
|
||||
return ESP_OK; // Already initialized
|
||||
}
|
||||
|
||||
// ADC1 oneshot mode
|
||||
adc_oneshot_unit_init_cfg_t init_cfg = {
|
||||
.unit_id = ADC_UNIT_1,
|
||||
};
|
||||
ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_cfg, &adc1_handle));
|
||||
|
||||
// Configure all channels
|
||||
adc_oneshot_chan_cfg_t chan_cfg = {
|
||||
.atten = ADC_ATTEN_DB_11,
|
||||
.bitwidth = ADC_BITWIDTH_12,
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, PIN_V_ISENS1, &chan_cfg));
|
||||
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, PIN_V_ISENS2, &chan_cfg));
|
||||
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, PIN_V_ISENS3, &chan_cfg));
|
||||
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, PIN_V_SENS_BAT, &chan_cfg));
|
||||
|
||||
// Line fitting calibration (modern scheme)
|
||||
adc_cali_line_fitting_config_t cali_cfg = {
|
||||
.unit_id = ADC_UNIT_1,
|
||||
.atten = ADC_ATTEN_DB_11,
|
||||
.bitwidth = ADC_BITWIDTH_12,
|
||||
};
|
||||
ESP_ERROR_CHECK(adc_cali_create_scheme_line_fitting(&cali_cfg, &adc_cali_handle));
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void autozero_enable(bridge_t bridge, bool enable) {
|
||||
if (bridge >= N_BRIDGES) return;
|
||||
autozero[bridge].enabled = enable;
|
||||
if (!enable) {
|
||||
autozero[bridge].learned_offset_mv = 0.0f;
|
||||
autozero[bridge].initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
void autozero_set_threshold(bridge_t bridge, float threshold_ma) {
|
||||
if (bridge >= N_BRIDGES) return;
|
||||
autozero[bridge].threshold_ma = fmaxf(0.0f, threshold_ma);
|
||||
}
|
||||
|
||||
float autozero_get_offset_mv(bridge_t bridge) {
|
||||
if (bridge >= N_BRIDGES) return 0.0f;
|
||||
return autozero[bridge].learned_offset_mv;
|
||||
}
|
||||
|
||||
void autozero_reset(bridge_t bridge) {
|
||||
if (bridge >= N_BRIDGES) return;
|
||||
autozero[bridge].learned_offset_mv = 0.0f;
|
||||
autozero[bridge].initialized = false;
|
||||
}
|
||||
|
||||
void autozero_reset_all(void) {
|
||||
for (uint8_t i = 0; i < N_BRIDGES; i++) {
|
||||
autozero_reset((bridge_t)i);
|
||||
}
|
||||
}
|
||||
|
||||
// === Raw Current Reading (mA) ===
|
||||
static int32_t read_bridge_current_raw(bridge_t bridge) {
|
||||
int adc_raw = 0;
|
||||
int voltage_mv = 0;
|
||||
|
||||
adc_channel_t pin;
|
||||
switch(bridge) {
|
||||
case BRIDGE_DRIVE: pin = PIN_V_ISENS1; break;
|
||||
case BRIDGE_AUX: pin = PIN_V_ISENS3; break;
|
||||
case BRIDGE_JACK: pin = PIN_V_ISENS2; break;
|
||||
default: return -42069; // lol
|
||||
}
|
||||
|
||||
if (adc_oneshot_read(adc1_handle, pin, &adc_raw) != ESP_OK) {
|
||||
return 0;
|
||||
}
|
||||
if (adc_cali_raw_to_voltage(adc_cali_handle, adc_raw, &voltage_mv) != ESP_OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
float current_sense_mv = (float)voltage_mv;
|
||||
autozero_t *az = &autozero[bridge];
|
||||
|
||||
// === AUTO-ZERO LEARNING PHASE ===
|
||||
if (az->enabled && get_bridge_state(bridge)==0) {
|
||||
float raw_current_ma = 0.0f;
|
||||
switch (bridge) {
|
||||
case BRIDGE_JACK:
|
||||
case BRIDGE_AUX:
|
||||
// ACS37042KLHBLT-030B3 is 30A capable and 44 mV/A
|
||||
raw_current_ma = (current_sense_mv - 1650.0f) * 1000.0f / 44.0f;
|
||||
break;
|
||||
case BRIDGE_DRIVE:
|
||||
// ACS37220LEZATR-100B3 is 100A capable and 13.2 mV/A
|
||||
raw_current_ma = (current_sense_mv - 1650.0f) * 1000.0f / 13.20f;
|
||||
break;
|
||||
}
|
||||
|
||||
if (fabsf(raw_current_ma) <= az->threshold_ma) {
|
||||
// Valid zero sample
|
||||
if (!az->initialized) {
|
||||
az->learned_offset_mv = current_sense_mv - 1650.0f;
|
||||
az->initialized = true;
|
||||
} else {
|
||||
// EMA on offset (slow adaptation)
|
||||
float alpha = 0.1f;
|
||||
az->learned_offset_mv = alpha * (current_sense_mv - 1650.0f) +
|
||||
(1.0f - alpha) * az->learned_offset_mv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// === APPLY AUTO-ZERO OFFSET ===
|
||||
float corrected_mv = current_sense_mv - az->learned_offset_mv;
|
||||
|
||||
int32_t offset_mv = (int32_t)(corrected_mv - 1650.0f);
|
||||
int32_t current_ma = 0;
|
||||
|
||||
switch (bridge) {
|
||||
case BRIDGE_JACK:
|
||||
case BRIDGE_AUX:
|
||||
current_ma = offset_mv * 1000 / 44; // 44 mV/A
|
||||
break;
|
||||
case BRIDGE_DRIVE:
|
||||
current_ma = offset_mv * 10000 / 132; // 13.2 mV/A
|
||||
break;
|
||||
}
|
||||
|
||||
return current_ma;
|
||||
}
|
||||
|
||||
// === Raw Battery Voltage Reading (mV) ===
|
||||
static int32_t read_battery_voltage_raw(void)
|
||||
{
|
||||
int adc_raw = 0;
|
||||
int voltage_mv = 0;
|
||||
|
||||
if (adc_oneshot_read(adc1_handle, PIN_V_SENS_BAT, &adc_raw) != ESP_OK) {
|
||||
return 0;
|
||||
}
|
||||
if (adc_cali_raw_to_voltage(adc_cali_handle, adc_raw, &voltage_mv) != ESP_OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Voltage divider: 150kΩ to 1MΩ → gain = 1.15 → scale = 1150/150
|
||||
return (int32_t)voltage_mv * 1150 / 150;
|
||||
}
|
||||
|
||||
// === EMA Filter Update ===
|
||||
static void apply_ema(float *state, bool *init, float alpha, int32_t raw, volatile int32_t *out)
|
||||
{
|
||||
if (!*init) {
|
||||
*state = (float)raw;
|
||||
*init = true;
|
||||
} else {
|
||||
*state = alpha * (float)raw + (1.0f - alpha) * *state;
|
||||
}
|
||||
*out = (int32_t)(*state + 0.5f);
|
||||
}
|
||||
|
||||
// === Public Accessors ===
|
||||
int32_t get_bridge_mA(uint8_t bridge)
|
||||
{
|
||||
if (bridge >= N_BRIDGES) return -1;
|
||||
return (int32_t)bridgeCurrents_mA[bridge];
|
||||
}
|
||||
|
||||
int32_t get_battery_mV(void)
|
||||
{
|
||||
return (int32_t)batteryVoltage_mV;
|
||||
}
|
||||
|
||||
// === E-Fuse: Trip Logic (called every cycle) ===
|
||||
static void efuse_update(uint8_t bridge, float I, float dt, uint64_t now)
|
||||
{
|
||||
float I_rated = (float)get_param_i8(currentLimits_A[bridge]);
|
||||
float I_norm = I / I_rated;
|
||||
|
||||
// Instant trip on extreme overcurrent
|
||||
if (I_norm >= i_instant[bridge]) {
|
||||
efuse_tripped[bridge] = true;
|
||||
efuse_trip_time[bridge] = now;
|
||||
return;
|
||||
}
|
||||
|
||||
// Cooling when below threshold
|
||||
if (I_norm < 1.1f) {
|
||||
efuse_heat[bridge] -= efuse_heat[bridge] * cool_rate[bridge] * dt;
|
||||
efuse_heat[bridge] = fmaxf(0.0f, efuse_heat[bridge]);
|
||||
efuse_tripped[bridge] = false; // Auto-clear if cooled
|
||||
return;
|
||||
}
|
||||
|
||||
// Accumulate heat (I²t)
|
||||
efuse_heat[bridge] += (I_norm * I_norm) * dt;
|
||||
|
||||
if (efuse_heat[bridge] >= i2t_thresholds[bridge]) {
|
||||
efuse_tripped[bridge] = true;
|
||||
efuse_trip_time[bridge] = now;
|
||||
}
|
||||
}
|
||||
|
||||
// === E-Fuse: Auto-Reset After Cooldown ===
|
||||
static void efuse_cooldown_check(uint64_t now)
|
||||
{
|
||||
for (uint8_t i = 0; i < N_BRIDGES; i++) {
|
||||
if (efuse_tripped[i] &&
|
||||
(now - efuse_trip_time[i]) >= (cooldown_ms[i] * 1000ULL)) {
|
||||
efuse_heat[i] = 0.0f;
|
||||
efuse_tripped[i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// === Public E-Fuse Controls ===
|
||||
void efuse_reset_all(void)
|
||||
{
|
||||
for (uint8_t i = 0; i < N_BRIDGES; i++) {
|
||||
efuse_heat[i] = 0.0f;
|
||||
efuse_tripped[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool efuse_is_tripped(uint8_t bridge)
|
||||
{
|
||||
if (bridge >= N_BRIDGES) return false;
|
||||
return efuse_tripped[bridge];
|
||||
}
|
||||
|
||||
|
||||
// === Power Management Task ===
|
||||
void power_mgmt_task(void *param) {
|
||||
esp_task_wdt_add(NULL);
|
||||
|
||||
/*gpio_config_t io_conf = {
|
||||
.pin_bit_mask = (1ULL << PIN_CHG_DISABLE) | (1ULL << PIN_CHG_BULK),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
};
|
||||
gpio_config(&io_conf);*/
|
||||
|
||||
/*// Enable RTC GPIO domain (required for hold)
|
||||
rtc_gpio_init(PIN_CHG_DISABLE);
|
||||
rtc_gpio_init(PIN_CHG_BULK);
|
||||
|
||||
// Set as output
|
||||
rtc_gpio_set_direction(PIN_CHG_DISABLE, RTC_GPIO_MODE_OUTPUT_ONLY);
|
||||
rtc_gpio_set_direction(PIN_CHG_BULK, RTC_GPIO_MODE_OUTPUT_ONLY);
|
||||
|
||||
// Optional: set initial level (will be held)
|
||||
//rtc_gpio_set_level(PIN_CHG_DISABLE, 1); // e.g., start disabled
|
||||
//rtc_gpio_set_level(PIN_CHG_BULK, 0);
|
||||
|
||||
// **Critical: Enable hold function**
|
||||
rtc_gpio_hold_en(PIN_CHG_DISABLE);
|
||||
rtc_gpio_hold_en(PIN_CHG_BULK);*/
|
||||
|
||||
ESP_ERROR_CHECK(adc_init());
|
||||
|
||||
TickType_t xLastWakeTime = xTaskGetTickCount();
|
||||
const TickType_t xFrequency = pdMS_TO_TICKS(20);
|
||||
|
||||
// Optional: Enable auto-zero with default threshold
|
||||
autozero_enable(BRIDGE_DRIVE, true);
|
||||
autozero_enable(BRIDGE_AUX, true);
|
||||
autozero_enable(BRIDGE_JACK, true);
|
||||
|
||||
autozero_set_threshold(BRIDGE_DRIVE, AUTOZERO_THRESH);
|
||||
autozero_set_threshold(BRIDGE_AUX, AUTOZERO_THRESH);
|
||||
autozero_set_threshold(BRIDGE_JACK, AUTOZERO_THRESH);
|
||||
|
||||
//uint64_t last_wake_time = esp_timer_get_time();
|
||||
//const uint64_t period = 5000; // 100 us => 10kHz
|
||||
while (1) {
|
||||
vTaskDelayUntil(&xLastWakeTime, xFrequency);
|
||||
uint64_t now_us = esp_timer_get_time();
|
||||
|
||||
/*if (now - last_wake_time < period) {
|
||||
uint32_t delay_us = (period - (now - last_wake_time)) / 1000;
|
||||
if (delay_us > 0) vTaskDelay(pdMS_TO_TICKS(delay_us));
|
||||
continue;
|
||||
}
|
||||
last_wake_time = now;*/
|
||||
|
||||
// Sample currents
|
||||
for (uint8_t i = 0; i < N_BRIDGES; i++) {
|
||||
int32_t raw_ma = read_bridge_current_raw((bridge_t)i);
|
||||
apply_ema(&ema_current[i], &ema_init[i], EMA_ALPHA_CURRENT,
|
||||
raw_ma, &bridgeCurrents_mA[i]);
|
||||
|
||||
// Reset spike timer if under limit
|
||||
/*if (bridgeCurrents_mA[i] < currentLimits_mA[i]) {
|
||||
currentSpikeSafeTimes[i] = now + CURRENT_SPIKE_TIME_US;
|
||||
}*/
|
||||
|
||||
// === E-FUSE UPDATE ===
|
||||
float I = (float)bridgeCurrents_mA[i] / 1000.0f;
|
||||
float dt = 0.020f; // 20 ms task period
|
||||
efuse_update(i, I, dt, now_us);
|
||||
}
|
||||
|
||||
/*ESP_LOGI("PWR", "[ %6ld | %6ld | %6ld mA ] { %6ld mV }",
|
||||
(long)bridgeCurrents_mA[BRIDGE_DRIVE],
|
||||
(long)bridgeCurrents_mA[BRIDGE_JACK],
|
||||
(long)bridgeCurrents_mA[BRIDGE_AUX],
|
||||
(long)batteryVoltage_mV);*/
|
||||
|
||||
// Sample battery
|
||||
int32_t raw_bat = read_battery_voltage_raw();
|
||||
apply_ema(&ema_battery, &ema_battery_init, EMA_ALPHA_BATTERY,
|
||||
raw_bat, &batteryVoltage_mV);
|
||||
|
||||
|
||||
//run_charge_fsm();
|
||||
efuse_cooldown_check(now_us);
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
}
|
||||
|
||||
void start_power() {
|
||||
xTaskCreate(power_mgmt_task, "PWR", 4096, NULL, 5, NULL);
|
||||
}
|
||||
|
||||
void shutdown_power() {
|
||||
|
||||
}
|
||||
28
main/prvtkey.pem
Normal file
28
main/prvtkey.pem
Normal file
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCc4kQulPmDvj52
|
||||
HrvgQPMrGrMsSQdtOKFOFBT0o7uTXXWK2y48TMdy3RKKNVaIu0nhKpsFSBfekyAe
|
||||
iUJH4N/1ih+byJtUZJ3iMyfDrPoElmAPBQJYkjwvM8V94ug648GV5YF20C9hNOyi
|
||||
7Z9BIdRvd3DiNexuYz+3C2vRGW/lHu9r7HdK1u4nv9SF10jZhjfa0DidotKaDrul
|
||||
558QoHskrQkxOQa5hKRcB4KmceRihs5bU9qngrgdSlax0LUBhpBBBsgUxsKdvht3
|
||||
C4R55MmAkDWuYYvqa8cAX8+XWylILRjlvktZhDrWFOlXbTxShD9ax3zUfuJRj8Jx
|
||||
t0/SLamZAgMBAAECggEAA/dwk+DuYhdYSvJB+8yImWlmaFM8XdWVtnypfvn4zyQI
|
||||
ycb650llrZDLXDU3B+P8XTYPj1WgTN9Za4w64chcwT+Jxw2OZ9bXaxWyBq+D7sPC
|
||||
j/6nbYfc/7CGaMVo67xAc8LGwDNJT2LgLMpnQWVSkrLpZr7ISI432S/vvOywuJFC
|
||||
gQVdslNvVDAwC0KU+0Y0P4CTq2gQYeThODMMstRm0Ui/L/nENUNWCNmNd+WQYx4E
|
||||
8DQfCCLh2u9W7whpYFbaOSQxUzDMRcgZMTzVjU48/oZTagNMEFfYmv5pSQN6Lhf2
|
||||
PvBbYRip3h0sdj1gmFuyGOEl0Mw4AzZyeBohxMNSUQKBgQDXy5A+Cd/8dPM8mL88
|
||||
RtKrV3+Dy+otML1bK7eDN1jJ6XDCmvOAtWIwH2v1quls7uWX54lDDYLs6F2w5+Hz
|
||||
dRnfkMO/JtWInYjLqh1pu5iVPbP+6HVSX6wslMvg8K+M5DOsG/q6J62j6e643o9G
|
||||
fCiNR8rX8V/BdaCvtCBiCtNPjQKBgQC6HOd3302D6PKQSWLJss7QYdEQ5sYesoIu
|
||||
GW6KfJEh6FafJ/fwJoDOH+9klvN9EBJLlXZa/9NM23DqovI/Ca+ABfFjjzea70+U
|
||||
f9UbzaAMl6ENKU7vmAyM2WwHdZPJ4PCQ9J7nBkODzKAm++eQh12iOglcIMKdUPiL
|
||||
72Ygx1bJPQKBgA9Ae/lmiUY2ndpykVGZT9p8XK7cArke8MM428eSadwbe7TFbuBx
|
||||
8XalQeQjKExitid+Xd03X0GPSs/uE7I5XJLIkI06GW2GdNywMVP/xlEGA2rI00H3
|
||||
MRwViDNlz4KNvnkzoQz3MPac2hqG4GmC7PrPUC7jCHmL7sd8W62SRk0hAoGAEwEI
|
||||
kbD3lVSgECOuNrJPc+/JDVTDPjc0G8j1BKcbmr7CuZW3N4p29JVGOJtBWa/ebmFg
|
||||
qIIe7WYq7Yqd+dnfVc9FiskBAI0XLy6ucBxbD24cP9/L86MvBOLeqRRUdvTFG8ge
|
||||
wbBeDINEhzaJurRX10zdz854kN/HwWI8p3QzZHECgYBeDTRyYbi9c7eo6Uyo+pjz
|
||||
bFWyVtAjzjChHa9ifI6GCgs1qakaNBrwb4yOlheEkuakscZY1myzHwHRH1QTQK2c
|
||||
4du0I3/JFkk1JmYXw1VLo/BKs2S6RGBx+4jE5bkSXrxnQmT0EtbexkfIJHEAlIqU
|
||||
DMmi7yrQo4dydJ20IHEF6A==
|
||||
-----END PRIVATE KEY-----
|
||||
148
main/rf_433.c
148
main/rf_433.c
@@ -37,10 +37,11 @@ typedef struct {
|
||||
size_t num_symbols;
|
||||
} rf_code_t;
|
||||
|
||||
// Global queue for passing decoded codes between tasks
|
||||
static QueueHandle_t g_code_queue = NULL;
|
||||
|
||||
int learn_flag = -1;
|
||||
bool controls_enabled = true;
|
||||
|
||||
// Temporary storage for learned keycodes (not committed to params yet)
|
||||
static int64_t temp_keycodes[NUM_RF_BUTTONS] = {0};
|
||||
|
||||
// For rmt_rx_register_event_callbacks
|
||||
static bool rfrx_done(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *edata, void *udata) {
|
||||
@@ -52,8 +53,8 @@ static bool rfrx_done(rmt_channel_handle_t channel, const rmt_rx_done_event_data
|
||||
|
||||
// Task that receives and decodes RF signals
|
||||
static void rf_433_receiver_task(void* param) {
|
||||
esp_task_wdt_add(NULL);
|
||||
esp_log_level_set("rmt", ESP_LOG_NONE); // disable rmt messages about hw buffer too small
|
||||
esp_task_wdt_add(NULL);
|
||||
esp_log_level_set("rmt", ESP_LOG_NONE); // disable rmt messages about hw buffer too small
|
||||
const uint16_t tlow = (P_HIGH - P_LOW - (2 * P_MARGIN));
|
||||
const uint16_t thigh = (P_HIGH - P_LOW + (2 * P_MARGIN));
|
||||
|
||||
@@ -130,45 +131,38 @@ static void rf_433_receiver_task(void* param) {
|
||||
}
|
||||
}
|
||||
|
||||
// If we got a valid code, send it to processing task
|
||||
// If we got a valid code, process it
|
||||
if (code) {
|
||||
int64_t encoded = ((int64_t)len << 56) | code;
|
||||
|
||||
ESP_LOGI(TAG, "GOT KEYCODE 0x%lx [%d]", (long) code, len);
|
||||
|
||||
if (learn_flag >= 0) {
|
||||
set_param_value_t(PARAM_KEYCODE_0 + learn_flag,
|
||||
(param_value_t){.i64 = encoded});
|
||||
ESP_LOGI(TAG, "LEARNED KEYCODE");
|
||||
learn_flag = -1;
|
||||
} else {
|
||||
rf_code_t rf_msg = {
|
||||
.code = code,
|
||||
.high_avg = high / 24,
|
||||
.low_avg = low / 24,
|
||||
.errors = err,
|
||||
.num_symbols = len
|
||||
};
|
||||
|
||||
// Don't do this anymore. No need to pass data between threads. Just act on it.
|
||||
// Non-blocking send - if queue is full, just drop it
|
||||
//xQueueSend(g_code_queue, &rf_msg, 0);
|
||||
|
||||
|
||||
for (uint8_t i = 0; i < NUM_RF_BUTTONS; i++) {
|
||||
int64_t match = get_param_value_t(PARAM_KEYCODE_0+i).i64;
|
||||
if (encoded == match) {
|
||||
switch (i) {
|
||||
case 0: pulseOverride(RELAY_A1); pulseOverride(RELAY_A3); break;
|
||||
case 1: pulseOverride(RELAY_B1); pulseOverride(RELAY_A3); break;
|
||||
case 2: pulseOverride(RELAY_A2); break;
|
||||
case 3: pulseOverride(RELAY_B2); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ESP_LOGI(TAG, "GOT KEYCODE 0x%lx [%d]", (long) code, len);
|
||||
|
||||
if (learn_flag >= 0) {
|
||||
// Store to temporary storage, not to params yet
|
||||
temp_keycodes[learn_flag] = (uint32_t)code;
|
||||
ESP_LOGI(TAG, "LEARNED KEYCODE (temp storage)");
|
||||
learn_flag = -1;
|
||||
} else if (controls_enabled) {
|
||||
// Only process RF commands if controls are enabled
|
||||
rf_code_t rf_msg = {
|
||||
.code = code,
|
||||
.high_avg = high / 24,
|
||||
.low_avg = low / 24,
|
||||
.errors = err,
|
||||
.num_symbols = len
|
||||
};
|
||||
|
||||
for (uint8_t i = 0; i < NUM_RF_BUTTONS; i++) {
|
||||
uint32_t match = get_param_value_t(PARAM_KEYCODE_0+i).u32;
|
||||
// Compare just the code (lower 32 bits)
|
||||
if ((uint32_t)match == code && code!=0) {
|
||||
switch (i) {
|
||||
case 0: pulseOverride(RELAY_A1); pulseOverride(RELAY_A3); break;
|
||||
case 1: pulseOverride(RELAY_B1); pulseOverride(RELAY_A3); break;
|
||||
case 2: pulseOverride(RELAY_A2); break;
|
||||
case 3: pulseOverride(RELAY_B2); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,11 +197,10 @@ static void rf_433_receiver_task(void* param) {
|
||||
}
|
||||
|
||||
// Start next receive
|
||||
|
||||
rmt_receive(rx_channel, symbols, sizeof(symbols), &rx_config);
|
||||
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
|
||||
// Cleanup (never reached in this case)
|
||||
@@ -216,53 +209,46 @@ static void rf_433_receiver_task(void* param) {
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
esp_err_t rf_433_init() {
|
||||
g_code_queue = xQueueCreate(5, sizeof(rf_code_t));
|
||||
assert(g_code_queue);
|
||||
|
||||
esp_err_t rf_433_init() {
|
||||
xTaskCreate(rf_433_receiver_task, TAG, 4096, NULL, 10, NULL);
|
||||
|
||||
return ESP_OK;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rf_433_stop() { return ESP_OK; }
|
||||
|
||||
void rf_433_set_keycode(uint8_t index, int64_t code) {
|
||||
set_param_value_t(PARAM_KEYCODE_0+index, (param_value_t){.i64=code});
|
||||
void rf_433_set_keycode(uint8_t index, uint32_t code) {
|
||||
set_param_value_t(PARAM_KEYCODE_0+index, (param_value_t){.u32=code});
|
||||
}
|
||||
|
||||
void rf_433_learn_keycode(uint8_t index) {
|
||||
if (index >= 8) return;
|
||||
learn_flag = index;
|
||||
if (index >= 8) return;
|
||||
learn_flag = index;
|
||||
}
|
||||
|
||||
void rf_433_cancel_learn_keycode() {
|
||||
learn_flag = -1;
|
||||
learn_flag = -1;
|
||||
}
|
||||
|
||||
/*int8_t rf_433_get_keycode() {
|
||||
rf_code_t received_code;
|
||||
|
||||
if (xQueueReceive(g_code_queue, &received_code, 0) == pdPASS) {
|
||||
int64_t newcode = ((int64_t)received_code.num_symbols << 56) | received_code.code;
|
||||
|
||||
for (uint8_t i = 0; i < NUM_RF_BUTTONS; i++) {
|
||||
if (newcode == get_param_value_t(PARAM_KEYCODE_0+i).i64)
|
||||
return i;
|
||||
}
|
||||
ESP_LOGI("RF", "Received unknown code 0x%08lx (%d) [0x%16llx]", (unsigned long)received_code.code, received_code.num_symbols, (unsigned long long) newcode);
|
||||
}
|
||||
return -1;
|
||||
void rf_433_disable_controls() {
|
||||
controls_enabled = false;
|
||||
}
|
||||
|
||||
int64_t rf_433_get_raw_keycode() {
|
||||
rf_code_t received_code;
|
||||
int64_t code = -1;
|
||||
if (xQueueReceive(g_code_queue, &received_code, 0) == pdPASS) {
|
||||
code = ((int64_t)received_code.num_symbols << 56) | received_code.code;
|
||||
//ESP_LOGI("RF", "Raw Code 0x%08lx (%d) [0x%16llx]", (unsigned long)received_code.code, received_code.num_symbols, (unsigned long long) code);
|
||||
void rf_433_enable_controls() {
|
||||
controls_enabled = true;
|
||||
}
|
||||
|
||||
int32_t rf_433_get_temp_keycode(uint8_t index) {
|
||||
if (index >= NUM_RF_BUTTONS) return 0;
|
||||
return temp_keycodes[index];
|
||||
}
|
||||
|
||||
void rf_433_set_temp_keycode(uint8_t index, uint32_t code) {
|
||||
if (index >= NUM_RF_BUTTONS) return;
|
||||
temp_keycodes[index] = code;
|
||||
}
|
||||
|
||||
void rf_433_clear_temp_keycodes() {
|
||||
for (uint8_t i = 0; i < NUM_RF_BUTTONS; i++) {
|
||||
temp_keycodes[i] = 0;
|
||||
}
|
||||
return code;
|
||||
}*/
|
||||
|
||||
void rf_433_clear_queue() {
|
||||
xQueueReset(g_code_queue);
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
#ifndef RF_H
|
||||
#define RF_H
|
||||
|
||||
@@ -17,7 +16,7 @@ int64_t recieveKeycode();
|
||||
esp_err_t rf_433_init();
|
||||
esp_err_t rf_433_stop();
|
||||
|
||||
void rf_433_set_keycode(uint8_t index, int64_t code);
|
||||
void rf_433_set_keycode(uint8_t index, uint32_t code);
|
||||
|
||||
/*
|
||||
int8_t rf_433_get_keycode();
|
||||
@@ -27,4 +26,11 @@ int64_t rf_433_get_raw_keycode();
|
||||
void rf_433_learn_keycode(uint8_t index);
|
||||
void rf_433_cancel_learn_keycode();
|
||||
|
||||
void rf_433_disable_controls();
|
||||
void rf_433_enable_controls();
|
||||
|
||||
int32_t rf_433_get_temp_keycode(uint8_t index);
|
||||
void rf_433_set_temp_keycode(uint8_t index, uint32_t code);
|
||||
void rf_433_clear_temp_keycodes();
|
||||
|
||||
#endif
|
||||
76
main/rtc.c
76
main/rtc.c
@@ -67,13 +67,13 @@ esp_err_t rtc_xtal_init(void) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void reset_shutdown_timer(void)
|
||||
void rtc_reset_shutdown_timer(void)
|
||||
{
|
||||
last_activity_tick = xTaskGetTickCount();
|
||||
rtc_wdt_feed();
|
||||
}
|
||||
|
||||
void enter_deep_sleep(void)
|
||||
void rtc_enter_deep_sleep(void)
|
||||
{
|
||||
//close_current_log();
|
||||
fsm_request(FSM_CMD_STOP);
|
||||
@@ -82,37 +82,32 @@ void enter_deep_sleep(void)
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
|
||||
void rtc_set_time(struct tm *tm) {
|
||||
rtc_set = true;
|
||||
struct timeval tv = { .tv_sec = mktime(tm), .tv_usec = 0 };
|
||||
settimeofday(&tv, NULL);
|
||||
reset_solar_fsm();
|
||||
}
|
||||
|
||||
void rtc_get_time(struct tm *tm)
|
||||
{
|
||||
time_t raw;
|
||||
time(&raw);
|
||||
localtime_r(&raw, tm);
|
||||
}
|
||||
|
||||
int64_t system_rtc_get_raw_time(void)
|
||||
int64_t rtc_get_s(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (int64_t)tv.tv_sec;
|
||||
}
|
||||
|
||||
uint64_t rtc_time_ms(void)
|
||||
|
||||
void rtc_set_s(int64_t tv_sec)
|
||||
{
|
||||
rtc_set = true;
|
||||
settimeofday(&(struct timeval){.tv_sec = tv_sec, .tv_usec=0}, NULL);
|
||||
solar_reset_fsm();
|
||||
rtc_schedule_next_alarm();
|
||||
}
|
||||
|
||||
int64_t rtc_get_ms(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (uint64_t)tv.tv_sec * 1000ULL + tv.tv_usec / 1000ULL;
|
||||
return (int64_t)tv.tv_sec * 1000ULL + tv.tv_usec / 1000ULL;
|
||||
}
|
||||
|
||||
int64_t system_rtc_seconds_into_day(void)
|
||||
int64_t rtc_get_s_in_day(void)
|
||||
{
|
||||
return system_rtc_get_raw_time() % 86400UL;
|
||||
return rtc_get_s() % 86400UL;
|
||||
}
|
||||
|
||||
esp_sleep_wakeup_cause_t rtc_wakeup_cause(void)
|
||||
@@ -129,18 +124,18 @@ esp_sleep_wakeup_cause_t rtc_wakeup_cause(void)
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Unified periodic update */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
void check_shutdown_timer(void)
|
||||
void rtc_check_shutdown_timer(void)
|
||||
{
|
||||
|
||||
TickType_t elapsed = xTaskGetTickCount() - last_activity_tick;
|
||||
if (elapsed * portTICK_PERIOD_MS >= POWER_INACTIVITY_TIMEOUT_MS)
|
||||
enter_deep_sleep();
|
||||
rtc_enter_deep_sleep();
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Time adjustment helpers */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
void adjust_rtc_hour(char *key, int8_t dir)
|
||||
/*void adjust_rtc_hour(char *key, int8_t dir)
|
||||
{
|
||||
struct tm t;
|
||||
rtc_get_time(&t);
|
||||
@@ -162,13 +157,13 @@ void adjust_rtc_min(char *key, int8_t dir)
|
||||
if (t.tm_min < 0) t.tm_min = 59;
|
||||
rtc_set_time(&t);
|
||||
set_next_alarm();
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
void set_next_alarm(void) {
|
||||
int8_t start_h = 0; //get_param_i8("sched_start");
|
||||
int8_t end_h = 23; //get_param_i8("sched_end");
|
||||
int8_t num = 0; //get_param_i8("sched_num");
|
||||
void rtc_schedule_next_alarm(void) {
|
||||
int64_t start_sec = get_param_value_t(PARAM_MOVE_START).u32;
|
||||
int64_t end_sec = get_param_value_t(PARAM_MOVE_END).u32;
|
||||
int16_t num = get_param_value_t(PARAM_NUM_MOVES).i16;
|
||||
|
||||
if (num <= 0) {
|
||||
next_alarm_time_s = -1;
|
||||
@@ -176,15 +171,12 @@ void set_next_alarm(void) {
|
||||
}
|
||||
|
||||
// Current time info
|
||||
uint32_t s_into_day = system_rtc_seconds_into_day();
|
||||
time_t current_time = system_rtc_get_raw_time();
|
||||
int64_t s_into_day = rtc_get_s_in_day();
|
||||
time_t current_time = rtc_get_s();
|
||||
time_t today_midnight = current_time - s_into_day;
|
||||
|
||||
int start_sec = start_h * 3600;
|
||||
int end_sec = end_h * 3600;
|
||||
|
||||
bool overnight = (start_h > end_h);
|
||||
int total_duration = overnight ? (86400 - start_sec) + end_sec : end_sec - start_sec;
|
||||
bool overnight = (start_sec > end_sec);
|
||||
int64_t total_duration = overnight ? (86400 - start_sec) + end_sec : end_sec - start_sec;
|
||||
|
||||
// Determine period start
|
||||
time_t period_start;
|
||||
@@ -209,7 +201,7 @@ void set_next_alarm(void) {
|
||||
int64_t spacing = total_duration / (num - 1);
|
||||
time_t next_alarm = -1;
|
||||
|
||||
for (int8_t i = 0; i < num; i++) {
|
||||
for (int16_t i = 0; i < num; i++) {
|
||||
time_t alarm_time = period_start + spacing * i;
|
||||
if (alarm_time > current_time) {
|
||||
next_alarm = alarm_time;
|
||||
@@ -227,12 +219,16 @@ void set_next_alarm(void) {
|
||||
ESP_LOGI("ALARM", "SET FOR %lld (in %lld s)", next_alarm_time_s, next_alarm_time_s - current_time);
|
||||
}
|
||||
|
||||
bool alarm_tripped() {
|
||||
int64_t rtc_get_next_alarm_s() {
|
||||
return next_alarm_time_s;
|
||||
}
|
||||
|
||||
bool rtc_alarm_tripped() {
|
||||
if (!rtc_is_set())
|
||||
return false;
|
||||
if (next_alarm_time_s < 0) {
|
||||
set_next_alarm();
|
||||
rtc_schedule_next_alarm();
|
||||
return false;
|
||||
}
|
||||
return system_rtc_get_raw_time() > next_alarm_time_s;
|
||||
return rtc_get_s() > next_alarm_time_s;
|
||||
}
|
||||
23
main/rtc.h
23
main/rtc.h
@@ -16,6 +16,7 @@
|
||||
#include "esp_sleep.h"
|
||||
#include "esp_timer.h"
|
||||
#include "esp_err.h"
|
||||
#include <time.h>
|
||||
|
||||
|
||||
#define POWER_INACTIVITY_TIMEOUT_MS 180000
|
||||
@@ -29,23 +30,23 @@ esp_err_t rtc_xtal_init();
|
||||
|
||||
bool rtc_is_set();
|
||||
|
||||
void set_next_alarm(void);
|
||||
|
||||
void reset_shutdown_timer(); // reset shutoff timer
|
||||
void enter_deep_sleep();
|
||||
void check_shutdown_timer();
|
||||
void rtc_check_shutdown_timer();
|
||||
void rtc_reset_shutdown_timer(); // reset shutoff timer
|
||||
void rtc_enter_deep_sleep();
|
||||
esp_sleep_wakeup_cause_t rtc_wakeup_cause();
|
||||
|
||||
void adjust_rtc_hour(char *key, int8_t dir);
|
||||
void adjust_rtc_min(char *key, int8_t dir);
|
||||
/*void adjust_rtc_hour(char *key, int8_t dir);
|
||||
void adjust_rtc_min(char *key, int8_t dir);*/
|
||||
|
||||
void rtc_get_time(struct tm * timeinfo);
|
||||
int64_t rtc_get_s (void);
|
||||
int64_t rtc_get_ms(void);
|
||||
void rtc_set_s(int64_t);
|
||||
|
||||
int64_t system_rtc_get_raw_time(void);
|
||||
void rtc_schedule_next_alarm(void);
|
||||
int64_t rtc_get_next_alarm_s();
|
||||
|
||||
bool alarm_tripped();
|
||||
|
||||
uint64_t rtc_time_ms();
|
||||
bool rtc_alarm_tripped();
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
#endif /* MAIN_RTC_H_ */
|
||||
@@ -58,7 +58,7 @@ static void sensor_debounce_task(void* param) {
|
||||
|
||||
|
||||
uint8_t i = 0;
|
||||
int64_t now = -1;
|
||||
//int64_t now = -1;
|
||||
|
||||
while (1) {
|
||||
if (xQueueReceive(sensor_event_queue, &evt, pdMS_TO_TICKS(100)) == pdTRUE) {
|
||||
@@ -84,7 +84,7 @@ static void sensor_debounce_task(void* param) {
|
||||
}
|
||||
|
||||
|
||||
now = esp_timer_get_time();
|
||||
//now = esp_timer_get_time();
|
||||
|
||||
/*// Wait for debounce period since last ISR
|
||||
if (now - sensor_last_isr_time[i] >= (DEBOUNCE_TIME_US)) {
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
#define SENSOR_DEBOUNCE_US 500 // Reduced to 0.5 ms for responsiveness
|
||||
|
||||
typedef enum {
|
||||
SENSOR_DRIVE = 0,
|
||||
SENSOR_JACK = 1,
|
||||
N_SENSORS = 2
|
||||
SENSOR_SAFETY = 0,
|
||||
SENSOR_DRIVE = 1,
|
||||
N_SENSORS = 2
|
||||
} sensor_t;
|
||||
|
||||
void reset_sensor_counter(sensor_t i);
|
||||
|
||||
19
main/servercert.pem
Normal file
19
main/servercert.pem
Normal file
@@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDIjCCAgqgAwIBAgIUDpXEqSZ2cdhTBSkwUpC6uSIsfvEwDQYJKoZIhvcNAQEL
|
||||
BQAwEzERMA8GA1UEAwwIc2MubG9jYWwwHhcNMjUxMjMwMTcyMDMwWhcNMzUxMjI4
|
||||
MTcyMDMwWjATMREwDwYDVQQDDAhzYy5sb2NhbDCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBAJziRC6U+YO+PnYeu+BA8ysasyxJB204oU4UFPSju5NddYrb
|
||||
LjxMx3LdEoo1Voi7SeEqmwVIF96TIB6JQkfg3/WKH5vIm1RkneIzJ8Os+gSWYA8F
|
||||
AliSPC8zxX3i6DrjwZXlgXbQL2E07KLtn0Eh1G93cOI17G5jP7cLa9EZb+Ue72vs
|
||||
d0rW7ie/1IXXSNmGN9rQOJ2i0poOu6XnnxCgeyStCTE5BrmEpFwHgqZx5GKGzltT
|
||||
2qeCuB1KVrHQtQGGkEEGyBTGwp2+G3cLhHnkyYCQNa5hi+prxwBfz5dbKUgtGOW+
|
||||
S1mEOtYU6VdtPFKEP1rHfNR+4lGPwnG3T9ItqZkCAwEAAaNuMGwwHQYDVR0OBBYE
|
||||
FICBmIRVzS0CQHS5OZmXSLQcTOz6MB8GA1UdIwQYMBaAFICBmIRVzS0CQHS5OZmX
|
||||
SLQcTOz6MA8GA1UdEwEB/wQFMAMBAf8wGQYDVR0RBBIwEIIIc2MubG9jYWyHBMCo
|
||||
BAEwDQYJKoZIhvcNAQELBQADggEBAIn1zeotOH72CcRUq5e+nsKLRCZSUZV1Gvip
|
||||
nTADfFI8MpMGe0ikPJqetSYmP1HVIzGWQlWamqGhXckBeR9uq1e2k1Jsjf80w6o6
|
||||
ild+fr1oga7n1xwXIMumDbSFjtsWe0fO9xI5NVGP3h6ikj1SN0o6T5EtTyjZ+vGw
|
||||
u73tFmD7c/YBKkvLlP1UxVbAvJFEHL+O7e3QiIzeyryWFDEWRjOHPuPLCV84J5Q6
|
||||
55mzfuUFkf7piLpLUXZ6lJ3MYa+iylll7Z9jQ8W5LWPpZhbTwyK4j7L6IiJoluzL
|
||||
eV0ZuqoHda9Igd+Gigih1YOH4raMc98KVrNIUjNFoWlOx4rvWkY=
|
||||
-----END CERTIFICATE-----
|
||||
143
main/simple_dns_server.c
Normal file
143
main/simple_dns_server.c
Normal file
@@ -0,0 +1,143 @@
|
||||
#include "simple_dns_server.h"
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/netdb.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include <string.h>
|
||||
|
||||
static const char *TAG = "DNS_SERVER";
|
||||
static int dns_socket = -1;
|
||||
static TaskHandle_t dns_task_handle = NULL;
|
||||
static char dns_ip[16] = {0};
|
||||
|
||||
// DNS header structure
|
||||
typedef struct {
|
||||
uint16_t id;
|
||||
uint16_t flags;
|
||||
uint16_t qdcount;
|
||||
uint16_t ancount;
|
||||
uint16_t nscount;
|
||||
uint16_t arcount;
|
||||
} dns_header_t;
|
||||
|
||||
static void dns_server_task(void *pvParameters) {
|
||||
char rx_buffer[512];
|
||||
char tx_buffer[512];
|
||||
struct sockaddr_in dest_addr;
|
||||
|
||||
dest_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
dest_addr.sin_family = AF_INET;
|
||||
dest_addr.sin_port = htons(53);
|
||||
|
||||
dns_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
|
||||
if (dns_socket < 0) {
|
||||
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
int err = bind(dns_socket, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
|
||||
if (err < 0) {
|
||||
ESP_LOGE(TAG, "Socket bind failed: errno %d", errno);
|
||||
close(dns_socket);
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "DNS server started on port 53");
|
||||
|
||||
while (1) {
|
||||
struct sockaddr_in source_addr;
|
||||
socklen_t socklen = sizeof(source_addr);
|
||||
|
||||
int len = recvfrom(dns_socket, rx_buffer, sizeof(rx_buffer) - 1, 0,
|
||||
(struct sockaddr *)&source_addr, &socklen);
|
||||
|
||||
if (len < 0) {
|
||||
ESP_LOGE(TAG, "recvfrom failed: errno %d", errno);
|
||||
break;
|
||||
}
|
||||
|
||||
if (len < sizeof(dns_header_t)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Parse DNS query
|
||||
dns_header_t *header = (dns_header_t *)rx_buffer;
|
||||
|
||||
// Build DNS response
|
||||
memcpy(tx_buffer, rx_buffer, len);
|
||||
dns_header_t *response = (dns_header_t *)tx_buffer;
|
||||
|
||||
// Set response flags
|
||||
response->flags = htons(0x8180); // Standard query response, no error
|
||||
response->ancount = htons(1); // One answer
|
||||
|
||||
// Add answer section (Type A record)
|
||||
int pos = len;
|
||||
|
||||
// Name pointer to question
|
||||
tx_buffer[pos++] = 0xC0;
|
||||
tx_buffer[pos++] = 0x0C;
|
||||
|
||||
// Type A
|
||||
tx_buffer[pos++] = 0x00;
|
||||
tx_buffer[pos++] = 0x01;
|
||||
|
||||
// Class IN
|
||||
tx_buffer[pos++] = 0x00;
|
||||
tx_buffer[pos++] = 0x01;
|
||||
|
||||
// TTL (60 seconds)
|
||||
tx_buffer[pos++] = 0x00;
|
||||
tx_buffer[pos++] = 0x00;
|
||||
tx_buffer[pos++] = 0x00;
|
||||
tx_buffer[pos++] = 0x3C;
|
||||
|
||||
// Data length (4 bytes for IPv4)
|
||||
tx_buffer[pos++] = 0x00;
|
||||
tx_buffer[pos++] = 0x04;
|
||||
|
||||
// IP address
|
||||
int a, b, c, d;
|
||||
sscanf(dns_ip, "%d.%d.%d.%d", &a, &b, &c, &d);
|
||||
tx_buffer[pos++] = a;
|
||||
tx_buffer[pos++] = b;
|
||||
tx_buffer[pos++] = c;
|
||||
tx_buffer[pos++] = d;
|
||||
|
||||
// Send response
|
||||
sendto(dns_socket, tx_buffer, pos, 0,
|
||||
(struct sockaddr *)&source_addr, sizeof(source_addr));
|
||||
}
|
||||
|
||||
close(dns_socket);
|
||||
dns_socket = -1;
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
esp_err_t simple_dns_server_start(const char *ap_ip) {
|
||||
if (dns_task_handle != NULL) {
|
||||
ESP_LOGW(TAG, "DNS server already running");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
strncpy(dns_ip, ap_ip, sizeof(dns_ip) - 1);
|
||||
|
||||
xTaskCreate(dns_server_task, "dns_server", 4096, NULL, 5, &dns_task_handle);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void simple_dns_server_stop(void) {
|
||||
if (dns_task_handle != NULL) {
|
||||
if (dns_socket >= 0) {
|
||||
close(dns_socket);
|
||||
dns_socket = -1;
|
||||
}
|
||||
vTaskDelete(dns_task_handle);
|
||||
dns_task_handle = NULL;
|
||||
ESP_LOGI(TAG, "DNS server stopped");
|
||||
}
|
||||
}
|
||||
19
main/simple_dns_server.h
Normal file
19
main/simple_dns_server.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef SIMPLE_DNS_SERVER_H
|
||||
#define SIMPLE_DNS_SERVER_H
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
/**
|
||||
* @brief Start a simple DNS server that redirects all queries to the AP IP
|
||||
*
|
||||
* @param ap_ip The IP address to return for all DNS queries (e.g., "192.168.4.1")
|
||||
* @return esp_err_t ESP_OK on success
|
||||
*/
|
||||
esp_err_t simple_dns_server_start(const char *ap_ip);
|
||||
|
||||
/**
|
||||
* @brief Stop the DNS server
|
||||
*/
|
||||
void simple_dns_server_stop(void);
|
||||
|
||||
#endif // SIMPLE_DNS_SERVER_H
|
||||
10
main/solar.c
10
main/solar.c
@@ -16,7 +16,7 @@ typedef enum {
|
||||
RTC_DATA_ATTR charge_state_t current_charge_state = CHG_STATE_FLOAT;
|
||||
RTC_DATA_ATTR int64_t timer;
|
||||
|
||||
esp_err_t reset_solar_fsm() {
|
||||
esp_err_t solar_reset_fsm() {
|
||||
timer = -1;
|
||||
current_charge_state = CHG_STATE_FLOAT;
|
||||
return ESP_OK;
|
||||
@@ -32,10 +32,10 @@ esp_err_t init_solar_gpio() {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t run_solar_fsm() {
|
||||
esp_err_t solar_run_fsm() {
|
||||
init_solar_gpio();
|
||||
|
||||
int64_t now = system_rtc_get_raw_time();
|
||||
int64_t now = rtc_get_ms();
|
||||
|
||||
//ESP_LOGI("BAT", "FSM STATE %d", current_charge_state);
|
||||
|
||||
@@ -50,7 +50,7 @@ esp_err_t run_solar_fsm() {
|
||||
//if (rtc_is_set()) {
|
||||
switch(current_charge_state) {
|
||||
case CHG_STATE_BULK:
|
||||
if (now > timer+get_param_value_t(PARAM_CHG_BULK_S).i64) {
|
||||
if (now > timer+get_param_value_t(PARAM_CHG_BULK_S).u32) {
|
||||
current_charge_state = CHG_STATE_FLOAT;
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ esp_err_t run_solar_fsm() {
|
||||
timer = now;
|
||||
}
|
||||
|
||||
if (now > timer+get_param_value_t(PARAM_CHG_LOW_S).i64) {
|
||||
if (now > timer+get_param_value_t(PARAM_CHG_LOW_S).u32) {
|
||||
timer = now;
|
||||
current_charge_state = CHG_STATE_BULK;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
esp_err_t run_solar_fsm();
|
||||
esp_err_t reset_solar_fsm();
|
||||
esp_err_t solar_run_fsm();
|
||||
esp_err_t solar_reset_fsm();
|
||||
|
||||
#endif /* MAIN_SOLAR_H_ */
|
||||
|
||||
452
main/storage.c
452
main/storage.c
@@ -1,9 +1,13 @@
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include "esp_partition.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_crc.h"
|
||||
#include "storage.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "version.h"
|
||||
|
||||
#define TAG "STORAGE"
|
||||
|
||||
@@ -17,43 +21,68 @@
|
||||
#define PARAM_NAME_STR(name) #name
|
||||
|
||||
// Generate parameter table with live values (initialized to defaults)
|
||||
#define PARAM_DEF(name, type, default_val) PARAM_VALUE_INIT(type, default_val),
|
||||
#define PARAM_DEF(name, type, default_val, unit) PARAM_VALUE_INIT(type, default_val),
|
||||
param_value_t parameter_table[NUM_PARAMS] = {
|
||||
PARAM_LIST
|
||||
};
|
||||
#undef PARAM_DEF
|
||||
|
||||
// Generate default values array
|
||||
#define PARAM_DEF(name, type, default_val) PARAM_VALUE_INIT(type, default_val),
|
||||
#define PARAM_DEF(name, type, default_val, unit) PARAM_VALUE_INIT(type, default_val),
|
||||
const param_value_t parameter_defaults[NUM_PARAMS] = {
|
||||
PARAM_LIST
|
||||
};
|
||||
#undef PARAM_DEF
|
||||
|
||||
// Generate parameter types array
|
||||
#define PARAM_DEF(name, type, default_val) PARAM_TYPE_ENUM(type),
|
||||
#define PARAM_DEF(name, type, default_val, unit) PARAM_TYPE_ENUM(type),
|
||||
const param_type_e parameter_types[NUM_PARAMS] = {
|
||||
PARAM_LIST
|
||||
};
|
||||
#undef PARAM_DEF
|
||||
|
||||
// Generate parameter names array
|
||||
#define PARAM_DEF(name, type, default_val) PARAM_NAME_STR(name),
|
||||
#define PARAM_DEF(name, type, default_val, unit) PARAM_NAME_STR(name),
|
||||
const char* parameter_names[NUM_PARAMS] = {
|
||||
PARAM_LIST
|
||||
};
|
||||
#undef PARAM_DEF
|
||||
|
||||
// Generate parameter units array (8 chars max per unit)
|
||||
#define PARAM_DEF(name, type, default_val, unit) unit,
|
||||
const char parameter_units[NUM_PARAMS][8] = {
|
||||
PARAM_LIST
|
||||
};
|
||||
#undef PARAM_DEF
|
||||
|
||||
// Partition pointer
|
||||
static const esp_partition_t *storage_partition = NULL;
|
||||
|
||||
// Log head tracking
|
||||
// Log head tracking with mutex protection
|
||||
static uint32_t log_head_index = 0;
|
||||
static uint32_t log_tail_index = 0;
|
||||
static SemaphoreHandle_t log_mutex = NULL;
|
||||
static bool log_initialized = false;
|
||||
|
||||
// Calculate offset for log area (after parameters sector)
|
||||
#define LOG_START_OFFSET FLASH_SECTOR_SIZE
|
||||
uint32_t get_log_head(void) {
|
||||
uint32_t head;
|
||||
if (log_mutex) xSemaphoreTake(log_mutex, portMAX_DELAY);
|
||||
head = LOG_START_OFFSET + (log_head_index * LOG_ENTRY_SIZE);
|
||||
if (log_mutex) xSemaphoreGive(log_mutex);
|
||||
return head;
|
||||
}
|
||||
|
||||
uint32_t get_log_tail(void) {
|
||||
uint32_t tail;
|
||||
if (log_mutex) xSemaphoreTake(log_mutex, portMAX_DELAY);
|
||||
tail = LOG_START_OFFSET + (log_tail_index * LOG_ENTRY_SIZE);
|
||||
if (log_mutex) xSemaphoreGive(log_mutex);
|
||||
return tail;
|
||||
}
|
||||
|
||||
uint32_t get_log_offset(void) {
|
||||
return LOG_START_OFFSET;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// PARAMETER FUNCTIONS
|
||||
@@ -78,13 +107,101 @@ esp_err_t set_param_value_t(param_idx_t id, param_value_t val) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t set_param_string(param_idx_t id, const char* str) {
|
||||
if (id >= NUM_PARAMS) {
|
||||
ESP_LOGE(TAG, "Invalid parameter ID: %d", id);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (parameter_types[id] != PARAM_TYPE_str) {
|
||||
ESP_LOGE(TAG, "Parameter %d (%s) is not a string type", id, parameter_names[id]);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (str == NULL) {
|
||||
parameter_table[id].str[0] = '\0';
|
||||
} else {
|
||||
strncpy(parameter_table[id].str, str, 15);
|
||||
parameter_table[id].str[15] = '\0'; // Ensure null termination
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "String parameter %d (%s) set to '%s' (not committed)",
|
||||
id, parameter_names[id], parameter_table[id].str);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
char* get_param_string(param_idx_t id) {
|
||||
if (id >= NUM_PARAMS) {
|
||||
ESP_LOGE(TAG, "Invalid parameter ID: %d", id);
|
||||
return "";
|
||||
}
|
||||
|
||||
if (parameter_types[id] != PARAM_TYPE_str) {
|
||||
ESP_LOGE(TAG, "Parameter %d (%s) is not a string type", id, parameter_names[id]);
|
||||
return "";
|
||||
}
|
||||
|
||||
return parameter_table[id].str;
|
||||
}
|
||||
|
||||
param_type_e get_param_type(param_idx_t id) {
|
||||
if (id >= NUM_PARAMS) {
|
||||
return PARAM_TYPE_u64; // Default fallback
|
||||
return PARAM_TYPE_f64; // Default fallback
|
||||
}
|
||||
return parameter_types[id];
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// JSON-FRIENDLY STRING CONVERSION
|
||||
// ============================================================================
|
||||
const char* get_param_json_string(param_idx_t id, char* buffer, size_t buf_size) {
|
||||
if (id >= NUM_PARAMS || buffer == NULL || buf_size == 0) {
|
||||
if (buffer && buf_size > 0) buffer[0] = '\0';
|
||||
return "";
|
||||
}
|
||||
|
||||
param_type_e type = parameter_types[id];
|
||||
param_value_t val = parameter_table[id];
|
||||
|
||||
switch(type) {
|
||||
case PARAM_TYPE_u16:
|
||||
snprintf(buffer, buf_size, "%u", val.u16);
|
||||
break;
|
||||
case PARAM_TYPE_i16:
|
||||
snprintf(buffer, buf_size, "%d", val.i16);
|
||||
break;
|
||||
case PARAM_TYPE_u32:
|
||||
snprintf(buffer, buf_size, "%lu", (unsigned long)val.u32);
|
||||
break;
|
||||
case PARAM_TYPE_i32:
|
||||
snprintf(buffer, buf_size, "%ld", (long)val.i32);
|
||||
break;
|
||||
case PARAM_TYPE_f32:
|
||||
if (isnan(val.f32) || isinf(val.f32)) {
|
||||
snprintf(buffer, buf_size, "null");
|
||||
} else {
|
||||
snprintf(buffer, buf_size, "%.6g", val.f32);
|
||||
}
|
||||
break;
|
||||
case PARAM_TYPE_f64:
|
||||
if (isnan(val.f64) || isinf(val.f64)) {
|
||||
snprintf(buffer, buf_size, "null");
|
||||
} else {
|
||||
snprintf(buffer, buf_size, "%.15g", val.f64);
|
||||
}
|
||||
break;
|
||||
case PARAM_TYPE_str:
|
||||
// Escape quotes and backslashes for JSON string
|
||||
snprintf(buffer, buf_size, "\"%s\"", val.str);
|
||||
break;
|
||||
default:
|
||||
snprintf(buffer, buf_size, "null");
|
||||
break;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
const char* get_param_name(param_idx_t id) {
|
||||
if (id >= NUM_PARAMS) {
|
||||
return "INVALID";
|
||||
@@ -100,39 +217,164 @@ param_value_t get_param_default(param_idx_t id) {
|
||||
return parameter_defaults[id];
|
||||
}
|
||||
|
||||
esp_err_t commit_params() {
|
||||
const char* get_param_unit(param_idx_t id) {
|
||||
if (id >= NUM_PARAMS) {
|
||||
return "";
|
||||
}
|
||||
return parameter_units[id];
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// STORAGE HELPER: Pack parameter value into buffer
|
||||
// ============================================================================
|
||||
static void pack_param(uint8_t *dest, param_idx_t id) {
|
||||
param_type_e type = parameter_types[id];
|
||||
|
||||
switch(type) {
|
||||
case PARAM_TYPE_u16:
|
||||
memcpy(dest, ¶meter_table[id].u16, 2);
|
||||
break;
|
||||
case PARAM_TYPE_i16:
|
||||
memcpy(dest, ¶meter_table[id].i16, 2);
|
||||
break;
|
||||
case PARAM_TYPE_u32:
|
||||
memcpy(dest, ¶meter_table[id].u32, 4);
|
||||
break;
|
||||
case PARAM_TYPE_i32:
|
||||
memcpy(dest, ¶meter_table[id].i32, 4);
|
||||
break;
|
||||
case PARAM_TYPE_f32:
|
||||
memcpy(dest, ¶meter_table[id].f32, 4);
|
||||
break;
|
||||
case PARAM_TYPE_f64:
|
||||
memcpy(dest, ¶meter_table[id].f64, 8);
|
||||
break;
|
||||
case PARAM_TYPE_str:
|
||||
memcpy(dest, parameter_table[id].str, 16);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// STORAGE HELPER: Unpack parameter value from buffer
|
||||
// ============================================================================
|
||||
static void unpack_param(const uint8_t *src, param_idx_t id) {
|
||||
param_type_e type = parameter_types[id];
|
||||
|
||||
switch(type) {
|
||||
case PARAM_TYPE_u16:
|
||||
memcpy(¶meter_table[id].u16, src, 2);
|
||||
break;
|
||||
case PARAM_TYPE_i16:
|
||||
memcpy(¶meter_table[id].i16, src, 2);
|
||||
break;
|
||||
case PARAM_TYPE_u32:
|
||||
memcpy(¶meter_table[id].u32, src, 4);
|
||||
break;
|
||||
case PARAM_TYPE_i32:
|
||||
memcpy(¶meter_table[id].i32, src, 4);
|
||||
break;
|
||||
case PARAM_TYPE_f32:
|
||||
memcpy(¶meter_table[id].f32, src, 4);
|
||||
break;
|
||||
case PARAM_TYPE_f64:
|
||||
memcpy(¶meter_table[id].f64, src, 8);
|
||||
break;
|
||||
case PARAM_TYPE_str:
|
||||
memcpy(parameter_table[id].str, src, 16);
|
||||
parameter_table[id].str[15] = '\0'; // Ensure null termination
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// COMMIT PARAMETERS TO FLASH
|
||||
// ============================================================================
|
||||
esp_err_t commit_params(void) {
|
||||
if (storage_partition == NULL) {
|
||||
ESP_LOGE(TAG, "Storage partition not initialized");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// Prepare storage buffer with parameters and CRCs
|
||||
param_stored_t params_to_store[NUM_PARAMS];
|
||||
set_param_string(PARAM_BUILD_VERSION, FIRMWARE_VERSION);
|
||||
|
||||
// Calculate flash offset for each parameter
|
||||
uint32_t flash_offset = PARAMS_OFFSET;
|
||||
|
||||
// Erase the parameter sectors
|
||||
esp_err_t err = esp_partition_erase_range(storage_partition, PARAMS_OFFSET,
|
||||
LOG_START_OFFSET);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to erase parameter sectors: %s", esp_err_to_name(err));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// Write each parameter with its CRC
|
||||
for (int i = 0; i < NUM_PARAMS; i++) {
|
||||
params_to_store[i].val = parameter_table[i];
|
||||
// Calculate CRC32 for each parameter value
|
||||
params_to_store[i].crc = esp_crc32_le(0, (uint8_t*)¶meter_table[i], sizeof(param_value_t));
|
||||
}
|
||||
|
||||
// Erase the first sector (4096 bytes)
|
||||
esp_err_t err = esp_partition_erase_range(storage_partition, PARAMS_OFFSET, FLASH_SECTOR_SIZE);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to erase parameter sector: %s", esp_err_to_name(err));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// Write parameters to flash
|
||||
err = esp_partition_write(storage_partition, PARAMS_OFFSET, params_to_store, PARAMS_TOTAL_SIZE);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to write parameters: %s", esp_err_to_name(err));
|
||||
return ESP_FAIL;
|
||||
param_stored_t stored;
|
||||
memset(&stored, 0, sizeof(stored));
|
||||
|
||||
// Pack the parameter value
|
||||
uint8_t size = param_type_size(parameter_types[i]);
|
||||
pack_param(stored.data, i);
|
||||
|
||||
// Calculate CRC over the actual data size used
|
||||
uint32_t crc_input = PARAM_CRC_SALT;
|
||||
//uint32_t crc = esp_crc32_le(0, (uint8_t*)&crc_input, sizeof(crc_input));
|
||||
stored.crc = esp_crc32_le(crc_input, stored.data, size);
|
||||
|
||||
// Write to flash
|
||||
err = esp_partition_write(storage_partition, flash_offset,
|
||||
&stored, sizeof(param_stored_t));
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to write parameter %d (%s): %s",
|
||||
i, parameter_names[i], esp_err_to_name(err));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
flash_offset += sizeof(param_stored_t);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Parameters committed to flash successfully");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// FACTORY RESET
|
||||
// ============================================================================
|
||||
esp_err_t factory_reset(void) {
|
||||
if (storage_partition == NULL) {
|
||||
ESP_LOGE(TAG, "Storage partition not initialized");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
ESP_LOGW(TAG, "FACTORY RESET: Erasing entire storage partition...");
|
||||
|
||||
// Erase the entire storage partition
|
||||
esp_err_t err = esp_partition_erase_range(storage_partition, 0, storage_partition->size);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to erase storage partition: %s", esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Storage partition erased successfully");
|
||||
|
||||
// Reset all parameters to defaults in RAM
|
||||
for (int i = 0; i < NUM_PARAMS; i++) {
|
||||
memcpy(¶meter_table[i], ¶meter_defaults[i], sizeof(param_value_t));
|
||||
}
|
||||
|
||||
// Reset log indices
|
||||
if (log_mutex) xSemaphoreTake(log_mutex, portMAX_DELAY);
|
||||
log_head_index = 0;
|
||||
log_tail_index = 0;
|
||||
if (log_mutex) xSemaphoreGive(log_mutex);
|
||||
|
||||
ESP_LOGI(TAG, "Factory reset complete - all data erased");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// INITIALIZATION FUNCTIONS
|
||||
// ============================================================================
|
||||
@@ -148,31 +390,44 @@ esp_err_t storage_init(void) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Storage partition found: size=%lu bytes", (unsigned long)storage_partition->size);
|
||||
ESP_LOGI(TAG, "Storage partition found: size=%lu bytes",
|
||||
(unsigned long)storage_partition->size);
|
||||
|
||||
// Load parameters from flash
|
||||
param_stored_t params_stored[NUM_PARAMS];
|
||||
esp_err_t err = esp_partition_read(storage_partition, PARAMS_OFFSET,
|
||||
params_stored, PARAMS_TOTAL_SIZE);
|
||||
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Failed to read parameters, using defaults");
|
||||
return err;
|
||||
}
|
||||
|
||||
// Validate and load each parameter
|
||||
uint32_t flash_offset = PARAMS_OFFSET;
|
||||
bool all_valid = true;
|
||||
|
||||
for (int i = 0; i < NUM_PARAMS; i++) {
|
||||
uint32_t calculated_crc = esp_crc32_le(0, (uint8_t*)¶ms_stored[i].val,
|
||||
sizeof(param_value_t));
|
||||
param_stored_t stored;
|
||||
|
||||
if (calculated_crc == params_stored[i].crc) {
|
||||
parameter_table[i] = params_stored[i].val;
|
||||
esp_err_t err = esp_partition_read(storage_partition, flash_offset,
|
||||
&stored, sizeof(param_stored_t));
|
||||
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Failed to read parameter %d (%s), using default",
|
||||
i, parameter_names[i]);
|
||||
memcpy(¶meter_table[i], ¶meter_defaults[i], sizeof(param_value_t)); // SET DEFAULT HERE
|
||||
all_valid = false;
|
||||
flash_offset += sizeof(param_stored_t);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Validate CRC over actual data size
|
||||
uint8_t size = param_type_size(parameter_types[i]);
|
||||
uint32_t crc_input = PARAM_CRC_SALT;
|
||||
//uint32_t crc = esp_crc32_le(0, (uint8_t*)&crc_input, sizeof(crc_input));
|
||||
uint32_t calculated_crc = esp_crc32_le(crc_input, stored.data, size);
|
||||
|
||||
if (calculated_crc == stored.crc) {
|
||||
unpack_param(stored.data, i);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Parameter %d (%s) failed CRC check, using default",
|
||||
i, parameter_names[i]);
|
||||
memcpy(¶meter_table[i], ¶meter_defaults[i], sizeof(param_value_t)); // SET DEFAULT HERE
|
||||
all_valid = false;
|
||||
}
|
||||
|
||||
flash_offset += sizeof(param_stored_t);
|
||||
}
|
||||
|
||||
if (all_valid) {
|
||||
@@ -185,7 +440,7 @@ esp_err_t storage_init(void) {
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// LOGGING FUNCTIONS
|
||||
// LOGGING FUNCTIONS (unchanged from original)
|
||||
// ============================================================================
|
||||
|
||||
static esp_err_t find_log_head(void) {
|
||||
@@ -193,16 +448,13 @@ static esp_err_t find_log_head(void) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
// Calculate total log area size
|
||||
uint32_t log_area_size = storage_partition->size - LOG_START_OFFSET;
|
||||
uint32_t max_entries = log_area_size / LOG_ENTRY_SIZE;
|
||||
|
||||
// Read through entries to find first uninitialized (all 0xFF)
|
||||
uint8_t entry[LOG_ENTRY_SIZE];
|
||||
uint8_t empty_entry[LOG_ENTRY_SIZE];
|
||||
memset(empty_entry, 0xFF, LOG_ENTRY_SIZE);
|
||||
|
||||
// Binary search would be faster, but linear is safer for circular buffer
|
||||
for (uint32_t i = 0; i < max_entries; i++) {
|
||||
uint32_t offset = LOG_START_OFFSET + (i * LOG_ENTRY_SIZE);
|
||||
|
||||
@@ -212,7 +464,6 @@ static esp_err_t find_log_head(void) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// Check if this entry is uninitialized
|
||||
if (memcmp(entry, empty_entry, LOG_ENTRY_SIZE) == 0) {
|
||||
log_head_index = i;
|
||||
ESP_LOGI(TAG, "Log head found at index %lu", (unsigned long)log_head_index);
|
||||
@@ -220,11 +471,9 @@ static esp_err_t find_log_head(void) {
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here, all entries are full - wrap to beginning
|
||||
log_head_index = 0;
|
||||
ESP_LOGI(TAG, "Log is full, wrapping to beginning");
|
||||
|
||||
// Erase the first log sector to start fresh
|
||||
esp_err_t err = esp_partition_erase_range(storage_partition, LOG_START_OFFSET,
|
||||
FLASH_SECTOR_SIZE);
|
||||
if (err != ESP_OK) {
|
||||
@@ -241,8 +490,16 @@ esp_err_t log_init(void) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
log_mutex = xSemaphoreCreateMutex();
|
||||
if (log_mutex == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to create log mutex");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
esp_err_t err = find_log_head();
|
||||
if (err != ESP_OK) {
|
||||
vSemaphoreDelete(log_mutex);
|
||||
log_mutex = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -256,64 +513,121 @@ esp_err_t write_log(char* entry) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (log_mutex) xSemaphoreTake(log_mutex, portMAX_DELAY);
|
||||
|
||||
uint32_t log_area_end = storage_partition->size;
|
||||
uint32_t max_entries = (log_area_end - LOG_START_OFFSET) / LOG_ENTRY_SIZE;
|
||||
//uint32_t max_sectors = max_entries / FLASH_SECTOR_SIZE;
|
||||
|
||||
// Calculate current offset
|
||||
uint32_t current_offset = LOG_START_OFFSET + (log_head_index * LOG_ENTRY_SIZE);
|
||||
|
||||
// Check if we need to erase the next sector
|
||||
uint32_t current_sector = current_offset / FLASH_SECTOR_SIZE;
|
||||
uint32_t next_offset = current_offset + LOG_ENTRY_SIZE;
|
||||
if (next_offset >= log_area_end)
|
||||
next_offset = LOG_START_OFFSET;
|
||||
if (next_offset >= log_area_end) {
|
||||
next_offset = LOG_START_OFFSET;
|
||||
}
|
||||
|
||||
uint32_t current_sector = current_offset / FLASH_SECTOR_SIZE;
|
||||
uint32_t next_sector = next_offset / FLASH_SECTOR_SIZE;
|
||||
|
||||
// If we're crossing into a new sector, check if it needs erasing
|
||||
if (next_sector != current_sector) {
|
||||
// Check if next sector is uninitialized
|
||||
uint8_t check_byte;
|
||||
esp_err_t err = esp_partition_read(storage_partition, next_sector * FLASH_SECTOR_SIZE,
|
||||
&check_byte, 1);
|
||||
|
||||
if (err == ESP_OK && check_byte != 0xFF) {
|
||||
// Sector needs erasing
|
||||
ESP_LOGI(TAG, "Erasing sector %lu for log", (unsigned long)next_sector);
|
||||
err = esp_partition_erase_range(storage_partition,
|
||||
next_sector * FLASH_SECTOR_SIZE,
|
||||
FLASH_SECTOR_SIZE);
|
||||
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to erase sector: %s", esp_err_to_name(err));
|
||||
if (log_mutex) xSemaphoreGive(log_mutex);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
} else if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Next sector %ld clear, no erasing needed", (unsigned long)next_sector);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Error checking byte (sector %ld)", (unsigned long)next_sector);
|
||||
}
|
||||
|
||||
uint32_t tail_offset = next_sector * FLASH_SECTOR_SIZE;
|
||||
if (tail_offset < LOG_START_OFFSET) {
|
||||
tail_offset = LOG_START_OFFSET;
|
||||
}
|
||||
log_tail_index = (tail_offset - LOG_START_OFFSET) / LOG_ENTRY_SIZE;
|
||||
|
||||
if (log_tail_index >= max_entries) {
|
||||
log_tail_index = 0;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Tail/Head are now %ld/%ld", (long)log_tail_index, (long)log_head_index);
|
||||
}
|
||||
}
|
||||
|
||||
// Write the log entry
|
||||
esp_err_t err = esp_partition_write(storage_partition, current_offset, entry, LOG_ENTRY_SIZE);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to write log entry: %s", esp_err_to_name(err));
|
||||
if (log_mutex) xSemaphoreGive(log_mutex);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
//ESP_LOGI(TAG, "Log @ sector %lu / index %lu / offset %lu", (unsigned long) current_sector, (unsigned long) log_head_index, (unsigned long)current_offset);
|
||||
|
||||
|
||||
log_head_index++;
|
||||
if (log_head_index >= max_entries) {
|
||||
log_head_index = 0;
|
||||
ESP_LOGI(TAG, "Log wrapped to beginning");
|
||||
}
|
||||
|
||||
if (log_mutex) xSemaphoreGive(log_mutex);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t write_dummy_log_1(void) {
|
||||
if (log_mutex) xSemaphoreTake(log_mutex, portMAX_DELAY);
|
||||
log_head_index = 0;
|
||||
log_tail_index = 0;
|
||||
if (log_mutex) xSemaphoreGive(log_mutex);
|
||||
|
||||
uint32_t log_area_end = storage_partition->size;
|
||||
uint32_t max_entries = (log_area_end - LOG_START_OFFSET) / LOG_ENTRY_SIZE;
|
||||
for (uint32_t i=0; i<max_entries*3/2; i++) {
|
||||
ESP_LOGI(TAG, "log[%ld]", (long)i);
|
||||
char entry[32] = {32, i>>24,i>>16,i>>8,i>>0};
|
||||
write_log(entry);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t write_dummy_log_2(void) {
|
||||
if (log_mutex) xSemaphoreTake(log_mutex, portMAX_DELAY);
|
||||
log_head_index = 56;
|
||||
log_tail_index = 105;
|
||||
if (log_mutex) xSemaphoreGive(log_mutex);
|
||||
|
||||
uint32_t log_area_end = storage_partition->size;
|
||||
uint32_t max_entries = (log_area_end - LOG_START_OFFSET) / LOG_ENTRY_SIZE;
|
||||
for (uint32_t i=0; i<max_entries*3/2; i++) {
|
||||
ESP_LOGI(TAG, "log[%ld]", (long)i);
|
||||
char entry[32] = {32, i>>24,i>>16,i>>8,i>>0};
|
||||
write_log(entry);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t write_dummy_log_3(void) {
|
||||
if (log_mutex) xSemaphoreTake(log_mutex, portMAX_DELAY);
|
||||
log_head_index = 105;
|
||||
log_tail_index = 34;
|
||||
if (log_mutex) xSemaphoreGive(log_mutex);
|
||||
|
||||
uint32_t log_area_end = storage_partition->size;
|
||||
uint32_t max_entries = (log_area_end - LOG_START_OFFSET) / LOG_ENTRY_SIZE;
|
||||
for (uint32_t i=0; i<max_entries*3/2; i++) {
|
||||
ESP_LOGI(TAG, "log[%ld]", (long)i);
|
||||
char entry[32] = {32, i>>24,i>>16,i>>8,i>>0};
|
||||
write_log(entry);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void storage_deinit(void) {
|
||||
storage_partition = NULL;
|
||||
log_initialized = false;
|
||||
if (log_mutex) {
|
||||
vSemaphoreDelete(log_mutex);
|
||||
log_mutex = NULL;
|
||||
}
|
||||
}
|
||||
179
main/storage.h
179
main/storage.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* storage.h
|
||||
* storage.h - Simple variable-size parameter storage with per-param CRC
|
||||
*
|
||||
* Created on: Nov 5, 2025
|
||||
* Author: Thad
|
||||
@@ -17,127 +17,164 @@
|
||||
#include <stdarg.h>
|
||||
#include "i2c.h"
|
||||
|
||||
#define PARAM_CRC_SALT 0xDEADBEEF // Salt to prevent all-zero CRC collision
|
||||
|
||||
// Union for parameter values - now sized appropriately
|
||||
typedef union {
|
||||
uint8_t u8;
|
||||
int8_t i8;
|
||||
uint16_t u16;
|
||||
int16_t i16;
|
||||
uint32_t u32;
|
||||
int32_t i32;
|
||||
uint64_t u64;
|
||||
int64_t i64;
|
||||
float f32;
|
||||
double f64;
|
||||
char str[16]; // 15 chars + null terminator
|
||||
} param_value_t;
|
||||
|
||||
typedef struct {
|
||||
param_value_t val;
|
||||
uint32_t crc;
|
||||
// Enum for parameter types
|
||||
typedef enum {
|
||||
PARAM_TYPE_u16 = 0,
|
||||
PARAM_TYPE_i16 = 1,
|
||||
PARAM_TYPE_u32 = 2,
|
||||
PARAM_TYPE_i32 = 3,
|
||||
PARAM_TYPE_f32 = 6,
|
||||
PARAM_TYPE_f64 = 7,
|
||||
PARAM_TYPE_str = 8
|
||||
} param_type_e;
|
||||
|
||||
// Storage format: each param stored as [data][crc32]
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t data[16]; // Max size needed (for strings)
|
||||
uint32_t crc; // CRC of actual data bytes used
|
||||
} param_stored_t;
|
||||
|
||||
typedef enum {
|
||||
PARAM_TYPE_u8,
|
||||
PARAM_TYPE_i8,
|
||||
PARAM_TYPE_u16,
|
||||
PARAM_TYPE_i16,
|
||||
PARAM_TYPE_u32,
|
||||
PARAM_TYPE_i32,
|
||||
PARAM_TYPE_u64,
|
||||
PARAM_TYPE_i64,
|
||||
PARAM_TYPE_f32,
|
||||
PARAM_TYPE_f64
|
||||
} param_type_e;
|
||||
// Get storage size for a given type (data only, not including CRC)
|
||||
static inline uint8_t param_type_size(param_type_e type) {
|
||||
switch(type) {
|
||||
case PARAM_TYPE_u16:
|
||||
case PARAM_TYPE_i16: return 2;
|
||||
case PARAM_TYPE_u32:
|
||||
case PARAM_TYPE_i32:
|
||||
case PARAM_TYPE_f32: return 4;
|
||||
case PARAM_TYPE_f64: return 8;
|
||||
case PARAM_TYPE_str: return 16;
|
||||
default: return 8; // Fallback
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// PARAMETER DEFINITION MACRO
|
||||
// ============================================================================
|
||||
// Usage: PARAM_DEF(NAME, TYPE, DEFAULT_VALUE)
|
||||
// Usage: PARAM_DEF(NAME, TYPE, DEFAULT_VALUE, UNIT)
|
||||
//
|
||||
// Examples:
|
||||
// PARAM_DEF(NUM_MOVES, u32, 0)
|
||||
// PARAM_DEF(EFUSE_1_AS, u16, 2400)
|
||||
// PARAM_DEF(JACK_DIST, u8, 5)
|
||||
// PARAM_DEF(KEYCODE_0, i64, -1)
|
||||
// PARAM_DEF(TEMPERATURE, f32, 25.5)
|
||||
// PARAM_DEF(NUM_MOVES, u32, 0, "")
|
||||
// PARAM_DEF(EFUSE_1_AS, u16, 2400, "mA")
|
||||
// PARAM_DEF(KEYCODE_0, i64, -1, "")
|
||||
// PARAM_DEF(TEMPERATURE, f32, 25.5, "C")
|
||||
// PARAM_DEF(DEVICE_NAME, str, "ESP32", "")
|
||||
// ============================================================================
|
||||
// REMEMBER: ORDER IS IMPERATIVE! PARAMETERS ARE ENTERED IN THE TABLE BY INDEX!
|
||||
// ============================================================================
|
||||
|
||||
#define PARAM_LIST \
|
||||
PARAM_DEF(NUM_MOVES, u32, 0) \
|
||||
PARAM_DEF(MOVE_START, u32, 0) \
|
||||
PARAM_DEF(MOVE_END, u32, 0) \
|
||||
PARAM_DEF(DRIVE_DIST, u16, 10) /*3*/\
|
||||
PARAM_DEF(JACK_DIST, u8, 5) \
|
||||
PARAM_DEF(DRIVE_TPDF, u16, 4000) \
|
||||
PARAM_DEF(DRIVE_MSPF, u16, 600) \
|
||||
PARAM_DEF(JACK_MSPI, u16, 600) /*7*/\
|
||||
PARAM_DEF(KEYCODE_0, i64, 0x19000000005D0C61) \
|
||||
PARAM_DEF(KEYCODE_1, i64, 0x19000000005D0C62) \
|
||||
PARAM_DEF(KEYCODE_2, i64, 0x19000000005D0C64) \
|
||||
PARAM_DEF(KEYCODE_3, i64, 0x19000000005D0C68) /*11*/\
|
||||
PARAM_DEF(KEYCODE_4, i64, -1) \
|
||||
PARAM_DEF(KEYCODE_5, i64, -1) \
|
||||
PARAM_DEF(KEYCODE_6, i64, -1) \
|
||||
PARAM_DEF(KEYCODE_7, i64, -1) /*15*/\
|
||||
PARAM_DEF(ADC_ALPHA_BATTERY, f32, 0.02) \
|
||||
PARAM_DEF(ADC_ALPHA_ISENS, f32, 0.02) \
|
||||
PARAM_DEF(ADC_ALPHA_IAZ, f32, 0.005) \
|
||||
PARAM_DEF(ADC_DB_IAZ, f32, 5.0) /*19*/\
|
||||
PARAM_DEF(EFUSE_INOM_1, f32, 40.0) \
|
||||
PARAM_DEF(EFUSE_INOM_2, f32, 6.0) \
|
||||
PARAM_DEF(EFUSE_INOM_3, f32, 2.0) \
|
||||
PARAM_DEF(EFUSE_HEAT_THRESH, f32, 60.0) /*23*/\
|
||||
PARAM_DEF(EFUSE_KINST, f32, 4.0) \
|
||||
PARAM_DEF(EFUSE_TAUCOOL, f32, 0.2) \
|
||||
PARAM_DEF(EFUSE_TCOOL, i64, 5000000) \
|
||||
PARAM_DEF(LOW_PROTECTION_V, f32, 10.0) /*27*/\
|
||||
PARAM_DEF(LOW_PROTECTION_S, i64, 10) \
|
||||
PARAM_DEF(CHG_LOW_V, f32, 5.0) \
|
||||
PARAM_DEF(CHG_LOW_S, i64, 5.0) \
|
||||
PARAM_DEF(CHG_BULK_S, i64, 20) /*31*/\
|
||||
PARAM_DEF(RF_PULSE_LENGTH, u64, 350000) \
|
||||
|
||||
|
||||
PARAM_DEF(BOOT_TIME, i32, 0, "us") \
|
||||
PARAM_DEF(NUM_MOVES, u32, 0, "") \
|
||||
PARAM_DEF(MOVE_START, u32, 0, "s") \
|
||||
PARAM_DEF(MOVE_END, u32, 0, "s") \
|
||||
PARAM_DEF(DRIVE_DIST, f32, 10, "ft") \
|
||||
PARAM_DEF(JACK_DIST, f32, 5, "in") \
|
||||
PARAM_DEF(DRIVE_KE, f32, 29.2, "n/ft") \
|
||||
PARAM_DEF(DRIVE_KT, f32, 2880000, "us/ft") \
|
||||
PARAM_DEF(JACK_KT, f32, 1428571, "ms/in") \
|
||||
PARAM_DEF(KEYCODE_0, u32, 0, "") \
|
||||
PARAM_DEF(KEYCODE_1, u32, 0, "") \
|
||||
PARAM_DEF(KEYCODE_2, u32, 0, "") \
|
||||
PARAM_DEF(KEYCODE_3, u32, 0, "") \
|
||||
PARAM_DEF(KEYCODE_4, u32, 0, "") \
|
||||
PARAM_DEF(KEYCODE_5, u32, 0, "") \
|
||||
PARAM_DEF(KEYCODE_6, u32, 0, "") \
|
||||
PARAM_DEF(KEYCODE_7, u32, 0, "") \
|
||||
PARAM_DEF(ADC_ALPHA_BATTERY, f32, 0.5, "-") \
|
||||
PARAM_DEF(ADC_ALPHA_ISENS, f32, 0.6, "-") \
|
||||
PARAM_DEF(ADC_ALPHA_IAZ, f32, 0.005, "-") \
|
||||
PARAM_DEF(ADC_DB_IAZ, f32, 5.0, "A") \
|
||||
PARAM_DEF(EFUSE_INOM_1, f32, 40.0, "A") \
|
||||
PARAM_DEF(EFUSE_INOM_2, f32, 6.0, "A") \
|
||||
PARAM_DEF(EFUSE_INOM_3, f32, 4.0, "A") \
|
||||
PARAM_DEF(EFUSE_HEAT_THRESH, f32, 60.0, "i/i^2-s") \
|
||||
PARAM_DEF(EFUSE_KINST, f32, 5.0, "i/i") \
|
||||
PARAM_DEF(EFUSE_TAUCOOL, f32, 0.2, "i") \
|
||||
PARAM_DEF(EFUSE_TCOOL, u32, 5000000, "us") \
|
||||
PARAM_DEF(LOW_PROTECTION_V, f32, 10.0, "V") \
|
||||
PARAM_DEF(LOW_PROTECTION_S, u32, 10, "s") \
|
||||
PARAM_DEF(CHG_LOW_V, f32, 5.0, "V") \
|
||||
PARAM_DEF(CHG_LOW_S, u32, 5, "s") \
|
||||
PARAM_DEF(CHG_BULK_S, u32, 20, "s") \
|
||||
PARAM_DEF(RF_PULSE_LENGTH, u32, 350000, "us") \
|
||||
PARAM_DEF(V_SENS_OFFSET, f32, 0.4, "V") \
|
||||
PARAM_DEF(WIFI_CHANNEL, u16, 6, "") \
|
||||
PARAM_DEF(WIFI_SSID, str, "sc.local", "") \
|
||||
PARAM_DEF(WIFI_PASS, str, "password", "") \
|
||||
PARAM_DEF(EFUSE_INRUSH_US, u32, 300000, "us") \
|
||||
PARAM_DEF(JACK_I_UP, f32, 5.0, "A") \
|
||||
PARAM_DEF(JACK_I_DOWN, f32, 8.0, "A") \
|
||||
PARAM_DEF(V_SENS_K, f32, 0.00766666666, "V/mV") \
|
||||
PARAM_DEF(BUILD_VERSION, str, "undefined", "") \
|
||||
|
||||
|
||||
// Generate enum for parameter indices
|
||||
#define PARAM_DEF(name, type, default_val) PARAM_##name,
|
||||
#define PARAM_DEF(name, type, default_val, unit) PARAM_##name,
|
||||
typedef enum {
|
||||
PARAM_LIST
|
||||
NUM_PARAMS
|
||||
} param_idx_t;
|
||||
#undef PARAM_DEF
|
||||
|
||||
#define PARAMS_SIZE sizeof(param_stored_t)
|
||||
#define FLASH_SECTOR_SIZE 4096
|
||||
#define PARAMS_OFFSET 0
|
||||
#define PARAMS_TOTAL_SIZE (NUM_PARAMS * PARAMS_SIZE)
|
||||
#define PARAMETER_NUM_SECTORS 4
|
||||
#define LOG_START_OFFSET (FLASH_SECTOR_SIZE * PARAMETER_NUM_SECTORS)
|
||||
|
||||
// External declarations
|
||||
extern param_value_t parameter_table[NUM_PARAMS];
|
||||
extern const param_value_t parameter_defaults[NUM_PARAMS];
|
||||
extern const param_type_e parameter_types[NUM_PARAMS];
|
||||
extern const char* parameter_names[NUM_PARAMS];
|
||||
extern const char parameter_units[NUM_PARAMS][8];
|
||||
|
||||
esp_err_t storage_init();
|
||||
esp_err_t log_init();
|
||||
// Core functions
|
||||
esp_err_t storage_init(void);
|
||||
esp_err_t log_init(void);
|
||||
void storage_deinit(void);
|
||||
|
||||
// Parameter access functions
|
||||
param_value_t get_param_value_t(param_idx_t id);
|
||||
esp_err_t set_param_value_t(param_idx_t id, param_value_t val);
|
||||
param_type_e get_param_type(param_idx_t id);
|
||||
const char* get_param_name(param_idx_t id);
|
||||
param_value_t get_param_default(param_idx_t id);
|
||||
const char* get_param_unit(param_idx_t id);
|
||||
const char* get_param_json_string(param_idx_t id, char* buffer, size_t buf_size);
|
||||
|
||||
esp_err_t commit_params();
|
||||
|
||||
// Helper functions for string parameters
|
||||
esp_err_t set_param_string(param_idx_t id, const char* str);
|
||||
char* get_param_string(param_idx_t id);
|
||||
|
||||
// Storage operations
|
||||
esp_err_t commit_params(void);
|
||||
esp_err_t factory_reset(void);
|
||||
|
||||
// Log functions
|
||||
#define LOG_ENTRY_SIZE 32
|
||||
#define LOG_NUM_ENTRIES 512
|
||||
#define FLASH_SECTOR_SIZE 4096
|
||||
|
||||
uint32_t get_log_head(void);
|
||||
uint32_t get_log_tail(void);
|
||||
uint32_t get_log_offset(void);
|
||||
esp_err_t write_log(char* entry);
|
||||
|
||||
void storage_deinit();
|
||||
// Test functions
|
||||
esp_err_t write_dummy_log_1(void);
|
||||
esp_err_t write_dummy_log_2(void);
|
||||
esp_err_t write_dummy_log_3(void);
|
||||
|
||||
#endif /* MAIN_STORAGE_H_ */
|
||||
@@ -51,16 +51,9 @@ static bool parse_uint64(const char *str, uint64_t *result) {
|
||||
static void print_param_value(param_idx_t id, param_value_t val) {
|
||||
param_type_e type = get_param_type(id);
|
||||
|
||||
char sbuf[9] = {0};
|
||||
|
||||
switch (type) {
|
||||
case PARAM_TYPE_u8:
|
||||
printf("%u (0x%02X)\n", val.u8, val.u8);
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_i8:
|
||||
printf("%d (0x%02X)\n",
|
||||
val.i8, (uint8_t)val.i8);
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_u16:
|
||||
printf("%u (0x%04X)\n",
|
||||
val.u16, val.u16);
|
||||
@@ -81,25 +74,21 @@ static void print_param_value(param_idx_t id, param_value_t val) {
|
||||
(long)val.i32, (unsigned long)val.i32);
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_u64:
|
||||
printf("%llu (0x%016llX)\n",
|
||||
(unsigned long long)val.u64,
|
||||
(unsigned long long)val.u64);
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_i64:
|
||||
printf("%lld (0x%016llX)\n",
|
||||
(long long)val.i64, (unsigned long long)val.i64);
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_f32:
|
||||
printf("%.6f (0x%08lX as bits)\n",
|
||||
val.f32, (unsigned long)val.u32);
|
||||
break;
|
||||
|
||||
|
||||
case PARAM_TYPE_f64:
|
||||
printf("%.6f (0x%016llX as bits)\n",
|
||||
val.f64, (unsigned long long)val.u64);
|
||||
val.f64, (unsigned long long)val.f64);
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_str:
|
||||
memcpy(val.str, sbuf, 8);
|
||||
sbuf[8] = '\0';
|
||||
printf("\"%s\"", sbuf);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -114,7 +103,7 @@ static esp_err_t parse_param_value(const char *orig_str, param_type_e type, para
|
||||
while (isspace((unsigned char)*str)) str++;
|
||||
|
||||
// Check for negative sign on unsigned integer types
|
||||
bool is_unsigned_int = (type == PARAM_TYPE_u8 || type == PARAM_TYPE_u16 || type == PARAM_TYPE_u32 || type == PARAM_TYPE_u64);
|
||||
bool is_unsigned_int = (type == PARAM_TYPE_u16 || type == PARAM_TYPE_u32);
|
||||
if (is_unsigned_int && *str == '-') {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
@@ -123,18 +112,18 @@ static esp_err_t parse_param_value(const char *orig_str, param_type_e type, para
|
||||
errno = 0;
|
||||
|
||||
switch (type) {
|
||||
case PARAM_TYPE_u8:
|
||||
case PARAM_TYPE_u16:
|
||||
val->u16 = strtoull(str, &endptr, 0);
|
||||
break;
|
||||
case PARAM_TYPE_u32:
|
||||
case PARAM_TYPE_u64:
|
||||
val->u64 = strtoull(str, &endptr, 0);
|
||||
val->u32 = strtoull(str, &endptr, 0);
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_i8:
|
||||
case PARAM_TYPE_i16:
|
||||
val->i16 = strtoll(str, &endptr, 0);
|
||||
break;
|
||||
case PARAM_TYPE_i32:
|
||||
case PARAM_TYPE_i64:
|
||||
val->i64 = strtoll(str, &endptr, 0);
|
||||
val->i32 = strtoll(str, &endptr, 0);
|
||||
break;
|
||||
|
||||
case PARAM_TYPE_f32:
|
||||
|
||||
37
main/version.cmake
Normal file
37
main/version.cmake
Normal file
@@ -0,0 +1,37 @@
|
||||
# version.cmake
|
||||
execute_process(
|
||||
COMMAND git describe --tags --always --dirty
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/..
|
||||
OUTPUT_VARIABLE GIT_VERSION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
)
|
||||
|
||||
execute_process(
|
||||
COMMAND git rev-parse --abbrev-ref HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/..
|
||||
OUTPUT_VARIABLE GIT_BRANCH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
)
|
||||
|
||||
string(TIMESTAMP BUILD_DATE "%Y-%m-%d %H:%M:%S" UTC)
|
||||
|
||||
# Fallback if not in a git repo
|
||||
if(NOT GIT_VERSION)
|
||||
set(GIT_VERSION "unknown")
|
||||
endif()
|
||||
|
||||
if(NOT GIT_BRANCH)
|
||||
set(GIT_BRANCH "unknown")
|
||||
endif()
|
||||
|
||||
message(STATUS "Firmware Version: ${GIT_VERSION}")
|
||||
message(STATUS "Git Branch: ${GIT_BRANCH}")
|
||||
message(STATUS "Build Date: ${BUILD_DATE}")
|
||||
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_LIST_DIR}/version.h.in
|
||||
${CMAKE_BINARY_DIR}/version.h
|
||||
@ONLY
|
||||
)
|
||||
10
main/version.h.in
Normal file
10
main/version.h.in
Normal file
@@ -0,0 +1,10 @@
|
||||
// version.h.in
|
||||
#ifndef VERSION_H
|
||||
#define VERSION_H
|
||||
|
||||
#define FIRMWARE_VERSION "@GIT_VERSION@"
|
||||
#define FIRMWARE_BRANCH "@GIT_BRANCH@"
|
||||
#define BUILD_DATE "@BUILD_DATE@"
|
||||
#define FIRMWARE_STRING "V_" FIRMWARE_VERSION " (" BUILD_DATE ")"
|
||||
|
||||
#endif
|
||||
File diff suppressed because one or more lines are too long
383
main/webpage_brotli.h
Normal file
383
main/webpage_brotli.h
Normal file
@@ -0,0 +1,383 @@
|
||||
#ifndef HTML_CONTENT_BR_H
|
||||
#define HTML_CONTENT_BR_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
const unsigned char PROGMEM html_content_br[] = {
|
||||
0x1b, 0x75, 0x60, 0x11, 0x95, 0xac, 0x8c, 0x00, 0x3a, 0x12, 0xca, 0xb6, 0x9b, 0x34, 0xff, 0x95,
|
||||
0xc9, 0x8e, 0xfd, 0x65, 0x22, 0x13, 0x79, 0x9e, 0x98, 0xd2, 0x08, 0x49, 0x66, 0xff, 0xf7, 0x75,
|
||||
0xfa, 0xdf, 0xcd, 0xcf, 0x97, 0x18, 0x75, 0x74, 0xc3, 0x45, 0x88, 0xd5, 0x61, 0x45, 0xa6, 0x34,
|
||||
0x21, 0xdd, 0xa4, 0x99, 0x6f, 0xf0, 0x38, 0xbe, 0x06, 0x1b, 0xea, 0x13, 0x23, 0x38, 0x42, 0x59,
|
||||
0x4f, 0x08, 0xfa, 0x5f, 0x8b, 0xb5, 0x72, 0xe1, 0x2c, 0x82, 0x76, 0x43, 0xb2, 0x5e, 0x34, 0xf8,
|
||||
0xc1, 0x11, 0x17, 0x76, 0x19, 0xdc, 0x7d, 0x20, 0xc2, 0x53, 0x2e, 0xf7, 0xca, 0xde, 0xa1, 0x76,
|
||||
0xa9, 0x29, 0x80, 0xdb, 0x18, 0x87, 0xaa, 0x2f, 0x19, 0x42, 0x75, 0xa5, 0xfd, 0xcc, 0xff, 0x3f,
|
||||
0x5b, 0x96, 0x97, 0x81, 0x01, 0xa3, 0xcd, 0x2e, 0x48, 0x9c, 0x44, 0xcc, 0xd1, 0xc5, 0x4e, 0x42,
|
||||
0xf5, 0x87, 0xaa, 0x55, 0x75, 0x57, 0xeb, 0xdd, 0xe0, 0xbb, 0x99, 0x91, 0xb4, 0x34, 0xd2, 0x01,
|
||||
0xc0, 0xff, 0x55, 0xd5, 0x83, 0xda, 0x15, 0x2c, 0x8d, 0xb4, 0x7c, 0x00, 0x1c, 0x19, 0x5f, 0xee,
|
||||
0x30, 0x04, 0x0a, 0x42, 0x67, 0x91, 0x64, 0x4e, 0x2f, 0x74, 0x66, 0xab, 0xbb, 0xce, 0xde, 0x45,
|
||||
0x0a, 0xdf, 0xed, 0x31, 0x4a, 0x6b, 0x9f, 0xa4, 0x4f, 0xd2, 0xb4, 0x77, 0x9b, 0x19, 0x45, 0x44,
|
||||
0x54, 0x14, 0x74, 0x9e, 0x36, 0xf4, 0x84, 0x57, 0x73, 0x64, 0x71, 0x43, 0xca, 0x02, 0xc4, 0x0c,
|
||||
0x2e, 0x0b, 0x83, 0x18, 0x48, 0xc1, 0xf3, 0x18, 0x09, 0x4a, 0x34, 0xa7, 0xcb, 0x4d, 0xcc, 0x0f,
|
||||
0x86, 0x7f, 0x7c, 0x92, 0x91, 0x7c, 0x83, 0x1e, 0x53, 0x3c, 0x16, 0x9d, 0x85, 0x2f, 0x3c, 0xfb,
|
||||
0x18, 0xa5, 0x59, 0xc7, 0x5b, 0xab, 0x5f, 0x7c, 0x09, 0x8d, 0x90, 0xfb, 0x7e, 0x53, 0x2f, 0x19,
|
||||
0x6a, 0xc3, 0x50, 0x52, 0x34, 0x8f, 0xd3, 0xd2, 0xd6, 0xd0, 0xc0, 0x4e, 0x2e, 0xc4, 0x38, 0x16,
|
||||
0x48, 0x98, 0x04, 0x7d, 0x19, 0x4e, 0x7c, 0xb6, 0xad, 0xf5, 0x56, 0xff, 0x9d, 0xa2, 0x5a, 0x47,
|
||||
0x98, 0xb3, 0x15, 0xbd, 0xfe, 0xf4, 0xe9, 0xd6, 0x6d, 0xd9, 0x4d, 0x66, 0xf6, 0x78, 0x5f, 0xd8,
|
||||
0x3c, 0x33, 0x19, 0x2f, 0xab, 0x19, 0x1c, 0x6f, 0xec, 0xd9, 0x62, 0x13, 0x92, 0xa2, 0xc0, 0x24,
|
||||
0x55, 0x58, 0x51, 0x86, 0x88, 0xc7, 0x3a, 0x86, 0xc7, 0xdd, 0x8b, 0x55, 0x91, 0x17, 0x1f, 0x55,
|
||||
0x3e, 0x96, 0xc9, 0x77, 0xf7, 0x45, 0x7d, 0x7c, 0x37, 0x5c, 0x28, 0x00, 0x77, 0xb4, 0x95, 0x97,
|
||||
0x8f, 0xfb, 0x38, 0x77, 0xc8, 0x01, 0x41, 0x74, 0xcb, 0x67, 0xc5, 0x1a, 0xbc, 0x6c, 0x9c, 0xe3,
|
||||
0x42, 0x3a, 0x2c, 0x84, 0x31, 0x1f, 0xc9, 0xc3, 0x1b, 0xcd, 0x96, 0x9b, 0xd8, 0x37, 0xb0, 0x1d,
|
||||
0x6c, 0x37, 0x62, 0x9a, 0x47, 0xce, 0x0d, 0xfe, 0x3b, 0x39, 0xc4, 0x91, 0xa9, 0xde, 0x0c, 0x82,
|
||||
0xd3, 0xdb, 0xd8, 0x98, 0xa9, 0xff, 0xaa, 0x74, 0x11, 0x63, 0x89, 0x2b, 0x73, 0x54, 0x04, 0xfe,
|
||||
0x2b, 0xf4, 0xb2, 0xc1, 0xc7, 0x7e, 0xee, 0x6c, 0x53, 0x68, 0x1c, 0xd1, 0xe3, 0xc0, 0xe0, 0x6c,
|
||||
0x7f, 0xdf, 0xeb, 0xbf, 0x59, 0x44, 0xc6, 0x10, 0x60, 0x28, 0x37, 0xa8, 0x72, 0x8b, 0x68, 0x79,
|
||||
0xc9, 0x60, 0xf8, 0x56, 0x15, 0xd4, 0x23, 0x32, 0x83, 0xd2, 0x02, 0x55, 0xde, 0x6e, 0x7b, 0x2f,
|
||||
0x65, 0x68, 0xe5, 0x6c, 0x93, 0x1c, 0x36, 0x5c, 0xbd, 0xc6, 0x44, 0x67, 0xff, 0x87, 0xc3, 0x2b,
|
||||
0x64, 0xfa, 0x46, 0xd7, 0x2e, 0x75, 0x63, 0xf1, 0xfa, 0xc9, 0xc1, 0x60, 0x80, 0x79, 0x7b, 0xa2,
|
||||
0xcf, 0xe0, 0xe6, 0xc9, 0x44, 0x55, 0x14, 0x48, 0xde, 0xd8, 0xc1, 0xbd, 0x7c, 0xa1, 0x20, 0x79,
|
||||
0x8b, 0x98, 0xce, 0xc6, 0x73, 0xff, 0x07, 0xf8, 0x50, 0xe2, 0x4c, 0xf4, 0x50, 0x65, 0x56, 0x89,
|
||||
0xa7, 0x41, 0x8c, 0x41, 0x0d, 0xe8, 0xe7, 0x16, 0x7d, 0x5b, 0x6c, 0xe8, 0xf7, 0x2c, 0xb1, 0x1c,
|
||||
0xb9, 0x4f, 0x07, 0x95, 0xb1, 0x3e, 0x32, 0x7c, 0xbc, 0xc6, 0x66, 0xad, 0x19, 0x6e, 0xe3, 0x9f,
|
||||
0x4b, 0xa9, 0xed, 0x7b, 0xce, 0xb1, 0xfc, 0xf5, 0xed, 0x02, 0xb8, 0xf4, 0x85, 0x21, 0x48, 0x1c,
|
||||
0x11, 0x94, 0x59, 0x7e, 0x5a, 0x5c, 0xf4, 0x95, 0x20, 0x21, 0x37, 0xd8, 0x60, 0x0a, 0x11, 0x0c,
|
||||
0x32, 0x6f, 0x17, 0xd3, 0xbc, 0x58, 0x12, 0xd5, 0xd4, 0x32, 0xf8, 0x5c, 0x97, 0xea, 0x56, 0x92,
|
||||
0xc0, 0x92, 0xdd, 0x29, 0x36, 0xaa, 0x4b, 0x55, 0xf3, 0x78, 0x89, 0xa4, 0x09, 0x4c, 0xf2, 0x76,
|
||||
0xa4, 0xd4, 0x4e, 0xcb, 0x27, 0x01, 0x32, 0x13, 0x57, 0x8a, 0x12, 0xf3, 0x23, 0x03, 0x4b, 0x77,
|
||||
0xac, 0xfa, 0xa1, 0xec, 0xa1, 0x6a, 0xe5, 0x7e, 0xb1, 0x64, 0x83, 0xdd, 0x0b, 0x7b, 0x77, 0x33,
|
||||
0x05, 0xb6, 0x1a, 0xe4, 0x78, 0xcd, 0xb2, 0x3f, 0xbd, 0xf7, 0x34, 0x44, 0x54, 0x26, 0x99, 0x28,
|
||||
0xc1, 0x1c, 0xf5, 0xee, 0xa2, 0x13, 0xfb, 0x23, 0xdd, 0xfc, 0x93, 0xac, 0x2a, 0x8f, 0x2c, 0x16,
|
||||
0xe3, 0xd5, 0x39, 0xd5, 0x7d, 0x59, 0x6c, 0x6b, 0xf0, 0x15, 0x04, 0x25, 0x87, 0xac, 0x13, 0xe6,
|
||||
0x87, 0x40, 0xf9, 0xb7, 0xeb, 0x2c, 0x63, 0xfb, 0x68, 0xb1, 0x2b, 0xbd, 0x6b, 0xb1, 0xe5, 0xf2,
|
||||
0x09, 0xbe, 0xe2, 0x44, 0x32, 0x07, 0x5c, 0x9b, 0x68, 0xb3, 0x38, 0xb1, 0x46, 0x1f, 0xd3, 0xe5,
|
||||
0x5e, 0xbc, 0xec, 0x9f, 0xb0, 0x8b, 0xff, 0x91, 0xc4, 0x6e, 0x8d, 0x75, 0x95, 0x35, 0x8a, 0xb4,
|
||||
0x63, 0xbd, 0x90, 0x01, 0x54, 0xe8, 0xa3, 0x60, 0xff, 0x0e, 0x55, 0x6b, 0x81, 0x12, 0x6e, 0xf8,
|
||||
0x35, 0xcc, 0xf2, 0xa6, 0x19, 0x8a, 0x07, 0xcb, 0xc3, 0xe3, 0xb2, 0x5e, 0xa1, 0x18, 0x47, 0x96,
|
||||
0x9b, 0xd2, 0xf1, 0xf5, 0x7c, 0x12, 0x24, 0xd2, 0x99, 0x87, 0xb1, 0x5c, 0x7b, 0x80, 0x42, 0x21,
|
||||
0xc5, 0xd2, 0xe4, 0x1e, 0x1f, 0xb2, 0xf7, 0x72, 0x30, 0x04, 0x80, 0x15, 0x9e, 0xda, 0x7e, 0xea,
|
||||
0xd1, 0x78, 0x5e, 0xc7, 0x04, 0xd9, 0xcc, 0x24, 0x04, 0x4d, 0xfc, 0xf4, 0x4c, 0x3c, 0xfc, 0xda,
|
||||
0x5d, 0x93, 0x3e, 0x92, 0x81, 0x3a, 0x62, 0xff, 0xad, 0xe0, 0xc8, 0xcf, 0x86, 0xfe, 0xf0, 0x32,
|
||||
0xb5, 0x9f, 0x48, 0x56, 0x72, 0x96, 0x52, 0xa4, 0x18, 0x2d, 0xcd, 0x72, 0x9b, 0x5d, 0xc6, 0xfc,
|
||||
0xea, 0x92, 0x96, 0x8a, 0x3b, 0x6b, 0x2a, 0x70, 0xf3, 0x1c, 0x5b, 0x25, 0xbc, 0x21, 0x41, 0x23,
|
||||
0x22, 0x97, 0x49, 0xeb, 0xc5, 0x0a, 0xb5, 0x20, 0x4f, 0xb3, 0x9f, 0x3a, 0x3f, 0xde, 0x47, 0xb5,
|
||||
0x05, 0x18, 0xa2, 0x7a, 0x78, 0x39, 0xf2, 0xa4, 0x79, 0x64, 0xdb, 0x1b, 0xa6, 0x39, 0x52, 0x0d,
|
||||
0xd6, 0xe6, 0xed, 0xee, 0x12, 0xb4, 0x75, 0xad, 0x54, 0x43, 0xb9, 0x64, 0x1f, 0xdf, 0x07, 0x1a,
|
||||
0xe0, 0x63, 0x3c, 0x9a, 0x7c, 0x8b, 0xf7, 0xea, 0xdd, 0xf4, 0xfc, 0xf2, 0x12, 0x13, 0xe8, 0x35,
|
||||
0x59, 0xc4, 0x60, 0xe1, 0x8d, 0xfd, 0x64, 0xcc, 0xef, 0xca, 0x66, 0xad, 0x99, 0xb4, 0xa5, 0xa0,
|
||||
0xa4, 0x7a, 0xeb, 0xdc, 0xfd, 0x9d, 0xee, 0xc7, 0xbb, 0x1c, 0x7a, 0x0c, 0x2d, 0x00, 0x9e, 0x5a,
|
||||
0x94, 0x37, 0xbb, 0x07, 0x26, 0x51, 0x75, 0xdd, 0x35, 0x69, 0x83, 0x36, 0x02, 0xc8, 0xfd, 0x79,
|
||||
0xbb, 0x91, 0xd0, 0x4c, 0x58, 0x3c, 0x01, 0x5a, 0xc7, 0xf8, 0x2c, 0x98, 0xd8, 0x28, 0xcb, 0xfd,
|
||||
0x87, 0xfe, 0xd9, 0xb7, 0x4e, 0x7d, 0xe6, 0x90, 0xdc, 0xbc, 0x9a, 0x25, 0x5b, 0x18, 0x8d, 0x26,
|
||||
0x27, 0xb5, 0x51, 0xb2, 0x62, 0x03, 0xcc, 0x12, 0x53, 0x63, 0x0c, 0x7b, 0x3a, 0x9f, 0xa7, 0x49,
|
||||
0x2c, 0xf0, 0xa6, 0x7f, 0x1a, 0x08, 0x84, 0x3a, 0xe1, 0x0c, 0xf8, 0x26, 0x07, 0x76, 0xb6, 0x13,
|
||||
0x93, 0xbf, 0x40, 0xdb, 0x7b, 0x48, 0x2f, 0x79, 0x63, 0xef, 0x36, 0x9e, 0x40, 0xe7, 0x3c, 0x7b,
|
||||
0xbd, 0x74, 0xa7, 0x77, 0xbf, 0xbe, 0xde, 0xec, 0x1b, 0xb6, 0x29, 0x8d, 0x96, 0xef, 0x24, 0x6f,
|
||||
0xc7, 0x1e, 0xa0, 0xc0, 0x85, 0xf7, 0xb3, 0x60, 0x63, 0xf7, 0x02, 0xbb, 0x78, 0x7f, 0xaf, 0x74,
|
||||
0xfc, 0x73, 0x7c, 0xfd, 0x8b, 0x4f, 0xa2, 0xe9, 0x1a, 0x83, 0x4f, 0x3f, 0x3f, 0xcf, 0x46, 0x65,
|
||||
0xfc, 0x04, 0xf8, 0x2a, 0x10, 0xd0, 0x2b, 0x5f, 0x4f, 0x7e, 0xa5, 0xe7, 0xdf, 0x6e, 0xd2, 0x87,
|
||||
0x1a, 0xd9, 0x76, 0x34, 0x0c, 0xc0, 0x21, 0x16, 0xab, 0x1e, 0x35, 0x8c, 0x55, 0xd5, 0xb0, 0x71,
|
||||
0x37, 0xf8, 0xe9, 0x75, 0xc8, 0xf4, 0x04, 0xab, 0x01, 0x52, 0x3d, 0x9c, 0x0d, 0x2f, 0x4d, 0xb0,
|
||||
0x70, 0x6c, 0x01, 0xbb, 0xe2, 0xc2, 0x23, 0xc0, 0x8e, 0xcb, 0xef, 0x03, 0x64, 0xf5, 0x76, 0x62,
|
||||
0xf6, 0xf6, 0x89, 0xba, 0xa9, 0x71, 0x7d, 0x71, 0x8a, 0x04, 0xd2, 0x4a, 0x22, 0x6e, 0xf9, 0xcf,
|
||||
0x7d, 0x36, 0x27, 0x53, 0xb2, 0x04, 0x08, 0x7c, 0x20, 0xa8, 0x3c, 0x93, 0x71, 0x72, 0x61, 0xc4,
|
||||
0x50, 0x4d, 0x0b, 0x04, 0xd0, 0xb4, 0x0d, 0x13, 0x11, 0x98, 0xed, 0x9e, 0xa2, 0xde, 0x93, 0x43,
|
||||
0x1c, 0x54, 0x32, 0x08, 0x6e, 0x39, 0xb3, 0x39, 0xfc, 0x38, 0x34, 0xdb, 0xf0, 0xb1, 0xbf, 0x69,
|
||||
0x31, 0xcd, 0x0b, 0xdd, 0xe1, 0x90, 0x58, 0x47, 0xf0, 0x8c, 0xc9, 0xf2, 0x5e, 0xcc, 0xff, 0x73,
|
||||
0xcf, 0xc4, 0x5c, 0xc2, 0xed, 0x8d, 0x22, 0x39, 0x67, 0xe4, 0xfc, 0x33, 0x8e, 0x3b, 0x27, 0x32,
|
||||
0xeb, 0x40, 0x25, 0xc5, 0x68, 0xc8, 0x73, 0xe4, 0x8a, 0x95, 0x0a, 0xd1, 0xf2, 0xce, 0xfc, 0x78,
|
||||
0xf5, 0xcb, 0x8f, 0xd1, 0x24, 0xf2, 0x1a, 0xa8, 0x03, 0xfb, 0x73, 0xd0, 0x55, 0xba, 0x63, 0x2a,
|
||||
0xdb, 0xb1, 0x0a, 0x35, 0x01, 0x60, 0x77, 0x94, 0xd3, 0x35, 0x0d, 0xdf, 0x4a, 0x58, 0xbb, 0xf9,
|
||||
0x71, 0xf7, 0x66, 0x42, 0xda, 0x5e, 0x98, 0xfc, 0xbe, 0x92, 0x5c, 0xfc, 0x75, 0x1e, 0xeb, 0xca,
|
||||
0xe8, 0x5f, 0x0d, 0x96, 0x27, 0x72, 0xbc, 0x7b, 0x7f, 0x5f, 0x6d, 0xd7, 0x93, 0xfb, 0x93, 0x7d,
|
||||
0xdc, 0x5d, 0xc8, 0xed, 0x6e, 0xbe, 0x9d, 0xb2, 0xbb, 0xdf, 0x17, 0x58, 0x5c, 0xfd, 0x41, 0xae,
|
||||
0x77, 0xf3, 0x03, 0x8e, 0xd1, 0x61, 0x60, 0xaf, 0x67, 0x9f, 0x3d, 0xbe, 0x5c, 0x94, 0xe3, 0x5d,
|
||||
0xfd, 0x77, 0x76, 0x7c, 0xf7, 0x77, 0x41, 0x64, 0xb3, 0x76, 0x3c, 0x9f, 0xdf, 0xe1, 0x7c, 0x3c,
|
||||
0xfd, 0x32, 0xb9, 0x3e, 0x3d, 0xd2, 0xea, 0x2d, 0x20, 0x48, 0xca, 0xc3, 0x07, 0xab, 0x2f, 0x6c,
|
||||
0xb9, 0x94, 0x28, 0xa7, 0x15, 0x4b, 0x87, 0x10, 0x4f, 0xd8, 0x79, 0xcc, 0x06, 0xd4, 0xab, 0x04,
|
||||
0x0d, 0xc0, 0x10, 0x35, 0xf9, 0x8e, 0x1d, 0xb3, 0x70, 0x45, 0x0b, 0xad, 0xd8, 0x35, 0x56, 0x94,
|
||||
0xb3, 0xda, 0x98, 0x7b, 0x79, 0xa3, 0xf5, 0x01, 0xad, 0x4d, 0xfe, 0x0d, 0x03, 0x55, 0x1f, 0xf3,
|
||||
0x39, 0xb3, 0x05, 0x04, 0xea, 0x0c, 0x3f, 0xac, 0xc5, 0xa2, 0xc9, 0x6c, 0x7e, 0xe5, 0xd4, 0xa5,
|
||||
0xaa, 0x27, 0x92, 0x76, 0x95, 0x36, 0x0d, 0xab, 0x2d, 0x70, 0xb0, 0x29, 0x61, 0xb2, 0x1e, 0x75,
|
||||
0x22, 0xeb, 0x77, 0x5a, 0xcc, 0x61, 0x63, 0xbe, 0xc1, 0x85, 0x25, 0xbb, 0xa6, 0xc6, 0x1a, 0x54,
|
||||
0x28, 0x33, 0x17, 0x65, 0x85, 0xb0, 0x0c, 0x6d, 0x7b, 0xe5, 0xfa, 0xcd, 0xf4, 0x56, 0x67, 0x3a,
|
||||
0xb8, 0x00, 0x8f, 0xf3, 0xd2, 0x79, 0xe6, 0xa9, 0xb5, 0x16, 0x73, 0x03, 0xc0, 0xc5, 0x27, 0x72,
|
||||
0x65, 0xba, 0x9c, 0x5e, 0xb3, 0xe8, 0x68, 0x06, 0xdf, 0x2c, 0xa8, 0x5d, 0x4f, 0x0e, 0xef, 0xc4,
|
||||
0xbc, 0x56, 0x0a, 0x0c, 0x35, 0x40, 0x83, 0xbd, 0xcc, 0xa1, 0xfe, 0x3e, 0x39, 0x76, 0x94, 0x68,
|
||||
0x5e, 0x89, 0x75, 0xd4, 0xeb, 0xae, 0xac, 0xd0, 0x1a, 0xd1, 0x22, 0x1b, 0xb9, 0xde, 0xa8, 0xef,
|
||||
0x1e, 0x35, 0x2e, 0x1b, 0x4e, 0x77, 0x0f, 0x56, 0x00, 0x64, 0x31, 0xb6, 0x83, 0x14, 0x69, 0x03,
|
||||
0xc7, 0x38, 0xcb, 0xb2, 0xb3, 0xf6, 0x16, 0x47, 0x96, 0xe2, 0xc5, 0xd1, 0xd1, 0x9f, 0x46, 0xd1,
|
||||
0xd3, 0xa9, 0x70, 0x43, 0x11, 0x0e, 0x6b, 0x1f, 0x50, 0x1f, 0x86, 0x83, 0x94, 0x79, 0x2b, 0x05,
|
||||
0x87, 0x74, 0xad, 0x8b, 0x2a, 0x2d, 0x33, 0x4a, 0x3c, 0xd7, 0x2a, 0xa7, 0x9b, 0x37, 0xe6, 0x59,
|
||||
0xb5, 0x11, 0x0d, 0x5c, 0x5a, 0xaa, 0x6d, 0xab, 0x7e, 0x40, 0x6c, 0x5d, 0xe8, 0x32, 0xd7, 0x89,
|
||||
0x56, 0x63, 0xb5, 0xcc, 0x41, 0xe9, 0x42, 0x40, 0xff, 0xe1, 0x7e, 0xc1, 0xca, 0xcb, 0xc1, 0x89,
|
||||
0xe4, 0x91, 0x26, 0x1e, 0x91, 0xee, 0xeb, 0xf5, 0x1c, 0x55, 0x28, 0x37, 0xe8, 0x16, 0xc0, 0x63,
|
||||
0xca, 0x84, 0x5f, 0x93, 0x0e, 0x63, 0x9c, 0xf4, 0xe9, 0x12, 0x20, 0xf4, 0x93, 0x9a, 0x54, 0x9e,
|
||||
0xd0, 0x69, 0x8b, 0x00, 0x8d, 0x8a, 0x7f, 0xc8, 0x31, 0x3c, 0x18, 0xe3, 0x8a, 0xbf, 0xf9, 0x6f,
|
||||
0x66, 0x98, 0x5e, 0x76, 0x04, 0x78, 0xa2, 0xdf, 0x38, 0x43, 0x18, 0x18, 0x14, 0x68, 0x35, 0xcf,
|
||||
0x8b, 0x04, 0x8a, 0x0e, 0xb0, 0xdf, 0x69, 0xac, 0xc9, 0x1a, 0xd3, 0x54, 0x87, 0xf5, 0x56, 0x35,
|
||||
0xeb, 0xf5, 0x72, 0x43, 0x7e, 0x27, 0x52, 0x0a, 0x07, 0xb1, 0x6f, 0x31, 0xe2, 0xb8, 0x07, 0x34,
|
||||
0x5c, 0x75, 0x4d, 0xf7, 0x5b, 0x49, 0x08, 0xe2, 0xae, 0xdb, 0x19, 0x40, 0xb8, 0x02, 0x94, 0x71,
|
||||
0x9d, 0xc3, 0x81, 0x50, 0x11, 0x4e, 0x51, 0x1b, 0x16, 0xb8, 0xa2, 0xc2, 0x32, 0x73, 0xf1, 0xa9,
|
||||
0x07, 0xde, 0xe8, 0x87, 0x1c, 0x50, 0x8f, 0x9e, 0xe4, 0xc1, 0xf6, 0x2f, 0x82, 0x4e, 0x30, 0xec,
|
||||
0x3c, 0x5d, 0x6f, 0x06, 0x7a, 0x29, 0x01, 0xe2, 0xa8, 0x40, 0x0e, 0x2b, 0x29, 0x65, 0x35, 0x75,
|
||||
0x3a, 0x44, 0x8a, 0x0f, 0x69, 0x35, 0xd3, 0x1c, 0x38, 0xd5, 0x2b, 0x0f, 0x87, 0xc4, 0x4a, 0x7b,
|
||||
0xd2, 0x4f, 0x5f, 0xa1, 0xc4, 0xe8, 0xe4, 0x2f, 0x49, 0x4a, 0xbe, 0x02, 0x27, 0x4d, 0x02, 0x28,
|
||||
0x3a, 0x95, 0x1a, 0x25, 0xcb, 0x96, 0xb1, 0xa4, 0x0b, 0xad, 0x19, 0x45, 0x8e, 0xb1, 0x8c, 0x83,
|
||||
0x73, 0x12, 0x7b, 0x73, 0x96, 0xe7, 0x1c, 0x27, 0x96, 0x23, 0x4b, 0x51, 0x44, 0x36, 0x05, 0x90,
|
||||
0x21, 0xad, 0xe3, 0x14, 0x9d, 0xb0, 0xde, 0x77, 0x01, 0x42, 0x48, 0x98, 0x1e, 0x44, 0xf8, 0xf1,
|
||||
0x38, 0x8d, 0x46, 0x82, 0x93, 0x31, 0x95, 0xfb, 0x2f, 0x89, 0x22, 0x2d, 0xcb, 0x0a, 0x1e, 0x54,
|
||||
0x0d, 0xb0, 0x54, 0xa8, 0x01, 0xaa, 0x56, 0x29, 0x93, 0xe7, 0x1a, 0x13, 0xa3, 0x4e, 0xcd, 0x5c,
|
||||
0x2e, 0x31, 0x1e, 0x47, 0x02, 0xe1, 0xb5, 0x76, 0x94, 0xd6, 0x6c, 0x01, 0xf8, 0xc5, 0x76, 0x32,
|
||||
0xf4, 0x0e, 0x21, 0x1c, 0x0e, 0x10, 0x20, 0x8d, 0x16, 0x1f, 0x78, 0xdd, 0xc8, 0xcd, 0x5f, 0xa1,
|
||||
0xae, 0x3a, 0xf9, 0x72, 0xc5, 0xab, 0x78, 0xe0, 0x55, 0x9b, 0x31, 0x31, 0xae, 0xb0, 0x04, 0xbe,
|
||||
0x50, 0xd3, 0x92, 0x6f, 0x26, 0xe5, 0x63, 0x7c, 0x8e, 0xd1, 0x01, 0xc2, 0x49, 0x9c, 0x7a, 0x66,
|
||||
0xb9, 0xa5, 0xc5, 0x39, 0x45, 0x36, 0x80, 0xf2, 0x34, 0x32, 0x7a, 0xea, 0x45, 0x3a, 0xe0, 0xcb,
|
||||
0x4e, 0x5c, 0x63, 0x70, 0xa4, 0x17, 0x7e, 0x8c, 0x44, 0x46, 0xd1, 0xca, 0xe9, 0x33, 0xb7, 0x3b,
|
||||
0xb5, 0xbb, 0x73, 0x98, 0x2e, 0x98, 0xc2, 0xa8, 0x98, 0xd1, 0xe6, 0x6f, 0x12, 0xaf, 0xd4, 0xb0,
|
||||
0x4c, 0xfd, 0x33, 0xa9, 0xf6, 0xc7, 0x7a, 0xf2, 0xa3, 0x67, 0x43, 0x8a, 0xd8, 0x64, 0x17, 0x85,
|
||||
0x66, 0x50, 0xca, 0x71, 0x64, 0x9e, 0x85, 0x1f, 0x09, 0xd6, 0x8e, 0xa2, 0x9c, 0x42, 0xaa, 0x71,
|
||||
0x34, 0x36, 0xa0, 0x2d, 0x11, 0xdd, 0xb1, 0xb0, 0x9c, 0x07, 0x5e, 0x85, 0x97, 0x13, 0x20, 0x04,
|
||||
0xb1, 0x16, 0x58, 0x37, 0xa2, 0x59, 0xc2, 0x63, 0x20, 0x98, 0x71, 0x92, 0x3e, 0x47, 0x6f, 0x50,
|
||||
0xb9, 0x2a, 0x09, 0x96, 0x12, 0xd0, 0xe3, 0xdf, 0xa6, 0x50, 0x95, 0x49, 0x4e, 0x1f, 0x7c, 0x3d,
|
||||
0xe5, 0xd5, 0xb3, 0x84, 0xc2, 0x28, 0x3d, 0xcb, 0xb5, 0xfa, 0x6e, 0x76, 0x4b, 0xa2, 0xeb, 0x7f,
|
||||
0x20, 0xbf, 0x62, 0xc0, 0x82, 0x0c, 0xf8, 0xe0, 0x1f, 0xd5, 0x48, 0xae, 0x44, 0xa8, 0xfa, 0x6d,
|
||||
0x6a, 0x56, 0x95, 0x64, 0x18, 0xb6, 0x68, 0x78, 0x3e, 0x37, 0x25, 0x4d, 0x7e, 0x97, 0x22, 0x36,
|
||||
0x27, 0x2f, 0x54, 0xf0, 0x9f, 0x35, 0xa1, 0x94, 0x90, 0xaf, 0xb5, 0x8e, 0xdd, 0x98, 0x33, 0x16,
|
||||
0xad, 0x13, 0x1e, 0x52, 0x6d, 0xbf, 0xef, 0x06, 0x5c, 0xd9, 0xbe, 0xfc, 0xb1, 0xa2, 0x29, 0x91,
|
||||
0xb7, 0xb3, 0xf4, 0x31, 0xc3, 0x1c, 0x02, 0xea, 0x38, 0x15, 0x4e, 0xf0, 0x85, 0x36, 0xf8, 0xb4,
|
||||
0x8b, 0x2e, 0x03, 0x46, 0x0f, 0x42, 0x9d, 0xbc, 0xbb, 0x63, 0xd9, 0xdd, 0x24, 0x34, 0x1c, 0xc1,
|
||||
0x0a, 0xf3, 0x94, 0x6a, 0xd0, 0xcd, 0xd4, 0x59, 0x85, 0x9e, 0x34, 0xa2, 0xe8, 0xc2, 0xb9, 0x75,
|
||||
0xf3, 0xc8, 0x16, 0xe8, 0x54, 0xd9, 0xb6, 0x20, 0x5e, 0x43, 0xc9, 0xbf, 0xdb, 0x92, 0xa7, 0x8d,
|
||||
0xad, 0x66, 0x82, 0xd5, 0x56, 0x6c, 0x18, 0x8b, 0x2f, 0x18, 0xe5, 0xb1, 0x38, 0xfe, 0x13, 0x51,
|
||||
0x18, 0xb8, 0x34, 0x86, 0x02, 0x3d, 0x01, 0x74, 0x7e, 0xdd, 0x0c, 0x31, 0x59, 0x55, 0x44, 0xa0,
|
||||
0x60, 0xce, 0x0f, 0x72, 0x73, 0x87, 0xd2, 0xac, 0x09, 0x31, 0x00, 0x02, 0xfb, 0xdf, 0xba, 0x65,
|
||||
0xa3, 0x24, 0xc2, 0x86, 0x08, 0xb3, 0x30, 0x19, 0x81, 0xc1, 0xb6, 0x7b, 0xcb, 0xa1, 0x0d, 0x19,
|
||||
0x1f, 0x7e, 0xc5, 0xdd, 0x84, 0x20, 0x5c, 0xcf, 0x0b, 0x60, 0xe3, 0x76, 0x59, 0x2f, 0xf0, 0xb9,
|
||||
0x95, 0xa7, 0xe5, 0xd9, 0x94, 0xc0, 0xfa, 0xda, 0x3a, 0xdb, 0xa2, 0xdd, 0x06, 0x51, 0x51, 0xe4,
|
||||
0xb3, 0xce, 0x67, 0x09, 0x94, 0xd7, 0xd9, 0x28, 0xe2, 0x4b, 0xb4, 0x98, 0x61, 0xd7, 0x8d, 0x00,
|
||||
0x7a, 0xd7, 0x9e, 0x9a, 0x53, 0xe9, 0xbd, 0x0a, 0x0b, 0xe3, 0xbe, 0x35, 0x60, 0xcf, 0xe4, 0x6b,
|
||||
0x84, 0x80, 0xbe, 0xe8, 0x53, 0xbe, 0x76, 0x9c, 0xe9, 0x2c, 0x62, 0x77, 0x30, 0xc3, 0xfc, 0x85,
|
||||
0x53, 0x1d, 0xbb, 0xc1, 0x11, 0x72, 0xfb, 0x67, 0xdf, 0xab, 0xd1, 0x86, 0x4e, 0xda, 0xe5, 0x2f,
|
||||
0xee, 0xff, 0x66, 0xb7, 0x36, 0x6e, 0xfd, 0xbf, 0xc8, 0x05, 0x71, 0x99, 0xd5, 0x86, 0xc4, 0x79,
|
||||
0xaa, 0xc4, 0x63, 0x37, 0x76, 0x19, 0x06, 0x12, 0x38, 0xa0, 0x4e, 0xa9, 0x61, 0x36, 0x3f, 0x0d,
|
||||
0xf4, 0x8c, 0xba, 0x90, 0x17, 0xa9, 0x39, 0xf3, 0x17, 0x78, 0x2e, 0x6b, 0x8a, 0xfc, 0x72, 0x35,
|
||||
0xb9, 0xbc, 0xd5, 0xb5, 0x6e, 0xd3, 0x25, 0xe3, 0x4d, 0xc4, 0xa4, 0xd3, 0xed, 0x87, 0x03, 0xf7,
|
||||
0xb8, 0x51, 0x62, 0xac, 0x79, 0x13, 0x7e, 0xb4, 0x0d, 0xb8, 0x16, 0x21, 0xf3, 0xd9, 0x5d, 0x55,
|
||||
0x82, 0xf2, 0x19, 0xad, 0xe4, 0xc1, 0x58, 0x94, 0x4c, 0xc5, 0xcd, 0xd1, 0x25, 0xf2, 0xb1, 0x7f,
|
||||
0x1c, 0x2d, 0x15, 0x27, 0xb7, 0x40, 0xa8, 0x70, 0xe3, 0xfa, 0xeb, 0xdf, 0xf2, 0x42, 0x5b, 0x44,
|
||||
0x83, 0xbe, 0xff, 0xdf, 0x6c, 0x37, 0xb8, 0x09, 0x7c, 0x43, 0xda, 0xac, 0x78, 0x86, 0x7a, 0xce,
|
||||
0x57, 0x6f, 0xc2, 0xe6, 0x9f, 0x3a, 0x65, 0xfa, 0x41, 0x4a, 0xd8, 0xa1, 0x96, 0x8d, 0xfe, 0x3f,
|
||||
0xc1, 0x6d, 0xc7, 0x96, 0x85, 0x5c, 0xe0, 0x3d, 0xf7, 0xff, 0xfc, 0x6c, 0x14, 0x85, 0x65, 0x94,
|
||||
0x11, 0x44, 0x73, 0x8b, 0x28, 0x62, 0x3c, 0xb1, 0x76, 0x0b, 0x40, 0x9c, 0x95, 0xcf, 0x48, 0x2e,
|
||||
0x0a, 0xb8, 0x07, 0xd6, 0xfc, 0xce, 0xa1, 0x54, 0xfd, 0x63, 0x63, 0x1e, 0x83, 0x13, 0xd4, 0xf2,
|
||||
0x4a, 0xe5, 0x1e, 0x5a, 0x2f, 0x5b, 0x68, 0x9a, 0x70, 0xb5, 0x91, 0x9b, 0x4b, 0x3a, 0x90, 0x38,
|
||||
0xcb, 0x7e, 0x09, 0xc8, 0x67, 0x48, 0x9c, 0x23, 0x14, 0x45, 0x35, 0x86, 0xd3, 0x95, 0xa5, 0x63,
|
||||
0x90, 0x21, 0x1a, 0x11, 0xd2, 0x50, 0xc3, 0xa2, 0x3d, 0xe6, 0x91, 0x8f, 0x7b, 0xe4, 0xd9, 0x04,
|
||||
0x10, 0x45, 0x50, 0xa9, 0x43, 0x25, 0xe9, 0x4e, 0x9c, 0x45, 0x25, 0x18, 0xb9, 0xee, 0xb1, 0x36,
|
||||
0xfb, 0x76, 0x94, 0xe1, 0xfc, 0x94, 0x66, 0xb7, 0x25, 0xbb, 0x63, 0x5b, 0x58, 0xdb, 0x82, 0x25,
|
||||
0xe6, 0x94, 0x51, 0x90, 0xd8, 0xad, 0x52, 0xf9, 0x86, 0x8e, 0x23, 0x20, 0x1d, 0xb0, 0x12, 0x30,
|
||||
0xa4, 0xb1, 0x9d, 0x2c, 0x34, 0xb0, 0x07, 0xae, 0x70, 0xcb, 0x3f, 0x1c, 0xd1, 0xb1, 0x9a, 0xec,
|
||||
0x11, 0xb6, 0xef, 0xaa, 0xa0, 0xc3, 0x40, 0xb6, 0x41, 0x68, 0xc6, 0xda, 0xdf, 0xc7, 0xad, 0x5e,
|
||||
0x5e, 0xe5, 0xed, 0xe3, 0xff, 0x1e, 0xc3, 0x7e, 0x12, 0xac, 0x71, 0x3b, 0x14, 0xf0, 0x90, 0xaa,
|
||||
0x61, 0x53, 0xd5, 0x64, 0x5e, 0xfa, 0xf0, 0x72, 0xf5, 0xca, 0xdb, 0x72, 0xe4, 0x71, 0x4c, 0xb0,
|
||||
0x71, 0x00, 0x69, 0x63, 0xb0, 0xb8, 0x51, 0x6c, 0x1f, 0xc0, 0x63, 0xa2, 0xa4, 0x00, 0xcf, 0xb0,
|
||||
0xb6, 0xa5, 0xe3, 0xa6, 0xf7, 0x5d, 0x1c, 0xcf, 0x90, 0xbd, 0x1a, 0x77, 0x4d, 0x0f, 0x81, 0x4c,
|
||||
0x36, 0xa7, 0x84, 0xc5, 0x30, 0xb1, 0x5b, 0x3b, 0xd0, 0x6c, 0xd4, 0x53, 0x42, 0xba, 0x4d, 0x1e,
|
||||
0xd5, 0x46, 0xa3, 0x71, 0xa3, 0x15, 0xa9, 0x42, 0xdb, 0x83, 0x1c, 0xc1, 0x9c, 0xd6, 0xe7, 0x15,
|
||||
0xbc, 0xd5, 0xee, 0xfb, 0x10, 0x95, 0x6b, 0x5e, 0x01, 0xd1, 0xe7, 0xf1, 0x2f, 0x68, 0x6b, 0x0a,
|
||||
0x08, 0x37, 0x0b, 0x51, 0x27, 0x3f, 0x66, 0x20, 0x08, 0xcc, 0x2b, 0x7a, 0x58, 0xa1, 0x9d, 0x4e,
|
||||
0x82, 0xab, 0x41, 0x18, 0x96, 0x02, 0xd6, 0xd0, 0x71, 0x7b, 0x2d, 0x8d, 0xe8, 0x7b, 0x9e, 0x3e,
|
||||
0xfd, 0x68, 0x8c, 0x1d, 0xb2, 0x8e, 0x08, 0x1a, 0xe5, 0x08, 0xb4, 0x0c, 0xc6, 0x17, 0x0c, 0x05,
|
||||
0x06, 0xe1, 0xd7, 0x9a, 0x1e, 0x72, 0x2b, 0x88, 0xfd, 0x76, 0x04, 0xde, 0xf8, 0xdb, 0x78, 0x91,
|
||||
0xbd, 0xce, 0x43, 0xe3, 0x88, 0x08, 0x70, 0x22, 0x0d, 0x58, 0x66, 0x3e, 0xd8, 0x8e, 0x1d, 0x77,
|
||||
0x20, 0x9c, 0xb3, 0x14, 0xc2, 0x49, 0x44, 0xae, 0x6b, 0xcb, 0x01, 0x9e, 0xc1, 0x92, 0x65, 0x0f,
|
||||
0x81, 0xac, 0xb6, 0xc4, 0x85, 0xda, 0xe0, 0xe4, 0x01, 0x79, 0x68, 0xb0, 0x4c, 0x63, 0xd9, 0x45,
|
||||
0xd7, 0x9a, 0x74, 0xfb, 0x19, 0xc6, 0x67, 0x3d, 0x3b, 0x61, 0x9f, 0xd2, 0xf4, 0x40, 0xf9, 0x6e,
|
||||
0x49, 0x53, 0x76, 0xd2, 0x99, 0x49, 0x86, 0xe4, 0xb1, 0x9b, 0xf5, 0x09, 0x8e, 0x51, 0x44, 0x97,
|
||||
0x40, 0x2d, 0xe7, 0xbe, 0x9e, 0x3b, 0xd0, 0xf4, 0xc6, 0x67, 0x21, 0x06, 0xa6, 0x46, 0x84, 0x53,
|
||||
0xa1, 0x7c, 0xb3, 0x86, 0x76, 0xd3, 0x8f, 0x39, 0xe1, 0xf5, 0x78, 0x4a, 0x96, 0x1f, 0xa4, 0xad,
|
||||
0x2e, 0x88, 0x5d, 0xe5, 0x67, 0x91, 0xe4, 0xf9, 0x02, 0x92, 0x24, 0xf7, 0x10, 0xf4, 0x71, 0xb8,
|
||||
0x7e, 0x7e, 0xcd, 0x5b, 0x9c, 0xb4, 0x31, 0x7a, 0xfd, 0x9a, 0x31, 0x6f, 0xd1, 0xb5, 0xfa, 0x5f,
|
||||
0xda, 0x84, 0xec, 0xe7, 0xdf, 0x44, 0x68, 0x07, 0x82, 0x94, 0x90, 0x75, 0x91, 0x5a, 0xff, 0x1a,
|
||||
0x6b, 0x05, 0xbe, 0xa8, 0x3a, 0x76, 0x8a, 0xe5, 0x23, 0x33, 0xa0, 0xa9, 0xd0, 0xe9, 0xb6, 0x08,
|
||||
0x76, 0x2c, 0x17, 0xfa, 0x67, 0xd1, 0x01, 0x0a, 0xdc, 0x91, 0xdf, 0x22, 0xc8, 0x44, 0x13, 0x02,
|
||||
0x42, 0x6e, 0x9a, 0xc7, 0x97, 0x44, 0x21, 0x63, 0xb1, 0x8f, 0xc2, 0xf9, 0x45, 0x7b, 0xbd, 0x26,
|
||||
0xeb, 0x91, 0x25, 0x42, 0x6c, 0x3c, 0xb2, 0xd4, 0x9a, 0x62, 0x64, 0x4b, 0xd8, 0x12, 0x64, 0xcb,
|
||||
0x6a, 0xf9, 0x37, 0xd0, 0x5c, 0x0c, 0x09, 0x69, 0xf8, 0xbb, 0xaf, 0x97, 0x34, 0x64, 0xac, 0x45,
|
||||
0xb1, 0x1f, 0x7a, 0x24, 0xe5, 0x27, 0x3c, 0x46, 0xc3, 0xa5, 0xb4, 0xe9, 0x1d, 0xce, 0x8a, 0x32,
|
||||
0x37, 0xd4, 0x7f, 0x76, 0x84, 0x40, 0x40, 0x6f, 0xf3, 0xa5, 0xd7, 0x30, 0x64, 0xfe, 0xb2, 0xe0,
|
||||
0x4c, 0xa1, 0xe7, 0x9c, 0x30, 0x89, 0x5c, 0x9e, 0xcf, 0x4e, 0xef, 0x2f, 0x1f, 0xd7, 0xaf, 0xd7,
|
||||
0xce, 0x99, 0x8d, 0x79, 0xbc, 0xd1, 0x43, 0x89, 0x01, 0xb1, 0xa9, 0x1d, 0x1f, 0x86, 0xd0, 0x06,
|
||||
0x15, 0x82, 0xe5, 0xf7, 0x5c, 0x60, 0xf5, 0x4f, 0xde, 0xc9, 0xd6, 0xfb, 0x3c, 0xe4, 0xd4, 0x83,
|
||||
0x13, 0xf1, 0x80, 0xe3, 0x40, 0x5e, 0xc3, 0x45, 0xdf, 0x66, 0x8e, 0x87, 0x79, 0x11, 0x1c, 0x0e,
|
||||
0x32, 0x29, 0x69, 0xd8, 0xc0, 0xf8, 0x4d, 0xb2, 0xdc, 0x99, 0xab, 0x5f, 0x69, 0xb9, 0xd0, 0xf7,
|
||||
0x6c, 0xed, 0x54, 0x79, 0x9a, 0x6a, 0x76, 0xe0, 0x03, 0x0c, 0xa2, 0x69, 0x97, 0xab, 0x10, 0x4c,
|
||||
0x46, 0xdd, 0xa2, 0xe9, 0xbd, 0x74, 0x66, 0x97, 0x39, 0x49, 0xe3, 0xc9, 0x90, 0xe4, 0x61, 0xa9,
|
||||
0xe7, 0x35, 0xd0, 0xb3, 0x87, 0x43, 0xcd, 0x3b, 0x0a, 0x14, 0x66, 0xb5, 0xe4, 0x71, 0x33, 0x84,
|
||||
0x44, 0x32, 0xfa, 0x9c, 0xd8, 0x36, 0x71, 0x68, 0xcc, 0x04, 0xbf, 0x2f, 0x6b, 0xb3, 0x24, 0x55,
|
||||
0x71, 0x88, 0x25, 0xde, 0x47, 0xd9, 0xa8, 0x1e, 0xa9, 0x11, 0xa6, 0xf5, 0x3d, 0x3a, 0xfd, 0x77,
|
||||
0x52, 0x42, 0xfa, 0xa6, 0x3b, 0xff, 0xc8, 0xdb, 0xe7, 0xe8, 0xbc, 0x93, 0xa0, 0x12, 0xa5, 0xad,
|
||||
0x29, 0x07, 0x30, 0xcc, 0xe4, 0x82, 0x82, 0xc3, 0x8a, 0x95, 0x0f, 0xc4, 0x0b, 0x21, 0xe8, 0x61,
|
||||
0x3c, 0xc2, 0xb5, 0xb7, 0x6e, 0xaf, 0xd0, 0x8d, 0x88, 0xc8, 0x39, 0xd4, 0x7e, 0xe1, 0xa8, 0x1b,
|
||||
0x1a, 0x92, 0x73, 0xd7, 0xad, 0x1d, 0x57, 0x15, 0x07, 0xb4, 0xa1, 0x39, 0x56, 0x7f, 0xbc, 0x40,
|
||||
0xf3, 0x4a, 0xd6, 0x1b, 0x0e, 0xea, 0x2d, 0xea, 0x17, 0xad, 0xd5, 0x6b, 0x23, 0x6f, 0x45, 0xb7,
|
||||
0xa0, 0x38, 0x0d, 0xa7, 0xb4, 0xd4, 0x30, 0x08, 0xa5, 0xa5, 0x32, 0xd7, 0xd9, 0x14, 0x42, 0xc9,
|
||||
0xa8, 0xb6, 0x59, 0x7d, 0x40, 0xce, 0x96, 0xf2, 0xe8, 0x3a, 0x63, 0x8c, 0x33, 0xfb, 0x7b, 0xc0,
|
||||
0x1f, 0x99, 0xd5, 0x87, 0xd4, 0x10, 0x39, 0x8e, 0xcf, 0xe1, 0x55, 0x5c, 0x39, 0xf4, 0xf1, 0x50,
|
||||
0xaf, 0x4b, 0xa9, 0x0a, 0xc8, 0x31, 0x35, 0x68, 0x31, 0x17, 0xf6, 0x36, 0xa1, 0x79, 0x8d, 0x2d,
|
||||
0xd8, 0x3d, 0xb6, 0xd4, 0x79, 0x9d, 0x2d, 0xc4, 0xbd, 0x8a, 0xad, 0x13, 0x4c, 0xa5, 0xb8, 0x03,
|
||||
0x82, 0xb9, 0x41, 0xdc, 0xdd, 0x9e, 0x71, 0x1c, 0x09, 0x25, 0x40, 0x62, 0x1c, 0x8b, 0x0a, 0x03,
|
||||
0xb9, 0x0e, 0x9d, 0x96, 0x30, 0xa6, 0xb0, 0xa2, 0x81, 0x31, 0xea, 0x6a, 0x11, 0x04, 0x65, 0x07,
|
||||
0x36, 0xb9, 0x54, 0x1e, 0x57, 0x85, 0x40, 0xe8, 0x6d, 0x44, 0x01, 0xa4, 0xf3, 0xaa, 0x06, 0x53,
|
||||
0x0f, 0x9b, 0x6c, 0xd9, 0x20, 0xa0, 0x2c, 0xf2, 0x0f, 0x8a, 0x71, 0xba, 0x80, 0xec, 0x2d, 0x01,
|
||||
0xf9, 0x4b, 0x02, 0x9e, 0xa0, 0x32, 0x11, 0x59, 0x54, 0x1d, 0xa1, 0x28, 0xe2, 0xae, 0x13, 0xb1,
|
||||
0x69, 0x01, 0x46, 0x40, 0x8c, 0xbe, 0x9a, 0x2b, 0x9d, 0x49, 0xb7, 0x70, 0x5d, 0x98, 0x21, 0xd5,
|
||||
0x98, 0x6b, 0x7e, 0xbe, 0x34, 0xb8, 0xf9, 0x2a, 0xce, 0x7a, 0xe6, 0x6b, 0x86, 0xf3, 0x20, 0x50,
|
||||
0x02, 0xe8, 0xc3, 0x05, 0x4a, 0x36, 0xe4, 0xd0, 0x07, 0x21, 0x15, 0xda, 0x89, 0xb1, 0x61, 0x7c,
|
||||
0x39, 0x0f, 0x3a, 0x1b, 0xbc, 0x64, 0xa8, 0x73, 0x91, 0xd5, 0x21, 0x51, 0xd1, 0x3b, 0x31, 0x95,
|
||||
0x9c, 0xd4, 0x8b, 0x2b, 0x3f, 0xd2, 0xa5, 0x83, 0x6f, 0x58, 0xfe, 0x07, 0x4a, 0xe1, 0x31, 0x58,
|
||||
0x66, 0x09, 0xe8, 0x70, 0xab, 0x24, 0xf6, 0x3f, 0xde, 0x1a, 0x47, 0x89, 0x60, 0xd8, 0x06, 0x83,
|
||||
0x95, 0x29, 0x40, 0x9e, 0x69, 0x03, 0x3a, 0x3b, 0xc5, 0xe0, 0xcd, 0xd2, 0x19, 0x38, 0x8c, 0x83,
|
||||
0xb3, 0xce, 0x80, 0x1f, 0xb6, 0x73, 0x45, 0x8e, 0x5c, 0xfa, 0xb2, 0x75, 0xdc, 0x08, 0x5f, 0x0d,
|
||||
0xc0, 0x0a, 0x77, 0xf9, 0xee, 0x1b, 0xa7, 0x4a, 0x18, 0x21, 0x9c, 0xdc, 0x9b, 0x90, 0x01, 0x66,
|
||||
0xb6, 0x5f, 0x63, 0x55, 0x90, 0x16, 0xb0, 0x9c, 0xff, 0xf3, 0x5b, 0x10, 0x36, 0xcb, 0x74, 0x8f,
|
||||
0x3b, 0x1c, 0xba, 0xc9, 0x30, 0xf4, 0x3b, 0x8a, 0xcd, 0x5a, 0xd7, 0xb4, 0x0d, 0xb6, 0x86, 0x0e,
|
||||
0x39, 0x48, 0xcb, 0x8c, 0x6e, 0x12, 0x54, 0x15, 0xc6, 0x1d, 0xfb, 0x60, 0xd3, 0xc6, 0xa0, 0x2f,
|
||||
0x5e, 0x15, 0xf0, 0xc9, 0x1f, 0x5d, 0xe1, 0x3c, 0xb1, 0xe1, 0x37, 0x06, 0x00, 0x94, 0xb5, 0x38,
|
||||
0x10, 0xd2, 0xa7, 0xa6, 0x31, 0x1b, 0x0f, 0x87, 0xe5, 0x10, 0x01, 0x0f, 0x80, 0xd9, 0x8d, 0xfd,
|
||||
0x1d, 0xf1, 0xfe, 0x9a, 0x5a, 0xc4, 0x38, 0xb5, 0x40, 0x1c, 0x69, 0x11, 0x50, 0xd6, 0x86, 0x02,
|
||||
0x76, 0xea, 0xb7, 0x86, 0x42, 0xb1, 0x42, 0x05, 0xdc, 0xc8, 0xd8, 0xf8, 0x9a, 0x9f, 0x4a, 0x12,
|
||||
0xc4, 0x0f, 0x10, 0x45, 0x57, 0xd4, 0x2c, 0x14, 0x53, 0x03, 0xa5, 0xb5, 0x60, 0x04, 0x16, 0xee,
|
||||
0xa4, 0x20, 0xf7, 0xca, 0xb7, 0xaa, 0xfc, 0xa9, 0xde, 0x38, 0xf3, 0xdd, 0xed, 0x59, 0x13, 0xc6,
|
||||
0xba, 0xa8, 0xfe, 0xb0, 0x3e, 0x2a, 0x3e, 0xec, 0x67, 0xd5, 0x87, 0xbd, 0x57, 0x7f, 0xd8, 0x47,
|
||||
0xf2, 0xa3, 0x0c, 0xa9, 0xb7, 0x7c, 0xf9, 0xe8, 0xae, 0xca, 0x1a, 0x5a, 0x26, 0xe2, 0xaf, 0x31,
|
||||
0xbc, 0xb8, 0x34, 0xab, 0x32, 0xbb, 0x49, 0xca, 0xca, 0xc4, 0xd7, 0xbe, 0x29, 0x09, 0x38, 0xd0,
|
||||
0xbf, 0xfb, 0xee, 0x48, 0x23, 0x51, 0xbf, 0xf6, 0xa2, 0x88, 0x97, 0x2b, 0x0b, 0xbf, 0x0d, 0x76,
|
||||
0xce, 0x82, 0x2b, 0xb6, 0x0f, 0xb8, 0x46, 0x55, 0x8d, 0x3f, 0x91, 0x07, 0xb5, 0x70, 0xe2, 0xd4,
|
||||
0x3d, 0xf4, 0xa1, 0xb2, 0xa3, 0x86, 0x33, 0xc4, 0x7c, 0x19, 0x01, 0x77, 0x86, 0x28, 0xe2, 0x2b,
|
||||
0x38, 0xed, 0x63, 0xb8, 0xd9, 0x42, 0xec, 0x0a, 0x2f, 0x0a, 0xdb, 0x08, 0x61, 0x90, 0xfb, 0x9c,
|
||||
0x7b, 0x8e, 0x71, 0xc6, 0x0f, 0xe8, 0x39, 0xb9, 0x51, 0xeb, 0x8a, 0xdc, 0x71, 0x63, 0xaf, 0x87,
|
||||
0x75, 0xf3, 0xcf, 0x0b, 0x56, 0x88, 0xde, 0x0e, 0x4e, 0xd2, 0xe5, 0x03, 0x24, 0xc3, 0x72, 0xd2,
|
||||
0x29, 0x53, 0x6a, 0xa3, 0x8d, 0xbf, 0x2f, 0x7e, 0x68, 0x5e, 0xe7, 0x0b, 0x9d, 0x43, 0x1e, 0x08,
|
||||
0x9b, 0x4f, 0x79, 0x90, 0x9a, 0x8f, 0xcc, 0x6e, 0xbc, 0x8a, 0x62, 0x97, 0xcc, 0xb7, 0x2b, 0x86,
|
||||
0x00, 0x21, 0x19, 0x69, 0x6a, 0x65, 0xa2, 0x22, 0x64, 0x2c, 0x5c, 0x7f, 0xe1, 0xa0, 0x56, 0xd2,
|
||||
0xdc, 0x5f, 0xc8, 0xac, 0x1a, 0x1c, 0x24, 0xd9, 0xa1, 0x80, 0x39, 0xdd, 0x1b, 0x7e, 0x45, 0x28,
|
||||
0x6a, 0x6a, 0xd5, 0x3c, 0x78, 0x44, 0x82, 0x06, 0x4c, 0x64, 0x06, 0x11, 0xe7, 0x15, 0xeb, 0xb3,
|
||||
0x86, 0x70, 0xc5, 0xbe, 0xee, 0xae, 0x55, 0x32, 0x30, 0x3b, 0xc1, 0x35, 0x5d, 0x5d, 0xe7, 0x35,
|
||||
0x70, 0xb6, 0xe2, 0x0b, 0xf7, 0xfa, 0x35, 0x7b, 0x5d, 0x0f, 0xca, 0x8f, 0xd6, 0x69, 0xad, 0xde,
|
||||
0x78, 0x55, 0x34, 0x4d, 0x33, 0xbc, 0x61, 0xd3, 0x28, 0x25, 0x09, 0xf3, 0x44, 0x2c, 0x44, 0x9c,
|
||||
0x86, 0x21, 0x1c, 0x36, 0x68, 0xa4, 0x7c, 0x2c, 0x63, 0x29, 0xb9, 0xc4, 0xd6, 0xcd, 0x04, 0x9d,
|
||||
0x56, 0x93, 0x91, 0xb4, 0xbc, 0xd4, 0x0c, 0x67, 0x50, 0xd3, 0x04, 0x84, 0xc7, 0x06, 0x15, 0x21,
|
||||
0x92, 0xda, 0xec, 0x85, 0x3b, 0x61, 0x2a, 0xb5, 0xe8, 0xb6, 0x24, 0x10, 0x1b, 0x9d, 0xbf, 0x46,
|
||||
0x6d, 0x1c, 0xd0, 0x02, 0x63, 0x23, 0x21, 0x32, 0x80, 0x00, 0xfd, 0xbc, 0x64, 0x81, 0xca, 0x74,
|
||||
0x2a, 0x98, 0xff, 0x4d, 0x96, 0x62, 0x5d, 0xd0, 0x4e, 0x15, 0x6f, 0xb3, 0xab, 0x56, 0xd5, 0xec,
|
||||
0xda, 0x2a, 0x36, 0x6b, 0xd6, 0x05, 0xd9, 0x81, 0x18, 0xed, 0x5b, 0x8a, 0xb6, 0x9a, 0x7c, 0x68,
|
||||
0x12, 0x82, 0x6e, 0x87, 0x1d, 0x01, 0xba, 0xa5, 0x0a, 0x76, 0x44, 0xbb, 0x87, 0x67, 0x60, 0x71,
|
||||
0x02, 0xd9, 0x06, 0x9e, 0x93, 0x36, 0x06, 0x3e, 0xe0, 0xd8, 0x0c, 0xfa, 0xa2, 0x30, 0x79, 0xd3,
|
||||
0x09, 0x6c, 0x77, 0xe1, 0x23, 0x22, 0xdf, 0xf2, 0x3c, 0x0f, 0x74, 0x12, 0x89, 0xc0, 0x35, 0x86,
|
||||
0x25, 0x64, 0xf6, 0x94, 0xde, 0x6f, 0xb6, 0xd5, 0x35, 0x91, 0x47, 0x8f, 0xab, 0xac, 0xde, 0xf4,
|
||||
0x38, 0xbc, 0x9e, 0x50, 0x1f, 0xfd, 0x67, 0x1e, 0x46, 0x43, 0x83, 0x73, 0x48, 0x11, 0x65, 0x47,
|
||||
0x44, 0xdf, 0x38, 0xce, 0x7f, 0xcd, 0x27, 0x48, 0xa0, 0x59, 0xd8, 0x77, 0x04, 0x28, 0x57, 0x2d,
|
||||
0x73, 0x55, 0x2a, 0x46, 0x46, 0x03, 0x5b, 0x54, 0x26, 0x7d, 0xb6, 0x11, 0x32, 0x57, 0x45, 0x6c,
|
||||
0xbe, 0x09, 0x1e, 0x48, 0xf9, 0x9a, 0x06, 0xc9, 0xd1, 0x9b, 0x37, 0xec, 0x3f, 0x03, 0xf0, 0x1e,
|
||||
0x98, 0xc2, 0x86, 0x27, 0x4b, 0x11, 0x08, 0x29, 0x3a, 0x74, 0x85, 0x10, 0xb6, 0xa7, 0xc3, 0x09,
|
||||
0x52, 0x4f, 0xc0, 0x01, 0xd3, 0x3a, 0x4c, 0x51, 0xf3, 0x29, 0xd1, 0x4c, 0x1f, 0x44, 0xd4, 0xb2,
|
||||
0xbd, 0x2f, 0x5e, 0xc7, 0x97, 0x6f, 0xc3, 0xa7, 0x15, 0x42, 0x65, 0xdf, 0x7d, 0xf9, 0xd8, 0x1e,
|
||||
0x8a, 0xc0, 0x7c, 0xb5, 0xf3, 0xaa, 0x54, 0x08, 0xb0, 0xb1, 0xfc, 0x65, 0x02, 0x6a, 0x13, 0xda,
|
||||
0x9c, 0x51, 0x7f, 0x8a, 0xd9, 0x51, 0x62, 0xc8, 0x54, 0x94, 0x55, 0x78, 0xe6, 0x1e, 0x33, 0x89,
|
||||
0x0c, 0x75, 0x34, 0x60, 0x64, 0x1b, 0xbc, 0x9e, 0x17, 0xc5, 0x7a, 0xa7, 0x38, 0xb6, 0x08, 0x77,
|
||||
0x62, 0xae, 0xe8, 0x11, 0x7a, 0xba, 0x81, 0x69, 0x28, 0xb6, 0x4b, 0x04, 0xea, 0x29, 0xea, 0xff,
|
||||
0xc5, 0x43, 0xdf, 0x42, 0xe8, 0xdc, 0xad, 0x45, 0x6f, 0x09, 0x42, 0xf6, 0x22, 0xa8, 0x9c, 0x3b,
|
||||
0xc7, 0x74, 0x4e, 0x35, 0x57, 0x8f, 0x3b, 0xa5, 0x0a, 0x2a, 0x57, 0xa0, 0x4e, 0x84, 0x2c, 0x00,
|
||||
0x64, 0x91, 0x50, 0x1c, 0x71, 0xab, 0xec, 0x95, 0x12, 0x1d, 0xa4, 0x8c, 0xa2, 0x85, 0xb7, 0x9e,
|
||||
0x46, 0x29, 0x47, 0x99, 0xbb, 0x88, 0x01, 0x4f, 0xe4, 0x92, 0x22, 0xb6, 0xb3, 0x6c, 0x3e, 0xb3,
|
||||
0x6a, 0x18, 0x09, 0xdc, 0x87, 0x25, 0xba, 0x99, 0x0d, 0xa5, 0x5a, 0x02, 0x82, 0xd8, 0x7e, 0xe3,
|
||||
0x7b, 0x85, 0x70, 0x75, 0x8b, 0x97, 0x66, 0x9c, 0x25, 0x12, 0x25, 0x07, 0xf2, 0xb9, 0x6c, 0xb1,
|
||||
0xb5, 0xae, 0x7a, 0xc4, 0xa8, 0xa5, 0x5e, 0xaf, 0x0a, 0xc8, 0x59, 0x7c, 0x44, 0xc1, 0x29, 0xa2,
|
||||
0xe2, 0x4e, 0x8e, 0xbb, 0x22, 0x3a, 0x5b, 0x97, 0x51, 0xa0, 0x8b, 0x7b, 0x1c, 0x6f, 0xd2, 0x8f,
|
||||
0xce, 0xc3, 0x18, 0x3d, 0x1f, 0xdf, 0x4d, 0x78, 0x97, 0xed, 0xd2, 0x15, 0xae, 0x3d, 0xb9, 0x8d,
|
||||
0x85, 0x31, 0x6b, 0x72, 0x5e, 0x98, 0x98, 0x32, 0x59, 0xa7, 0xbd, 0x32, 0x5f, 0x30, 0xa5, 0x0a,
|
||||
0x9d, 0xb4, 0xb6, 0x6c, 0xdb, 0xa5, 0xf4, 0xad, 0xf0, 0xd6, 0x93, 0xf9, 0x37, 0x6b, 0xac, 0xb0,
|
||||
0x6b, 0x96, 0xfb, 0x97, 0x1b, 0x4a, 0xb3, 0x16, 0xe2, 0xe0, 0x45, 0xfe, 0x7e, 0x37, 0xb0, 0xb1,
|
||||
0x5d, 0x11, 0xca, 0xba, 0x36, 0x52, 0x99, 0x4d, 0x9f, 0x74, 0xd0, 0xc8, 0x5e, 0x09, 0x3b, 0x80,
|
||||
0xf1, 0x7f, 0x9d, 0x97, 0xe0, 0xd5, 0xae, 0x87, 0xb0, 0xef, 0x34, 0xe2, 0x8b, 0x86, 0xf0, 0x1b,
|
||||
0x23, 0xec, 0x2e, 0xbc, 0x1e, 0x14, 0x30, 0x62, 0x03, 0x2b, 0xa5, 0x29, 0x35, 0x74, 0x28, 0x82,
|
||||
0x12, 0x8a, 0xf7, 0xb1, 0x28, 0x1b, 0xbc, 0x77, 0x4a, 0x19, 0xee, 0x70, 0xb7, 0x23, 0xe4, 0x3c,
|
||||
0x8d, 0x9a, 0x73, 0x9c, 0x9d, 0xaa, 0x73, 0x66, 0xee, 0x05, 0x87, 0x2c, 0x04, 0xfe, 0x71, 0x94,
|
||||
0x73, 0x2d, 0x36, 0x63, 0x03, 0x86, 0x37, 0x35, 0x36, 0x18, 0x12, 0xfa, 0xd1, 0xe9, 0xd9, 0x01,
|
||||
0xaa, 0x98, 0xbd, 0x68, 0xab, 0x1f, 0x1d, 0xcd, 0x09, 0x7d, 0xd3, 0xe5, 0x0f, 0x16, 0x6d, 0x3a,
|
||||
0x60, 0x33, 0xf5, 0x62, 0xf2, 0xc2, 0x7c, 0x67, 0xcf, 0xf7, 0x61, 0xdd, 0x0b, 0xf5, 0x37, 0xa5,
|
||||
0x05, 0x72, 0xe0, 0x5b, 0x37, 0x75, 0x6c, 0x76, 0x14, 0x3a, 0x3d, 0x11, 0x00, 0x90, 0x04, 0xbe,
|
||||
0x78, 0x8b, 0xda, 0x5a, 0x44, 0xda, 0x83, 0x11, 0xe3, 0xde, 0x4d, 0xfc, 0x3c, 0x46, 0xf8, 0xc6,
|
||||
0x5e, 0xe1, 0x61, 0x26, 0x1b, 0x13, 0x11, 0x0a, 0x28, 0xd6, 0xf2, 0xb9, 0x12, 0x8d, 0x21, 0xee,
|
||||
0xd5, 0x6c, 0x93, 0x2c, 0x3f, 0xcb, 0x7e, 0x5d, 0x5e, 0x4e, 0xa3, 0x1e, 0x62, 0xc5, 0x04, 0xcd,
|
||||
0xbf, 0x7a, 0xd9, 0x1d, 0xca, 0x56, 0x37, 0x74, 0x06, 0x05, 0x86, 0xc8, 0x68, 0xa8, 0xdb, 0x03,
|
||||
0x99, 0x15, 0x79, 0x1b, 0x59, 0x38, 0xec, 0x64, 0x81, 0x0d, 0xc6, 0xa2, 0x89, 0xee, 0x38, 0x8f,
|
||||
0x80, 0x6a, 0x9c, 0x7c, 0x53, 0xae, 0x80, 0x89, 0x57, 0x61, 0x1e, 0xc6, 0x0e, 0xdf, 0xda, 0x69,
|
||||
0x4f, 0x47, 0x76, 0x39, 0x06, 0x67, 0x96, 0x6d, 0x3f, 0x9a, 0x99, 0xe7, 0xee, 0x91, 0x83, 0x20,
|
||||
0x64, 0x34, 0x35, 0xa1, 0xfa, 0x5f, 0x4b, 0x80, 0xb4, 0xaf, 0x4f, 0xba, 0x99, 0x65, 0x0f, 0x67,
|
||||
0x5d, 0x92, 0x6f, 0x12, 0xb2, 0x6d, 0xbc, 0x63, 0xda, 0xcc, 0x53, 0x08, 0x0c, 0x9e, 0xd6, 0x4f,
|
||||
0x2e, 0xcb, 0x4b, 0x4c, 0xda, 0x42, 0x6b, 0x9c, 0x30, 0xae, 0x89, 0x7d, 0xe7, 0x13, 0x95, 0x4f,
|
||||
0xb8, 0xe1, 0x81, 0x0b, 0xf9, 0xd1, 0x53, 0x5a, 0x39, 0x13, 0xbb, 0x50, 0x6f, 0x0d, 0x08, 0xd3,
|
||||
0x69, 0x15, 0xb7, 0x89, 0x61, 0xa9, 0xb3, 0xfa, 0x74, 0x0f, 0x25, 0x43, 0x03, 0x57, 0x76, 0x16,
|
||||
0x38, 0x79, 0x55, 0xed, 0x82, 0x71, 0xad, 0xc5, 0x2e, 0x5d, 0xe2, 0x25, 0x46, 0xbc, 0x83, 0x87,
|
||||
0xbf, 0x2b, 0x68, 0x87, 0xd2, 0xa6, 0x2f, 0xbb, 0x79, 0xa2, 0xdd, 0x33, 0xa1, 0xe8, 0xc6, 0x6c,
|
||||
0x49, 0xc8, 0xc6, 0x53, 0xf4, 0x54, 0xb5, 0x74, 0x03, 0xbd, 0x59, 0xc6, 0x10, 0xae, 0x70, 0x66,
|
||||
0xed, 0xd7, 0xe8, 0x7e, 0x85, 0xff, 0x1a, 0xbd, 0xaf, 0x08, 0x5f, 0xa3, 0xff, 0xff, 0x15, 0xe7,
|
||||
0x41, 0x95, 0xf3, 0x22, 0xa6, 0x58, 0x06, 0xea, 0x02, 0x7e, 0x98, 0x94, 0xaf, 0xa6, 0x65, 0x3b,
|
||||
0x46, 0x41, 0xa9, 0x6e, 0x75, 0xe8, 0x28, 0xe7, 0x0d, 0x47, 0x39, 0xc7, 0xfa, 0xe3, 0x4a, 0x9a,
|
||||
0x47, 0xaa, 0xb6, 0x8e, 0x69, 0x7e, 0xdf, 0x3b, 0x79, 0xa6, 0x5d, 0x98, 0x7a, 0x19, 0x45, 0x6e,
|
||||
0x1e, 0x54, 0xde, 0xd6, 0xcc, 0xb0, 0x21, 0x27, 0x6b, 0x37, 0xed, 0xd1, 0xe7, 0xad, 0x1d, 0x1d,
|
||||
0x91, 0x4a, 0xdc, 0x58, 0x29, 0xe0, 0x47, 0x70, 0x77, 0x6e, 0x69, 0x6a, 0xa9, 0x6e, 0xdc, 0xb5,
|
||||
0xb7, 0x91, 0x76, 0xe2, 0x14, 0xbb, 0xdc, 0xaa, 0xe9, 0x81, 0x17, 0xc1, 0xe7, 0x64, 0x95, 0x0e,
|
||||
0x0c, 0x4a, 0xd7, 0x48, 0xac, 0xe1, 0x4c, 0x56, 0x9c, 0x42, 0x9c, 0xe5, 0xa4, 0xa9, 0x83, 0xb5,
|
||||
0xd4, 0xbc, 0x2a, 0xbf, 0x94, 0xfb, 0xbd, 0x59, 0x05, 0x91, 0xf9, 0x67, 0xad, 0xe9, 0x51, 0x69,
|
||||
0x84, 0xd4, 0xa8, 0x79, 0xc0, 0xd2, 0x23, 0xfa, 0xf5, 0x0c, 0x92, 0xb2, 0x68, 0x8c, 0x32, 0xb1,
|
||||
0x10, 0xc4, 0xb0, 0x3b, 0xac, 0xb1, 0x71, 0x11, 0xd6, 0x23, 0x63, 0x72, 0xc4, 0x0c, 0x29, 0x8a,
|
||||
0xb8, 0xcd, 0xa1, 0x15, 0xe9, 0x55, 0xb8, 0x4b, 0x66, 0x30, 0x7d, 0x74, 0xb3, 0x74, 0xfb, 0x9b,
|
||||
0x5d, 0x37, 0x38, 0x30, 0x9f, 0xbf, 0x21, 0x41, 0x64, 0x73, 0x0f, 0xf8, 0x8a, 0x2f, 0x67, 0x36,
|
||||
0x02, 0xe8, 0x8a, 0x5a, 0x49, 0x59, 0x82, 0x52, 0xdf, 0x3c, 0x20, 0x96, 0x9b, 0x69, 0x7d, 0xe3,
|
||||
0x70, 0x78, 0x7e, 0x52, 0x90, 0x09, 0xa9, 0x6d, 0xea, 0xeb, 0x38, 0x9a, 0x50, 0x95, 0xf5, 0x05,
|
||||
0x04, 0x41, 0x2a, 0x80, 0x9b, 0xf7, 0xd3, 0x9a, 0xee, 0xae, 0xc0, 0x10, 0xc3, 0x3c, 0x3d, 0xe3,
|
||||
0xa9, 0xb9, 0x20, 0xeb, 0xdf, 0xcc, 0xfc, 0xd9, 0xc6, 0x29, 0x7f, 0xdf, 0xe2, 0xb9, 0x87, 0x13,
|
||||
0x8f, 0xa1, 0xc3, 0x4c, 0x90, 0x4d, 0x47, 0xa3, 0xbd, 0x87, 0x05, 0x79, 0xe2, 0xb3, 0xf3, 0xba,
|
||||
0xc6, 0x7d, 0x66, 0x32, 0xc5, 0x50, 0x28, 0xb8, 0x54, 0xe1, 0x2a, 0xf2, 0xb5, 0xc6, 0x73, 0x09,
|
||||
0xa7, 0x7e, 0x59, 0x65, 0x3b, 0x48, 0x56, 0x32, 0x7a, 0xa6, 0x6a, 0x65, 0xf1, 0x01, 0xed, 0x77,
|
||||
0x59, 0x14, 0x9d, 0x64, 0xb9, 0x77, 0xa7, 0xdb, 0x03, 0xbc, 0x65, 0xf5, 0xd7, 0x70, 0xef, 0xe9,
|
||||
0xa4, 0x2b, 0x7a, 0xf8, 0xc0, 0xb7, 0x2a, 0x89, 0x6c, 0x24, 0x3b, 0x3f, 0x26, 0xe4, 0x3f, 0xc5,
|
||||
0x01, 0xa8, 0xe5, 0xd8, 0xf7, 0xf6, 0x11, 0x7f, 0xd0, 0x46, 0x8f, 0xdd, 0xb4, 0xf8, 0x4a, 0x44,
|
||||
0x40, 0xb7, 0xf8, 0x98, 0x14, 0x8b, 0x5c, 0x76, 0xdb, 0x58, 0x30, 0x23, 0x79, 0x1c, 0x15, 0x0a,
|
||||
0xed, 0x2b, 0xa2, 0xbb, 0x29, 0xb7, 0xba, 0xe5, 0xfe, 0xad, 0xce, 0x47, 0x6e, 0x3f, 0x4a, 0xeb,
|
||||
0x70, 0x08, 0x37, 0x92, 0xc8, 0x34, 0xe1, 0x87, 0x4a, 0xdc, 0x72, 0x59, 0x43, 0x40, 0x0b, 0xa3,
|
||||
0xb5, 0x79, 0xe2, 0x1c, 0xa6, 0x1f, 0x13, 0x3e, 0xe9, 0xf5, 0x0d, 0x9d, 0x55, 0x20, 0x5e, 0x27,
|
||||
0xef, 0xf7, 0x0b, 0xff, 0x99, 0x67, 0x0c, 0x85, 0x59, 0xc6, 0x4b, 0xef, 0x96, 0xbb, 0x66, 0x52,
|
||||
0x8b, 0x6d, 0xfc, 0xe9, 0x78, 0x9a, 0x7b, 0xf6, 0xa4, 0x5c, 0xa3, 0x0d, 0x7d, 0x9e, 0xb4, 0x20,
|
||||
0x88, 0x31, 0x36, 0x3d, 0x95, 0x21, 0x72, 0x18, 0x9a, 0xaf, 0x30, 0x2d, 0x23, 0x8a, 0x38, 0x91,
|
||||
0xed, 0x9e, 0x24, 0x00, 0xcb, 0x85, 0x64, 0x8c, 0xcf, 0x37, 0xcd, 0x69, 0xe6, 0x12, 0xe3, 0x21,
|
||||
0xb4, 0xb9, 0xa5, 0xdb, 0x50, 0x12, 0x36, 0xda, 0x6c, 0xc4, 0x39, 0x5c, 0xd2, 0x92, 0x65, 0xdb,
|
||||
0xfd, 0x60, 0xd4, 0xfd, 0x54, 0x69, 0xa6, 0x75, 0xd7, 0x24, 0xca, 0x9e, 0x33, 0xc4, 0xc2, 0x49,
|
||||
0x26, 0x7a, 0x55, 0x70, 0x4c, 0x4f, 0x08, 0x82, 0x23, 0x69, 0x0f, 0x28, 0xd8, 0xb6, 0x4a, 0x95,
|
||||
0x72, 0x7c, 0x10, 0x15, 0x78, 0x70, 0x9a, 0x95, 0x8a, 0x8f, 0xa7, 0xb2, 0x72, 0x4d, 0xd5, 0xaa,
|
||||
0x09, 0x68, 0x9e, 0xe9, 0x51, 0x43, 0x34, 0x78, 0x33, 0x34, 0xec, 0x63, 0xdb, 0xb1, 0x6f, 0x17,
|
||||
0x05, 0x22, 0x2c, 0x3f, 0x7b, 0xae, 0x68, 0xf2, 0x4f, 0x13, 0x9e, 0x77, 0x5c, 0x91, 0x2f, 0x39,
|
||||
0x25, 0x1a, 0xfb, 0xfc, 0xdf, 0xbc, 0xe9, 0x67, 0xf4, 0x7d, 0x3c, 0x25, 0xe4, 0x62, 0xf2, 0x99,
|
||||
0x90, 0x5f, 0xe3, 0x6b, 0x42, 0xc6, 0xbf, 0xaf, 0x3f, 0xae, 0xfc, 0xa7, 0xfb, 0xfd, 0x6e, 0xfa,
|
||||
0xaf, 0x2b, 0x7f, 0xee, 0x1b, 0xdf, 0x7d, 0xd9, 0x77, 0x33, 0xf9, 0xbd, 0xef, 0xf2, 0xec, 0x76,
|
||||
0xdf, 0xf4, 0xf2, 0xfe, 0x35, 0x9c, 0x4f, 0xce, 0x68, 0x3e, 0x1b, 0x36, 0x70, 0xf2, 0xf3, 0x30,
|
||||
0xc8, 0x20, 0xcd, 0x94, 0x63, 0x50, 0xc3, 0x01, 0x1e, 0x4e, 0xf8, 0xb2, 0x95, 0x5e, 0x5d, 0xff,
|
||||
0xd4, 0x31, 0x93, 0x29, 0x41, 0xc6, 0x39, 0x4e, 0xbd, 0xb3, 0x03, 0xcc, 0x4a, 0x68, 0x97, 0x09,
|
||||
0xe3, 0x70, 0x28, 0x7e, 0xf7, 0xd4, 0x2f, 0x5b, 0x61, 0x16, 0x89, 0xd9, 0xd4, 0xf4, 0xaa, 0xed,
|
||||
0x6f, 0x4f, 0x4d, 0xde, 0x3c, 0x28, 0x2e, 0x27, 0xe0, 0xbc, 0xf2, 0x4a, 0x69, 0xbc, 0x9a, 0x01,
|
||||
0xb3, 0x86, 0x55, 0x3b, 0xe5, 0x76, 0x8d, 0xfd, 0x0d, 0x48, 0xff, 0xb4, 0xe5, 0x69, 0xfb, 0xb0,
|
||||
0xf4, 0x68, 0x2b, 0x19, 0x16, 0x59, 0x3c, 0xca, 0x7a, 0xd4, 0x64, 0xb7, 0xa7, 0xde, 0x48, 0xdd,
|
||||
0xd0, 0x6b, 0xca, 0x30, 0x12, 0x20, 0x1c, 0xec, 0x13, 0x05, 0x90, 0x76, 0xb3, 0x7a, 0xc1, 0x59,
|
||||
0x4f, 0x2e, 0xa3, 0xfb, 0xec, 0xa5, 0xd3, 0xc7, 0xc2, 0x58, 0xf4, 0x07, 0xf1, 0x09, 0x90, 0x0a,
|
||||
0x48, 0x64, 0x1c, 0x9f, 0x72, 0x61, 0x1e, 0xa9, 0x13, 0x01, 0x88, 0x6d, 0x12, 0x50, 0xe1, 0xa4,
|
||||
0x75, 0xe6, 0xd6, 0x2f, 0x6d, 0x2d, 0x60, 0x7c, 0x84, 0xcb, 0xe9, 0x88, 0x25, 0x6e, 0x6d, 0x08,
|
||||
0xe3, 0xec, 0x79, 0x3b, 0x34, 0x32, 0xd8, 0x61, 0x59, 0x78, 0x6a, 0xc2, 0x8f, 0x86, 0x6d, 0x37,
|
||||
0xe8, 0xcd, 0x41, 0x00,
|
||||
};
|
||||
|
||||
const unsigned int html_content_br_len = 5940;
|
||||
|
||||
#endif // HTML_CONTENT_BR_H
|
||||
@@ -1,31 +1,225 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Enhanced HTML/CSS/JS Minifier and Compressor
|
||||
This script provides multiple levels of optimization for embedded web pages
|
||||
"""
|
||||
|
||||
import minify_html
|
||||
import gzip
|
||||
import brotli
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
with open("landingpage.html", "r", encoding="utf-8") as fin:
|
||||
original_html = fin.read()
|
||||
# Try to import optional JavaScript minifier
|
||||
try:
|
||||
import jsmin
|
||||
HAS_JSMIN = True
|
||||
except ImportError:
|
||||
HAS_JSMIN = False
|
||||
print("Warning: jsmin not installed. Install with: pip install jsmin --break-system-packages")
|
||||
|
||||
minified_html = minify_html.minify(
|
||||
original_html,
|
||||
minify_js=True,
|
||||
minify_css=True,
|
||||
keep_comments=False, # Remove comments
|
||||
keep_html_and_head_opening_tags=False, # Remove <html> and <head> if possible
|
||||
keep_closing_tags=True, # Keep closing tags (safer; set False for more aggression if you test thoroughly)
|
||||
remove_processing_instructions=True, # Remove <?xml ...> etc.
|
||||
#keep_comments=False,
|
||||
remove_bangs=False # Keep <!DOCTYPE> bang (removing saves bytes but can break some edge cases)
|
||||
)
|
||||
# Try to import rjsmin (faster alternative)
|
||||
try:
|
||||
import rjsmin
|
||||
HAS_RJSMIN = True
|
||||
except ImportError:
|
||||
HAS_RJSMIN = False
|
||||
|
||||
with open("webpage_minified.html", "w") as fout:
|
||||
fout.write(minified_html)
|
||||
|
||||
|
||||
minified_bytes = minified_html.encode('utf-8')
|
||||
gzipped_bytes = gzip.compress(minified_bytes, compresslevel=9)
|
||||
|
||||
|
||||
with open("webpage.h", "w") as fout:
|
||||
fout.write("const char html_content[] = {")
|
||||
fout.write(','.join(f'0x{byte:02x}' for byte in gzipped_bytes))
|
||||
fout.write("};\n\n")
|
||||
fout.write(f"const unsigned int html_content_len = {len(gzipped_bytes)};\n")
|
||||
def extract_and_minify_js(html_content):
|
||||
"""Extract JavaScript, minify it, and reinsert into HTML"""
|
||||
if not (HAS_JSMIN or HAS_RJSMIN):
|
||||
return html_content
|
||||
|
||||
# Find all script tags
|
||||
script_pattern = re.compile(r'<script>(.*?)</script>', re.DOTALL)
|
||||
|
||||
def minify_script_content(match):
|
||||
script_content = match.group(1)
|
||||
|
||||
# Skip if empty or too small
|
||||
if len(script_content.strip()) < 50:
|
||||
return match.group(0)
|
||||
|
||||
try:
|
||||
# Use rjsmin if available (faster), otherwise jsmin
|
||||
if HAS_RJSMIN:
|
||||
minified = rjsmin.jsmin(script_content)
|
||||
elif HAS_JSMIN:
|
||||
minified = jsmin.jsmin(script_content)
|
||||
else:
|
||||
minified = script_content
|
||||
|
||||
return f'<script>{minified}</script>'
|
||||
except Exception as e:
|
||||
print(f"Warning: JS minification failed: {e}")
|
||||
return match.group(0)
|
||||
|
||||
return script_pattern.sub(minify_script_content, html_content)
|
||||
|
||||
|
||||
def aggressive_html_minify(html_content):
|
||||
"""Apply aggressive minification strategies"""
|
||||
|
||||
# First pass: minify JavaScript
|
||||
html_content = extract_and_minify_js(html_content)
|
||||
|
||||
# Use minify_html library
|
||||
minified = minify_html.minify(
|
||||
html_content,
|
||||
minify_js=True,
|
||||
minify_css=True,
|
||||
keep_comments=False,
|
||||
keep_html_and_head_opening_tags=False,
|
||||
keep_closing_tags=True, # Safer - can set to False for more aggressive
|
||||
remove_processing_instructions=True,
|
||||
remove_bangs=False, # Keep <!DOCTYPE>
|
||||
#do_not_minify_doctype=True,
|
||||
#ensure_spec_compliant_unquoted_attribute_values=True,
|
||||
#keep_spaces_between_attributes=False,
|
||||
)
|
||||
|
||||
return minified
|
||||
|
||||
|
||||
def generate_c_header(data, variable_name="html_content", use_progmem=True):
|
||||
"""Generate C/C++ header file with compressed data"""
|
||||
lines = []
|
||||
|
||||
# Add header guard
|
||||
guard = variable_name.upper() + "_H"
|
||||
lines.append(f"#ifndef {guard}")
|
||||
lines.append(f"#define {guard}")
|
||||
lines.append("")
|
||||
|
||||
# Add includes if using PROGMEM
|
||||
if use_progmem:
|
||||
lines.append("#include <Arduino.h>")
|
||||
lines.append("")
|
||||
|
||||
# Add array declaration
|
||||
progmem_keyword = "PROGMEM " if use_progmem else ""
|
||||
lines.append(f"const unsigned char {progmem_keyword}{variable_name}[] = {{")
|
||||
|
||||
# Format bytes in rows of 16
|
||||
hex_bytes = [f'0x{byte:02x}' for byte in data]
|
||||
for i in range(0, len(hex_bytes), 16):
|
||||
row = hex_bytes[i:i+16]
|
||||
lines.append(" " + ", ".join(row) + ",")
|
||||
|
||||
lines.append("};")
|
||||
lines.append("")
|
||||
lines.append(f"const unsigned int {variable_name}_len = {len(data)};")
|
||||
lines.append("")
|
||||
lines.append(f"#endif // {guard}")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def print_compression_stats(original_size, minified_size, gzip_size, brotli_size=None):
|
||||
"""Print compression statistics"""
|
||||
print("\n" + "="*60)
|
||||
print("COMPRESSION STATISTICS")
|
||||
print("="*60)
|
||||
print(f"Original HTML: {original_size:,} bytes")
|
||||
print(f"Minified HTML: {minified_size:,} bytes ({minified_size/original_size*100:.1f}%)")
|
||||
print(f"Gzip (level 9): {gzip_size:,} bytes ({gzip_size/original_size*100:.1f}%)")
|
||||
|
||||
if brotli_size:
|
||||
print(f"Brotli (level 11): {brotli_size:,} bytes ({brotli_size/original_size*100:.1f}%)")
|
||||
|
||||
print(f"\nSavings (gzip): {original_size - gzip_size:,} bytes ({(1-gzip_size/original_size)*100:.1f}% reduction)")
|
||||
|
||||
if brotli_size:
|
||||
print(f"Savings (brotli): {original_size - brotli_size:,} bytes ({(1-brotli_size/original_size)*100:.1f}% reduction)")
|
||||
|
||||
print("="*60 + "\n")
|
||||
|
||||
|
||||
def main():
|
||||
input_file = "landingpage.html"
|
||||
|
||||
# Check if input file exists
|
||||
if not Path(input_file).exists():
|
||||
print(f"Error: {input_file} not found")
|
||||
sys.exit(1)
|
||||
|
||||
# Read original HTML
|
||||
print(f"Reading {input_file}...")
|
||||
with open(input_file, "r", encoding="utf-8") as fin:
|
||||
original_html = fin.read()
|
||||
|
||||
original_size = len(original_html.encode('utf-8'))
|
||||
|
||||
# Minify HTML
|
||||
print("Minifying HTML/CSS/JS...")
|
||||
minified_html = aggressive_html_minify(original_html)
|
||||
minified_size = len(minified_html.encode('utf-8'))
|
||||
|
||||
# Save minified HTML
|
||||
with open("webpage_minified.html", "w", encoding="utf-8") as fout:
|
||||
fout.write(minified_html)
|
||||
print("Saved: webpage_minified.html")
|
||||
|
||||
# Compress with gzip
|
||||
print("Compressing with gzip (level 9)...")
|
||||
minified_bytes = minified_html.encode('utf-8')
|
||||
gzipped_bytes = gzip.compress(minified_bytes, compresslevel=9)
|
||||
gzip_size = len(gzipped_bytes)
|
||||
|
||||
# Compress with brotli (if available)
|
||||
brotli_size = None
|
||||
brotli_bytes = None
|
||||
try:
|
||||
print("Compressing with brotli (level 11)...")
|
||||
brotli_bytes = brotli.compress(minified_bytes, quality=11)
|
||||
brotli_size = len(brotli_bytes)
|
||||
except Exception as e:
|
||||
print(f"Brotli compression not available: {e}")
|
||||
|
||||
# Generate C headers
|
||||
print("\nGenerating C header files...")
|
||||
|
||||
# Gzip version
|
||||
with open("webpage_gzip.h", "w") as fout:
|
||||
fout.write(generate_c_header(gzipped_bytes, "html_content_gz", use_progmem=True))
|
||||
print("Saved: webpage_gzip.h")
|
||||
|
||||
# Brotli version (if available)
|
||||
if brotli_bytes:
|
||||
with open("webpage_brotli.h", "w") as fout:
|
||||
fout.write(generate_c_header(brotli_bytes, "html_content_br", use_progmem=True))
|
||||
print("Saved: webpage_brotli.h")
|
||||
|
||||
# Also generate the old format for compatibility
|
||||
with open("webpage.h", "w") as fout:
|
||||
fout.write("const char html_content[] = {")
|
||||
fout.write(','.join(f'0x{byte:02x}' for byte in gzipped_bytes))
|
||||
fout.write("};\n\n")
|
||||
fout.write(f"const unsigned int html_content_len = {len(gzipped_bytes)};\n")
|
||||
print("Saved: webpage.h (legacy format)")
|
||||
|
||||
# Print statistics
|
||||
print_compression_stats(original_size, minified_size, gzip_size, brotli_size)
|
||||
|
||||
# Recommendations
|
||||
print("RECOMMENDATIONS:")
|
||||
print("-" * 60)
|
||||
if brotli_size and brotli_size < gzip_size:
|
||||
savings = gzip_size - brotli_size
|
||||
print(f"Use Brotli compression (saves {savings} bytes vs gzip)")
|
||||
print(f" Include: webpage_brotli.h")
|
||||
else:
|
||||
print(f"Use Gzip compression")
|
||||
print(f" Include: webpage_gzip.h")
|
||||
|
||||
if not HAS_RJSMIN and not HAS_JSMIN:
|
||||
print("\nInstall rjsmin for better JS compression:")
|
||||
print(" pip install rjsmin --break-system-packages")
|
||||
|
||||
print("-" * 60)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
439
main/webpage_gzip.h
Normal file
439
main/webpage_gzip.h
Normal file
@@ -0,0 +1,439 @@
|
||||
#ifndef HTML_CONTENT_GZ_H
|
||||
#define HTML_CONTENT_GZ_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
const unsigned char PROGMEM html_content_gz[] = {
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x38, 0xff, 0x5b, 0x69, 0x02, 0xff, 0xed, 0x3d, 0x6b, 0x57, 0xdb, 0x48,
|
||||
0xb2, 0x9f, 0x77, 0x7e, 0x45, 0xc3, 0x24, 0x8c, 0x94, 0x08, 0xd9, 0x06, 0x32, 0x0f, 0x1b, 0x99,
|
||||
0x25, 0xe0, 0x4c, 0x32, 0x09, 0x8f, 0xc3, 0x23, 0x33, 0x7b, 0x59, 0x0e, 0x92, 0xad, 0x36, 0xd6,
|
||||
0x20, 0x4b, 0x1a, 0x49, 0x86, 0x30, 0xc2, 0xff, 0x7d, 0xab, 0xfa, 0x21, 0xb5, 0x64, 0xd9, 0x98,
|
||||
0x64, 0x33, 0x73, 0xee, 0xb9, 0x77, 0xf7, 0x2c, 0xb1, 0x5b, 0xdd, 0xd5, 0xd5, 0xf5, 0xae, 0xea,
|
||||
0x92, 0x77, 0x7b, 0xc5, 0x0d, 0x07, 0xe9, 0x7d, 0x44, 0xc9, 0x28, 0x1d, 0xfb, 0xdd, 0xed, 0xd4,
|
||||
0x4b, 0x7d, 0xda, 0xdd, 0x0b, 0x83, 0x34, 0x0e, 0x7d, 0x72, 0xec, 0x04, 0xd4, 0xdf, 0x6e, 0xf0,
|
||||
0xc1, 0xed, 0x31, 0x4d, 0x1d, 0x32, 0x80, 0x47, 0x34, 0x48, 0xad, 0xd5, 0x3b, 0xcf, 0x4d, 0x47,
|
||||
0x96, 0x4b, 0x6f, 0xbd, 0x01, 0x5d, 0x67, 0x5f, 0x0c, 0x2f, 0xf0, 0x52, 0xcf, 0xf1, 0xd7, 0x93,
|
||||
0x81, 0xe3, 0x53, 0xab, 0x65, 0x36, 0x57, 0x49, 0xe0, 0x8c, 0xa9, 0x75, 0xeb, 0xd1, 0xbb, 0x28,
|
||||
0x8c, 0xd3, 0xee, 0x76, 0x92, 0xde, 0x03, 0xa4, 0x6f, 0xef, 0x62, 0x27, 0x8a, 0x68, 0x9c, 0xa5,
|
||||
0xf4, 0x53, 0xba, 0xee, 0xf8, 0xde, 0x75, 0xd0, 0x1e, 0x00, 0x50, 0x1a, 0x77, 0xfa, 0xe1, 0xa7,
|
||||
0xf5, 0xc4, 0xfb, 0xd3, 0x0b, 0xae, 0xdb, 0xfd, 0x30, 0x76, 0x69, 0xbc, 0x0e, 0x23, 0xd3, 0x6f,
|
||||
0xc5, 0xae, 0xd9, 0xd8, 0xf9, 0xc4, 0xf7, 0x6a, 0xbf, 0x6a, 0x36, 0xa3, 0x4f, 0x9d, 0xb1, 0x13,
|
||||
0x5f, 0x7b, 0x41, 0xdb, 0x99, 0xa4, 0x61, 0x27, 0x72, 0x5c, 0x17, 0xd7, 0x35, 0x49, 0x0b, 0x1e,
|
||||
0x4d, 0xfb, 0xa1, 0x7b, 0x5f, 0xb3, 0x81, 0x58, 0xd1, 0x2c, 0xa6, 0x4f, 0x5f, 0x64, 0x83, 0xd0,
|
||||
0x0f, 0xe3, 0xf6, 0xb7, 0x1b, 0x43, 0xfc, 0x6f, 0xa7, 0xef, 0x0c, 0x6e, 0xae, 0xe3, 0x70, 0x12,
|
||||
0xb8, 0xeb, 0xe2, 0xc1, 0x70, 0x38, 0xec, 0x0c, 0x01, 0x85, 0xf5, 0xa1, 0x33, 0xf6, 0xfc, 0xfb,
|
||||
0xf6, 0x61, 0x98, 0x86, 0xe4, 0xd4, 0x09, 0x12, 0xe3, 0x23, 0x8d, 0x5d, 0x27, 0x70, 0x8c, 0x04,
|
||||
0xbe, 0xac, 0x27, 0x34, 0xf6, 0xc4, 0x44, 0x38, 0x03, 0x6d, 0xb7, 0xcc, 0x8d, 0x98, 0x8e, 0xa7,
|
||||
0x5e, 0x10, 0x4d, 0x52, 0xa3, 0x3f, 0x49, 0xd3, 0x30, 0x50, 0x31, 0x8a, 0xbd, 0xeb, 0x51, 0x5a,
|
||||
0x7f, 0xe2, 0x1a, 0x1c, 0xe8, 0x90, 0xba, 0xf4, 0xa7, 0x0e, 0x9f, 0xd3, 0x6e, 0x45, 0x9f, 0x48,
|
||||
0x12, 0xfa, 0x9e, 0x4b, 0xbe, 0xed, 0x3b, 0x3f, 0x7d, 0xff, 0xaa, 0x2f, 0x1e, 0xac, 0xc7, 0x8e,
|
||||
0xeb, 0x4d, 0x92, 0xf6, 0x2b, 0x20, 0x0e, 0x27, 0x54, 0xab, 0xd9, 0x7c, 0xce, 0x51, 0xb8, 0x40,
|
||||
0x3e, 0x5b, 0x88, 0xc0, 0xa5, 0xa1, 0x0c, 0x04, 0x93, 0x71, 0x9f, 0xc6, 0x97, 0x99, 0x7a, 0xc0,
|
||||
0x71, 0x18, 0x84, 0x49, 0xe4, 0x0c, 0xa8, 0x58, 0x19, 0x53, 0xc7, 0x0d, 0x03, 0xff, 0xfe, 0x32,
|
||||
0xab, 0x41, 0x6c, 0x0b, 0xff, 0x3b, 0x9d, 0x3d, 0x1f, 0xa7, 0xf8, 0xd4, 0x1c, 0x8c, 0x9c, 0xe0,
|
||||
0x9a, 0xba, 0x06, 0x70, 0x71, 0x3c, 0xf6, 0xd2, 0xab, 0x7e, 0x1a, 0x64, 0x05, 0x61, 0x57, 0xbc,
|
||||
0x31, 0xca, 0x86, 0x13, 0xa4, 0x35, 0x87, 0xde, 0x70, 0xb6, 0x7e, 0xda, 0x74, 0x8b, 0x29, 0x20,
|
||||
0x09, 0x4e, 0x30, 0xa0, 0xfe, 0x53, 0x60, 0xfc, 0xb0, 0xb1, 0x59, 0x02, 0x90, 0x23, 0x61, 0x94,
|
||||
0x80, 0x4d, 0xe2, 0x04, 0x66, 0x47, 0xa1, 0x27, 0xe4, 0x90, 0x91, 0x39, 0x08, 0x03, 0x2a, 0xe8,
|
||||
0xb8, 0xf5, 0xea, 0xb9, 0x10, 0x9e, 0xf5, 0x34, 0x8c, 0xda, 0x28, 0x63, 0xb9, 0x0c, 0xb1, 0x2f,
|
||||
0x8c, 0x7e, 0x77, 0x14, 0x99, 0xda, 0xfe, 0xa1, 0xd9, 0x54, 0x77, 0xba, 0x70, 0xbd, 0xc4, 0xe9,
|
||||
0xfb, 0xd4, 0xbd, 0x54, 0xf7, 0x2c, 0x46, 0xe5, 0x51, 0x7e, 0xfc, 0xf1, 0xc7, 0x8e, 0x40, 0x24,
|
||||
0x08, 0x91, 0x8c, 0x7e, 0x78, 0x47, 0xdd, 0x9a, 0x33, 0x6d, 0x6d, 0x6d, 0x29, 0x67, 0x4a, 0x11,
|
||||
0x4a, 0x26, 0x04, 0x00, 0x66, 0xf8, 0x4e, 0x94, 0xd0, 0xb6, 0xfc, 0xd0, 0x51, 0x58, 0xe2, 0xd3,
|
||||
0x61, 0xaa, 0xca, 0x45, 0xea, 0x66, 0xb9, 0xd0, 0x01, 0xfb, 0xc6, 0xaa, 0x5c, 0x09, 0x81, 0x93,
|
||||
0x67, 0xfc, 0x11, 0x74, 0x2a, 0x99, 0x8c, 0x81, 0x04, 0x25, 0xb5, 0x62, 0x10, 0x15, 0x35, 0xa9,
|
||||
0xa5, 0x7f, 0x8d, 0x70, 0x4a, 0xb0, 0xe6, 0x26, 0xa8, 0xc8, 0x0c, 0xed, 0xcc, 0xc1, 0x58, 0x62,
|
||||
0xc6, 0x79, 0xa0, 0x2a, 0xd5, 0x2b, 0x54, 0xaa, 0x6f, 0xc7, 0xc9, 0x75, 0x8d, 0xb0, 0x8d, 0x5a,
|
||||
0x59, 0x31, 0x75, 0x43, 0x4c, 0x8d, 0xc2, 0x68, 0x12, 0xad, 0x87, 0xb7, 0x34, 0xf6, 0x9d, 0xfb,
|
||||
0xec, 0xcf, 0x75, 0x2f, 0x70, 0xe9, 0x27, 0x24, 0x40, 0xb3, 0x06, 0xdd, 0x26, 0xfb, 0x4f, 0x7f,
|
||||
0xb3, 0xf3, 0xfb, 0x24, 0x49, 0xbd, 0xe1, 0xfd, 0xba, 0xb0, 0x3d, 0xd2, 0x80, 0xb0, 0xed, 0xd6,
|
||||
0xbd, 0x94, 0x8e, 0x13, 0x39, 0x54, 0x10, 0xb4, 0x33, 0xe2, 0x67, 0x60, 0x9f, 0x81, 0xbd, 0x11,
|
||||
0x6c, 0xc8, 0x0f, 0x10, 0x85, 0x09, 0x18, 0xc7, 0x30, 0x68, 0x0f, 0xbd, 0x4f, 0xc0, 0x52, 0x14,
|
||||
0xa1, 0x66, 0x07, 0x89, 0x07, 0x06, 0x48, 0x20, 0x28, 0x8d, 0x9c, 0x42, 0xcd, 0x1a, 0x03, 0x39,
|
||||
0x47, 0x47, 0x2a, 0x24, 0x6e, 0x71, 0xeb, 0x28, 0xad, 0xe5, 0x56, 0x53, 0x15, 0xd7, 0x4d, 0xfc,
|
||||
0xc2, 0xec, 0xce, 0x08, 0xd4, 0xfa, 0x0e, 0x2c, 0xe6, 0x16, 0xb0, 0xfd, 0x7b, 0xf8, 0x9f, 0x38,
|
||||
0xfd, 0x96, 0x5b, 0xc1, 0x89, 0x8c, 0x36, 0xb2, 0x85, 0x4c, 0x16, 0x48, 0x28, 0x0a, 0x52, 0x3d,
|
||||
0x16, 0x89, 0x96, 0x82, 0xa0, 0x32, 0xba, 0x85, 0xdc, 0xfb, 0xe7, 0x98, 0xba, 0x9e, 0x43, 0x92,
|
||||
0x41, 0x4c, 0x69, 0x40, 0x9c, 0xc0, 0x25, 0x1a, 0x3b, 0xd3, 0xb6, 0xb5, 0xf9, 0x0a, 0xce, 0xa1,
|
||||
0x67, 0x35, 0xce, 0x81, 0x91, 0xbf, 0xf0, 0x07, 0x20, 0x6f, 0x5c, 0x47, 0x48, 0x1a, 0x13, 0x26,
|
||||
0xf2, 0x75, 0x26, 0x57, 0x59, 0x2a, 0x39, 0xd7, 0xf7, 0xc3, 0xc1, 0x4d, 0xbe, 0x34, 0x13, 0xa7,
|
||||
0x93, 0xaa, 0x82, 0x54, 0x2c, 0xcf, 0x94, 0x47, 0xe6, 0xb6, 0x30, 0xc9, 0xe6, 0x9f, 0xd2, 0xa7,
|
||||
0x80, 0x2b, 0x78, 0xc1, 0x36, 0xfe, 0x99, 0x27, 0x6a, 0xd7, 0x4e, 0x24, 0x19, 0x99, 0x93, 0x75,
|
||||
0x43, 0xdd, 0x15, 0xc1, 0x54, 0xf6, 0x24, 0xc2, 0x0e, 0x97, 0x5d, 0x5a, 0xd5, 0xba, 0xfd, 0x17,
|
||||
0xbc, 0xcb, 0x18, 0x10, 0xca, 0x49, 0x56, 0xb1, 0x85, 0x64, 0xa3, 0xd6, 0x20, 0xd6, 0x21, 0xda,
|
||||
0x1e, 0xa1, 0x5e, 0x1a, 0xb5, 0xcf, 0xcc, 0x28, 0xf6, 0x98, 0xbd, 0x59, 0x28, 0x38, 0x1c, 0xc3,
|
||||
0xe9, 0x42, 0x08, 0x7c, 0x97, 0x1a, 0x7e, 0xfc, 0xe8, 0xfc, 0xd0, 0xdc, 0x7a, 0x25, 0x17, 0x33,
|
||||
0x67, 0xc7, 0xb8, 0xe0, 0x78, 0x41, 0xed, 0xfc, 0x92, 0x9c, 0x33, 0x66, 0x90, 0x66, 0x69, 0x75,
|
||||
0x85, 0xf0, 0xcb, 0x28, 0xf0, 0x97, 0x78, 0xf6, 0x1a, 0x17, 0xa4, 0x2a, 0x8f, 0x99, 0xfc, 0x81,
|
||||
0xce, 0x8d, 0xcf, 0xdf, 0x7c, 0xf5, 0xbc, 0x6c, 0x02, 0xaa, 0x0c, 0xda, 0x6e, 0xf0, 0xf8, 0x6c,
|
||||
0xbb, 0x31, 0x02, 0x7f, 0xdf, 0xdd, 0xc6, 0x10, 0xaa, 0xbb, 0xed, 0x7a, 0xb7, 0xc4, 0x73, 0x2d,
|
||||
0x11, 0xb3, 0xe5, 0xdf, 0x85, 0xac, 0x76, 0xb7, 0x47, 0xad, 0xee, 0x9e, 0x3f, 0x19, 0xdc, 0xec,
|
||||
0x81, 0xbb, 0x03, 0xf5, 0x84, 0xc5, 0x2d, 0x88, 0x23, 0x51, 0x67, 0xe0, 0x1f, 0x98, 0x9f, 0x22,
|
||||
0x24, 0xc6, 0x0d, 0x12, 0x06, 0x03, 0xdf, 0x1b, 0xdc, 0x58, 0xab, 0x09, 0x0d, 0x5c, 0x31, 0x5f,
|
||||
0xfb, 0x2e, 0x49, 0x9d, 0x38, 0xfd, 0x4e, 0x5f, 0x25, 0x03, 0xdf, 0x49, 0x12, 0x0b, 0x4c, 0x7f,
|
||||
0xf7, 0xf4, 0x6c, 0xf7, 0xe4, 0x6c, 0xbb, 0xc1, 0x97, 0x01, 0x3e, 0x08, 0x63, 0x09, 0x38, 0x61,
|
||||
0x54, 0x02, 0x43, 0xd8, 0x71, 0xac, 0xc7, 0xbc, 0x13, 0xec, 0x76, 0x74, 0xfc, 0xd4, 0xcd, 0x00,
|
||||
0x44, 0x58, 0xc6, 0xf9, 0xfc, 0x70, 0xff, 0xa8, 0x02, 0xa5, 0x81, 0xe7, 0x6f, 0x48, 0x5a, 0xa8,
|
||||
0x24, 0x81, 0x38, 0xda, 0x87, 0x00, 0x2b, 0xb0, 0x36, 0xbb, 0xdb, 0x4c, 0x6e, 0x90, 0xa4, 0xe0,
|
||||
0xd2, 0x88, 0x8c, 0xb4, 0x54, 0x08, 0x0b, 0x96, 0x9c, 0xff, 0x76, 0x75, 0xf6, 0xee, 0xa0, 0x87,
|
||||
0x48, 0xb2, 0x28, 0xcb, 0x02, 0xc9, 0xbc, 0xd9, 0xe3, 0x01, 0x97, 0x96, 0x8e, 0xbc, 0x44, 0x07,
|
||||
0x22, 0xd0, 0xc8, 0x6a, 0x11, 0x16, 0xeb, 0xb9, 0x4e, 0x4a, 0x53, 0x6f, 0x4c, 0xd7, 0xc1, 0x5c,
|
||||
0x39, 0x7e, 0x97, 0xc8, 0x33, 0x02, 0xa4, 0x20, 0xbc, 0xc3, 0xa0, 0x24, 0x3f, 0x6e, 0x42, 0xd3,
|
||||
0x33, 0x98, 0x79, 0x16, 0x1e, 0x86, 0x77, 0x9a, 0xde, 0x3d, 0xbd, 0x0f, 0x06, 0x04, 0x07, 0xea,
|
||||
0x8e, 0x28, 0xd8, 0x7c, 0x3a, 0x18, 0x51, 0x77, 0x02, 0xb6, 0xf2, 0x14, 0x39, 0x5a, 0x10, 0x52,
|
||||
0xc5, 0xf6, 0xe0, 0xe8, 0x63, 0xef, 0x8a, 0xb1, 0xb7, 0xc0, 0x99, 0xff, 0x23, 0x57, 0x0b, 0xb4,
|
||||
0x79, 0xb0, 0x0a, 0x1b, 0x2e, 0xda, 0xa8, 0x87, 0xf2, 0x36, 0x77, 0x9b, 0xde, 0xe1, 0xfe, 0x17,
|
||||
0x6c, 0xf2, 0x2d, 0x39, 0x00, 0xa3, 0x91, 0x34, 0xf6, 0x9d, 0xfb, 0xfa, 0x3d, 0x0e, 0xcf, 0x0f,
|
||||
0xd8, 0x3e, 0xa7, 0x04, 0x6c, 0xa1, 0xd5, 0x5c, 0x66, 0x2b, 0x1e, 0x6b, 0xd7, 0x6c, 0x76, 0x08,
|
||||
0x76, 0x82, 0xed, 0x47, 0x76, 0xe7, 0x10, 0xee, 0xb0, 0xf7, 0xdb, 0xd9, 0xd5, 0xee, 0x87, 0xdd,
|
||||
0x93, 0x83, 0x5c, 0x46, 0x6a, 0x79, 0x3a, 0x0b, 0xfb, 0x84, 0x8e, 0xc1, 0x9c, 0x99, 0x64, 0xdf,
|
||||
0x03, 0x4d, 0x83, 0xe0, 0x93, 0x68, 0xc3, 0x54, 0xaf, 0xdf, 0xe4, 0xa4, 0x77, 0x70, 0xb5, 0xff,
|
||||
0xee, 0x54, 0xe1, 0x0d, 0xfc, 0x75, 0x7d, 0xca, 0x41, 0x80, 0xe1, 0x40, 0x18, 0x5c, 0xbc, 0x96,
|
||||
0x3a, 0x16, 0x3b, 0xd1, 0x12, 0xfb, 0xee, 0x9f, 0xbc, 0x03, 0x7e, 0xb1, 0x9d, 0xbf, 0x9c, 0x96,
|
||||
0xbf, 0x80, 0x92, 0x93, 0xb7, 0xcc, 0xac, 0x11, 0xcd, 0x0b, 0xe6, 0x6c, 0xf9, 0xcb, 0xee, 0xde,
|
||||
0xfb, 0xff, 0xd6, 0x8e, 0xaf, 0x9d, 0x14, 0x4c, 0xfb, 0x3d, 0xd1, 0x3e, 0xd6, 0x6d, 0x76, 0x1b,
|
||||
0xfa, 0xa9, 0x73, 0x4d, 0x17, 0xa8, 0x76, 0xf7, 0x38, 0x0e, 0xaf, 0x63, 0x67, 0x4c, 0x4e, 0xde,
|
||||
0x10, 0x20, 0x75, 0x98, 0xd2, 0xb9, 0x56, 0x28, 0xe2, 0x33, 0x4f, 0xde, 0x9c, 0xd2, 0x3f, 0x26,
|
||||
0x14, 0xa8, 0x0a, 0xba, 0x29, 0x57, 0xef, 0xfa, 0x3e, 0x79, 0xcd, 0xfd, 0xdf, 0x22, 0x43, 0x24,
|
||||
0x20, 0xca, 0xec, 0x83, 0x19, 0xf3, 0x3c, 0x29, 0xc9, 0x37, 0x42, 0x69, 0xc2, 0x80, 0xd5, 0x8c,
|
||||
0xa9, 0x1f, 0x3a, 0xae, 0xa6, 0x77, 0xba, 0xc0, 0xc8, 0x81, 0x13, 0xbb, 0x05, 0xec, 0x3a, 0x48,
|
||||
0x79, 0xd2, 0x93, 0x43, 0xe2, 0x43, 0xc7, 0x0e, 0xa0, 0x98, 0xa0, 0x25, 0x71, 0x40, 0x26, 0xb8,
|
||||
0x0c, 0x29, 0x68, 0xf6, 0x63, 0xfe, 0x3f, 0x97, 0x82, 0xef, 0xf5, 0x93, 0xee, 0xb6, 0xc8, 0x35,
|
||||
0xba, 0x20, 0x92, 0x47, 0x67, 0x3d, 0xb2, 0x77, 0x74, 0x78, 0x76, 0x72, 0xf4, 0x01, 0x5c, 0x94,
|
||||
0x18, 0x27, 0x38, 0x9d, 0x14, 0xe4, 0x19, 0x87, 0x93, 0x84, 0x42, 0x34, 0x1b, 0x80, 0xa1, 0x46,
|
||||
0xf3, 0xc3, 0xe9, 0xa8, 0x7d, 0x37, 0xbc, 0x73, 0xbf, 0x33, 0x08, 0xbd, 0x05, 0x5f, 0x05, 0xe6,
|
||||
0x1a, 0x9c, 0x56, 0x38, 0x19, 0x8c, 0xd8, 0x8c, 0x85, 0x13, 0xb9, 0x5d, 0x67, 0xee, 0x53, 0x02,
|
||||
0xf7, 0x29, 0x60, 0x6e, 0xa1, 0x97, 0x11, 0x4b, 0x74, 0xf9, 0x64, 0x12, 0x55, 0x87, 0xd9, 0x2e,
|
||||
0xe0, 0x2f, 0x4a, 0xe3, 0xdd, 0x37, 0xbf, 0xee, 0xe7, 0x27, 0x5e, 0x02, 0xf5, 0x98, 0xde, 0x2e,
|
||||
0x87, 0x7a, 0x79, 0xe2, 0x57, 0x41, 0xfd, 0xa4, 0xf7, 0xf1, 0x29, 0xa8, 0x4f, 0xa2, 0xe5, 0x30,
|
||||
0x2f, 0xcd, 0xfb, 0x2a, 0x88, 0x9f, 0x1f, 0x3f, 0x05, 0x6f, 0x1c, 0x5a, 0x0e, 0xf3, 0xca, 0xcc,
|
||||
0xaf, 0x82, 0xfb, 0xfe, 0xd1, 0xaf, 0x87, 0x4f, 0xc1, 0xde, 0x99, 0x7c, 0x5a, 0x0e, 0xf9, 0xf2,
|
||||
0xc4, 0xaf, 0x82, 0xfb, 0xee, 0xf9, 0x6f, 0x8a, 0x11, 0xca, 0xd5, 0xba, 0x56, 0xc7, 0xf7, 0x77,
|
||||
0x0f, 0x7f, 0xee, 0x9d, 0x90, 0xff, 0x39, 0x3a, 0xec, 0xa9, 0x0a, 0x5e, 0x0e, 0x22, 0xf7, 0x20,
|
||||
0x8c, 0xee, 0xc7, 0xcc, 0x26, 0xcd, 0x8f, 0xd1, 0x06, 0x62, 0x12, 0x9c, 0xf1, 0x77, 0x70, 0x03,
|
||||
0x10, 0xa1, 0x71, 0x77, 0x50, 0x5a, 0x3c, 0x4b, 0xd0, 0xd9, 0xd5, 0x6e, 0xec, 0xdd, 0x52, 0x5c,
|
||||
0xbe, 0x8f, 0x1f, 0x6a, 0xd7, 0xcf, 0x9a, 0xf1, 0xbd, 0x49, 0x1c, 0x63, 0xaa, 0xfb, 0x91, 0xc6,
|
||||
0x49, 0x09, 0xcd, 0xc2, 0x17, 0xf0, 0x27, 0x8b, 0x7c, 0xc1, 0x1b, 0x2f, 0x1e, 0xdf, 0x39, 0x31,
|
||||
0xad, 0xae, 0x76, 0x06, 0x03, 0x1a, 0xa5, 0x96, 0xd9, 0xf7, 0x58, 0xbc, 0x36, 0x14, 0xd3, 0xae,
|
||||
0x86, 0x1e, 0x04, 0x42, 0x3c, 0xd2, 0x55, 0x2b, 0x0e, 0xdc, 0x65, 0xe1, 0xc3, 0x2e, 0x51, 0xe3,
|
||||
0xbc, 0x49, 0x84, 0xe6, 0xbc, 0x64, 0xa0, 0xf9, 0x90, 0xdc, 0x17, 0x75, 0x86, 0x0d, 0x90, 0x02,
|
||||
0x93, 0xb9, 0x27, 0xfe, 0x10, 0x5e, 0xc3, 0x34, 0x7f, 0xd6, 0x5f, 0xc1, 0x4e, 0x7e, 0x78, 0x5d,
|
||||
0xda, 0x06, 0x05, 0x16, 0xe1, 0xc2, 0x1a, 0x5c, 0x82, 0xf2, 0x2d, 0x46, 0x08, 0x0c, 0x2d, 0xf0,
|
||||
0x58, 0x42, 0x12, 0x10, 0xa6, 0x10, 0x89, 0xfc, 0xc1, 0xc2, 0x18, 0x3d, 0xa6, 0xfd, 0x30, 0x4c,
|
||||
0x3f, 0x2b, 0x25, 0x38, 0xe9, 0xbd, 0x3e, 0x3a, 0x3a, 0x5b, 0x20, 0x2a, 0xe5, 0xcc, 0xc3, 0xa7,
|
||||
0xf4, 0xe9, 0xa9, 0xc7, 0xc6, 0xe6, 0x0f, 0xdd, 0xd3, 0x0f, 0xbd, 0xde, 0x71, 0x9d, 0x9e, 0x34,
|
||||
0x20, 0xcd, 0x92, 0x7f, 0x45, 0xc6, 0x55, 0x2a, 0x63, 0x55, 0x46, 0x8b, 0x6c, 0x6c, 0xa3, 0x18,
|
||||
0x14, 0x75, 0xfb, 0xc6, 0x68, 0xa3, 0xbb, 0x1d, 0x15, 0xc3, 0x63, 0x9a, 0x24, 0x10, 0x8f, 0xc0,
|
||||
0x83, 0xa8, 0x02, 0xa5, 0x92, 0xff, 0xd6, 0x48, 0x95, 0x22, 0xca, 0xca, 0x92, 0x5a, 0x44, 0x45,
|
||||
0x26, 0x5e, 0x3e, 0x0a, 0xff, 0x9b, 0x0c, 0x62, 0x2f, 0x4a, 0xbb, 0x3e, 0x4d, 0x09, 0x44, 0xaf,
|
||||
0x8e, 0x95, 0x4d, 0x8d, 0x08, 0xc3, 0x83, 0x33, 0xe4, 0xea, 0x1e, 0xe8, 0x46, 0x4a, 0x5d, 0x6b,
|
||||
0xa5, 0x65, 0x44, 0xa1, 0xef, 0xbf, 0xc3, 0xac, 0xf9, 0xd6, 0xf1, 0x21, 0xfa, 0xf2, 0x7d, 0x63,
|
||||
0x1c, 0xba, 0x8e, 0x7f, 0x42, 0x21, 0x41, 0xbe, 0xa5, 0x6c, 0xa4, 0x03, 0xd8, 0x26, 0x29, 0x81,
|
||||
0xb8, 0x0d, 0x36, 0xee, 0xba, 0xe1, 0x60, 0x32, 0x06, 0x3a, 0x98, 0xd7, 0x34, 0xed, 0xf9, 0x14,
|
||||
0x3f, 0xbe, 0xbe, 0x7f, 0xe7, 0x6a, 0x9e, 0xab, 0x77, 0x86, 0x93, 0x60, 0x80, 0xfa, 0x4b, 0x92,
|
||||
0x51, 0x78, 0x77, 0x80, 0x70, 0x34, 0x46, 0x20, 0x43, 0xd0, 0x43, 0x54, 0xe8, 0x13, 0xeb, 0xe2,
|
||||
0xd2, 0x08, 0x23, 0x9c, 0x99, 0x00, 0x62, 0x7a, 0x86, 0x58, 0x0a, 0xa2, 0x5b, 0xf3, 0xe0, 0xdb,
|
||||
0x25, 0xde, 0xd8, 0xba, 0xc1, 0x20, 0xf7, 0xfc, 0xc7, 0x16, 0xb0, 0x69, 0x30, 0x5d, 0xa0, 0xf0,
|
||||
0xf8, 0x02, 0x31, 0x11, 0x96, 0x08, 0x6c, 0x1f, 0x5f, 0x22, 0x26, 0xc2, 0x12, 0xc6, 0xab, 0x3d,
|
||||
0xc9, 0xdd, 0xc7, 0xd6, 0x55, 0x84, 0x41, 0xae, 0x7f, 0x7c, 0x43, 0x36, 0xcd, 0xd6, 0x3b, 0x82,
|
||||
0x06, 0x26, 0xd6, 0x40, 0xf6, 0xc4, 0xb5, 0x51, 0x89, 0xe2, 0xf0, 0xcc, 0x0b, 0x00, 0xf4, 0xdb,
|
||||
0xb3, 0x83, 0x0f, 0x96, 0xe4, 0x82, 0x20, 0xbd, 0x89, 0x5c, 0x7a, 0x87, 0x90, 0x76, 0xb4, 0x32,
|
||||
0xde, 0x26, 0x93, 0x4a, 0x53, 0x48, 0xa5, 0x65, 0xb3, 0xd2, 0x9b, 0x2d, 0x91, 0x33, 0x99, 0xd9,
|
||||
0x93, 0x40, 0xd8, 0xe0, 0x19, 0x8c, 0x3c, 0x3c, 0xd8, 0x88, 0x46, 0x31, 0x0d, 0x24, 0x6a, 0x52,
|
||||
0x99, 0xf7, 0x11, 0x87, 0x60, 0x62, 0x31, 0x09, 0x36, 0x18, 0xd0, 0x51, 0xe8, 0xbb, 0x40, 0xad,
|
||||
0xd2, 0xd4, 0xe3, 0xe2, 0x01, 0x5b, 0x20, 0x92, 0xe5, 0x70, 0x92, 0x6a, 0x9a, 0x6e, 0x75, 0xe5,
|
||||
0xfa, 0x21, 0x10, 0x0a, 0x42, 0x5e, 0xa3, 0xd5, 0x6c, 0xea, 0x7a, 0x7b, 0xf1, 0x31, 0x50, 0xbb,
|
||||
0xec, 0x82, 0xab, 0x0a, 0x65, 0x6c, 0xbb, 0x83, 0x32, 0xc8, 0x1f, 0x09, 0x7a, 0xa3, 0x94, 0x76,
|
||||
0xc4, 0x64, 0xd8, 0x26, 0xee, 0x39, 0x83, 0x91, 0x06, 0xc6, 0xd6, 0xea, 0x66, 0xc5, 0xdc, 0x82,
|
||||
0x51, 0x03, 0xa6, 0x53, 0x62, 0xad, 0x66, 0xf3, 0xc7, 0xc0, 0x22, 0x51, 0x25, 0x53, 0x39, 0x04,
|
||||
0x40, 0xd8, 0x77, 0x03, 0x3f, 0x88, 0xf2, 0xd9, 0xda, 0x9a, 0x98, 0xc8, 0xec, 0xdb, 0x07, 0xc8,
|
||||
0xe7, 0x4c, 0xc7, 0x45, 0x7e, 0xf3, 0xc7, 0xb9, 0x34, 0x9a, 0xd2, 0x3c, 0x22, 0x11, 0x18, 0x22,
|
||||
0x31, 0x4d, 0x26, 0x7e, 0x6a, 0xcd, 0x32, 0x35, 0x13, 0xe5, 0x3f, 0xdc, 0x85, 0xf1, 0x82, 0x13,
|
||||
0xbd, 0x5d, 0xe2, 0xcf, 0xb4, 0x78, 0xdc, 0x51, 0x35, 0x7f, 0x6d, 0xcd, 0xd2, 0xd4, 0xef, 0x1a,
|
||||
0xdf, 0x46, 0x37, 0xd0, 0x22, 0xe8, 0xc6, 0xc8, 0x73, 0x29, 0x57, 0x70, 0x9d, 0x9d, 0x02, 0xdc,
|
||||
0xba, 0x8f, 0xe6, 0x17, 0x8e, 0xa1, 0x7c, 0x93, 0x8b, 0xa6, 0x0a, 0xd1, 0xb1, 0xc4, 0x05, 0x76,
|
||||
0x7d, 0xe4, 0xf9, 0xae, 0xc6, 0x47, 0xe5, 0xd1, 0x24, 0xdd, 0xcd, 0x68, 0x92, 0x8c, 0x34, 0x81,
|
||||
0x3d, 0x42, 0x9f, 0xea, 0x53, 0x9d, 0xf1, 0xe7, 0x86, 0xde, 0xbf, 0x65, 0xc9, 0x72, 0x6c, 0x51,
|
||||
0x38, 0xbd, 0x37, 0xd4, 0xa8, 0x09, 0x63, 0x96, 0x65, 0xd9, 0x3d, 0xb4, 0x61, 0xb6, 0x9e, 0x51,
|
||||
0x20, 0x28, 0x0b, 0xba, 0xf6, 0xe9, 0xd0, 0x81, 0xbd, 0x35, 0xbe, 0x52, 0x90, 0xf1, 0x35, 0xb0,
|
||||
0xaf, 0xb2, 0xd9, 0xd0, 0x03, 0xf7, 0xd2, 0xb7, 0xba, 0x7d, 0x53, 0xe1, 0x86, 0xde, 0x29, 0x16,
|
||||
0xec, 0x14, 0x1f, 0xcd, 0x9c, 0x47, 0xc0, 0x01, 0x4d, 0x6f, 0x57, 0x40, 0xf9, 0x34, 0xb8, 0x4e,
|
||||
0x47, 0xdd, 0xa6, 0xe4, 0xa5, 0x7c, 0x70, 0x51, 0x3b, 0x6f, 0xbd, 0x75, 0x59, 0x81, 0x37, 0xa5,
|
||||
0x7e, 0x02, 0x2e, 0x58, 0x3d, 0x15, 0x64, 0x83, 0x11, 0x9d, 0x7f, 0x2c, 0x9e, 0x54, 0x2e, 0x38,
|
||||
0xd5, 0x4a, 0xe5, 0x58, 0xf9, 0x82, 0x9d, 0xfc, 0xd3, 0xe7, 0x1e, 0xaa, 0x39, 0x83, 0xfe, 0xb4,
|
||||
0x73, 0x07, 0xdb, 0x86, 0x77, 0x26, 0x13, 0x9c, 0xf7, 0x39, 0xb3, 0xd6, 0xd6, 0x72, 0x2d, 0x89,
|
||||
0x21, 0x76, 0xbd, 0xa5, 0x3d, 0x3c, 0x09, 0xca, 0x38, 0x05, 0x05, 0xd4, 0x6c, 0x38, 0x2c, 0x06,
|
||||
0x2e, 0xb6, 0x51, 0xbf, 0x5c, 0x9f, 0x33, 0x6e, 0x15, 0xe2, 0x60, 0xe4, 0x1b, 0x80, 0xd2, 0xcc,
|
||||
0x83, 0x7e, 0xa3, 0x40, 0x14, 0x6e, 0xa4, 0x6a, 0x21, 0xb0, 0xda, 0x6f, 0x4f, 0x73, 0x37, 0xa6,
|
||||
0x48, 0xf9, 0x67, 0xf9, 0xa8, 0xce, 0x9c, 0x6d, 0xb8, 0x21, 0x5a, 0xa8, 0x6e, 0x2b, 0x2d, 0xa9,
|
||||
0x6a, 0xf3, 0x68, 0xaa, 0x7d, 0x1d, 0xa2, 0xb2, 0x4d, 0x0b, 0x12, 0xb0, 0xc7, 0x60, 0xb8, 0x30,
|
||||
0x16, 0xd6, 0xa4, 0x03, 0x61, 0x2e, 0xc6, 0xb2, 0xc5, 0x30, 0x88, 0x67, 0x4c, 0xd3, 0x49, 0x1c,
|
||||
0x90, 0x80, 0xde, 0x91, 0xe3, 0x38, 0x1c, 0x7b, 0x09, 0xb3, 0x17, 0x2c, 0x82, 0xe8, 0x66, 0xa5,
|
||||
0x80, 0x42, 0x0c, 0x1b, 0xf3, 0x22, 0x84, 0x0b, 0x76, 0xe3, 0xd8, 0xb6, 0xf7, 0x98, 0x78, 0xda,
|
||||
0x06, 0xb3, 0x4c, 0xed, 0x95, 0xd6, 0xd4, 0x10, 0x0f, 0x8e, 0xde, 0xe7, 0x83, 0x4d, 0x43, 0xde,
|
||||
0x3d, 0xac, 0x34, 0xa7, 0x97, 0x60, 0x24, 0x2a, 0x68, 0xef, 0xc2, 0x79, 0xd2, 0x2a, 0xd2, 0x87,
|
||||
0x61, 0xea, 0x0d, 0xe8, 0x57, 0xc1, 0xf9, 0x09, 0xa8, 0xe1, 0x8e, 0xd1, 0x0c, 0x6e, 0xcc, 0x6e,
|
||||
0xdb, 0x86, 0xcb, 0x75, 0x9c, 0x39, 0x4b, 0x70, 0x4d, 0x4f, 0x44, 0x15, 0x9d, 0x41, 0x37, 0xe3,
|
||||
0x1f, 0xd6, 0xd6, 0xf8, 0xbf, 0x42, 0x53, 0x77, 0xe2, 0x92, 0x31, 0xe7, 0x8e, 0x56, 0x6f, 0xcb,
|
||||
0x51, 0xce, 0xfa, 0xaf, 0xc0, 0x1a, 0x23, 0xcb, 0xbd, 0x12, 0x3e, 0xca, 0x43, 0x86, 0xb6, 0x1a,
|
||||
0x31, 0xb0, 0xe3, 0xb6, 0xd5, 0xb3, 0x1b, 0xd5, 0x40, 0xa0, 0x6d, 0xdb, 0xd3, 0x12, 0x2d, 0x11,
|
||||
0xec, 0x09, 0x4b, 0x41, 0xa4, 0x9a, 0x16, 0xc8, 0xdb, 0xfb, 0xac, 0x71, 0x86, 0xf0, 0xe7, 0x5e,
|
||||
0x70, 0x6d, 0x1b, 0xf6, 0x31, 0x16, 0x09, 0xef, 0x3c, 0xdf, 0x07, 0xaf, 0x39, 0x84, 0x63, 0x8f,
|
||||
0x08, 0x64, 0x7a, 0xdb, 0x58, 0xf2, 0xc7, 0xa0, 0x7a, 0x55, 0x06, 0xfa, 0x93, 0x20, 0x45, 0xdd,
|
||||
0x59, 0xed, 0xbe, 0x82, 0x5c, 0x19, 0x1e, 0x76, 0x49, 0x42, 0x21, 0x4a, 0x73, 0x13, 0xd3, 0x34,
|
||||
0x6d, 0xe3, 0xe2, 0x52, 0x18, 0x5f, 0x39, 0xcf, 0x7a, 0x65, 0xe4, 0x9f, 0xf3, 0x58, 0x1a, 0xe2,
|
||||
0x15, 0xf9, 0x99, 0x05, 0x2c, 0x59, 0x3e, 0x65, 0x7d, 0xbd, 0xbc, 0xfc, 0xf1, 0x70, 0x2f, 0x9f,
|
||||
0x0a, 0x26, 0x45, 0x59, 0x06, 0x36, 0x40, 0xf9, 0x56, 0x0a, 0x31, 0xf2, 0x71, 0xbd, 0x40, 0x6d,
|
||||
0xdb, 0x6a, 0xe2, 0x0a, 0x9f, 0x3a, 0x71, 0x8e, 0xd9, 0x0c, 0xde, 0xba, 0x31, 0x53, 0x95, 0x04,
|
||||
0x91, 0x68, 0xd1, 0xcd, 0x2a, 0xd5, 0xcf, 0xf6, 0xf0, 0xbe, 0xa2, 0x86, 0xec, 0x18, 0xa5, 0x11,
|
||||
0xd0, 0x32, 0x72, 0x4a, 0x81, 0xb5, 0xf6, 0xd9, 0x88, 0x12, 0xde, 0xc2, 0x04, 0xa9, 0x1b, 0x84,
|
||||
0x91, 0x20, 0xc5, 0xd4, 0x4d, 0x48, 0x1a, 0x92, 0x3e, 0xe4, 0xd4, 0x00, 0x62, 0x14, 0x87, 0x81,
|
||||
0xf7, 0x27, 0x75, 0x91, 0xb2, 0x42, 0x90, 0xf2, 0x9b, 0x90, 0x5a, 0x79, 0x32, 0x64, 0x78, 0xd1,
|
||||
0x76, 0x70, 0x3d, 0x23, 0x6e, 0xf9, 0x2a, 0xc5, 0x70, 0xee, 0x1c, 0x0f, 0x29, 0xac, 0x56, 0x45,
|
||||
0xa7, 0xa8, 0x87, 0x3c, 0x95, 0x81, 0x8c, 0x3b, 0xa0, 0xee, 0xd1, 0xb0, 0x77, 0x74, 0x06, 0x39,
|
||||
0x50, 0x39, 0x6d, 0x81, 0x31, 0x79, 0x28, 0x65, 0xda, 0xc3, 0x83, 0x56, 0x5a, 0xd4, 0x54, 0xb4,
|
||||
0xc4, 0x3e, 0x82, 0x6c, 0x2d, 0x1c, 0x92, 0xb3, 0xd8, 0xb9, 0x45, 0xbd, 0x90, 0x82, 0x07, 0x1e,
|
||||
0x36, 0x00, 0x32, 0xa0, 0x6d, 0x26, 0x40, 0x65, 0xcf, 0x87, 0x8f, 0x31, 0xde, 0x72, 0xe3, 0x34,
|
||||
0xac, 0xe8, 0xf2, 0x92, 0xbd, 0x97, 0x10, 0xd1, 0x85, 0xa2, 0x50, 0x60, 0xbe, 0x29, 0xd1, 0xa7,
|
||||
0x28, 0x3c, 0x9e, 0x60, 0xd7, 0x3b, 0x97, 0xa7, 0x68, 0xf9, 0x11, 0x62, 0x5e, 0x1c, 0x1a, 0xf0,
|
||||
0xbc, 0x19, 0x18, 0xa3, 0x24, 0xd1, 0x72, 0xb0, 0x93, 0xc6, 0xf7, 0x59, 0xe0, 0xdc, 0x7a, 0xd7,
|
||||
0x4e, 0x1a, 0xc6, 0xe6, 0xad, 0x28, 0xc8, 0x6c, 0x40, 0x08, 0x3d, 0x05, 0xde, 0x0f, 0x46, 0xd9,
|
||||
0x54, 0x61, 0xb6, 0x52, 0xd4, 0x12, 0x00, 0x0c, 0x5e, 0xd5, 0xca, 0xd8, 0x3f, 0x6b, 0x6b, 0xec,
|
||||
0x9f, 0x99, 0xf8, 0xc4, 0x28, 0x50, 0x5c, 0x5b, 0x2b, 0x0b, 0x5d, 0xf1, 0x44, 0x37, 0x2a, 0xf8,
|
||||
0x2a, 0xab, 0x66, 0x35, 0xa8, 0x32, 0x17, 0xc4, 0xf2, 0x55, 0x53, 0x15, 0x4b, 0xa5, 0x36, 0x96,
|
||||
0xa9, 0xbb, 0x5b, 0xda, 0xfc, 0xfd, 0xb9, 0xcd, 0x63, 0x82, 0x44, 0x0a, 0x48, 0x2a, 0xd1, 0xc6,
|
||||
0xee, 0xa1, 0x33, 0xa6, 0x3a, 0x46, 0x9b, 0x2b, 0xf2, 0x1b, 0xc6, 0x66, 0x8c, 0x30, 0xf6, 0xda,
|
||||
0xda, 0x0a, 0x17, 0xb6, 0x92, 0xa3, 0xb4, 0x7f, 0x45, 0x1b, 0xd3, 0xa7, 0xd7, 0x1e, 0xda, 0xfb,
|
||||
0x5b, 0x30, 0x3e, 0x64, 0x9d, 0x44, 0x80, 0x04, 0xc4, 0x77, 0x03, 0x3e, 0xc7, 0xb4, 0x75, 0x1d,
|
||||
0x16, 0xab, 0x10, 0x79, 0x31, 0x65, 0x1e, 0x48, 0x21, 0x55, 0xc2, 0x7a, 0xe1, 0x4c, 0x80, 0xc9,
|
||||
0x0e, 0x86, 0xe0, 0xb9, 0x6e, 0x61, 0xef, 0x86, 0x14, 0x2c, 0x93, 0xec, 0x82, 0xb4, 0xdd, 0x87,
|
||||
0x13, 0x92, 0x4c, 0x62, 0xba, 0x33, 0xbb, 0x1d, 0x2b, 0xa9, 0x2c, 0xb3, 0x1b, 0x9b, 0x38, 0x0b,
|
||||
0x4e, 0x47, 0x31, 0x12, 0x19, 0x48, 0x04, 0x7a, 0x45, 0x2d, 0x0e, 0x68, 0x48, 0x41, 0x84, 0x34,
|
||||
0xdb, 0x6c, 0x44, 0x61, 0x02, 0x16, 0x20, 0x1b, 0xd3, 0x74, 0x14, 0xba, 0x6d, 0xfb, 0xf8, 0xe8,
|
||||
0xf4, 0xcc, 0x36, 0xf0, 0xde, 0x9b, 0xc6, 0x49, 0x3b, 0x5b, 0x15, 0xb6, 0x6a, 0x1d, 0x3d, 0xc1,
|
||||
0x6a, 0xdb, 0x86, 0xc4, 0x00, 0xe2, 0x48, 0x66, 0x7a, 0x1a, 0xbf, 0x27, 0x90, 0x3b, 0x41, 0xd6,
|
||||
0x10, 0xba, 0xf7, 0xed, 0x5f, 0x4e, 0x8f, 0x0e, 0x21, 0x80, 0xc2, 0x53, 0x7a, 0xc3, 0x7b, 0x2d,
|
||||
0x83, 0x13, 0xb4, 0xc5, 0x29, 0x58, 0x62, 0x80, 0x7c, 0x91, 0x18, 0x98, 0xe1, 0x8d, 0x9e, 0x29,
|
||||
0xc7, 0xe1, 0x11, 0x80, 0x2d, 0x78, 0x49, 0xbe, 0x7b, 0x96, 0xc9, 0x95, 0xdf, 0x91, 0xa1, 0xe3,
|
||||
0xf9, 0xd4, 0x6d, 0x93, 0x67, 0x59, 0xbe, 0x1a, 0x08, 0x97, 0x4e, 0x92, 0xe9, 0xec, 0xd0, 0x19,
|
||||
0x28, 0xe5, 0x14, 0x8c, 0x2f, 0x77, 0xc4, 0xd3, 0x59, 0x9e, 0xed, 0xcc, 0x78, 0xa2, 0xb6, 0x92,
|
||||
0xb0, 0x32, 0x8a, 0x9c, 0x32, 0x48, 0x46, 0xa1, 0x65, 0x1a, 0x08, 0x15, 0xda, 0xa3, 0x10, 0x42,
|
||||
0x43, 0x3f, 0xbc, 0x86, 0xaf, 0xc6, 0x2c, 0xea, 0x87, 0x34, 0xbd, 0x0b, 0xe3, 0x1b, 0x42, 0xe3,
|
||||
0x38, 0x8c, 0x11, 0x59, 0x6a, 0x0a, 0x7f, 0x0c, 0xf8, 0x4c, 0xab, 0x82, 0x5b, 0x54, 0x57, 0x31,
|
||||
0x47, 0xe7, 0x41, 0xab, 0x44, 0x96, 0x65, 0xed, 0x80, 0x31, 0x16, 0x6d, 0xed, 0x1d, 0x1b, 0xa6,
|
||||
0x5e, 0xb1, 0x8f, 0x6d, 0xf6, 0x91, 0x15, 0x63, 0x6d, 0x24, 0x66, 0x9d, 0x34, 0x9c, 0x8d, 0xc0,
|
||||
0x4a, 0x31, 0x59, 0xc8, 0x77, 0x20, 0x29, 0x18, 0xf6, 0x67, 0x19, 0x42, 0x9d, 0x9a, 0x04, 0x79,
|
||||
0xe9, 0x05, 0x13, 0x26, 0x17, 0xff, 0x7b, 0xc4, 0xa2, 0xa8, 0x38, 0x7f, 0x89, 0x34, 0xcc, 0x02,
|
||||
0xe6, 0x64, 0xc1, 0xae, 0xcc, 0x78, 0x37, 0xd5, 0x9a, 0xba, 0x99, 0x86, 0xe7, 0xd8, 0xd9, 0xb1,
|
||||
0x07, 0xfa, 0xaf, 0xe9, 0x2f, 0xd9, 0xc3, 0x04, 0x4e, 0x45, 0xb5, 0x96, 0x3e, 0xcd, 0x49, 0x9a,
|
||||
0x5b, 0x5b, 0xf4, 0x04, 0xba, 0xb1, 0x94, 0xfc, 0x3c, 0x59, 0x60, 0x14, 0x1b, 0xa7, 0x7a, 0x4c,
|
||||
0xc6, 0xb0, 0x20, 0xbc, 0xb3, 0x1a, 0x2f, 0xc8, 0x3f, 0xaf, 0xae, 0x8e, 0xcf, 0x4f, 0x7a, 0x57,
|
||||
0x57, 0xe4, 0x45, 0x83, 0xc5, 0x9c, 0xfb, 0xc0, 0x6e, 0x1e, 0x8b, 0x59, 0xd7, 0x54, 0xb3, 0x45,
|
||||
0x43, 0x04, 0x10, 0x80, 0x8d, 0x89, 0x3a, 0x0f, 0x1c, 0x1a, 0xd6, 0x63, 0x00, 0xf3, 0x06, 0x4c,
|
||||
0xea, 0xbf, 0xc0, 0x2c, 0x81, 0xcb, 0x5d, 0x7f, 0x96, 0x9d, 0x32, 0x16, 0x69, 0xe2, 0xd9, 0x01,
|
||||
0x30, 0x77, 0x04, 0x24, 0x68, 0xe9, 0x66, 0xe4, 0xb8, 0xac, 0x89, 0x41, 0xdb, 0x30, 0xec, 0xa6,
|
||||
0x5d, 0x33, 0x17, 0xb7, 0x85, 0xe8, 0x63, 0x66, 0xe2, 0x59, 0x75, 0xe2, 0xdb, 0x70, 0x12, 0x27,
|
||||
0x75, 0x33, 0xdb, 0x33, 0xdb, 0x83, 0x8c, 0xa6, 0x74, 0xb9, 0xb9, 0xa7, 0x3c, 0xe4, 0xab, 0x9b,
|
||||
0x0b, 0xb9, 0x9b, 0xd2, 0x03, 0xc2, 0xa3, 0x68, 0x25, 0xc0, 0x57, 0x9e, 0x51, 0x1f, 0xdc, 0xa4,
|
||||
0x5f, 0x2d, 0xea, 0x88, 0x76, 0x5d, 0x60, 0x32, 0xd2, 0xb3, 0xb8, 0xcf, 0xb5, 0x75, 0x53, 0x5e,
|
||||
0xf4, 0x62, 0x6d, 0x96, 0x3d, 0xcc, 0xaf, 0x8d, 0xcb, 0x0f, 0x95, 0x24, 0x75, 0x6e, 0xfb, 0x00,
|
||||
0x47, 0x2c, 0xab, 0xc1, 0x95, 0x87, 0x41, 0x89, 0xb8, 0x80, 0x67, 0x81, 0x79, 0x62, 0x5d, 0xd8,
|
||||
0x45, 0xe7, 0x08, 0x44, 0x31, 0xb2, 0xbf, 0x03, 0x3e, 0xe6, 0x6d, 0x18, 0x18, 0xdc, 0xe4, 0x7d,
|
||||
0x04, 0xf0, 0x25, 0xbf, 0xe1, 0xb7, 0x2f, 0x8b, 0x10, 0xa4, 0x72, 0xbb, 0x3f, 0xf9, 0x74, 0x25,
|
||||
0x10, 0x01, 0x95, 0x64, 0x35, 0xe8, 0xab, 0x42, 0x96, 0x8e, 0x77, 0x4f, 0x76, 0x0f, 0xae, 0x9e,
|
||||
0x65, 0x72, 0x92, 0xe9, 0xb9, 0x66, 0x32, 0xe9, 0x73, 0xbd, 0xd6, 0x20, 0xe8, 0xc4, 0xca, 0xad,
|
||||
0x82, 0x7f, 0x0e, 0xac, 0x34, 0xaa, 0x40, 0xd5, 0x8d, 0x1c, 0x94, 0x34, 0x78, 0xd8, 0xb9, 0x61,
|
||||
0x33, 0x09, 0xbf, 0x18, 0xa1, 0xa4, 0x18, 0x63, 0x2e, 0x05, 0x97, 0x56, 0x3e, 0x95, 0x89, 0xb0,
|
||||
0x09, 0xd9, 0xb9, 0x07, 0x1a, 0xd4, 0x06, 0x4a, 0x8f, 0x9d, 0x48, 0x3b, 0x64, 0xbd, 0x08, 0x7a,
|
||||
0x47, 0x81, 0x2e, 0x64, 0x5d, 0x63, 0x70, 0x5e, 0x7c, 0xdf, 0x7c, 0x29, 0x40, 0xe9, 0xf0, 0x99,
|
||||
0x57, 0x6f, 0x66, 0x27, 0xc3, 0x48, 0x42, 0xdf, 0x40, 0x28, 0x9d, 0x6a, 0xe5, 0xfd, 0xf4, 0x87,
|
||||
0x87, 0x66, 0xc1, 0xc6, 0x49, 0x84, 0x5d, 0x26, 0xa7, 0x25, 0x96, 0x80, 0x5e, 0x0e, 0xc3, 0x58,
|
||||
0x63, 0x01, 0x9f, 0xd5, 0xec, 0x78, 0xdb, 0x65, 0x8e, 0x89, 0xda, 0x4c, 0xc7, 0x7b, 0xf9, 0x52,
|
||||
0x07, 0xda, 0x4a, 0xe8, 0x52, 0x49, 0x9f, 0x65, 0xe5, 0xe9, 0x17, 0xde, 0x25, 0x92, 0x73, 0x1e,
|
||||
0x0b, 0x6a, 0x27, 0xaf, 0x68, 0x2b, 0x12, 0xec, 0xc3, 0xc3, 0x8a, 0x4a, 0x67, 0x0c, 0x26, 0xf2,
|
||||
0xf3, 0x14, 0xf2, 0x2d, 0x8a, 0xd9, 0x89, 0x22, 0xe4, 0x0f, 0x0f, 0x45, 0x75, 0x06, 0xce, 0x7a,
|
||||
0x2b, 0x8b, 0xa4, 0xc0, 0x9b, 0x9c, 0x9d, 0x2a, 0xfe, 0x35, 0x8c, 0x23, 0x8c, 0xe0, 0xd6, 0x81,
|
||||
0x93, 0x8e, 0xcc, 0xa1, 0x1f, 0x02, 0x4d, 0x66, 0xe8, 0xdc, 0xd8, 0xfc, 0x1e, 0x2c, 0xa3, 0xe4,
|
||||
0xed, 0xc2, 0xa9, 0xcf, 0x71, 0x6a, 0xe3, 0xfb, 0xa6, 0xde, 0x29, 0x33, 0x04, 0x6d, 0x98, 0xb0,
|
||||
0x01, 0x6c, 0xbf, 0x45, 0x46, 0x42, 0x32, 0x7e, 0xd6, 0x36, 0x70, 0x39, 0xa8, 0x40, 0x9e, 0xc1,
|
||||
0x61, 0xc6, 0x73, 0x97, 0x72, 0x15, 0xee, 0xb8, 0x39, 0x01, 0x85, 0x76, 0xe6, 0x34, 0xfc, 0x63,
|
||||
0x42, 0xe3, 0xfb, 0x53, 0xea, 0xd3, 0x01, 0x04, 0xef, 0xbb, 0x3e, 0xe4, 0x1f, 0x82, 0x07, 0x92,
|
||||
0xde, 0xe8, 0xfa, 0x4a, 0x6b, 0x85, 0x9c, 0x00, 0x49, 0x9b, 0x3a, 0xf7, 0x59, 0xbc, 0x26, 0xea,
|
||||
0xdc, 0x63, 0x82, 0x67, 0x65, 0xd3, 0x4e, 0x2e, 0x65, 0xec, 0xe6, 0x09, 0x72, 0x99, 0xd2, 0x7a,
|
||||
0x8e, 0x0e, 0x24, 0xc8, 0x52, 0x45, 0x71, 0x07, 0xf8, 0x0a, 0x2c, 0xca, 0x7d, 0x01, 0x9b, 0xe2,
|
||||
0xa6, 0x96, 0xf4, 0x17, 0x9a, 0x2a, 0xe8, 0xc6, 0x3d, 0xb8, 0x03, 0xcb, 0x4d, 0xcb, 0xde, 0xc1,
|
||||
0x18, 0xa3, 0x33, 0x10, 0xc3, 0xc2, 0x31, 0x18, 0x2e, 0x96, 0xd7, 0xd2, 0xc2, 0xfc, 0x1b, 0x9c,
|
||||
0xf3, 0x7c, 0x48, 0x18, 0xfa, 0x9c, 0xc9, 0x62, 0xa9, 0x34, 0xea, 0x86, 0xc8, 0xd2, 0xc5, 0x78,
|
||||
0x6e, 0xc0, 0x3b, 0xe2, 0xa4, 0x26, 0x0a, 0x94, 0x2a, 0x19, 0xb8, 0x85, 0x79, 0x7e, 0xb6, 0xa7,
|
||||
0x21, 0x7e, 0x1c, 0x1d, 0x44, 0xc0, 0x28, 0x99, 0x09, 0x09, 0x55, 0x6f, 0xb0, 0x2c, 0x58, 0xd6,
|
||||
0x68, 0xf3, 0xf3, 0xcb, 0x86, 0x2e, 0x5b, 0x97, 0xdb, 0xc4, 0xd2, 0x16, 0x5f, 0x61, 0x2c, 0xae,
|
||||
0x1a, 0x80, 0x8a, 0xf6, 0x77, 0x0a, 0x60, 0x26, 0xf3, 0xfc, 0xc9, 0xaf, 0x1e, 0x50, 0x41, 0xa8,
|
||||
0x24, 0x84, 0x52, 0x19, 0xe7, 0x13, 0x08, 0x05, 0x0b, 0xe1, 0x4a, 0xc6, 0xf1, 0x7b, 0x9d, 0x67,
|
||||
0x88, 0x96, 0x02, 0xb4, 0x53, 0x56, 0x20, 0xde, 0x4d, 0x05, 0x21, 0xbe, 0x36, 0x63, 0x8a, 0x2a,
|
||||
0x98, 0xa0, 0x59, 0xe0, 0xc8, 0xb3, 0xdd, 0x28, 0x24, 0x48, 0xc9, 0xc3, 0x03, 0xbf, 0x35, 0xac,
|
||||
0x8e, 0x5f, 0xe4, 0x08, 0x5d, 0x5a, 0x5c, 0x96, 0xa7, 0x29, 0xeb, 0x20, 0x2e, 0x42, 0x59, 0xfb,
|
||||
0x14, 0x32, 0x28, 0x4c, 0x4b, 0xf0, 0xee, 0xb1, 0x6d, 0x4b, 0x20, 0xbc, 0x6e, 0xf2, 0x97, 0xc6,
|
||||
0x85, 0x72, 0xe7, 0xe5, 0x22, 0xc2, 0x37, 0x2c, 0x0a, 0xc4, 0xe2, 0x44, 0x82, 0x2d, 0x54, 0x5c,
|
||||
0x0b, 0x92, 0xcf, 0xcb, 0x11, 0x4a, 0x1a, 0x28, 0xef, 0x8f, 0xb8, 0xd9, 0xed, 0x56, 0xad, 0x26,
|
||||
0xaf, 0xe0, 0x2a, 0x36, 0x73, 0x61, 0x64, 0xd0, 0x5c, 0x14, 0x19, 0x34, 0xbf, 0x52, 0xe0, 0x58,
|
||||
0xb1, 0x57, 0x0a, 0x64, 0x30, 0x57, 0x8f, 0x85, 0xfc, 0xa0, 0x8d, 0x76, 0x0d, 0x03, 0xa4, 0xc8,
|
||||
0xb0, 0x2d, 0x55, 0xea, 0xb3, 0x85, 0x84, 0xd3, 0x15, 0xc4, 0xa7, 0x42, 0xe9, 0x9c, 0xc6, 0xec,
|
||||
0x66, 0x9b, 0x6f, 0x95, 0x4f, 0x41, 0x59, 0xd0, 0xb0, 0xea, 0xa5, 0x48, 0xe3, 0xcf, 0x61, 0x2a,
|
||||
0x25, 0x11, 0xff, 0x81, 0x18, 0x81, 0x39, 0xdb, 0xf3, 0x77, 0x5a, 0x4d, 0x2a, 0x26, 0x90, 0xe9,
|
||||
0xe1, 0x3f, 0x1c, 0x11, 0x14, 0xe4, 0x1c, 0x17, 0xaa, 0x06, 0xd1, 0x05, 0x9c, 0x0c, 0x01, 0x9b,
|
||||
0x71, 0x3a, 0xb8, 0x02, 0xf2, 0x3f, 0x3c, 0xcc, 0x96, 0xc8, 0xd8, 0xce, 0xe6, 0x38, 0xb9, 0x5e,
|
||||
0xb1, 0xac, 0xdb, 0xd0, 0x73, 0x09, 0x16, 0xe3, 0x90, 0x8f, 0x30, 0x04, 0x0c, 0xe4, 0x0a, 0x2a,
|
||||
0xe7, 0x88, 0xd9, 0xa2, 0xad, 0xb1, 0xba, 0x42, 0x0c, 0x97, 0x57, 0x89, 0x41, 0x48, 0x35, 0xde,
|
||||
0xe0, 0xeb, 0x2f, 0xda, 0x06, 0xc8, 0x90, 0xc6, 0x9e, 0xf4, 0x27, 0x9e, 0xef, 0x5e, 0x89, 0xb6,
|
||||
0x18, 0x70, 0xc6, 0xc5, 0x18, 0x22, 0xaf, 0x4b, 0xa0, 0xfc, 0x79, 0x19, 0x68, 0x69, 0xe9, 0x4b,
|
||||
0x9b, 0x68, 0xf6, 0xcb, 0xca, 0xf2, 0x97, 0xb6, 0x6e, 0x73, 0xb5, 0x46, 0xe3, 0xfa, 0xae, 0x2e,
|
||||
0x49, 0x18, 0x72, 0x34, 0xf0, 0xb9, 0x72, 0x92, 0x95, 0x7c, 0xfe, 0xe2, 0xe8, 0x41, 0xb9, 0x3c,
|
||||
0x2a, 0x45, 0x0f, 0x00, 0x2a, 0x87, 0x90, 0x7b, 0x9f, 0x79, 0xd9, 0x4b, 0x81, 0xc1, 0x0b, 0x34,
|
||||
0xe2, 0x9d, 0x62, 0xef, 0xdc, 0xf1, 0x73, 0x9f, 0x01, 0xce, 0xa0, 0x36, 0x7d, 0xc9, 0x9f, 0x2e,
|
||||
0x95, 0xc0, 0xe4, 0xb3, 0x1f, 0x4f, 0x61, 0xf2, 0xa9, 0x4b, 0x24, 0x31, 0x05, 0x12, 0xcb, 0xa4,
|
||||
0x31, 0xf9, 0xec, 0x45, 0x89, 0xcc, 0x54, 0x72, 0xee, 0x68, 0x92, 0x2a, 0xac, 0x2b, 0x3a, 0xa1,
|
||||
0x15, 0x06, 0x06, 0x60, 0xe0, 0xae, 0x1c, 0xdf, 0x89, 0xc7, 0x39, 0x1b, 0x97, 0x24, 0x7c, 0xb1,
|
||||
0xb2, 0x20, 0x3f, 0xdf, 0xf0, 0xff, 0x3c, 0xfd, 0x19, 0x7d, 0x0a, 0xdf, 0x0a, 0xca, 0xc8, 0x6d,
|
||||
0xca, 0x71, 0xde, 0xac, 0xa3, 0x49, 0x73, 0x55, 0xcd, 0x0d, 0xa4, 0x37, 0x55, 0x12, 0xbf, 0x92,
|
||||
0xfe, 0x15, 0x81, 0x49, 0x87, 0x1b, 0xa7, 0x52, 0x58, 0xa2, 0xaa, 0xe2, 0x2c, 0x8c, 0xcf, 0xd6,
|
||||
0xc9, 0x59, 0x50, 0x70, 0xa4, 0x1a, 0xf8, 0x8a, 0x91, 0x29, 0xe3, 0x95, 0x1b, 0xb0, 0x96, 0xae,
|
||||
0x57, 0x0d, 0xad, 0x4a, 0x14, 0x26, 0x79, 0xac, 0x47, 0x8d, 0x9d, 0x97, 0x7d, 0xc2, 0xaa, 0x49,
|
||||
0x88, 0xf5, 0x13, 0x1e, 0x47, 0x5b, 0x47, 0xfd, 0xdf, 0x21, 0x4a, 0x36, 0x01, 0xb3, 0xd8, 0x03,
|
||||
0x76, 0x55, 0x68, 0xad, 0x9b, 0x38, 0x59, 0xd3, 0x1c, 0xa3, 0xaf, 0x5b, 0x5d, 0x07, 0x2f, 0xb4,
|
||||
0x59, 0x7f, 0x3f, 0xdd, 0x0b, 0xc7, 0x11, 0x76, 0xe9, 0xf5, 0x61, 0x48, 0x67, 0xf2, 0x3f, 0xd3,
|
||||
0x3a, 0xa5, 0x8b, 0x88, 0xf9, 0xe2, 0x86, 0xde, 0xf3, 0x30, 0xec, 0x12, 0xa2, 0x66, 0x75, 0x73,
|
||||
0x11, 0x34, 0xcf, 0xa4, 0x59, 0xb0, 0x60, 0xca, 0x95, 0x8a, 0x67, 0x3e, 0x2b, 0xde, 0x17, 0xd1,
|
||||
0xdb, 0x13, 0x24, 0x56, 0x93, 0x0d, 0x1e, 0xd5, 0xb1, 0xe0, 0x32, 0xab, 0x6d, 0xfa, 0x9a, 0xa5,
|
||||
0xa6, 0xf4, 0xa8, 0x2c, 0xbc, 0xcd, 0x18, 0x31, 0xcb, 0xed, 0x31, 0x4b, 0x9e, 0x37, 0x0e, 0xef,
|
||||
0x2c, 0xb9, 0x3a, 0x81, 0xb0, 0xe2, 0x84, 0x5d, 0xc7, 0x40, 0x9c, 0xe2, 0xb7, 0x2c, 0x78, 0x26,
|
||||
0x46, 0xf7, 0xe0, 0xbb, 0xd6, 0xe4, 0xe3, 0x1b, 0xd5, 0xf1, 0x96, 0xde, 0x61, 0xf3, 0x4b, 0xf7,
|
||||
0x59, 0xb0, 0x6d, 0xa7, 0xa0, 0xe7, 0xbc, 0xa6, 0x1b, 0xd9, 0x16, 0xa5, 0x44, 0xc1, 0xf8, 0x07,
|
||||
0x30, 0xe5, 0x84, 0xc1, 0xa2, 0x3d, 0xea, 0xa6, 0xbd, 0xc3, 0x2f, 0x1e, 0xdb, 0x32, 0x42, 0x36,
|
||||
0x64, 0x66, 0x63, 0x95, 0xf9, 0x64, 0xcc, 0x90, 0x55, 0x8c, 0xe4, 0xaf, 0x32, 0x48, 0x09, 0xd5,
|
||||
0xca, 0x75, 0x16, 0xf6, 0x4a, 0xc3, 0x94, 0x1f, 0xb0, 0xd4, 0xf2, 0x22, 0x0a, 0x30, 0x8f, 0x65,
|
||||
0x73, 0xe0, 0x86, 0x2b, 0x21, 0x63, 0xc6, 0x37, 0x9e, 0xed, 0x6f, 0x60, 0xdd, 0x17, 0xb6, 0xa1,
|
||||
0x20, 0x82, 0x9b, 0x9b, 0x09, 0x83, 0xa9, 0xe1, 0x75, 0xa9, 0x5e, 0xd7, 0xfa, 0xd7, 0x9c, 0x09,
|
||||
0xe9, 0xaa, 0x3d, 0xaa, 0x8c, 0xa1, 0xd8, 0xdd, 0x5a, 0x58, 0x95, 0x52, 0x47, 0x2c, 0x10, 0x3a,
|
||||
0x7f, 0x2a, 0x7b, 0x40, 0x44, 0x05, 0xbb, 0xfe, 0xa6, 0xba, 0x98, 0x9d, 0x93, 0x0f, 0xef, 0x75,
|
||||
0xe4, 0xf5, 0xb3, 0xec, 0xf2, 0xc1, 0x69, 0x56, 0x31, 0x17, 0x3f, 0x61, 0xb7, 0x09, 0xaa, 0x0c,
|
||||
0x7e, 0xe6, 0x37, 0x31, 0xf8, 0xc9, 0xc4, 0x9f, 0x3e, 0x00, 0xed, 0x76, 0x45, 0xda, 0x84, 0x7d,
|
||||
0xbb, 0x98, 0x34, 0xcd, 0xc6, 0xb6, 0xc7, 0xfc, 0xea, 0x85, 0xd3, 0x84, 0x38, 0x84, 0x75, 0xf8,
|
||||
0x8a, 0x33, 0x08, 0xc9, 0x9f, 0x53, 0xf9, 0x16, 0x7d, 0xba, 0xf2, 0xe0, 0x6c, 0x11, 0x59, 0x7d,
|
||||
0x96, 0xe5, 0xfb, 0x4f, 0x57, 0x77, 0xfe, 0x1d, 0xfc, 0x3b, 0xa8, 0xb9, 0x9d, 0x71, 0x86, 0x60,
|
||||
0x65, 0x04, 0x55, 0x4d, 0xa5, 0x2e, 0xee, 0xc4, 0xb1, 0x73, 0xff, 0x7a, 0x32, 0x1c, 0xd2, 0x58,
|
||||
0xc6, 0xc9, 0x08, 0x4c, 0x19, 0x06, 0x7d, 0x54, 0xae, 0x17, 0x39, 0x0a, 0x18, 0x84, 0x4a, 0xde,
|
||||
0xd8, 0x86, 0xcd, 0x1a, 0x41, 0x79, 0xf3, 0xe8, 0xea, 0x4c, 0xdf, 0x2b, 0x91, 0x2f, 0x51, 0xae,
|
||||
0x76, 0xbf, 0xf9, 0xc7, 0x3f, 0x48, 0xe5, 0x3f, 0xcb, 0x2d, 0x25, 0xe5, 0x57, 0x71, 0xd9, 0x2f,
|
||||
0x3e, 0x00, 0xbc, 0x02, 0x19, 0x95, 0x06, 0xa6, 0x69, 0xf2, 0xbe, 0xd3, 0xcf, 0xdf, 0xae, 0x78,
|
||||
0xb1, 0x92, 0xe0, 0x4f, 0x3a, 0x88, 0x01, 0xf1, 0xea, 0x24, 0xe9, 0x87, 0x3e, 0x9c, 0x86, 0x5d,
|
||||
0xd2, 0x73, 0x82, 0xae, 0xb3, 0xb7, 0x74, 0x20, 0x3f, 0x59, 0xed, 0x36, 0x9f, 0xd7, 0xee, 0xcd,
|
||||
0x07, 0x8b, 0xeb, 0xfa, 0x4f, 0xa3, 0x98, 0x55, 0x27, 0x7e, 0x3b, 0xf8, 0xf0, 0x36, 0x4d, 0xa3,
|
||||
0x13, 0x7c, 0xb9, 0x27, 0x49, 0x3b, 0x30, 0x6c, 0x0a, 0x1e, 0xcd, 0xea, 0x96, 0xdc, 0x04, 0xc2,
|
||||
0x7e, 0xd9, 0x6f, 0xc6, 0x6b, 0x29, 0xe8, 0x22, 0x26, 0xcc, 0xd0, 0x89, 0x1c, 0x9d, 0xc6, 0xf8,
|
||||
0xf2, 0x29, 0x0e, 0xc3, 0x57, 0x51, 0x64, 0x60, 0x07, 0xc5, 0x25, 0x00, 0x9c, 0xba, 0x0d, 0x8c,
|
||||
0xcd, 0x53, 0xc7, 0x7f, 0x81, 0xad, 0x8a, 0x86, 0x84, 0xbc, 0xe8, 0xf2, 0xbf, 0x72, 0x52, 0x1b,
|
||||
0xbb, 0xd2, 0xe4, 0x2a, 0x30, 0xf9, 0xc5, 0x97, 0x92, 0xa9, 0xac, 0xa0, 0xf2, 0xd2, 0x7e, 0x8e,
|
||||
0xe9, 0x1b, 0xa7, 0x01, 0x87, 0x28, 0x34, 0xd3, 0x52, 0xb5, 0x54, 0xaa, 0x29, 0xe4, 0x5a, 0xe8,
|
||||
0x33, 0xf1, 0xba, 0x15, 0x29, 0x33, 0x4b, 0x12, 0x04, 0x60, 0x1b, 0x9a, 0x9c, 0xc0, 0xf3, 0xa2,
|
||||
0xae, 0x05, 0xd9, 0xe5, 0xda, 0x5a, 0x31, 0xb0, 0xbd, 0xd9, 0x6c, 0xe6, 0xdd, 0x26, 0xd8, 0x61,
|
||||
0x82, 0x40, 0xb5, 0x6a, 0x94, 0xd8, 0xe3, 0xa9, 0x96, 0xd4, 0xb1, 0xfc, 0x0a, 0xa6, 0x80, 0x33,
|
||||
0x2d, 0x7d, 0x13, 0x29, 0x36, 0x5a, 0xb4, 0x7a, 0xe4, 0x58, 0xee, 0x26, 0xb0, 0x5b, 0xbc, 0x67,
|
||||
0x29, 0xdb, 0x25, 0xee, 0x84, 0x5d, 0xa2, 0x72, 0xf2, 0x2c, 0xda, 0xc0, 0xe9, 0x83, 0xcb, 0x5b,
|
||||
0x6a, 0x03, 0x71, 0x28, 0x9e, 0xa5, 0xfb, 0x94, 0x43, 0x05, 0x36, 0x20, 0xdc, 0x10, 0xfc, 0x81,
|
||||
0x26, 0x0a, 0x1c, 0x90, 0x1d, 0x83, 0x54, 0xd8, 0x7c, 0x43, 0xc8, 0x1d, 0x85, 0x5c, 0xbe, 0x65,
|
||||
0x75, 0x0f, 0xbc, 0xba, 0x2c, 0xaa, 0x1e, 0x30, 0x59, 0xad, 0x7a, 0x84, 0x83, 0x94, 0x82, 0xca,
|
||||
0xa4, 0x60, 0xd1, 0xc7, 0xf9, 0x7a, 0x10, 0x38, 0xc5, 0x90, 0x48, 0x7b, 0x5c, 0xe2, 0xbb, 0xda,
|
||||
0xba, 0x20, 0x2d, 0x0a, 0x39, 0x67, 0x21, 0x01, 0xec, 0x90, 0x8f, 0xf0, 0x35, 0x90, 0x8f, 0x27,
|
||||
0x93, 0xc1, 0x00, 0xc4, 0x6c, 0x08, 0x71, 0xf9, 0xfd, 0x0a, 0x11, 0x86, 0xce, 0x4b, 0x84, 0x99,
|
||||
0x03, 0xba, 0xa1, 0xf6, 0xf7, 0xe3, 0xee, 0xff, 0x37, 0xd7, 0x7c, 0x41, 0x73, 0x4d, 0x5e, 0x86,
|
||||
0x50, 0x3b, 0x6b, 0x67, 0x1d, 0x59, 0xaf, 0xbe, 0x38, 0x53, 0x04, 0xca, 0xf9, 0xcb, 0x8b, 0x9a,
|
||||
0xa7, 0x67, 0x7f, 0xc1, 0x95, 0xab, 0x1d, 0x0f, 0xaf, 0xf0, 0xd0, 0x81, 0x6d, 0xa0, 0x4b, 0x0f,
|
||||
0xa8, 0xdf, 0xf6, 0x58, 0x8f, 0x56, 0x25, 0xb8, 0xa8, 0x79, 0xa9, 0x52, 0x69, 0xa3, 0xc6, 0x62,
|
||||
0x22, 0x5e, 0x40, 0xbd, 0x09, 0x63, 0x90, 0x3d, 0xb0, 0x2f, 0xf6, 0x09, 0xc5, 0xaa, 0x03, 0x0a,
|
||||
0xe4, 0x79, 0x84, 0xb7, 0x4e, 0xc8, 0x9f, 0x4b, 0x83, 0xed, 0x44, 0xdd, 0xbd, 0xd0, 0xc5, 0xe9,
|
||||
0xec, 0x75, 0x85, 0xf2, 0x9f, 0xcb, 0xc7, 0x6f, 0xb0, 0x05, 0x26, 0xd8, 0x74, 0x43, 0xb6, 0xf0,
|
||||
0x75, 0x50, 0xde, 0x56, 0x42, 0xe4, 0xcf, 0x1a, 0x78, 0x78, 0x37, 0xca, 0x71, 0x34, 0xbf, 0xf9,
|
||||
0xe6, 0x18, 0x2d, 0x2c, 0x39, 0x7a, 0xcf, 0x1b, 0x96, 0xc0, 0x21, 0x1a, 0x78, 0xf1, 0x0d, 0xc1,
|
||||
0x43, 0x88, 0x3d, 0x3b, 0xec, 0x12, 0x3c, 0x62, 0xbd, 0x7c, 0x89, 0xf9, 0xb7, 0x5e, 0x7d, 0x23,
|
||||
0x1f, 0x98, 0xf4, 0x5d, 0xa5, 0x74, 0x1c, 0xd9, 0xd3, 0x27, 0x17, 0x3c, 0xd9, 0x62, 0x24, 0x07,
|
||||
0xae, 0xc7, 0x5e, 0x9a, 0x98, 0x95, 0x98, 0x94, 0xf0, 0xe8, 0xef, 0x39, 0x94, 0xa8, 0x6c, 0xb2,
|
||||
0x13, 0x19, 0xcb, 0x1f, 0x47, 0x2c, 0xc3, 0x03, 0x0d, 0xf8, 0x4f, 0x6d, 0x25, 0xc5, 0x61, 0xca,
|
||||
0x97, 0x6a, 0x5b, 0xec, 0x02, 0x2d, 0xfb, 0x4b, 0x4f, 0x55, 0xa7, 0x32, 0x8b, 0x62, 0x67, 0xa5,
|
||||
0xa6, 0x2b, 0x1d, 0x35, 0x7b, 0xe3, 0xa1, 0xc6, 0x44, 0xf0, 0xd7, 0x93, 0xc1, 0x44, 0x78, 0x2f,
|
||||
0x5b, 0xd3, 0xc6, 0x16, 0x1a, 0x0b, 0x45, 0xc9, 0xf0, 0x5e, 0x0f, 0xe3, 0x55, 0x2e, 0xd7, 0xbc,
|
||||
0x87, 0xa3, 0xf2, 0x98, 0xe4, 0x2f, 0x62, 0x61, 0xbb, 0x4f, 0x2c, 0xf5, 0x03, 0xaf, 0xc5, 0x8b,
|
||||
0x95, 0xa0, 0x11, 0x77, 0xa8, 0x07, 0x2e, 0xbe, 0x07, 0xa7, 0x81, 0x0b, 0xc5, 0x1f, 0x58, 0x01,
|
||||
0x55, 0x28, 0xb4, 0x85, 0xbd, 0xdf, 0x48, 0x26, 0x81, 0xd0, 0xb7, 0x31, 0x24, 0xcd, 0x26, 0xb6,
|
||||
0x60, 0x0a, 0xf5, 0x7b, 0x2d, 0x5e, 0x90, 0x30, 0xfe, 0x4e, 0xba, 0xaf, 0xb7, 0x98, 0xa2, 0xfc,
|
||||
0xbd, 0x6a, 0xcb, 0x63, 0x9b, 0x7a, 0x95, 0xad, 0x2d, 0x4a, 0x0f, 0x46, 0x74, 0x70, 0x83, 0xf1,
|
||||
0x0a, 0x08, 0xf7, 0xdc, 0x1a, 0x79, 0xc9, 0x56, 0x02, 0x5b, 0x2d, 0x7e, 0xdb, 0x94, 0xe5, 0x6f,
|
||||
0x84, 0xd5, 0xd6, 0xcd, 0x3b, 0xd5, 0x55, 0xac, 0x66, 0x32, 0xc0, 0x6f, 0x3b, 0xc5, 0x47, 0x78,
|
||||
0xd0, 0x86, 0xfc, 0x71, 0x71, 0xe9, 0xbc, 0x16, 0x4b, 0x5a, 0x83, 0xd7, 0xb4, 0x3a, 0x62, 0xa1,
|
||||
0x2f, 0xfd, 0x6b, 0x59, 0x40, 0x53, 0x6e, 0x37, 0x0d, 0xfe, 0xc3, 0x55, 0x9e, 0x81, 0xe7, 0x84,
|
||||
0x33, 0xb2, 0x6e, 0xe3, 0x3a, 0x6b, 0x51, 0x57, 0xdc, 0x79, 0xdf, 0xfb, 0xd7, 0xde, 0xd1, 0x7e,
|
||||
0xef, 0x0a, 0x54, 0x6f, 0x2a, 0xab, 0x10, 0x95, 0xd2, 0x4c, 0xe5, 0xa8, 0x35, 0x7d, 0x24, 0xbc,
|
||||
0xbf, 0xb3, 0xa8, 0x52, 0x59, 0x99, 0x04, 0xdb, 0x6c, 0x97, 0x56, 0x37, 0x2f, 0x0d, 0xf9, 0xa4,
|
||||
0x55, 0x7e, 0xd2, 0x2a, 0x9e, 0x6c, 0x94, 0x9f, 0x6c, 0x14, 0x4f, 0x36, 0xcb, 0x4f, 0x36, 0x2f,
|
||||
0xa7, 0x9d, 0xbf, 0xdc, 0xc6, 0x17, 0xa7, 0x64, 0xf6, 0xaf, 0x64, 0xdc, 0xbf, 0x90, 0xea, 0x8f,
|
||||
0xde, 0xb0, 0x4d, 0x97, 0xbf, 0x50, 0x57, 0xee, 0xcf, 0xc5, 0x65, 0xc9, 0x67, 0x5d, 0xcc, 0x89,
|
||||
0xbb, 0xe3, 0x47, 0x6f, 0x1d, 0x99, 0xcb, 0x72, 0x9f, 0x7a, 0xed, 0xf8, 0x97, 0xea, 0x0b, 0x0d,
|
||||
0x72, 0x9f, 0xcc, 0xc2, 0x6d, 0xf1, 0x42, 0xb9, 0x65, 0xe7, 0xbf, 0xae, 0x41, 0x84, 0x9d, 0x1f,
|
||||
0xa3, 0x05, 0x90, 0xb9, 0xe8, 0xca, 0x37, 0xdf, 0xd8, 0x9d, 0x3a, 0xc6, 0xd6, 0x58, 0x80, 0x1d,
|
||||
0x01, 0xf3, 0x25, 0x5e, 0x0e, 0x54, 0x3c, 0x54, 0x9b, 0xac, 0xe3, 0x6f, 0x53, 0x34, 0xba, 0x76,
|
||||
0x7b, 0xe1, 0xac, 0x67, 0x59, 0x05, 0xf0, 0x94, 0xaf, 0xea, 0xcc, 0xf0, 0x40, 0x80, 0x29, 0x79,
|
||||
0x23, 0x79, 0xbb, 0xb9, 0xe8, 0xd2, 0x14, 0xce, 0x1b, 0x29, 0x07, 0x7d, 0x6a, 0x97, 0xa6, 0xf3,
|
||||
0xc9, 0x4b, 0x1e, 0xbf, 0x3d, 0xfd, 0x8a, 0xbc, 0xc4, 0xd6, 0xcf, 0x67, 0x19, 0xa2, 0x31, 0xbd,
|
||||
0xe2, 0x0d, 0xcd, 0x4f, 0x8f, 0x1c, 0xd9, 0x3a, 0x22, 0xa0, 0xa8, 0xdd, 0x8c, 0x75, 0x02, 0x5c,
|
||||
0x04, 0x61, 0xac, 0x14, 0x36, 0x4e, 0x2d, 0x05, 0xb4, 0x78, 0x2b, 0xc6, 0xe6, 0x21, 0x46, 0x11,
|
||||
0x86, 0xa0, 0xea, 0xc6, 0x26, 0x29, 0x0d, 0x3b, 0xd7, 0x0e, 0x44, 0xea, 0x6c, 0xfb, 0x30, 0x22,
|
||||
0x5e, 0x0a, 0xb1, 0xfa, 0x19, 0x04, 0x24, 0x06, 0x7b, 0x29, 0x9f, 0x05, 0x36, 0xce, 0x20, 0x9d,
|
||||
0x38, 0xbe, 0xe8, 0xb7, 0x47, 0x5c, 0x8b, 0x96, 0x7b, 0xc8, 0x48, 0x03, 0xf0, 0x4f, 0xe8, 0x91,
|
||||
0xd4, 0x2e, 0x50, 0x5e, 0x97, 0x47, 0xa4, 0x2c, 0xd6, 0x56, 0xff, 0xf0, 0xc0, 0x3f, 0xe3, 0x3b,
|
||||
0x38, 0x8b, 0xdb, 0x47, 0x95, 0x34, 0x5f, 0x3d, 0x9f, 0xdc, 0x51, 0xed, 0xbc, 0x00, 0x90, 0xbc,
|
||||
0xfc, 0x9f, 0x1c, 0x3a, 0x87, 0x9a, 0x9c, 0x81, 0x5d, 0x52, 0xe2, 0x23, 0xa4, 0x92, 0x75, 0xdb,
|
||||
0xbd, 0x0b, 0xc0, 0x85, 0x78, 0xca, 0x29, 0xd8, 0x8f, 0x9d, 0x51, 0x17, 0xe8, 0xc2, 0xab, 0x9b,
|
||||
0xec, 0x3b, 0x71, 0x08, 0xff, 0x1d, 0x44, 0x30, 0x24, 0xbc, 0xb8, 0x6d, 0xfe, 0xdd, 0x41, 0x3c,
|
||||
0xca, 0x18, 0x36, 0x00, 0x3c, 0x31, 0x82, 0xbf, 0x66, 0xef, 0x37, 0x16, 0x24, 0x66, 0x17, 0xf8,
|
||||
0x8f, 0x4a, 0x14, 0xac, 0xd8, 0x9f, 0x1f, 0xdd, 0x20, 0x77, 0x41, 0x4a, 0x91, 0xa5, 0xbc, 0xe1,
|
||||
0x99, 0xbb, 0x94, 0x1b, 0x6a, 0x89, 0x75, 0x26, 0x6d, 0xe4, 0x2c, 0x69, 0xb4, 0x36, 0x74, 0xe3,
|
||||
0x26, 0xcd, 0x1f, 0xa5, 0xe5, 0x47, 0x2f, 0x5a, 0xe6, 0x86, 0x71, 0xa3, 0x14, 0xc7, 0xb9, 0x3b,
|
||||
0xe2, 0xfd, 0x91, 0xef, 0x7b, 0x36, 0xae, 0x9d, 0xf3, 0x10, 0xaf, 0xe4, 0xc4, 0xca, 0x1d, 0xed,
|
||||
0xa6, 0x74, 0x13, 0x7d, 0xa3, 0xde, 0xe0, 0x97, 0xc2, 0x03, 0x31, 0x4f, 0xd7, 0xdb, 0x95, 0x70,
|
||||
0x6b, 0x2f, 0x9c, 0xf8, 0x2e, 0xc1, 0x57, 0x4d, 0xf0, 0xad, 0x4f, 0x32, 0x0f, 0x0d, 0xd8, 0xa9,
|
||||
0x74, 0xf7, 0xa6, 0x94, 0x28, 0x6f, 0x2a, 0xfd, 0x94, 0x62, 0xe2, 0xd3, 0xb6, 0x3a, 0xc3, 0xad,
|
||||
0x38, 0x8e, 0x0f, 0x0f, 0x72, 0xcf, 0x59, 0x06, 0xf3, 0x1f, 0xfb, 0x50, 0x19, 0x3b, 0x90, 0xde,
|
||||
0x01, 0xb3, 0x0b, 0xbc, 0x78, 0xe1, 0x4b, 0xed, 0xf7, 0x3d, 0x0d, 0x7f, 0x58, 0x2d, 0x69, 0x0c,
|
||||
0x53, 0xbd, 0x8d, 0xe3, 0x0a, 0x65, 0x20, 0x87, 0xb1, 0xf1, 0x6d, 0x30, 0x18, 0x4e, 0xe5, 0xf4,
|
||||
0x33, 0x2d, 0xe5, 0x29, 0x12, 0x19, 0xcb, 0x35, 0xe5, 0x33, 0xca, 0x45, 0x90, 0xc3, 0x88, 0xfb,
|
||||
0x00, 0xa5, 0xc9, 0x07, 0xd4, 0xa4, 0xbd, 0x0c, 0xb6, 0xb2, 0x4a, 0x59, 0x21, 0x85, 0xa4, 0x37,
|
||||
0x81, 0xc8, 0x57, 0x12, 0x44, 0x89, 0xe2, 0x00, 0x7a, 0xde, 0x39, 0x26, 0x25, 0x90, 0x75, 0xdf,
|
||||
0x0b, 0x01, 0x54, 0xa5, 0x4c, 0x0a, 0x59, 0x8d, 0xfc, 0xb0, 0x7e, 0x5b, 0x2e, 0x3e, 0x9f, 0xcd,
|
||||
0xd4, 0x9a, 0x94, 0x91, 0xfd, 0x7e, 0xcb, 0x5c, 0x96, 0xc0, 0x41, 0x54, 0xca, 0x7a, 0x81, 0x8e,
|
||||
0x6a, 0x38, 0x43, 0xda, 0x79, 0x54, 0xd5, 0xdb, 0xda, 0x32, 0x52, 0x94, 0x1f, 0x6d, 0x19, 0xfc,
|
||||
0xe6, 0x30, 0x41, 0xc0, 0x28, 0xe8, 0x8e, 0xdb, 0x4f, 0x17, 0xf9, 0x6f, 0xd5, 0x86, 0x2f, 0xe7,
|
||||
0xbc, 0x67, 0x7e, 0x62, 0xe5, 0x51, 0xf7, 0xed, 0x87, 0xd7, 0xf6, 0x13, 0x5d, 0xaa, 0xdc, 0x84,
|
||||
0xc0, 0x5a, 0x76, 0x3b, 0xf4, 0x59, 0x2d, 0x68, 0xac, 0xbe, 0xe6, 0x87, 0xfd, 0xaa, 0x31, 0xc4,
|
||||
0x31, 0x4d, 0x37, 0x16, 0xb6, 0xfb, 0x43, 0x94, 0x36, 0xc6, 0x9f, 0x5c, 0x73, 0xf1, 0x9b, 0xd2,
|
||||
0x18, 0xfb, 0x48, 0x6f, 0xfe, 0xb3, 0xec, 0xc2, 0xfe, 0x65, 0xf7, 0x10, 0xeb, 0xc8, 0xbd, 0xd7,
|
||||
0xd8, 0x44, 0xbe, 0x7b, 0x02, 0x7f, 0x77, 0x8f, 0x4f, 0xd8, 0xe7, 0x7f, 0x61, 0xcb, 0xf8, 0xf9,
|
||||
0x21, 0xfb, 0xfb, 0x01, 0xc7, 0xcf, 0x7f, 0x86, 0xbf, 0xa7, 0xbd, 0x63, 0xf8, 0x7b, 0xb4, 0x87,
|
||||
0xc5, 0xf0, 0xc3, 0xa3, 0x8f, 0x58, 0xed, 0xeb, 0xed, 0xd9, 0x97, 0x17, 0xe5, 0x57, 0x06, 0x2e,
|
||||
0xa7, 0x4b, 0xbd, 0x60, 0x30, 0xb7, 0x8d, 0xe3, 0x09, 0xaf, 0x02, 0xd8, 0xc6, 0x24, 0xf6, 0xad,
|
||||
0xf3, 0x93, 0x0f, 0xe2, 0x7e, 0x99, 0xb7, 0x11, 0xc0, 0x77, 0x0d, 0x29, 0x07, 0x02, 0x3a, 0xf7,
|
||||
0x02, 0xda, 0xc1, 0x40, 0xdc, 0x1c, 0xc5, 0x74, 0x68, 0x01, 0x08, 0xc3, 0x31, 0x25, 0x23, 0xf1,
|
||||
0xe6, 0x99, 0x55, 0xd4, 0x00, 0xe1, 0x12, 0x69, 0xa7, 0xec, 0xd2, 0xb2, 0x78, 0x7f, 0x1d, 0xdd,
|
||||
0x68, 0xe9, 0xc2, 0xd8, 0x81, 0xfd, 0xf2, 0xdb, 0xd5, 0xf2, 0x34, 0x9e, 0xd3, 0xe4, 0xd3, 0x10,
|
||||
0xe1, 0x98, 0xde, 0x86, 0x37, 0x0a, 0xc2, 0x80, 0x45, 0x1e, 0xbf, 0xa2, 0x78, 0xd7, 0x89, 0x1d,
|
||||
0x4f, 0xd7, 0x25, 0xa6, 0x18, 0xc6, 0xaa, 0x52, 0xc7, 0x96, 0xcd, 0x79, 0x85, 0x04, 0x89, 0x76,
|
||||
0x1c, 0xfa, 0x3e, 0x92, 0x55, 0x54, 0x9b, 0x65, 0xd0, 0x5c, 0xfe, 0x61, 0x19, 0xb5, 0x5e, 0xaf,
|
||||
0xf6, 0x24, 0x6e, 0x96, 0xdf, 0x2b, 0x85, 0x48, 0xae, 0x00, 0xa7, 0x02, 0x98, 0x7d, 0x87, 0x4f,
|
||||
0x7d, 0x2a, 0xdf, 0xe2, 0x5b, 0xf0, 0x23, 0x00, 0xb7, 0x5e, 0xe2, 0xf5, 0x3d, 0xdf, 0x4b, 0xef,
|
||||
0xb9, 0x61, 0x2a, 0xdd, 0x97, 0xe7, 0xeb, 0x46, 0x9e, 0xeb, 0xd2, 0x60, 0xa7, 0x84, 0x47, 0x5b,
|
||||
0xfb, 0xcc, 0x73, 0x61, 0xb4, 0x23, 0xde, 0xb1, 0x0f, 0xb9, 0x0c, 0x28, 0x5b, 0x7e, 0x41, 0x77,
|
||||
0x67, 0x89, 0xe8, 0xd3, 0xce, 0x76, 0x43, 0xfc, 0xd4, 0xcf, 0x76, 0x83, 0xff, 0x98, 0x6c, 0x83,
|
||||
0xfd, 0xdf, 0x0c, 0xfc, 0x07, 0x7d, 0x53, 0xca, 0x86, 0x76, 0x60, 0x00, 0x00,
|
||||
};
|
||||
|
||||
const unsigned int html_content_gz_len = 6845;
|
||||
|
||||
#endif // HTML_CONTENT_GZ_H
|
||||
File diff suppressed because one or more lines are too long
1442
main/webserver.c
1442
main/webserver.c
File diff suppressed because it is too large
Load Diff
@@ -1 +1 @@
|
||||
a8049b1e609679fb54b2d57b0399dd29c4d1fda09a797edac9926f7810aa5703
|
||||
689853bb8993434f9556af0f2816e808bf77b5d22100144b21f3519993daf237
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: esp_idf_lib_helpers
|
||||
description: Common support library for esp-idf-lib
|
||||
version: 1.3.10
|
||||
version: 1.4.0
|
||||
groups:
|
||||
- common
|
||||
code_owners:
|
||||
|
||||
@@ -2,6 +2,11 @@ examples/**/sdkconfig
|
||||
examples/**/sdkconfig.old
|
||||
examples/**/build/
|
||||
examples/**/dependencies.lock
|
||||
examples/**/managed_components/
|
||||
docs/_*/
|
||||
docs/doxygen.log
|
||||
docs/**/*.log
|
||||
*.swp
|
||||
*.bak
|
||||
*.orig
|
||||
build/
|
||||
.vscode/
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
* The default SPI_HOST for spi_host_device_t
|
||||
*/
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define HELPER_SPI_HOST_DEFAULT HSPI_HOST
|
||||
#define HELPER_SPI_HOST_DEFAULT SPI1_HOST
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
|
||||
#define HELPER_SPI_HOST_DEFAULT SPI2_HOST
|
||||
#elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32C61
|
||||
|
||||
@@ -12,7 +12,7 @@ maintainers:
|
||||
- Ruslan V. Uss (@UncleRus) <unclerus@gmail.com>
|
||||
repository: git://github.com/esp-idf-lib/esp_idf_lib_helpers.git
|
||||
repository_info:
|
||||
commit_sha: 57bbd8f3cda9c5ad390fc3ea5585e0ad80672584
|
||||
commit_sha: 918d82cafb1f00fd86f1ad8571271cb3e910588b
|
||||
path: .
|
||||
targets:
|
||||
- esp32
|
||||
@@ -26,4 +26,4 @@ targets:
|
||||
- esp32s2
|
||||
- esp32s3
|
||||
url: https://github.com/esp-idf-lib/core
|
||||
version: 1.3.10
|
||||
version: 1.4.0
|
||||
|
||||
@@ -1 +1 @@
|
||||
11c08f9e1a7d346b5dd763196dc2567cf2209ae49042402c2c2d296624601c14
|
||||
4f3838b2e68ab2b77fd43737139fa97dd0243b46af7b4a04588c67ff6b275ba1
|
||||
@@ -1,10 +1,12 @@
|
||||
name: i2cdev
|
||||
description: ESP-IDF I2C master thread-safe utilities
|
||||
version: 2.0.8
|
||||
version: 2.1.0
|
||||
groups:
|
||||
- common
|
||||
code_owners:
|
||||
- UncleRus
|
||||
- quinkq
|
||||
- trombik
|
||||
depends:
|
||||
- driver
|
||||
- freertos
|
||||
@@ -25,4 +27,6 @@ targets:
|
||||
license: MIT
|
||||
copyrights:
|
||||
- name: UncleRus
|
||||
year: 2018
|
||||
year: 2018
|
||||
- name: quinkq
|
||||
year: 2025
|
||||
|
||||
@@ -2,6 +2,11 @@ examples/**/sdkconfig
|
||||
examples/**/sdkconfig.old
|
||||
examples/**/build/
|
||||
examples/**/dependencies.lock
|
||||
examples/**/managed_components/
|
||||
docs/_*/
|
||||
docs/doxygen.log
|
||||
docs/**/*.log
|
||||
*.swp
|
||||
*.bak
|
||||
*.orig
|
||||
build/
|
||||
.vscode/
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
# ESP-IDF CMake component for i2cdev library
|
||||
set(req driver freertos esp_idf_lib_helpers)
|
||||
if(${IDF_VERSION_MAJOR} STREQUAL 5 AND ${IDF_VERSION_MINOR} LESS 3)
|
||||
# Use driver component as esp_driver_gpio is not available before 5.3
|
||||
set(req driver freertos log esp_timer)
|
||||
else()
|
||||
set(req esp_driver_gpio esp_driver_i2c freertos esp_idf_lib_helpers)
|
||||
endif()
|
||||
|
||||
# ESP-IDF version detection for automatic driver selection
|
||||
# Check for manual override via Kconfig
|
||||
@@ -14,7 +19,7 @@ elseif(IDF_VERSION_MAJOR LESS 5)
|
||||
set(USE_LEGACY_DRIVER TRUE)
|
||||
message(STATUS "i2cdev: ESP-IDF v${IDF_VERSION_MAJOR}.x detected, using legacy driver")
|
||||
elseif(IDF_VERSION_MAJOR EQUAL 5 AND IDF_VERSION_MINOR LESS 3)
|
||||
set(USE_LEGACY_DRIVER TRUE)
|
||||
set(USE_LEGACY_DRIVER TRUE)
|
||||
message(STATUS "i2cdev: ESP-IDF v${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR} detected, using legacy driver")
|
||||
else()
|
||||
set(USE_LEGACY_DRIVER FALSE)
|
||||
|
||||
@@ -107,7 +107,7 @@ static void deregister_device(i2c_dev_t *dev)
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t i2c_init(void)
|
||||
esp_err_t i2cdev_init(void)
|
||||
{
|
||||
ESP_LOGV(TAG, "Initializing I2C subsystem...");
|
||||
memset(active_devices, 0, sizeof(active_devices));
|
||||
|
||||
@@ -46,12 +46,18 @@
|
||||
#ifndef __I2CDEV_H__
|
||||
#define __I2CDEV_H__
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/i2c.h>
|
||||
#include <esp_err.h>
|
||||
#include <esp_idf_lib_helpers.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include <esp_idf_version.h>
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
|
||||
#include <driver/i2c_master.h>
|
||||
#else
|
||||
#include <driver/i2c.h>
|
||||
#endif
|
||||
|
||||
// Define missing types for older ESP-IDF versions
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0)
|
||||
@@ -193,7 +199,7 @@ typedef struct
|
||||
*
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
esp_err_t i2c_init(void);
|
||||
esp_err_t i2cdev_init(void);
|
||||
|
||||
/**
|
||||
* @brief Release I2C subsystem (deletes all devices, buses, and mutexes)
|
||||
|
||||
@@ -499,7 +499,7 @@ static esp_err_t i2c_setup_port(i2c_dev_t *dev)
|
||||
vTaskDelay(1);
|
||||
|
||||
// Target-specific driver installation/configuration sequence
|
||||
#if HELPER_TARGET_IS_ESP32 || HELPER_TARGET_IS_ESP32S2 || HELPER_TARGET_IS_ESP32S3 || HELPER_TARGET_IS_ESP32C3 || HELPER_TARGET_IS_ESP32C6
|
||||
#if HELPER_TARGET_IS_ESP32
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0)
|
||||
ESP_LOGD(TAG, "Using IDF >= 5.1.0 driver install order for ESP32 family");
|
||||
err = i2c_driver_install(dev->port, legacy_cfg.mode, 0, 0, 0);
|
||||
@@ -559,7 +559,7 @@ static esp_err_t i2c_setup_port(i2c_dev_t *dev)
|
||||
}
|
||||
|
||||
// Part 2: Timeout Configuration (ESP32 family specific hardware timeout)
|
||||
#if HELPER_TARGET_IS_ESP32 || HELPER_TARGET_IS_ESP32S2 || HELPER_TARGET_IS_ESP32S3 || HELPER_TARGET_IS_ESP32C3 || HELPER_TARGET_IS_ESP32C6
|
||||
#if HELPER_TARGET_IS_ESP32
|
||||
int current_timeout_hw;
|
||||
err = i2c_get_timeout(dev->port, ¤t_timeout_hw);
|
||||
if (err != ESP_OK)
|
||||
|
||||
@@ -13,7 +13,7 @@ maintainers:
|
||||
- Ruslan V. Uss (@UncleRus) <unclerus@gmail.com>
|
||||
repository: git://github.com/esp-idf-lib/i2cdev.git
|
||||
repository_info:
|
||||
commit_sha: abf0ebc8f0f826373e9a9ee07cf96727a49ed87b
|
||||
commit_sha: b4f09df5a02e576af61846954557bf7a61d35274
|
||||
path: .
|
||||
targets:
|
||||
- esp32
|
||||
@@ -27,4 +27,4 @@ targets:
|
||||
- esp32s2
|
||||
- esp32s3
|
||||
url: https://github.com/esp-idf-lib/core
|
||||
version: 2.0.8
|
||||
version: 2.1.0
|
||||
|
||||
1
managed_components/espressif__mdns/.component_hash
Normal file
1
managed_components/espressif__mdns/.component_hash
Normal file
@@ -0,0 +1 @@
|
||||
29e47564b1a7ee778135e17fbbf2a2773f71c97ebabfe626c8eda7c958a7ad16
|
||||
8
managed_components/espressif__mdns/.cz.yaml
Normal file
8
managed_components/espressif__mdns/.cz.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
commitizen:
|
||||
bump_message: 'bump(mdns): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py mdns
|
||||
tag_format: mdns-v$version
|
||||
version: 1.9.1
|
||||
version_files:
|
||||
- idf_component.yml
|
||||
607
managed_components/espressif__mdns/CHANGELOG.md
Normal file
607
managed_components/espressif__mdns/CHANGELOG.md
Normal file
@@ -0,0 +1,607 @@
|
||||
# Changelog
|
||||
|
||||
## [1.9.1](https://github.com/espressif/esp-protocols/commits/mdns-v1.9.1)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix to use tagged AFL image + minor format fix ([2b2f009a](https://github.com/espressif/esp-protocols/commit/2b2f009a))
|
||||
- Fix unused variable `dcst` warning for wifi-remote chips ([081eef88](https://github.com/espressif/esp-protocols/commit/081eef88))
|
||||
|
||||
## [1.9.0](https://github.com/espressif/esp-protocols/commits/mdns-v1.9.0)
|
||||
|
||||
### Features
|
||||
|
||||
- support null value for boolean txt records ([fa96de3b](https://github.com/espressif/esp-protocols/commit/fa96de3b))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Add test case for bool/NULL txt handling ([5068f221](https://github.com/espressif/esp-protocols/commit/5068f221))
|
||||
- Temporary fix for build issues on IDF master ([0197c994](https://github.com/espressif/esp-protocols/commit/0197c994))
|
||||
- Add tests for delegated answers ([487a746d](https://github.com/espressif/esp-protocols/commit/487a746d))
|
||||
- Add fuzzing into mdns CI ([af6bb1b5](https://github.com/espressif/esp-protocols/commit/af6bb1b5))
|
||||
- Host test to use hw_support include dir ([8bba3a97](https://github.com/espressif/esp-protocols/commit/8bba3a97))
|
||||
- Fixes case where we create our own malloc/free allocators, therefore we need to call mdns_mem_free and not free ([63bf7091](https://github.com/espressif/esp-protocols/commit/63bf7091))
|
||||
- put srv/txt records in additional section for ptr queries ([b7b8c5db](https://github.com/espressif/esp-protocols/commit/b7b8c5db))
|
||||
|
||||
### Updated
|
||||
|
||||
- ci(common): Update test component dir for IDFv6.0 ([18418c83](https://github.com/espressif/esp-protocols/commit/18418c83))
|
||||
|
||||
## [1.8.2](https://github.com/espressif/esp-protocols/commits/mdns-v1.8.2)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix parsing incorrect txt records ([8fd2c99f](https://github.com/espressif/esp-protocols/commit/8fd2c99f))
|
||||
|
||||
## [1.8.1](https://github.com/espressif/esp-protocols/commits/mdns-v1.8.1)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix potential task delete race ([8ca45f34](https://github.com/espressif/esp-protocols/commit/8ca45f34))
|
||||
|
||||
## [1.8.0](https://github.com/espressif/esp-protocols/commits/mdns-v1.8.0)
|
||||
|
||||
### Features
|
||||
|
||||
- Add version keys ([e01e67e7](https://github.com/espressif/esp-protocols/commit/e01e67e7))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Reformat mdns sources per indent-cont=120 ([c7663cde](https://github.com/espressif/esp-protocols/commit/c7663cde))
|
||||
|
||||
## [1.7.0](https://github.com/espressif/esp-protocols/commits/mdns-v1.7.0)
|
||||
|
||||
### Features
|
||||
|
||||
- Support user defined allocators ([88162d1f](https://github.com/espressif/esp-protocols/commit/88162d1f))
|
||||
- Allow allocate memory with configured caps ([7d29b476](https://github.com/espressif/esp-protocols/commit/7d29b476))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Adjust some formatting per indent-cont=120 ([5b2077e3](https://github.com/espressif/esp-protocols/commit/5b2077e3))
|
||||
|
||||
## [1.6.0](https://github.com/espressif/esp-protocols/commits/mdns-v1.6.0)
|
||||
|
||||
### Features
|
||||
|
||||
- support allocating mDNS task from SPIRAM ([8fcad10c](https://github.com/espressif/esp-protocols/commit/8fcad10c))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Use correct task delete function ([eb4ab524](https://github.com/espressif/esp-protocols/commit/eb4ab524))
|
||||
|
||||
### Updated
|
||||
|
||||
- ci(mdns): Fix mdns host test layers with static task creation ([0690eba3](https://github.com/espressif/esp-protocols/commit/0690eba3))
|
||||
|
||||
## [1.5.3](https://github.com/espressif/esp-protocols/commits/mdns-v1.5.3)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix responder to ignore only invalid queries ([cd07228f](https://github.com/espressif/esp-protocols/commit/cd07228f), [#754](https://github.com/espressif/esp-protocols/issues/754))
|
||||
|
||||
## [1.5.2](https://github.com/espressif/esp-protocols/commits/mdns-v1.5.2)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix potential NULL deref when sending sub-buy ([e7273c46](https://github.com/espressif/esp-protocols/commit/e7273c46))
|
||||
- Fix _mdns_append_fqdn excessive stack usage ([bd23c233](https://github.com/espressif/esp-protocols/commit/bd23c233))
|
||||
|
||||
## [1.5.1](https://github.com/espressif/esp-protocols/commits/mdns-v1.5.1)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix incorrect memory free for mdns browse ([4451a8c5](https://github.com/espressif/esp-protocols/commit/4451a8c5))
|
||||
|
||||
## [1.5.0](https://github.com/espressif/esp-protocols/commits/mdns-v1.5.0)
|
||||
|
||||
### Features
|
||||
|
||||
- supported removal of subtype when updating service ([4ad88e29](https://github.com/espressif/esp-protocols/commit/4ad88e29))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix zero-sized VLA clang-tidy warnings ([196198ec](https://github.com/espressif/esp-protocols/commit/196198ec))
|
||||
- Remove dead store to arg variable shared ([e838bf03](https://github.com/espressif/esp-protocols/commit/e838bf03))
|
||||
- Fix name mangling not to use strcpy() ([99b54ac3](https://github.com/espressif/esp-protocols/commit/99b54ac3))
|
||||
- Fix potential null derefernce in _mdns_execute_action() ([f5be2f41](https://github.com/espressif/esp-protocols/commit/f5be2f41))
|
||||
- Fix AFL test mock per espressif/esp-idf@a5bc08fb55c ([3d8835cf](https://github.com/espressif/esp-protocols/commit/3d8835cf))
|
||||
- Fixed potential out-of-bound interface error ([24f55ce9](https://github.com/espressif/esp-protocols/commit/24f55ce9))
|
||||
- Fixed incorrect error conversion ([8f8516cc](https://github.com/espressif/esp-protocols/commit/8f8516cc))
|
||||
- Fixed potential overflow when allocating txt data ([75a8e864](https://github.com/espressif/esp-protocols/commit/75a8e864))
|
||||
- Move MDNS_NAME_BUF_LEN to public headers ([907087c0](https://github.com/espressif/esp-protocols/commit/907087c0), [#724](https://github.com/espressif/esp-protocols/issues/724))
|
||||
- Cleanup includes in mdns.c ([68a9e148](https://github.com/espressif/esp-protocols/commit/68a9e148), [#725](https://github.com/espressif/esp-protocols/issues/725))
|
||||
- Allow advertizing service with port==0 ([827ea65f](https://github.com/espressif/esp-protocols/commit/827ea65f))
|
||||
- Fixed complier warning if MDNS_MAX_SERVICES==0 ([95377216](https://github.com/espressif/esp-protocols/commit/95377216), [#611](https://github.com/espressif/esp-protocols/issues/611))
|
||||
|
||||
## [1.4.3](https://github.com/espressif/esp-protocols/commits/mdns-v1.4.3)
|
||||
|
||||
### Features
|
||||
|
||||
- support zero item when update subtype ([5bd82c01](https://github.com/espressif/esp-protocols/commit/5bd82c01))
|
||||
|
||||
## [1.4.2](https://github.com/espressif/esp-protocols/commits/mdns-v1.4.2)
|
||||
|
||||
### Features
|
||||
|
||||
- support update subtype ([062b8dca](https://github.com/espressif/esp-protocols/commit/062b8dca))
|
||||
|
||||
### Updated
|
||||
|
||||
- chore(mdns): Add more info to idf_component.yml ([4a1cb65c](https://github.com/espressif/esp-protocols/commit/4a1cb65c))
|
||||
|
||||
## [1.4.1](https://github.com/espressif/esp-protocols/commits/mdns-v1.4.1)
|
||||
|
||||
### Features
|
||||
|
||||
- Send PTR query for mdns browse when interface is ready ([010a404a](https://github.com/espressif/esp-protocols/commit/010a404a))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Prevent deadlock when deleting a browse request ([3f48f9ea](https://github.com/espressif/esp-protocols/commit/3f48f9ea))
|
||||
- Fix use after free reported by coverity ([25b3d5fd](https://github.com/espressif/esp-protocols/commit/25b3d5fd))
|
||||
- Fixed dead-code reported by coverity ([11846c7d](https://github.com/espressif/esp-protocols/commit/11846c7d))
|
||||
|
||||
## [1.4.0](https://github.com/espressif/esp-protocols/commits/mdns-v1.4.0)
|
||||
|
||||
### Major changes
|
||||
|
||||
- Fixed mdns API issues when add/remove/update records from multiple threads ([Fix services API races to directly add/remove services](https://github.com/espressif/esp-protocols/commit/8a690503))
|
||||
|
||||
### Features
|
||||
|
||||
- Unit tests for add/remove/update deleg/selfhosted services ([0660ece1](https://github.com/espressif/esp-protocols/commit/0660ece1))
|
||||
- Add console command for mdns browsing ([1e8ede33](https://github.com/espressif/esp-protocols/commit/1e8ede33))
|
||||
- Console test: set instance for service ([f107dcd1](https://github.com/espressif/esp-protocols/commit/f107dcd1))
|
||||
- Console test: add subtype for service ([ee00e97b](https://github.com/espressif/esp-protocols/commit/ee00e97b))
|
||||
- Console test: set port for (delegated) srvs ([07b79abf](https://github.com/espressif/esp-protocols/commit/07b79abf))
|
||||
- Console test: add/remove TXT recs for delegated srvs ([c9a58d73](https://github.com/espressif/esp-protocols/commit/c9a58d73))
|
||||
- Console test for changing TXT records ([6b9a6ce6](https://github.com/espressif/esp-protocols/commit/6b9a6ce6))
|
||||
- Console test for add/remove delegated service APIs ([43de7e5c](https://github.com/espressif/esp-protocols/commit/43de7e5c))
|
||||
- Console test for add/remove delegated host APIs ([ce7f326a](https://github.com/espressif/esp-protocols/commit/ce7f326a))
|
||||
- Console test for lookup service APIs ([a91ead8e](https://github.com/espressif/esp-protocols/commit/a91ead8e))
|
||||
- Add linux console functional tests ([50d059af](https://github.com/espressif/esp-protocols/commit/50d059af))
|
||||
- check if the txt items is changed when browsing ([e2f0477a](https://github.com/espressif/esp-protocols/commit/e2f0477a))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix mdns_delegate_hostname_add() to block until done ([2c1b1661](https://github.com/espressif/esp-protocols/commit/2c1b1661))
|
||||
- Fix API races when removing all services ([169405b5](https://github.com/espressif/esp-protocols/commit/169405b5))
|
||||
- Fix API races setting instance name for services ([643dc6d4](https://github.com/espressif/esp-protocols/commit/643dc6d4))
|
||||
- Fix API races while adding subtypes for services ([f9f234c4](https://github.com/espressif/esp-protocols/commit/f9f234c4))
|
||||
- Fix API races removing txt item for services ([3f97a822](https://github.com/espressif/esp-protocols/commit/3f97a822))
|
||||
- Fix API races adding txt item for services ([c62b920b](https://github.com/espressif/esp-protocols/commit/c62b920b))
|
||||
- Fix API races while setting txt for services ([a927bf3a](https://github.com/espressif/esp-protocols/commit/a927bf3a))
|
||||
- Fix API races while setting port for services ([99d5fb27](https://github.com/espressif/esp-protocols/commit/99d5fb27))
|
||||
- Fix services API races to directly add/remove services ([8a690503](https://github.com/espressif/esp-protocols/commit/8a690503))
|
||||
- Fix mdns mdns_lookup_service() to handle empty TXT ([d4da9cb0](https://github.com/espressif/esp-protocols/commit/d4da9cb0))
|
||||
|
||||
## [1.3.2](https://github.com/espressif/esp-protocols/commits/mdns-v1.3.2)
|
||||
|
||||
### Features
|
||||
|
||||
- add check of instance when handling PTR query ([6af6ca5](https://github.com/espressif/esp-protocols/commit/6af6ca5))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix of mdns afl tests ([139166c](https://github.com/espressif/esp-protocols/commit/139166c))
|
||||
- remove same protocol services with different instances ([042533a](https://github.com/espressif/esp-protocols/commit/042533a))
|
||||
|
||||
## [1.3.1](https://github.com/espressif/esp-protocols/commits/mdns-v1.3.1)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- free txt value len ([afd98bb](https://github.com/espressif/esp-protocols/commit/afd98bb))
|
||||
|
||||
## [1.3.0](https://github.com/espressif/esp-protocols/commits/mdns-v1.3.0)
|
||||
|
||||
### Features
|
||||
|
||||
- add a new mdns query mode `browse` ([af330b6](https://github.com/espressif/esp-protocols/commit/af330b6))
|
||||
- Make including mdns_console KConfigurable ([27adbfe](https://github.com/espressif/esp-protocols/commit/27adbfe))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Schedule all queued Tx packets from timer task ([d4e693e](https://github.com/espressif/esp-protocols/commit/d4e693e))
|
||||
- add lock for some common apis ([21c84bf](https://github.com/espressif/esp-protocols/commit/21c84bf))
|
||||
- fix mdns answer append while host is invalid ([7be16bc](https://github.com/espressif/esp-protocols/commit/7be16bc))
|
||||
|
||||
## [1.2.5](https://github.com/espressif/esp-protocols/commits/mdns-v1.2.5)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fixed build issues for targets without WiFi caps ([302b46f](https://github.com/espressif/esp-protocols/commit/302b46f))
|
||||
|
||||
## [1.2.4](https://github.com/espressif/esp-protocols/commits/mdns-v1.2.4)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Correction on 6d2c475 MDNS_PREDEF_NETIF_ETH fix ([fc59f87c4e](https://github.com/espressif/esp-protocols/commit/fc59f87c4e))
|
||||
- fix the logic of creating pcb for networking socket ([5000a9a20a](https://github.com/espressif/esp-protocols/commit/5000a9a20a))
|
||||
- fix compiling issue when disabling IPv4 ([2646dcd23a](https://github.com/espressif/esp-protocols/commit/2646dcd23a))
|
||||
- Fix compile error when MDNS_PREDEF_NETIF_ETH is defined, but ETH_ENABLED is not (#459) ([6d2c475c20](https://github.com/espressif/esp-protocols/commit/6d2c475c20))
|
||||
|
||||
## [1.2.3](https://github.com/espressif/esp-protocols/commits/mdns-v1.2.3)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- fixed CI issues for host and afl tests ([4be5efc84e](https://github.com/espressif/esp-protocols/commit/4be5efc84e))
|
||||
- fix copy delegated host addr ([19fb36000c](https://github.com/espressif/esp-protocols/commit/19fb36000c))
|
||||
- enable CONFIG_ESP_WIFI_ENABLED if CONFIG_SOC_WIFI_SUPPORTED is also enabled (for ESP-IDF <= 5.1) ([d20a718320](https://github.com/espressif/esp-protocols/commit/d20a718320))
|
||||
- remove protocol_examples_common ([1ee9dae6bf](https://github.com/espressif/esp-protocols/commit/1ee9dae6bf))
|
||||
- move the example into a subdirectory ([d28232b9f8](https://github.com/espressif/esp-protocols/commit/d28232b9f8))
|
||||
- reference protocol_examples_common from IDF ([c83b76ea8f](https://github.com/espressif/esp-protocols/commit/c83b76ea8f))
|
||||
|
||||
## [1.2.2](https://github.com/espressif/esp-protocols/commits/mdns-v1.2.2)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- add terminator for the getting host name ([b6a4d94](https://github.com/espressif/esp-protocols/commit/b6a4d94))
|
||||
- Enable ESP_WIFI_CONFIG when ESP-IDF <= 5.1 ([0b783c0](https://github.com/espressif/esp-protocols/commit/0b783c0))
|
||||
- set host list NULL on destroy ([ea54eef](https://github.com/espressif/esp-protocols/commit/ea54eef))
|
||||
- removed Wno-format flag and fixed formatting warnings ([c48e442](https://github.com/espressif/esp-protocols/commit/c48e442))
|
||||
- remove the the range of MDNS_MAX_SERVICES and fix issues of string functions ([3dadce2](https://github.com/espressif/esp-protocols/commit/3dadce2))
|
||||
|
||||
## [1.2.1](https://github.com/espressif/esp-protocols/commits/mdns-v1.2.1)
|
||||
|
||||
### Features
|
||||
|
||||
- Allow setting length of mDNS action queue in menuconfig ([28cd898](https://github.com/espressif/esp-protocols/commit/28cd898))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- fix build issue if CONFIG_ESP_WIFI_ENABLED disabled ([24f7031](https://github.com/espressif/esp-protocols/commit/24f7031))
|
||||
- added idf_component.yml for examples ([d273e10](https://github.com/espressif/esp-protocols/commit/d273e10))
|
||||
- added guard check for null pointer ([71bb461](https://github.com/espressif/esp-protocols/commit/71bb461))
|
||||
|
||||
## [1.2.0](https://github.com/espressif/esp-protocols/commits/mdns-v1.2.0)
|
||||
|
||||
### Features
|
||||
|
||||
- add an API for setting address to a delegated host ([ddc3eb6](https://github.com/espressif/esp-protocols/commit/ddc3eb6))
|
||||
- Add support for lwip build under linux ([588465d](https://github.com/espressif/esp-protocols/commit/588465d))
|
||||
- Allow for adding a delegated host with no address ([c562461](https://github.com/espressif/esp-protocols/commit/c562461))
|
||||
- Add APIs for looking up self hosted services and getting the self hostname ([f0df12d](https://github.com/espressif/esp-protocols/commit/f0df12d))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Refactor freertos linux compat layers ([79a0e57](https://github.com/espressif/esp-protocols/commit/79a0e57))
|
||||
- Fix delegated service PTR response ([cab0e1d](https://github.com/espressif/esp-protocols/commit/cab0e1d))
|
||||
- Added unit tests to CI + minor fix to pass it ([c974c14](https://github.com/espressif/esp-protocols/commit/c974c14))
|
||||
|
||||
### Updated
|
||||
|
||||
- docs: update documentation links ([4de5298](https://github.com/espressif/esp-protocols/commit/4de5298))
|
||||
|
||||
## [1.1.0](https://github.com/espressif/esp-protocols/commits/mdns-v1.1.0)
|
||||
|
||||
### Features
|
||||
|
||||
- Decouple main module from mdns-networking ([d238e93](https://github.com/espressif/esp-protocols/commit/d238e93))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Use idf-build-apps package for building mdns ([1a0a41f](https://github.com/espressif/esp-protocols/commit/1a0a41f))
|
||||
- socket networking to init interfaces properly ([ee9b04f](https://github.com/espressif/esp-protocols/commit/ee9b04f))
|
||||
- Removed unused internal lock from mdns_server struct ([a06fb77](https://github.com/espressif/esp-protocols/commit/a06fb77))
|
||||
- Resolve conflicts only on self hosted items ([e69a9eb](https://github.com/espressif/esp-protocols/commit/e69a9eb), [#185](https://github.com/espressif/esp-protocols/issues/185))
|
||||
- Fix memory issues reported by valgrind ([0a682e7](https://github.com/espressif/esp-protocols/commit/0a682e7))
|
||||
|
||||
### Updated
|
||||
|
||||
- docs(common): updated component and example links ([f48d9b2](https://github.com/espressif/esp-protocols/commit/f48d9b2))
|
||||
- Add APIs to look up delegated services ([87dcd7d](https://github.com/espressif/esp-protocols/commit/87dcd7d))
|
||||
- Fix deadly mdns crash ([4fa3023](https://github.com/espressif/esp-protocols/commit/4fa3023))
|
||||
- docs(common): improving documentation ([ca3fce0](https://github.com/espressif/esp-protocols/commit/ca3fce0))
|
||||
- append all ipv6 address in mdns answer ([5ed3e9a](https://github.com/espressif/esp-protocols/commit/5ed3e9a))
|
||||
- test(mdns): Host tests to use IDF's esp_event_stub ([537d170](https://github.com/espressif/esp-protocols/commit/537d170))
|
||||
|
||||
## [1.0.9](https://github.com/espressif/esp-protocols/commits/mdns-v1.0.9)
|
||||
|
||||
### Features
|
||||
|
||||
- Add reverse lookup to the example and test ([d464ed7](https://github.com/espressif/esp-protocols/commit/d464ed7))
|
||||
- Add support for IPv6 reverse query ([d4825f5](https://github.com/espressif/esp-protocols/commit/d4825f5))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Reintroduce missing CHANGELOGs ([200cbb3](https://github.com/espressif/esp-protocols/commit/200cbb3))
|
||||
- use semaphore instead of task notification bits (IDFGH-9380) ([73f2800](https://github.com/espressif/esp-protocols/commit/73f2800), [IDF#10754](https://github.com/espressif/esp-idf/issues/10754))
|
||||
|
||||
### Updated
|
||||
|
||||
- ci(common): force scoping commit messages with components ([c55fcc0](https://github.com/espressif/esp-protocols/commit/c55fcc0))
|
||||
- Add homepage URL and License to all components ([ef3f0ee](https://github.com/espressif/esp-protocols/commit/ef3f0ee))
|
||||
- docs: fix of mdns link translation ([1c850dd](https://github.com/espressif/esp-protocols/commit/1c850dd))
|
||||
- unite all tags under common structure py test: update tags under common structure ([c6db3ea](https://github.com/espressif/esp-protocols/commit/c6db3ea))
|
||||
|
||||
## [1.0.8](https://github.com/espressif/esp-protocols/commits/b9b4a75)
|
||||
|
||||
### Features
|
||||
|
||||
- Add support for IPv4 reverse query ([b87bef5](https://github.com/espressif/esp-protocols/commit/b87bef5))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Host test with IDFv5.1 ([fb8a2f0](https://github.com/espressif/esp-protocols/commit/fb8a2f0))
|
||||
- Remove strict mode as it's invalid ([d0c9070](https://github.com/espressif/esp-protocols/commit/d0c9070))
|
||||
- Allow setting instance name only after hostname set ([a8339e4](https://github.com/espressif/esp-protocols/commit/a8339e4), [#190](https://github.com/espressif/esp-protocols/issues/190))
|
||||
- Make unit test executable with pytest ([12cfcb5](https://github.com/espressif/esp-protocols/commit/12cfcb5))
|
||||
- AFL port layer per IDF-latest changes ([0247926](https://github.com/espressif/esp-protocols/commit/0247926))
|
||||
|
||||
### Updated
|
||||
|
||||
- bump the component version to 1.0.8 ([b9b4a75](https://github.com/espressif/esp-protocols/commit/b9b4a75))
|
||||
- Make reverse query conditional per Kconfig ([91134f1](https://github.com/espressif/esp-protocols/commit/91134f1))
|
||||
- Added badges with version of components to the respective README files ([e4c8a59](https://github.com/espressif/esp-protocols/commit/e4c8a59))
|
||||
- fix some coverity reported issues ([c73c797](https://github.com/espressif/esp-protocols/commit/c73c797))
|
||||
- Examples: using pytest.ini from top level directory ([aee016d](https://github.com/espressif/esp-protocols/commit/aee016d))
|
||||
- mDNS: test_app pytest migration ([f71f61f](https://github.com/espressif/esp-protocols/commit/f71f61f))
|
||||
- CI: fixing the files to be complient with pre-commit hooks ([945bd17](https://github.com/espressif/esp-protocols/commit/945bd17))
|
||||
- prevent crash when hostname is null ([3498e86](https://github.com/espressif/esp-protocols/commit/3498e86))
|
||||
- Example tests integration ([a045c1c](https://github.com/espressif/esp-protocols/commit/a045c1c))
|
||||
- Replace hardcoded TTL values with named defines ([bb4c002](https://github.com/espressif/esp-protocols/commit/bb4c002))
|
||||
- Fix add_service() to report error if no-hostname ([656ab21](https://github.com/espressif/esp-protocols/commit/656ab21))
|
||||
|
||||
|
||||
## [1.0.7](https://github.com/espressif/esp-protocols/commits/088f7ac)
|
||||
|
||||
### Updated
|
||||
|
||||
- bump up the component version ([088f7ac](https://github.com/espressif/esp-protocols/commit/088f7ac))
|
||||
- fix IPV4 only build and also update CI configuration ([e079f8b](https://github.com/espressif/esp-protocols/commit/e079f8b))
|
||||
- add test configuration for IPV6 disabled build ([330332a](https://github.com/espressif/esp-protocols/commit/330332a))
|
||||
|
||||
|
||||
## [1.0.6](https://github.com/espressif/esp-protocols/commits/48c157b)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Example makefile to add only mdns as extra comps ([d74c296](https://github.com/espressif/esp-protocols/commit/d74c296))
|
||||
- ignore authoritative flag on reception ([415e04a](https://github.com/espressif/esp-protocols/commit/415e04a))
|
||||
|
||||
### Updated
|
||||
|
||||
- fix build issue with CONFIG_LWIP_IPV6 disabled ([48c157b](https://github.com/espressif/esp-protocols/commit/48c157b))
|
||||
- fix bit order issue in DNS header flags ([c4e85bd](https://github.com/espressif/esp-protocols/commit/c4e85bd))
|
||||
- updated package version to 0.1.19 ([469f953](https://github.com/espressif/esp-protocols/commit/469f953))
|
||||
|
||||
|
||||
## [1.0.5](https://github.com/espressif/esp-protocols/commits/36de9af)
|
||||
|
||||
### Features
|
||||
|
||||
- Define explicit dependencies on esp-wifi ([36de9af](https://github.com/espressif/esp-protocols/commit/36de9af))
|
||||
|
||||
### Updated
|
||||
|
||||
- bugfix: mdns IPv6 address convert error ([238ee96](https://github.com/espressif/esp-protocols/commit/238ee96))
|
||||
|
||||
|
||||
## [1.0.4](https://github.com/espressif/esp-protocols/commits/57afa38)
|
||||
|
||||
### Updated
|
||||
|
||||
- Bump asio/mdns/esp_websocket_client versions ([57afa38](https://github.com/espressif/esp-protocols/commit/57afa38))
|
||||
- ignore format warnings ([d66f9dc](https://github.com/espressif/esp-protocols/commit/d66f9dc))
|
||||
- Fix test_app build ([0b102f6](https://github.com/espressif/esp-protocols/commit/0b102f6))
|
||||
|
||||
|
||||
## [1.0.3](https://github.com/espressif/esp-protocols/commits/4868689)
|
||||
|
||||
### Updated
|
||||
|
||||
- Updated mDNS to explicitely use esp-eth dependency if needed ([4868689](https://github.com/espressif/esp-protocols/commit/4868689), [IDF@5e19b9c](https://github.com/espressif/esp-idf/commit/5e19b9c9518ae253d82400ab24b86af8af832425))
|
||||
|
||||
|
||||
## [1.0.2](https://github.com/espressif/esp-protocols/commits/8fe2a3a)
|
||||
|
||||
### Features
|
||||
|
||||
- fix bug when clean action memory ([81c219d](https://github.com/espressif/esp-protocols/commit/81c219d), [IDF@3d4deb9](https://github.com/espressif/esp-idf/commit/3d4deb972620cae8e8ce4d0050153cc6f39db372))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- add the maximum number of services ([0191d6f](https://github.com/espressif/esp-protocols/commit/0191d6f), [IDF@ba458c6](https://github.com/espressif/esp-idf/commit/ba458c69cfb2f18478d73690c289b09641c62004))
|
||||
- fix the exception when remove one of multiple service ([b26c866](https://github.com/espressif/esp-protocols/commit/b26c866), [IDF@696d733](https://github.com/espressif/esp-idf/commit/696d733eb04ee98f764dffdc82bcef51a724c9c6))
|
||||
|
||||
### Updated
|
||||
|
||||
- Minor fixes here and there ([8fe2a3a](https://github.com/espressif/esp-protocols/commit/8fe2a3a))
|
||||
- mDNS: Initial version based on IDF 5.0 ([b6b20ad](https://github.com/espressif/esp-protocols/commit/b6b20ad))
|
||||
- soc: moved kconfig options out of the target component. ([4a52cf2](https://github.com/espressif/esp-protocols/commit/4a52cf2), [IDF@d287209](https://github.com/espressif/esp-idf/commit/d2872095f93ed82fb91c776081bc1d032493d93e))
|
||||
- cmake: fix issue with passing cxx_std option for GCC 11, a common workaround ([87c2699](https://github.com/espressif/esp-protocols/commit/87c2699), [IDF@ea0d212](https://github.com/espressif/esp-idf/commit/ea0d2123c806bd0ad77bc49843ee905cf9be65ff))
|
||||
- kconfig: Changed default values of bool configs - Some bool configs were using default values true and false, instead of y and n. ([eb536a7](https://github.com/espressif/esp-protocols/commit/eb536a7), [IDF@25c5c21](https://github.com/espressif/esp-idf/commit/25c5c214f38ca690b03533e12fb5a4d774c7eae0))
|
||||
- esp_netif: Remove tcpip_adapter compatibility layer ([3e93ea9](https://github.com/espressif/esp-protocols/commit/3e93ea9), [IDF@795b7ed](https://github.com/espressif/esp-idf/commit/795b7ed993784e3134195e12b0978504d83dfd56))
|
||||
- Fix copyright messages, update API descrition ([2c764b1](https://github.com/espressif/esp-protocols/commit/2c764b1), [IDF@42ba8a8](https://github.com/espressif/esp-idf/commit/42ba8a8338fd5efd82498a5989fc5c105938d447))
|
||||
- Add API to control custom network interfaces ([f836ae7](https://github.com/espressif/esp-protocols/commit/f836ae7), [IDF@b02468d](https://github.com/espressif/esp-idf/commit/b02468dc98d614f931d14cd8b5e2373ca51fb18d))
|
||||
- CI/mdns: Fix fuzzer build ([4b5f24f](https://github.com/espressif/esp-protocols/commit/4b5f24f), [IDF@98e9426](https://github.com/espressif/esp-idf/commit/98e9426b660a6e825f811cccd45a0722cc801ccd))
|
||||
- Add support for registering custom netif ([30f37c0](https://github.com/espressif/esp-protocols/commit/30f37c0), [IDF@bec42ff](https://github.com/espressif/esp-idf/commit/bec42ff85d5091d71e1cb1063bea20d7c6ac8c76))
|
||||
- Indicate interface using esp_netif in search results ([ddc58e8](https://github.com/espressif/esp-protocols/commit/ddc58e8), [IDF@f8495f1](https://github.com/espressif/esp-idf/commit/f8495f1e86de9a8e7d046bf13d0ca04775041b4c))
|
||||
- Use predefined interfaces to prepare for custom netifs ([fa951bf](https://github.com/espressif/esp-protocols/commit/fa951bf), [IDF@f90b3b7](https://github.com/espressif/esp-idf/commit/f90b3b798b446382d848f8c55c5e1653c81871cd))
|
||||
- Prepare for dynamic esp-netif support ([605d1fa](https://github.com/espressif/esp-protocols/commit/605d1fa), [IDF@f9892f7](https://github.com/espressif/esp-idf/commit/f9892f77b88ba77dc6608ba746175f6dc64a7607))
|
||||
- esp_hw_support/esp_system: Re-evaluate header inclusions and include directories ([58bf218](https://github.com/espressif/esp-protocols/commit/58bf218), [IDF@a9fda54](https://github.com/espressif/esp-idf/commit/a9fda54d39d1321005c3bc9b3cc268d0b7e9f052))
|
||||
- system: move kconfig options out of target component ([ec491ec](https://github.com/espressif/esp-protocols/commit/ec491ec), [IDF@bb88338](https://github.com/espressif/esp-idf/commit/bb88338118957c2214a4c0a33cd4a152e2e1f8ba))
|
||||
- Update to drop our own packet if bounced back ([94ae672](https://github.com/espressif/esp-protocols/commit/94ae672), [IDF@b5149e3](https://github.com/espressif/esp-idf/commit/b5149e3ee73728f790798e6757d732fe426e21c7))
|
||||
- Fix potential read behind parsed packet ([e5a3a3d](https://github.com/espressif/esp-protocols/commit/e5a3a3d), [IDF@51a5de2](https://github.com/espressif/esp-idf/commit/51a5de2525d0e82adea2e298a0edcc9b2dee5edd))
|
||||
- Fix memleak when adding delegated host ([7710ea9](https://github.com/espressif/esp-protocols/commit/7710ea9), [IDF@9cbdb87](https://github.com/espressif/esp-idf/commit/9cbdb8767bdf6e9745e895b2c5af74d0376965e7))
|
||||
- Fix null-service issue when parsing packets ([034c55e](https://github.com/espressif/esp-protocols/commit/034c55e), [IDF#8307](https://github.com/espressif/esp-idf/issues/8307), [IDF@a57be7b](https://github.com/espressif/esp-idf/commit/a57be7b7d1135ddb29f9da636e9ad315f7fa1fa7))
|
||||
- Update fuzzer test (add delegation, check memory) ([ec03fec](https://github.com/espressif/esp-protocols/commit/ec03fec), [IDF@2c10071](https://github.com/espressif/esp-idf/commit/2c1007156e01b4707b5c89d73cad05c0eef0264f))
|
||||
- Remove legacy esp_event API ([5909e9e](https://github.com/espressif/esp-protocols/commit/5909e9e), [IDF@e46aa51](https://github.com/espressif/esp-idf/commit/e46aa515bdf5606a3d868f1034774d5fc96904b8))
|
||||
- added missing includes ([82e2a5d](https://github.com/espressif/esp-protocols/commit/82e2a5d), [IDF@28d09c7](https://github.com/espressif/esp-idf/commit/28d09c7dbe145ffa6a7dd90531062d4f7669a9c8))
|
||||
- Clear notification value in mdns_hostname_set ([48e4d40](https://github.com/espressif/esp-protocols/commit/48e4d40), [IDF@83a4ddb](https://github.com/espressif/esp-idf/commit/83a4ddbd250e2b386bccabb4705d4c58c1a22bcb))
|
||||
- esp_timer: remove legacy ESP32 FRC timer implementation. ([ac6dcb6](https://github.com/espressif/esp-protocols/commit/ac6dcb6), [IDF@edb76f1](https://github.com/espressif/esp-idf/commit/edb76f14d6b3e925568ff04a87befe733ecc4517))
|
||||
- freertos: Remove legacy data types ([085dbd8](https://github.com/espressif/esp-protocols/commit/085dbd8), [IDF@57fd78f](https://github.com/espressif/esp-idf/commit/57fd78f5baf93a368a82cf4b2e00ca17ffc09115))
|
||||
- Tools: Custom baud-rate setup is not possible for IDF Monitor from menuconfig anymore ([f78e8cf](https://github.com/espressif/esp-protocols/commit/f78e8cf), [IDF@36a4011](https://github.com/espressif/esp-idf/commit/36a4011ff8985bfbae08ba0272194e6c3ef93bbf))
|
||||
- Use memcpy() for copy to support non-text TXTs ([6cdf5ee](https://github.com/espressif/esp-protocols/commit/6cdf5ee), [IDF@6aefe9c](https://github.com/espressif/esp-idf/commit/6aefe9c18563ed567d384a956cf02b6f57d6894c))
|
||||
- Support for null-value TXT records ([fcb5515](https://github.com/espressif/esp-protocols/commit/fcb5515), [IDF#8267](https://github.com/espressif/esp-idf/issues/8267), [IDF@23c2db4](https://github.com/espressif/esp-idf/commit/23c2db406dee8df09dbdba21cb7eef9fbca8bf27))
|
||||
- Fix alloc issue if TXT has empty value ([9fdbe5f](https://github.com/espressif/esp-protocols/commit/9fdbe5f), [IDF@205f6ba](https://github.com/espressif/esp-idf/commit/205f6ba8541e12d958c7c56af5a7136090f12a0e))
|
||||
- Fix random crash when defalt service instance queried ([20e6e9e](https://github.com/espressif/esp-protocols/commit/20e6e9e), [IDF@f46dffc](https://github.com/espressif/esp-idf/commit/f46dffca627e9578e49a510580f9754ec1e27e2e))
|
||||
- Fix minor memory leaks when creating services ([c588263](https://github.com/espressif/esp-protocols/commit/c588263), [IDF@fad62cc](https://github.com/espressif/esp-idf/commit/fad62cc1ed3dce63b58297172a72a489d7af2d9d))
|
||||
- Fix mDNS memory leak ([6258edf](https://github.com/espressif/esp-protocols/commit/6258edf), [IDF@119b4a9](https://github.com/espressif/esp-idf/commit/119b4a9dd12cf89cc5eaf63f8aa19730607ef30b))
|
||||
- Fix mDNS memory leak ([c8b0d5e](https://github.com/espressif/esp-protocols/commit/c8b0d5e), [IDF@f5ffd53](https://github.com/espressif/esp-idf/commit/f5ffd53aeb402afc1333a98168bb2fa35d7cdc77))
|
||||
- Use multi/uni-cast types in API ([5252b1d](https://github.com/espressif/esp-protocols/commit/5252b1d), [IDF@125c312](https://github.com/espressif/esp-idf/commit/125c3125524c71f4f48f635eda12e22fa3bca500))
|
||||
- Allow for unicast PTR queries ([4e11cc8](https://github.com/espressif/esp-protocols/commit/4e11cc8), [IDF@7eeeb01](https://github.com/espressif/esp-idf/commit/7eeeb01ea705745b027bd8bc11d2b142418e9927))
|
||||
- Fix potential null deref for ANY query type ([7af91ec](https://github.com/espressif/esp-protocols/commit/7af91ec), [IDF@99dd8ee](https://github.com/espressif/esp-idf/commit/99dd8eedb1a0e957f5f74344e3e4172e61c29ef8))
|
||||
- Make fuzzer layers compatible with llvm>=6 ([01256d3](https://github.com/espressif/esp-protocols/commit/01256d3), [IDF@1882cbe](https://github.com/espressif/esp-idf/commit/1882cbe44e6140bebb2d27dc18af06dfcb0157f5))
|
||||
- Fix copyright ([5a2d4ea](https://github.com/espressif/esp-protocols/commit/5a2d4ea), [IDF@c83678f](https://github.com/espressif/esp-idf/commit/c83678f64fe27844fc28050bde6433ccb04a0704))
|
||||
- Add mDNS miss comment ([9de3f53](https://github.com/espressif/esp-protocols/commit/9de3f53), [IDF@08e0813](https://github.com/espressif/esp-idf/commit/08e081340d9d76d1244e9f2dc527e5ae370b1fbe))
|
||||
- freertos: remove FREERTOS_ASSERT option ([bcabc8e](https://github.com/espressif/esp-protocols/commit/bcabc8e), [IDF@7255497](https://github.com/espressif/esp-idf/commit/72554971467a5edc9bd6e390cf8fe7b05e6ade81))
|
||||
- Minor err print fix in socket-networking layer ([dfb27b3](https://github.com/espressif/esp-protocols/commit/dfb27b3), [IDF@f1b8f5c](https://github.com/espressif/esp-idf/commit/f1b8f5c1023df7d649161bc76f2bcc9a8f8f4d8b))
|
||||
- unified errno format ([076c095](https://github.com/espressif/esp-protocols/commit/076c095), [IDF@87506f4](https://github.com/espressif/esp-idf/commit/87506f46e2922710f48a6b96ca75e53543ff45c4))
|
||||
- always send A/AAAA records in announcements ([7dd0bc1](https://github.com/espressif/esp-protocols/commit/7dd0bc1), [IDF@456f80b](https://github.com/espressif/esp-idf/commit/456f80b754ebd0bd74e02c7febdf461c6b573b7a))
|
||||
- filter instance name for ANY queries ([7e82a7c](https://github.com/espressif/esp-protocols/commit/7e82a7c), [IDF@5d0c473](https://github.com/espressif/esp-idf/commit/5d0c47303dd9ead0f2ad291dca1d4b7ce4e23b2b))
|
||||
- Fix potential null deref reported by fuzzer test ([ae381b7](https://github.com/espressif/esp-protocols/commit/ae381b7), [IDF@cb5653f](https://github.com/espressif/esp-idf/commit/cb5653fd940a9cd41e8554a6d753fab46e0459d7))
|
||||
- Minor fix of API description and API usage ([941dc5c](https://github.com/espressif/esp-protocols/commit/941dc5c), [IDF@c297301](https://github.com/espressif/esp-idf/commit/c297301ecc350f8315d7eaf78c72b4aba68d422a))
|
||||
- Added results count to MDNS ([525c649](https://github.com/espressif/esp-protocols/commit/525c649), [IDF@f391d61](https://github.com/espressif/esp-idf/commit/f391d610e8185631b5361dc6c844c4c04aac30b1))
|
||||
- fix mdns server instance mismatch ([f0839d9](https://github.com/espressif/esp-protocols/commit/f0839d9), [IDF@6173dd7](https://github.com/espressif/esp-idf/commit/6173dd78097216261277c20ebd92a53c68c47f89))
|
||||
- support multiple instance for mdns service txt set ([69902ea](https://github.com/espressif/esp-protocols/commit/69902ea), [IDF@50f6302](https://github.com/espressif/esp-idf/commit/50f6302c5d7c0498fa1baa6fd6129d8233971a81))
|
||||
- fix wrong PTR record count ([d0bbe88](https://github.com/espressif/esp-protocols/commit/d0bbe88), [IDF@5d3f815](https://github.com/espressif/esp-idf/commit/5d3f8157e0e481363ef93d54a29d957fc91cca86))
|
||||
- Build & config: Remove leftover files from the unsupported "make" build system ([4a9d55e](https://github.com/espressif/esp-protocols/commit/4a9d55e), [IDF@766aa57](https://github.com/espressif/esp-idf/commit/766aa5708443099f3f033b739cda0e1de101cca6))
|
||||
- Build & config: Remove the "make" build system ([be2a924](https://github.com/espressif/esp-protocols/commit/be2a924), [IDF@9c1d4f5](https://github.com/espressif/esp-idf/commit/9c1d4f5b549d6a7125e5c7c323c80d37361991cb))
|
||||
- freertos: update freertos folder structure to match upstream ([76fcd41](https://github.com/espressif/esp-protocols/commit/76fcd41), [IDF@4846222](https://github.com/espressif/esp-idf/commit/48462221029c7da4b1ea233e9e781cd57ff91c7e))
|
||||
- support service subtype ([fd8499c](https://github.com/espressif/esp-protocols/commit/fd8499c), [IDF#5508](https://github.com/espressif/esp-idf/issues/5508), [IDF@e7e8610](https://github.com/espressif/esp-idf/commit/e7e8610f563e0b8532a093ea8b803f0eb132fd0e))
|
||||
- Fix parsing non-standard queries ([38b4fe2](https://github.com/espressif/esp-protocols/commit/38b4fe2), [IDF#7694](https://github.com/espressif/esp-idf/issues/7694), [IDF@d16f9ba](https://github.com/espressif/esp-idf/commit/d16f9bade5beab3785677dd5b39ebc4e9c895008))
|
||||
- allow mutiple instances with same service type ([b266062](https://github.com/espressif/esp-protocols/commit/b266062), [IDF@b7a99f4](https://github.com/espressif/esp-idf/commit/b7a99f46587a69a2cd07e7616c3bb30b7b1a6edf))
|
||||
- Update copyright header ([5e087d8](https://github.com/espressif/esp-protocols/commit/5e087d8), [IDF@2a2b95b](https://github.com/espressif/esp-idf/commit/2a2b95b9c22bc5090d87a4f4317288b64b14fcd9))
|
||||
- Fix potential null dereference identified by fuzzer tests ([91a3d95](https://github.com/espressif/esp-protocols/commit/91a3d95), [IDF@e7dabb1](https://github.com/espressif/esp-idf/commit/e7dabb14f7c8fd9bd2bea55d8f1accc65323a1c0))
|
||||
- components/bt: move config BT_RESERVE_DRAM from bluedroid to ESP32 controller ([6d6dd2b](https://github.com/espressif/esp-protocols/commit/6d6dd2b), [IDF@b310c06](https://github.com/espressif/esp-idf/commit/b310c062cd25f249e00dd03dd27baed783921630))
|
||||
- add notification callback for async APIs ([52306e9](https://github.com/espressif/esp-protocols/commit/52306e9), [IDF@986603c](https://github.com/espressif/esp-idf/commit/986603cf07413b46c88c76c324bf500edcfb6171))
|
||||
- add more mdns result attributes ([d37ab6d](https://github.com/espressif/esp-protocols/commit/d37ab6d), [IDF@76ec76c](https://github.com/espressif/esp-idf/commit/76ec76c12c871554147343bb7141da1e5de58011))
|
||||
- Add host test using linux target ([5c55ea6](https://github.com/espressif/esp-protocols/commit/5c55ea6), [IDF@fc7e2d9](https://github.com/espressif/esp-idf/commit/fc7e2d9e908f61fb4b852cfae72aa5ff7c662ebc))
|
||||
- Implement mdns_networking using BSD sockets ([0c71c7b](https://github.com/espressif/esp-protocols/commit/0c71c7b), [IDF@73dfe84](https://github.com/espressif/esp-idf/commit/73dfe84bf295a850edfad39b6b097a71f15964dc))
|
||||
- fix crash when adding services without hostname set ([4c368c0](https://github.com/espressif/esp-protocols/commit/4c368c0), [IDF@5e98772](https://github.com/espressif/esp-idf/commit/5e98772eaf7e50d96cf2e6ecdfedcd928b61c864))
|
||||
- Fix fuzzer IDF-mock layer ([af22753](https://github.com/espressif/esp-protocols/commit/af22753), [IDF@619235c](https://github.com/espressif/esp-idf/commit/619235c2ee5a1fe8411bd2be2de8798209f95902))
|
||||
- Clean the main mdns module from lwip dependencies ([b0957e7](https://github.com/espressif/esp-protocols/commit/b0957e7), [IDF@54e3294](https://github.com/espressif/esp-idf/commit/54e329444a5dd19c51e84b5f1e16455a0f1c6225))
|
||||
- Add asynchronous query API ([47c7266](https://github.com/espressif/esp-protocols/commit/47c7266), [IDF#7090](https://github.com/espressif/esp-idf/issues/7090), [IDF@d81482d](https://github.com/espressif/esp-idf/commit/d81482d699232b22f4a5cbee2a76199a5285dadb))
|
||||
- Fix crashes reported by the fuzzer tests ([40da0d2](https://github.com/espressif/esp-protocols/commit/40da0d2), [IDF@4a2e726](https://github.com/espressif/esp-idf/commit/4a2e72677c6fb7681a7e2acd1a878d3deb114079))
|
||||
- mdns/fuzzer: Fix non-instrumentation test to reproduce fuzzer issues ([5f6b6f9](https://github.com/espressif/esp-protocols/commit/5f6b6f9), [IDF@dae8033](https://github.com/espressif/esp-idf/commit/dae803335e6bc6d9751a360cd3f675ce4027853b))
|
||||
- return ESP_OK rather than ERR_OK in API functions ([8a12082](https://github.com/espressif/esp-protocols/commit/8a12082), [IDF@2386113](https://github.com/espressif/esp-idf/commit/2386113972ee51ea93e9740d8c34bfe9289ce909))
|
||||
- fix memory leak in mdns_free when adding delegated hostnames ([46f28a8](https://github.com/espressif/esp-protocols/commit/46f28a8), [IDF@0baee93](https://github.com/espressif/esp-idf/commit/0baee932111268c4a2103e1c1adeb7d99914a937))
|
||||
- Support for One-Shot mDNS queries ([5a81eae](https://github.com/espressif/esp-protocols/commit/5a81eae), [IDF@f167238](https://github.com/espressif/esp-idf/commit/f167238fac37818aed75dc689eed54ad47528ab9))
|
||||
- allow explicit txt value length ([2ddaee2](https://github.com/espressif/esp-protocols/commit/2ddaee2), [IDF@b4e0088](https://github.com/espressif/esp-idf/commit/b4e0088b68321acc4698b01faec7e2ffbe1e37c1))
|
||||
- Fix crashes reported by the fuzzer ([27fc285](https://github.com/espressif/esp-protocols/commit/27fc285), [IDF@79ba738](https://github.com/espressif/esp-idf/commit/79ba738626d643d8c6f32bdcd455e0d2476f94c7))
|
||||
- Minor correction of the test code ([93e6efe](https://github.com/espressif/esp-protocols/commit/93e6efe), [IDF@7d76245](https://github.com/espressif/esp-idf/commit/7d762451731cb305c3b090509827740f0195a496))
|
||||
- Fix fuzzer from miss-interpreting adding services as timeouts ([bc4cda8](https://github.com/espressif/esp-protocols/commit/bc4cda8), [IDF@14099fe](https://github.com/espressif/esp-idf/commit/14099fe15efb1b0cde0a8370096c55bba62ff937))
|
||||
- fix test script delayed response ([8a8d58d](https://github.com/espressif/esp-protocols/commit/8a8d58d), [IDF@a4f2639](https://github.com/espressif/esp-idf/commit/a4f263948c35c13340b6f4b59a649c5073787d5e))
|
||||
- fix wrong SRV/PTR record handling ([402baeb](https://github.com/espressif/esp-protocols/commit/402baeb), [IDF@e613555](https://github.com/espressif/esp-idf/commit/e6135552d26480e39e11632437020535b1667b7a))
|
||||
- fix wrong service hostname after mangling ([9fa25ef](https://github.com/espressif/esp-protocols/commit/9fa25ef), [IDF@439b31d](https://github.com/espressif/esp-idf/commit/439b31d065eddfdfb6eb4cf9c00454edfebc3d9b))
|
||||
- fix empty address change announce packets ([121b525](https://github.com/espressif/esp-protocols/commit/121b525), [IDF@7bbb72d](https://github.com/espressif/esp-idf/commit/7bbb72d86540f04d37b0e2c4efb6dc66ee9c9ea0))
|
||||
- fix mdns probe/reply behavior ([418fb60](https://github.com/espressif/esp-protocols/commit/418fb60), [IDF@d2a5d25](https://github.com/espressif/esp-idf/commit/d2a5d25984432d149ca31aea4a0d177f3509dd7b))
|
||||
- make delegate host address a list ([4049b3b](https://github.com/espressif/esp-protocols/commit/4049b3b), [IDF@2d34352](https://github.com/espressif/esp-idf/commit/2d34352f3db0fa71366a838933a29138a90eb2af))
|
||||
- add remove delegate host api ([c882119](https://github.com/espressif/esp-protocols/commit/c882119), [IDF@2174693](https://github.com/espressif/esp-idf/commit/2174693096b73ce93261611c44ecba647cd01859))
|
||||
- add mdns delegation ([1eb5df9](https://github.com/espressif/esp-protocols/commit/1eb5df9), [IDF@401ff56](https://github.com/espressif/esp-idf/commit/401ff56cc1ad1d11284143a348cc0c0e4a363e98))
|
||||
- fix memory free issue when repeating the query in reply ([b62b4b3](https://github.com/espressif/esp-protocols/commit/b62b4b3), [IDF@5f244c8](https://github.com/espressif/esp-idf/commit/5f244c86f29da46c17610563a245d1663a46b439))
|
||||
- Fix of crash when wifi interface get deleted and mdns receives the packets ([4d8aec1](https://github.com/espressif/esp-protocols/commit/4d8aec1), [IDF#6973](https://github.com/espressif/esp-idf/issues/6973), [IDF@03de74a](https://github.com/espressif/esp-idf/commit/03de74a728d4b278f55e1fc30e0425483b806e80))
|
||||
- Docs: Added README.md for lwip fuzzer tests ([6d64910](https://github.com/espressif/esp-protocols/commit/6d64910), [IDF@53c18a8](https://github.com/espressif/esp-idf/commit/53c18a85db104bb37ebeadec2faf5d42d764d0f9))
|
||||
- Fixed the ip header TTL to be correctly set to 255 ([ab3fa69](https://github.com/espressif/esp-protocols/commit/ab3fa69), [IDF@5cce919](https://github.com/espressif/esp-idf/commit/5cce919cbef87f543bb9f5275b77b97b3b1ea67e))
|
||||
- Fix parsing answers with questions when instance name not set ([c3a5826](https://github.com/espressif/esp-protocols/commit/c3a5826), [IDF#6598](https://github.com/espressif/esp-idf/issues/6598), [IDF@3404945](https://github.com/espressif/esp-idf/commit/34049454dfaf5132d9b258ef4d04921befc8997b))
|
||||
- Fix the resolver to correctly parse it's own non-strict answers ([cbcbe4f](https://github.com/espressif/esp-protocols/commit/cbcbe4f), [IDF@b649603](https://github.com/espressif/esp-idf/commit/b649603a0d70ec804567f57752c3eddaed56198f))
|
||||
- Add MDNS_STRICT_MODE config option ([adc3430](https://github.com/espressif/esp-protocols/commit/adc3430), [IDF@0eee315](https://github.com/espressif/esp-idf/commit/0eee31546dd4e6df0d1c1cc2740da0675dffb4bf))
|
||||
- freertos: common config header ([c30617d](https://github.com/espressif/esp-protocols/commit/c30617d), [IDF@39cf818](https://github.com/espressif/esp-idf/commit/39cf818838b0259b3e00b3c198ad47b4add41939))
|
||||
- Removed freeRTOS dependancies from fuzzer tests ([1e5eeb1](https://github.com/espressif/esp-protocols/commit/1e5eeb1), [IDF@5571694](https://github.com/espressif/esp-idf/commit/55716945a9908e057743d69e1d59399df03e49bd))
|
||||
- mDNS: Updated APIs description and shows the warning when hostname contains domain name during the query ([22c7c0a](https://github.com/espressif/esp-protocols/commit/22c7c0a), [IDF#6590](https://github.com/espressif/esp-idf/issues/6590), [IDF@9f8d2b9](https://github.com/espressif/esp-idf/commit/9f8d2b944d2b3736a012e0dff1a8459b6941d295))
|
||||
- components: Use CONFIG_LWIP_IPV6 to strip IPv6 function in components ([1623c0e](https://github.com/espressif/esp-protocols/commit/1623c0e), [IDF@da58235](https://github.com/espressif/esp-idf/commit/da58235a0ee262ff552c5f1155d531b5c31e8de6))
|
||||
- add bound check when setting interface as duplicate ([b114ed6](https://github.com/espressif/esp-protocols/commit/b114ed6), [IDF@2b9d2c0](https://github.com/espressif/esp-idf/commit/2b9d2c06f54924b680c41ae641978c8d81612f65))
|
||||
- mDNS: Fix of text length calculation when detecting a collision ([2ffd223](https://github.com/espressif/esp-protocols/commit/2ffd223), [IDF@be0ae1e](https://github.com/espressif/esp-idf/commit/be0ae1ebbbe9fae6ecf7de09e8d50cba063b61f4))
|
||||
- global: fix sign-compare warnings ([1fe901f](https://github.com/espressif/esp-protocols/commit/1fe901f), [IDF@753a929](https://github.com/espressif/esp-idf/commit/753a9295259126217a9fe6ef1c5e9da21e9b4e28))
|
||||
- lwip: Moved default SNTP API to esp_sntp.h ([2cf9fd8](https://github.com/espressif/esp-protocols/commit/2cf9fd8), [IDF@76f6dd6](https://github.com/espressif/esp-idf/commit/76f6dd6214ca583b1a94c7c553ccac739a27f6d5))
|
||||
- Allow resolve its own non-strict answers ([89439e0](https://github.com/espressif/esp-protocols/commit/89439e0), [IDF#6190](https://github.com/espressif/esp-idf/issues/6190), [IDF@0693e17](https://github.com/espressif/esp-idf/commit/0693e172de392086b9bfd8cf1474d8d133af3298))
|
||||
- mDNS: Fix of collision detection during txt length calculation ([becd5d0](https://github.com/espressif/esp-protocols/commit/becd5d0), [IDF#6114](https://github.com/espressif/esp-idf/issues/6114), [IDF@f33772c](https://github.com/espressif/esp-idf/commit/f33772c96037c795366e60082bdbbefe2a69165f))
|
||||
- esp32c3: Apply one-liner/small changes for ESP32-C3 ([0d7a309](https://github.com/espressif/esp-protocols/commit/0d7a309), [IDF@5228d9f](https://github.com/espressif/esp-idf/commit/5228d9f9ced16118d87326f94d9f9dfd411e0be9))
|
||||
- test: fix several test build error ([1fdffbb](https://github.com/espressif/esp-protocols/commit/1fdffbb), [IDF@b7ecccd](https://github.com/espressif/esp-idf/commit/b7ecccd9010f1deaba83de54374231c3c7f5b472))
|
||||
- freertos: Add RISC-V port ([988d120](https://github.com/espressif/esp-protocols/commit/988d120), [IDF@87e13ba](https://github.com/espressif/esp-idf/commit/87e13baaf12fe6deae715d95e912a310fea4ba88))
|
||||
- Fix wrong mdns source address if lwIP IPv6 zones disabled ([fd47df3](https://github.com/espressif/esp-protocols/commit/fd47df3), [IDF@7ac9761](https://github.com/espressif/esp-idf/commit/7ac97616c119e4d2f4cdd377dfc5abbf75ec5e30))
|
||||
- Whitespace: Automated whitespace fixes (large commit) ([2cb3a6e](https://github.com/espressif/esp-protocols/commit/2cb3a6e), [IDF@66fb5a2](https://github.com/espressif/esp-idf/commit/66fb5a29bbdc2482d67c52e6f66b303378c9b789))
|
||||
- test_compile_fuzzers: Fix include paths for host build ([825652f](https://github.com/espressif/esp-protocols/commit/825652f), [IDF@98a0cc7](https://github.com/espressif/esp-idf/commit/98a0cc783f701b238bea232b53250a538d34920a))
|
||||
- CI: Add a test to pre-check fuzzer tests compilation before weekly run ([fc53888](https://github.com/espressif/esp-protocols/commit/fc53888), [IDF@637f5c0](https://github.com/espressif/esp-idf/commit/637f5c0a6842c42ee6cf7f41d3c5ae0cb28a68af))
|
||||
- soc: descriptive part occupy whole component ([7635c04](https://github.com/espressif/esp-protocols/commit/7635c04), [IDF@79887fd](https://github.com/espressif/esp-idf/commit/79887fdc6c3d9a2e509cc189bb43c998d3f0f4ee))
|
||||
- Coredump config option rename throughout IDF ([d5fe42b](https://github.com/espressif/esp-protocols/commit/d5fe42b), [IDF@20af94f](https://github.com/espressif/esp-idf/commit/20af94ff53c5147a76342800d007a6c49be50a7b))
|
||||
- mdns, dns, dhcp, dhcps: update fuzzer test to work in CI ([e0bc60a](https://github.com/espressif/esp-protocols/commit/e0bc60a), [IDF@a43c06a](https://github.com/espressif/esp-idf/commit/a43c06a592bcf9404297b22268c33bb7a246632c))
|
||||
- cmock: added cmock as component ([9772e49](https://github.com/espressif/esp-protocols/commit/9772e49), [IDF@20c068e](https://github.com/espressif/esp-idf/commit/20c068ef3b49999387896b90f8011b02f718485f))
|
||||
- Support queries in responses in mDNS non-strict mode ([6021a88](https://github.com/espressif/esp-protocols/commit/6021a88), [IDF#5521](https://github.com/espressif/esp-idf/issues/5521), [IDF@bcfa36d](https://github.com/espressif/esp-idf/commit/bcfa36db8ffff997f1f95eaf6b011ffc4d46a10f))
|
||||
- Fix include query ID in reponses ([78f71ec](https://github.com/espressif/esp-protocols/commit/78f71ec), [IDF#5574](https://github.com/espressif/esp-idf/issues/5574), [IDF@f62e321](https://github.com/espressif/esp-idf/commit/f62e321d87c1d520cccca951715c27730e06607a))
|
||||
- Allow config mDNS task stack size ([3319844](https://github.com/espressif/esp-protocols/commit/3319844), [IDF@cf7e48c](https://github.com/espressif/esp-idf/commit/cf7e48c779edd84c3f99d5e8ed81027932302382))
|
||||
- Remove mbedtls dependency ([ac70c9a](https://github.com/espressif/esp-protocols/commit/ac70c9a), [IDF@f4a4549](https://github.com/espressif/esp-idf/commit/f4a4549a344e7ff2444a188adbebbc136b47a7bb))
|
||||
- limit the GOT_IP6_EVENT to only known network interfaces ([2b7d43e](https://github.com/espressif/esp-protocols/commit/2b7d43e), [IDF@ab8cab1](https://github.com/espressif/esp-idf/commit/ab8cab1c553ee5312ef47a7dea002f2585605006))
|
||||
- esp32: add implementation of esp_timer based on TG0 LAC timer ([4eb3e89](https://github.com/espressif/esp-protocols/commit/4eb3e89), [IDF@739eb05](https://github.com/espressif/esp-idf/commit/739eb05bb97736b70507e7ebcfee58e670672d23))
|
||||
- fixed typos in the variable names and the comments ([b5e5a64](https://github.com/espressif/esp-protocols/commit/b5e5a64), [IDF@ecca39e](https://github.com/espressif/esp-idf/commit/ecca39e19f663e32e16aef2a09df15443de347e9))
|
||||
- fix preset of esp_netif ptr for local interfaces ([6713ffe](https://github.com/espressif/esp-protocols/commit/6713ffe), [IDF@09e36f9](https://github.com/espressif/esp-idf/commit/09e36f9f3354092b2a528baaaaccab28ff4774d6))
|
||||
- fixed crash on event during deinit ([817c4fd](https://github.com/espressif/esp-protocols/commit/817c4fd), [IDF@eaa2f12](https://github.com/espressif/esp-idf/commit/eaa2f12d6761710d2633b4934fe09f6f45e20f4f))
|
||||
- respond to discovery with the proper pseudo name _services._dns-sd._udp ([8f0dc6d](https://github.com/espressif/esp-protocols/commit/8f0dc6d), [IDF#4369](https://github.com/espressif/esp-idf/issues/4369), [IDF@de17a14](https://github.com/espressif/esp-idf/commit/de17a1487f8ba6f432b06199f2261132ec6e735f))
|
||||
- fixed forgotten merge conflicts in debug code ([d20666f](https://github.com/espressif/esp-protocols/commit/d20666f), [IDF@d9433ef](https://github.com/espressif/esp-idf/commit/d9433ef69223a32d05abdca543fb530f2e6679e4))
|
||||
- add missing include of esp_task.h ([662a4ce](https://github.com/espressif/esp-protocols/commit/662a4ce), [IDF@5884b80](https://github.com/espressif/esp-idf/commit/5884b80908d680874e27fa0c8b2df85b69d03dd3))
|
||||
- add configuration values for task priority, affinity and internal service timeouts ([fb1de80](https://github.com/espressif/esp-protocols/commit/fb1de80), [IDF@c6f38f0](https://github.com/espressif/esp-idf/commit/c6f38f04f8eec1aae937cc87c111609772681cb3))
|
||||
- tcpip_adapter: updated tcpip_adapter compatablity layer to include all public API and keep 100% backward compatibility update build of tcpip adapter when ethernet disabled ([1f35e9a](https://github.com/espressif/esp-protocols/commit/1f35e9a), [IDF@7f5cda1](https://github.com/espressif/esp-idf/commit/7f5cda1b825586903f85dc4ad7736b35712e46d7))
|
||||
- update mdns to use esp-netif for mdns supported services such as STA, AP, ETH ([48b819b](https://github.com/espressif/esp-protocols/commit/48b819b), [IDF@19e24fe](https://github.com/espressif/esp-idf/commit/19e24fe61ed5ea6698dfd5e1f427e783360aa846))
|
||||
- esp_netif: Introduction of esp-netif component as a replacement of tcpip_adpter ([53e2aa3](https://github.com/espressif/esp-protocols/commit/53e2aa3), [IDF@ffe043b](https://github.com/espressif/esp-idf/commit/ffe043b1a81a0f9e1cc2cfa8873e21318ec89143))
|
||||
- examples: removed ip4addr_ntoa and used prefered IP2STR for displaying IP addresses ([3cc6446](https://github.com/espressif/esp-protocols/commit/3cc6446), [IDF@ec9f245](https://github.com/espressif/esp-idf/commit/ec9f245dd35d3e8e7b19a8dec5e05e003dc21f39))
|
||||
- esp_event, mdns: fixes for CONFIG_ETH_ENABLED=n ([248b11b](https://github.com/espressif/esp-protocols/commit/248b11b), [IDF@569ad75](https://github.com/espressif/esp-idf/commit/569ad7545c32a2f1d0eff3f1e81df70fb76ad125))
|
||||
- build and link hello-world for esp32s2beta ([901124b](https://github.com/espressif/esp-protocols/commit/901124b), [IDF@84b2f9f](https://github.com/espressif/esp-idf/commit/84b2f9f14d16533c84db2210f13a24cd817e0b0a))
|
||||
- fix crash for hostname queries ([f6ff165](https://github.com/espressif/esp-protocols/commit/f6ff165), [IDF#4224](https://github.com/espressif/esp-idf/issues/4224), [IDF@3d11700](https://github.com/espressif/esp-idf/commit/3d1170031b340a231949fdc0d9c46d87af0d1b5d))
|
||||
- fix possible race condition when checking DHCP status on WIFI_EVENT_STA_CONNECTED event. ([f44c569](https://github.com/espressif/esp-protocols/commit/f44c569), [IDF@7f410a0](https://github.com/espressif/esp-idf/commit/7f410a0bcbafa85dba05807c53c3c38999506509))
|
||||
- use constant size of AAAA answer in mdns packets instead of deriving from lwip struct size, since the struct could contain also zones ([286c646](https://github.com/espressif/esp-protocols/commit/286c646), [IDF@e5e31c5](https://github.com/espressif/esp-idf/commit/e5e31c5d0172d68fd207fa31cc5d3bba82dad020))
|
||||
- esp_wifi: wifi support new event mechanism ([c70d527](https://github.com/espressif/esp-protocols/commit/c70d527), [IDF@003a987](https://github.com/espressif/esp-idf/commit/003a9872b7de69d799e9d37521cfbcaff9b37e85))
|
||||
- fix missing bye packet if services removed with mdns_service_remove_all() or mdns_free() ([7cdf96c](https://github.com/espressif/esp-protocols/commit/7cdf96c), [IDF#3660](https://github.com/espressif/esp-idf/issues/3660), [IDF@a001998](https://github.com/espressif/esp-idf/commit/a001998d5283b29ca9a374adf7cef3357b39a03a))
|
||||
- mdns_service_remove_all doesn't take an argument ([407875d](https://github.com/espressif/esp-protocols/commit/407875d), [IDF@c2764f6](https://github.com/espressif/esp-idf/commit/c2764f6fe85681cfaf5dbbe168295284f09c09cd))
|
||||
- tools: Mass fixing of empty prototypes (for -Wstrict-prototypes) ([3e753f5](https://github.com/espressif/esp-protocols/commit/3e753f5), [IDF@afbaf74](https://github.com/espressif/esp-idf/commit/afbaf74007e89d016dbade4072bf2e7a3874139a))
|
||||
- fix ignoring mdns packet with some invalid name entries in question field ([144d4ad](https://github.com/espressif/esp-protocols/commit/144d4ad), [IDF@4bd4c7c](https://github.com/espressif/esp-idf/commit/4bd4c7caf3f9ef8402c5a27ab44561537407eb60))
|
||||
- add esp_eth component ([680bad6](https://github.com/espressif/esp-protocols/commit/680bad6), [IDF@90c4827](https://github.com/espressif/esp-idf/commit/90c4827bd22aa61894a5b22b3b39247a7e44d6cf))
|
||||
- components: use new component registration api ([7fb6686](https://github.com/espressif/esp-protocols/commit/7fb6686), [IDF@9eccd7c](https://github.com/espressif/esp-idf/commit/9eccd7c0826d6cc2e9de59304d1e5f76c0063ccf))
|
||||
- fix static analysis warnings ([4912bef](https://github.com/espressif/esp-protocols/commit/4912bef), [IDF@c34de4c](https://github.com/espressif/esp-idf/commit/c34de4cba658e8331f8a3ab2f466190c7640595b))
|
||||
- added initial suite of api unit tests ([181a22e](https://github.com/espressif/esp-protocols/commit/181a22e), [IDF@e680191](https://github.com/espressif/esp-idf/commit/e6801912c5c4861f828ab1f447280628bba9a5d7))
|
||||
- mdns tests: adapt mdns fuzzer test to compile with event loop library ([4172219](https://github.com/espressif/esp-protocols/commit/4172219), [IDF@38d15cb](https://github.com/espressif/esp-idf/commit/38d15cbd637e8b8baacda9fc43e8e99d224530f5))
|
||||
- fixed mdns crashing on reception of txt packet without a corresponding service closes #2866 ([98d2c1a](https://github.com/espressif/esp-protocols/commit/98d2c1a), [IDF@af48977](https://github.com/espressif/esp-idf/commit/af48977f21cea6b18dae10b2c8b64a78acfc647f))
|
||||
- use const char* for mdns txt items types to remove warning when assigning ([84cbb1f](https://github.com/espressif/esp-protocols/commit/84cbb1f), [IDF@c050a75](https://github.com/espressif/esp-idf/commit/c050a75616803c7871ef11c060e440fae09000d9))
|
||||
- updated doxygen comments documenting mdns api ([4c6818e](https://github.com/espressif/esp-protocols/commit/4c6818e), [IDF#1718](https://github.com/espressif/esp-idf/issues/1718), [IDF@a851aac](https://github.com/espressif/esp-idf/commit/a851aac255311124529f504486ca55bad15c1951))
|
||||
- update mdns_out_question_s to be in line with mdns_parsed_question_s struct ([c440114](https://github.com/espressif/esp-protocols/commit/c440114), [IDF#1568]( https://github.com/espressif/esp-idf/issues/1568), [IDF@eddd5c4](https://github.com/espressif/esp-idf/commit/eddd5c4f2c686d9a1d6d3258569cc33752e78880))
|
||||
- use esp_event library to handle events ([6ea0ea9](https://github.com/espressif/esp-protocols/commit/6ea0ea9), [IDF@a2d5952](https://github.com/espressif/esp-idf/commit/a2d59525e53099ee1ad63c3d60ff853f573ab535))
|
||||
- fuzzer tests: update of mdns and lwip host compilation for fuzzer testing ([d9aec9f](https://github.com/espressif/esp-protocols/commit/d9aec9f), [IDF@bc60bbb](https://github.com/espressif/esp-idf/commit/bc60bbbeaf89f2bbfc5db4bd4f1e7ace81a2ab37))
|
||||
- fix possible crash when probing on particular interface with duplicated service instances due to naming conflicts on network ([985e691](https://github.com/espressif/esp-protocols/commit/985e691), [IDF@265e983](https://github.com/espressif/esp-idf/commit/265e983a452a7eaefc1662cdc0e6ed839a37fe1a))
|
||||
- enable pcbs before starting service thread to avoid updating pcb's internal variables from concurent tasks ([75deebb](https://github.com/espressif/esp-protocols/commit/75deebb), [IDF@c87f0cb](https://github.com/espressif/esp-idf/commit/c87f0cb6cad3c36b077f4aaeb1ca52fe6ed0cdaf))
|
||||
- fix possible deadlock on mdns deinit calling mdns_free() ([fdd27dc](https://github.com/espressif/esp-protocols/commit/fdd27dc), [IDF#1696](https://github.com/espressif/esp-idf/issues/1696), [IDF@48b5501](https://github.com/espressif/esp-idf/commit/48b5501c250ed90da51a55ad4fc18e09f466a517))
|
||||
- mdsn: fix race condition in updating packet data from user task when failed to allocate or queue a new service ([2ec3b55](https://github.com/espressif/esp-protocols/commit/2ec3b55), [IDF@021dc5d](https://github.com/espressif/esp-idf/commit/021dc5d453e21e2d1707f194668e69cf63ef4e84))
|
||||
- fix possible crash when packet scheduled to transmit contained service which might have been already removed ([450cbf0](https://github.com/espressif/esp-protocols/commit/450cbf0), [IDF@67051a2](https://github.com/espressif/esp-idf/commit/67051a286ba60a01d4755c3682129153c2f95953))
|
||||
- use binary semaphore instead of mutex when searching ([34f6d8d](https://github.com/espressif/esp-protocols/commit/34f6d8d), [IDF@eef0b50](https://github.com/espressif/esp-idf/commit/eef0b5090aee87efef1a6a37772b3b88c9ce8df8))
|
||||
- fix memory leak in pbuf if tcpipadapter failed to get netif ([b6efc68](https://github.com/espressif/esp-protocols/commit/b6efc68), [IDF@8462751](https://github.com/espressif/esp-idf/commit/8462751f95a3ff18bdc1b01d02fabd1829fd9135))
|
||||
- fix malfuctional query_txt ([90e4bab](https://github.com/espressif/esp-protocols/commit/90e4bab), [IDF@1a02773](https://github.com/espressif/esp-idf/commit/1a027734af06abf08fcb1c34ee65bdf50d12be4d))
|
||||
- fix possible crash when mdns_free called while action queue not empty ([c546ab8](https://github.com/espressif/esp-protocols/commit/c546ab8), [IDF@206b47c](https://github.com/espressif/esp-idf/commit/206b47c03aca0acdf40d1d9c250e18aeddfe1bd7))
|
||||
- fix memory leak when query for service receives multiple ptr entries for one instance ([6582b41](https://github.com/espressif/esp-protocols/commit/6582b41), [IDF@9a4da97](https://github.com/espressif/esp-idf/commit/9a4da97fb4b3c241998cb969a08c3a917ffb4cd1))
|
||||
- fix crash after init if no memory for task ([358d26c](https://github.com/espressif/esp-protocols/commit/358d26c), [IDF@a47768d](https://github.com/espressif/esp-idf/commit/a47768dc4e4750fd7e1c29b15d6e2dd3c76e6591))
|
||||
- fixed crash on free undefined ptr after skipped strdup ([2ac83d0](https://github.com/espressif/esp-protocols/commit/2ac83d0), [IDF@e0a8044](https://github.com/espressif/esp-idf/commit/e0a8044a16907e642001b883469618a999dbe6db))
|
||||
- Correct Kconfigs according to the coding style ([98e3171](https://github.com/espressif/esp-protocols/commit/98e3171), [IDF@37126d3](https://github.com/espressif/esp-idf/commit/37126d3451eabb44eeeb48b8e2ee554dc233e2a8))
|
||||
- fix networking running udp_sendif from lwip thread ([2f85c07](https://github.com/espressif/esp-protocols/commit/2f85c07), [IDF@f7d4a4b](https://github.com/espressif/esp-idf/commit/f7d4a4be6a9e0b0ac5edb9400d3b123dbbed2ffc))
|
||||
- fixed static memory leak ([b30a7fe](https://github.com/espressif/esp-protocols/commit/b30a7fe), [IDF@6bb68a5](https://github.com/espressif/esp-idf/commit/6bb68a5a7567a94c3605136d44960ff060c74663))
|
||||
- check all mallocs for failure and add default hook to log error with free heap ([7a4fdad](https://github.com/espressif/esp-protocols/commit/7a4fdad), [IDF@c8cb4cd](https://github.com/espressif/esp-idf/commit/c8cb4cd3c8eb56d5901ade03302ad1231d7f3de5))
|
||||
- resolve memory leak when txt record received multiple times ([b4e5742](https://github.com/espressif/esp-protocols/commit/b4e5742), [IDF@a6b2b73](https://github.com/espressif/esp-idf/commit/a6b2b73f03bbb75a39685ddba6cf877fd1e5e6d7))
|
||||
- skip sending search when finished, not properly locked timer task ([2763bcd](https://github.com/espressif/esp-protocols/commit/2763bcd), [IDF@31163f0](https://github.com/espressif/esp-idf/commit/31163f02d5c414d8b492dce6f729b43a0061581b))
|
||||
- sending search packets also in probing and announcing state ([8cd0e8a](https://github.com/espressif/esp-protocols/commit/8cd0e8a), [IDF@d16762a](https://github.com/espressif/esp-idf/commit/d16762a036e35ce86ece86bb44e6e99f9cc7c431))
|
||||
- fixed crashes on network changes ([9b3b41c](https://github.com/espressif/esp-protocols/commit/9b3b41c), [IDF@097282a](https://github.com/espressif/esp-idf/commit/097282a8e3f85958747430d9931ce0a545d37700))
|
||||
- Update network code for mDNS to work with newest LwIP ([ea23007](https://github.com/espressif/esp-protocols/commit/ea23007), [IDF@3ec0e7e](https://github.com/espressif/esp-idf/commit/3ec0e7e2d2ddea70e9f8fb5025664d0fe24c301a))
|
||||
- bugfix: mdns_service_txt_set() wasn't allocating memory for TXT records ([0c17121](https://github.com/espressif/esp-protocols/commit/0c17121), [IDF@e5e2702](https://github.com/espressif/esp-idf/commit/e5e2702ca3f63a29da57eb138f75a20c74fb2a94))
|
||||
- cmake: make main a component again ([67173f6](https://github.com/espressif/esp-protocols/commit/67173f6), [IDF@d9939ce](https://github.com/espressif/esp-idf/commit/d9939cedd9b44d63dc148354c3a0a139b9c7113d))
|
||||
- Feature/sync lwip as submodule ([fed787f](https://github.com/espressif/esp-protocols/commit/fed787f), [IDF@3578fe3](https://github.com/espressif/esp-idf/commit/3578fe39e01ba0c2d54824ac70c3276502661c6b))
|
||||
- Fix a portion of the queries are issued with the wildcard query type ([b4ab30b](https://github.com/espressif/esp-protocols/commit/b4ab30b), [IDF@f3f0445](https://github.com/espressif/esp-idf/commit/f3f0445f4db7c9ad97ae10a9728767337aa7bb62))
|
||||
- added CI job for AFL fuzzer tests ([dd71494](https://github.com/espressif/esp-protocols/commit/dd71494), [IDF@0c14764](https://github.com/espressif/esp-idf/commit/0c147648f7642d058b63fbe2ddd5de31c2326304))
|
||||
- Minor fix for mdns_service_remove() ([39de491](https://github.com/espressif/esp-protocols/commit/39de491), [IDF@5c7eb7e](https://github.com/espressif/esp-idf/commit/5c7eb7e27be7508130459d896cf7d13ffefda87f))
|
||||
- Replace all DOS line endings with Unix ([19acac7](https://github.com/espressif/esp-protocols/commit/19acac7), [IDF@a67d5d8](https://github.com/espressif/esp-idf/commit/a67d5d89e0e90390fa7ff02816a6a79008d75d40))
|
||||
- remove executable permission from source files ([98069f9](https://github.com/espressif/esp-protocols/commit/98069f9), [IDF@cb649e4](https://github.com/espressif/esp-idf/commit/cb649e452f3c64a7db1f4a61e162a16b70248204))
|
||||
- Fixed nullptr dereference in MDNS.c ([ad29d34](https://github.com/espressif/esp-protocols/commit/ad29d34), [IDF@fffbf7b](https://github.com/espressif/esp-idf/commit/fffbf7b75065b5852e064e04b0c5102dd0fc2244))
|
||||
- MDNS-Fuzzer: AFL fuzzer tests for mdsn packet parser ([9f1be36](https://github.com/espressif/esp-protocols/commit/9f1be36), [IDF@e983230](https://github.com/espressif/esp-idf/commit/e983230be933fb83cebdd1945ba6539a7dc99b28))
|
||||
- cmake: Add component dependency support ([c7701d4](https://github.com/espressif/esp-protocols/commit/c7701d4), [IDF@1cb5712](https://github.com/espressif/esp-idf/commit/1cb5712463a8963cd3e8331da90fb5e03f13575f))
|
||||
- cmake: Remove defaults for COMPONENT_SRCDIRS, COMPONENT_SRCS, COMPONENT_ADD_INCLUDEDIRS ([f1ccc40](https://github.com/espressif/esp-protocols/commit/f1ccc40), [IDF@4f1a856](https://github.com/espressif/esp-idf/commit/4f1a856dbfd752336cd71730105e02ad8c045541))
|
||||
- build system: Initial cmake support, work in progress ([84bd1d7](https://github.com/espressif/esp-protocols/commit/84bd1d7), [IDF@c671a0c](https://github.com/espressif/esp-idf/commit/c671a0c3ebf90f18576d6db55b51b62730c58301))
|
||||
- fix the bug that in mdns test code redefine esp_err_t to uint32_t, which should be int32_t ([259d3fc](https://github.com/espressif/esp-protocols/commit/259d3fc), [IDF@81e4cad](https://github.com/espressif/esp-idf/commit/81e4cad61593cde879a5c44a08060d9d336e5a3f))
|
||||
- Fix exception when service is removed while there are pending packets that depend on it ([7784d00](https://github.com/espressif/esp-protocols/commit/7784d00), [IDF@421c6f1](https://github.com/espressif/esp-idf/commit/421c6f154b10d9253b78875ab28ee6bdcaaaf3c0))
|
||||
- Fix case where service is NULL and that will cause exception ([bce7d52](https://github.com/espressif/esp-protocols/commit/bce7d52), [IDF@4fa130a](https://github.com/espressif/esp-idf/commit/4fa130ae4fb5de99ddddc5a7bed7e26ae645591c))
|
||||
- Fix issue with some mDNS parsers ([ef924f1](https://github.com/espressif/esp-protocols/commit/ef924f1), [IDF@51dde19](https://github.com/espressif/esp-idf/commit/51dde19a765533af67fc7be21f116641773a9be4))
|
||||
- Import mDNS changes ([ad8c92d](https://github.com/espressif/esp-protocols/commit/ad8c92d), [IDF@4bddbc0](https://github.com/espressif/esp-idf/commit/4bddbc031cee83935c0e4df1dc72cc7000c97ba5))
|
||||
- Fix compilation errors when using gcc-7.2.0 for the crosstool-ng toolchain ([3aa605f](https://github.com/espressif/esp-protocols/commit/3aa605f), [IDF@519edc3](https://github.com/espressif/esp-idf/commit/519edc332dae0160069fd790467cde8de78f1a0e))
|
||||
- components/mdns: wrong Message compression detect ([00a72b8](https://github.com/espressif/esp-protocols/commit/00a72b8), [IDF@6e24566](https://github.com/espressif/esp-idf/commit/6e24566186c52dc5432b6b25c81abda577c21e85))
|
||||
- fix leak after _mdns_create_service if we have a malloc error. ([907e7ee](https://github.com/espressif/esp-protocols/commit/907e7ee), [IDF@b6b36bd](https://github.com/espressif/esp-idf/commit/b6b36bd9ddf169039a5528f8b766048d97b975f7))
|
||||
- Use LwIP IPC for low-level API calls ([b367484](https://github.com/espressif/esp-protocols/commit/b367484), [IDF@713964f](https://github.com/espressif/esp-idf/commit/713964fe9e98b4fa34145c497b7ab638dc57614c))
|
||||
- Add AFL fuzz test ([4a8582f](https://github.com/espressif/esp-protocols/commit/4a8582f), [IDF@4c26227](https://github.com/espressif/esp-idf/commit/4c2622755d92efa1818d062d433725553437993c))
|
||||
- implement fixes for issues found while fuzz testing ([75de31c](https://github.com/espressif/esp-protocols/commit/75de31c), [IDF@99d3990](https://github.com/espressif/esp-idf/commit/99d39909c4f19c63909d663e927ac0a8933a3ed5))
|
||||
- add simple dns-sd meta query support ([4acf639](https://github.com/espressif/esp-protocols/commit/4acf639), [IDF@96e8a3c](https://github.com/espressif/esp-idf/commit/96e8a3c725095562d2725aaefa15adcfc5d78dd5))
|
||||
- address security issues with mDNS ([91bb509](https://github.com/espressif/esp-protocols/commit/91bb509), [IDF@c89e11c](https://github.com/espressif/esp-idf/commit/c89e11c8fa64641edddf9a055745d825ae3fab9d))
|
||||
- Initial mDNS component and example ([7fbf8e5](https://github.com/espressif/esp-protocols/commit/7fbf8e5), [IDF@dd3f18d](https://github.com/espressif/esp-idf/commit/dd3f18d2d88ee78909d4af2840dfdf0b9f715f28))
|
||||
42
managed_components/espressif__mdns/CMakeLists.txt
Normal file
42
managed_components/espressif__mdns/CMakeLists.txt
Normal file
@@ -0,0 +1,42 @@
|
||||
if(CONFIG_MDNS_NETWORKING_SOCKET)
|
||||
set(MDNS_NETWORKING "mdns_networking_socket.c")
|
||||
else()
|
||||
set(MDNS_NETWORKING "mdns_networking_lwip.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_MDNS_ENABLE_CONSOLE_CLI)
|
||||
set(MDNS_CONSOLE "mdns_console.c")
|
||||
else()
|
||||
set(MDNS_CONSOLE "")
|
||||
endif()
|
||||
|
||||
set(MDNS_MEMORY "mdns_mem_caps.c")
|
||||
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
if(${target} STREQUAL "linux")
|
||||
set(dependencies esp_netif_linux esp_event)
|
||||
set(private_dependencies esp_timer console esp_system)
|
||||
set(srcs "mdns.c" ${MDNS_MEMORY} ${MDNS_NETWORKING} ${MDNS_CONSOLE})
|
||||
else()
|
||||
set(dependencies lwip console esp_netif)
|
||||
set(private_dependencies esp_timer esp_wifi)
|
||||
set(srcs "mdns.c" ${MDNS_MEMORY} ${MDNS_NETWORKING} ${MDNS_CONSOLE})
|
||||
endif()
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${srcs}
|
||||
INCLUDE_DIRS "include"
|
||||
PRIV_INCLUDE_DIRS "private_include"
|
||||
REQUIRES ${dependencies}
|
||||
PRIV_REQUIRES ${private_dependencies})
|
||||
|
||||
if(${target} STREQUAL "linux")
|
||||
target_link_libraries(${COMPONENT_LIB} PRIVATE "-lbsd")
|
||||
endif()
|
||||
|
||||
if(CONFIG_ETH_ENABLED)
|
||||
idf_component_optional_requires(PRIVATE esp_eth)
|
||||
endif()
|
||||
|
||||
idf_component_get_property(MDNS_VERSION ${COMPONENT_NAME} COMPONENT_VERSION)
|
||||
target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DESP_MDNS_VERSION_NUMBER=\"${MDNS_VERSION}\"")
|
||||
190
managed_components/espressif__mdns/Kconfig
Normal file
190
managed_components/espressif__mdns/Kconfig
Normal file
@@ -0,0 +1,190 @@
|
||||
menu "mDNS"
|
||||
|
||||
config MDNS_MAX_INTERFACES
|
||||
int "Max number of interfaces"
|
||||
range 1 9
|
||||
default 3
|
||||
help
|
||||
Number of network interfaces to be served by the mDNS library.
|
||||
Lowering this number helps to reduce some static RAM usage.
|
||||
|
||||
config MDNS_MAX_SERVICES
|
||||
int "Max number of services"
|
||||
default 10
|
||||
help
|
||||
Services take up a certain amount of memory, and allowing fewer
|
||||
services to be open at the same time conserves memory. Specify
|
||||
the maximum amount of services here.
|
||||
|
||||
config MDNS_TASK_PRIORITY
|
||||
int "mDNS task priority"
|
||||
range 1 255
|
||||
default 1
|
||||
help
|
||||
Allows setting mDNS task priority. Please do not set the task priority
|
||||
higher than priorities of system tasks. Compile time warning/error
|
||||
would be emitted if the chosen task priority were too high.
|
||||
|
||||
config MDNS_ACTION_QUEUE_LEN
|
||||
int "Maximum actions pending to the server"
|
||||
range 8 64
|
||||
default 16
|
||||
help
|
||||
Allows setting the length of mDNS action queue.
|
||||
|
||||
config MDNS_TASK_STACK_SIZE
|
||||
int "mDNS task stack size"
|
||||
default 4096
|
||||
help
|
||||
Allows setting mDNS task stacksize.
|
||||
|
||||
choice MDNS_TASK_AFFINITY
|
||||
prompt "mDNS task affinity"
|
||||
default MDNS_TASK_AFFINITY_CPU0
|
||||
help
|
||||
Allows setting mDNS tasks affinity, i.e. whether the task is pinned to
|
||||
CPU0, pinned to CPU1, or allowed to run on any CPU.
|
||||
|
||||
config MDNS_TASK_AFFINITY_NO_AFFINITY
|
||||
bool "No affinity"
|
||||
config MDNS_TASK_AFFINITY_CPU0
|
||||
bool "CPU0"
|
||||
config MDNS_TASK_AFFINITY_CPU1
|
||||
bool "CPU1"
|
||||
depends on !FREERTOS_UNICORE
|
||||
|
||||
endchoice
|
||||
|
||||
config MDNS_TASK_AFFINITY
|
||||
hex
|
||||
default FREERTOS_NO_AFFINITY if MDNS_TASK_AFFINITY_NO_AFFINITY
|
||||
default 0x0 if MDNS_TASK_AFFINITY_CPU0
|
||||
default 0x1 if MDNS_TASK_AFFINITY_CPU1
|
||||
|
||||
menu "MDNS Memory Configuration"
|
||||
|
||||
choice MDNS_TASK_MEMORY_ALLOC_FROM
|
||||
prompt "Select mDNS task create on which type of memory"
|
||||
default MDNS_TASK_CREATE_FROM_INTERNAL
|
||||
config MDNS_TASK_CREATE_FROM_SPIRAM
|
||||
bool "mDNS task creates on the SPIRAM (READ HELP)"
|
||||
depends on (SPIRAM_USE_CAPS_ALLOC || SPIRAM_USE_MALLOC)
|
||||
help
|
||||
mDNS task creates on the SPIRAM.
|
||||
This option requires FreeRTOS component to allow creating
|
||||
tasks on the external memory.
|
||||
Please read the documentation about FREERTOS_TASK_CREATE_ALLOW_EXT_MEM
|
||||
|
||||
config MDNS_TASK_CREATE_FROM_INTERNAL
|
||||
bool "mDNS task creates on the internal RAM"
|
||||
|
||||
endchoice
|
||||
|
||||
choice MDNS_MEMORY_ALLOC_FROM
|
||||
prompt "Select mDNS memory allocation type"
|
||||
default MDNS_MEMORY_ALLOC_INTERNAL
|
||||
|
||||
config MDNS_MEMORY_ALLOC_SPIRAM
|
||||
bool "Allocate mDNS memory from SPIRAM"
|
||||
depends on (SPIRAM_USE_CAPS_ALLOC || SPIRAM_USE_MALLOC)
|
||||
|
||||
config MDNS_MEMORY_ALLOC_INTERNAL
|
||||
bool "Allocate mDNS memory from internal RAM"
|
||||
|
||||
endchoice
|
||||
|
||||
config MDNS_MEMORY_CUSTOM_IMPL
|
||||
bool "Implement custom memory functions"
|
||||
default n
|
||||
help
|
||||
Enable to implement custom memory functions for mDNS library.
|
||||
This option is useful when the application wants to use custom
|
||||
memory allocation functions for mDNS library.
|
||||
|
||||
endmenu # MDNS Memory Configuration
|
||||
|
||||
config MDNS_SERVICE_ADD_TIMEOUT_MS
|
||||
int "mDNS adding service timeout (ms)"
|
||||
range 10 30000
|
||||
default 2000
|
||||
help
|
||||
Configures timeout for adding a new mDNS service. Adding a service
|
||||
fails if could not be completed within this time.
|
||||
|
||||
config MDNS_TIMER_PERIOD_MS
|
||||
int "mDNS timer period (ms)"
|
||||
range 10 10000
|
||||
default 100
|
||||
help
|
||||
Configures period of mDNS timer, which periodically transmits packets
|
||||
and schedules mDNS searches.
|
||||
|
||||
config MDNS_NETWORKING_SOCKET
|
||||
bool "Use BSD sockets for mDNS networking"
|
||||
default n
|
||||
help
|
||||
Enables optional mDNS networking implementation using BSD sockets
|
||||
in UDP multicast mode.
|
||||
This option creates a new thread to serve receiving packets (TODO).
|
||||
This option uses additional N sockets, where N is number of interfaces.
|
||||
|
||||
config MDNS_SKIP_SUPPRESSING_OWN_QUERIES
|
||||
bool "Skip suppressing our own packets"
|
||||
default n
|
||||
help
|
||||
Enable only if the querier and the responder share the same IP address.
|
||||
This usually happens in test mode, where we may run multiple instances of
|
||||
responders/queriers on the same interface.
|
||||
|
||||
config MDNS_ENABLE_DEBUG_PRINTS
|
||||
bool "Enable debug prints of mDNS packets"
|
||||
default n
|
||||
help
|
||||
Enable for the library to log received and sent mDNS packets to stdout.
|
||||
|
||||
config MDNS_ENABLE_CONSOLE_CLI
|
||||
bool "Enable Command Line Interface on device console"
|
||||
default y
|
||||
help
|
||||
Enable for the console cli to be available on the device.
|
||||
|
||||
config MDNS_RESPOND_REVERSE_QUERIES
|
||||
bool "Enable responding to IPv4 reverse queries"
|
||||
default n
|
||||
help
|
||||
Enables support for IPv4 reverse lookup. If enabled, the mDNS library
|
||||
response to PTR queries of "A.B.C.D.in-addr.arpa" type.
|
||||
|
||||
config MDNS_MULTIPLE_INSTANCE
|
||||
bool "Multiple instances under the same service type"
|
||||
default y
|
||||
help
|
||||
Enables adding multiple service instances under the same service type.
|
||||
|
||||
menu "MDNS Predefined interfaces"
|
||||
|
||||
config MDNS_PREDEF_NETIF_STA
|
||||
bool "Use predefined interface for WiFi Station"
|
||||
default y
|
||||
help
|
||||
Set up mDNS for the default WiFi station.
|
||||
Disable this option if you do not need mDNS on default WiFi STA.
|
||||
|
||||
config MDNS_PREDEF_NETIF_AP
|
||||
bool "Use predefined interface for WiFi Access Point"
|
||||
default y
|
||||
help
|
||||
Set up mDNS for the default WiFi Access Point.
|
||||
Disable this option if you do not need mDNS on default WiFi AP.
|
||||
|
||||
config MDNS_PREDEF_NETIF_ETH
|
||||
bool "Use predefined interface for Ethernet"
|
||||
depends on ETH_ENABLED
|
||||
default y
|
||||
help
|
||||
Set up mDNS for the default Ethernet interface.
|
||||
Disable this option if you do not need mDNS on default Ethernet.
|
||||
|
||||
endmenu # MDNS Predefined interfaces
|
||||
|
||||
endmenu
|
||||
202
managed_components/espressif__mdns/LICENSE
Normal file
202
managed_components/espressif__mdns/LICENSE
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
14
managed_components/espressif__mdns/README.md
Normal file
14
managed_components/espressif__mdns/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# mDNS Service
|
||||
|
||||
[](https://components.espressif.com/components/espressif/mdns)
|
||||
|
||||
mDNS is a multicast UDP service that is used to provide local network service and host discovery.
|
||||
|
||||
## Examples
|
||||
|
||||
Get started with example test [Example](https://github.com/espressif/esp-protocols/tree/master/components/mdns/examples):
|
||||
|
||||
## Documentation
|
||||
|
||||
* View the full [documentation(English)](https://docs.espressif.com/projects/esp-protocols/mdns/docs/latest/en/index.html)
|
||||
* View the full [documentation(Chinese)](https://docs.espressif.com/projects/esp-protocols/mdns/docs/latest/zh_CN/index.html)
|
||||
@@ -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(query_advertise)
|
||||
@@ -0,0 +1,91 @@
|
||||
# mDNS example
|
||||
|
||||
Shows how to use mDNS to advertise and query services and hosts
|
||||
|
||||
## Example workflow
|
||||
|
||||
- mDNS is initialized with host name and instance name defined through the project configuration and `_http._tcp` service is added to be advertised
|
||||
- A delegated host `esp32-delegated._local` is added and another `_http._tcp` service is added for this host.
|
||||
- WiFi STA is started and trying to connect to the access point defined through the project configuration
|
||||
- The system event handler is used to pass the network events to mDNS so the service is aware when the interface comes up or down
|
||||
- GPIO0 (BOOT Button) is initialized as pulled-up input that can be monitored for button press
|
||||
- Example task is started to check if the button is pressed so it can execute the mDNS queries defined
|
||||
|
||||
### Configure the project
|
||||
|
||||
* Open the project configuration menu (`idf.py menuconfig`)
|
||||
|
||||
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu
|
||||
* Set `mDNS Hostname` as host name prefix for the device and its instance name in `mDNS Instance Name`
|
||||
* Disable `Resolve test services` to prevent the example from querying defined names/services on startup (cause warnings in example logs, as illustrated below)
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
- Wait for WiFi to connect to your access point
|
||||
- You can now ping the device at `[board-hostname].local`, where `[board-hostname]` is preconfigured hostname, `esp32-mdns` by default.
|
||||
- You can also browse for `_http._tcp` on the same network to find the advertised service
|
||||
- Pressing the BOOT button will start querying the local network for the predefined in `check_button` hosts and services
|
||||
- Note that for purpose of CI tests, configuration options of `MDNS_RESOLVE_TEST_SERVICES` and `MDNS_ADD_MAC_TO_HOSTNAME` are available, but disabled by default. If enabled, then the hostname suffix of last 3 bytes from device MAC address is added, e.g. `esp32-mdns-80FFFF`, and a query for test service is issued.
|
||||
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
```
|
||||
I (0) cpu_start: Starting scheduler on APP CPU.
|
||||
I (276) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
|
||||
I (276) mdns-test: mdns hostname set to: [esp32-mdns]
|
||||
I (286) wifi: wifi driver task: 3ffc2fa4, prio:23, stack:3584, core=0
|
||||
I (286) wifi: wifi firmware version: a3be639
|
||||
I (286) wifi: config NVS flash: enabled
|
||||
I (296) wifi: config nano formating: disabled
|
||||
I (296) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
|
||||
I (306) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
|
||||
I (336) wifi: Init dynamic tx buffer num: 32
|
||||
I (336) wifi: Init data frame dynamic rx buffer num: 32
|
||||
I (336) wifi: Init management frame dynamic rx buffer num: 32
|
||||
I (346) wifi: Init static rx buffer size: 1600
|
||||
I (346) wifi: Init static rx buffer num: 10
|
||||
I (346) wifi: Init dynamic rx buffer num: 32
|
||||
I (356) mdns-test: Setting WiFi configuration SSID myssid...
|
||||
I (426) phy: phy_version: 4000, b6198fa, Sep 3 2018, 15:11:06, 0, 0
|
||||
I (426) wifi: mode : sta (30:ae:a4:80:FF:FF)
|
||||
I (426) gpio: GPIO[0]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (1756) wifi: n:11 0, o:1 0, ap:255 255, sta:11 0, prof:1
|
||||
I (2736) wifi: state: init -> auth (b0)
|
||||
I (2756) wifi: state: auth -> assoc (0)
|
||||
I (2766) wifi: state: assoc -> run (10)
|
||||
I (2786) wifi: connected with myssid, channel 11
|
||||
I (2786) wifi: pm start, type: 1
|
||||
|
||||
I (4786) event: sta ip: 192.168.0.139, mask: 255.255.255.0, gw: 192.168.0.2
|
||||
I (21126) mdns-test: Query A: esp32.local
|
||||
W (23176) mdns-test: ESP_ERR_NOT_FOUND: Host was not found!
|
||||
I (23176) mdns-test: Query PTR: _arduino._tcp.local
|
||||
W (26276) mdns-test: No results found!
|
||||
I (26276) mdns-test: Query PTR: _http._tcp.local
|
||||
1: Interface: STA, Type: V6
|
||||
PTR : HP Color LaserJet MFP M277dw (7C2E10)
|
||||
SRV : NPI7C2E10.local:80
|
||||
A : 254.128.0.0
|
||||
2: Interface: STA, Type: V4
|
||||
PTR : switch4e4919
|
||||
SRV : switch4e4919.local:80
|
||||
TXT : [1] path=/config/authentication_page.htm;
|
||||
A : 192.168.0.118
|
||||
I (29396) mdns-test: Query PTR: _printer._tcp.local
|
||||
1: Interface: STA, Type: V6
|
||||
PTR : HP Color LaserJet MFP M277dw (7C2E10)
|
||||
SRV : NPI7C2E10.local:515
|
||||
A : 254.128.0.0
|
||||
2: Interface: STA, Type: V4
|
||||
PTR : HP Color LaserJet MFP M277dw (7C2E10)
|
||||
```
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "mdns_example_main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,55 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps"
|
||||
|
||||
config MDNS_HOSTNAME
|
||||
string "mDNS Hostname"
|
||||
default "esp32-mdns"
|
||||
help
|
||||
mDNS Hostname for example to use
|
||||
|
||||
config MDNS_INSTANCE
|
||||
string "mDNS Instance Name"
|
||||
default "ESP32 with mDNS"
|
||||
help
|
||||
mDNS Instance Name for example to use
|
||||
|
||||
config MDNS_PUBLISH_DELEGATE_HOST
|
||||
bool "Publish a delegated host"
|
||||
help
|
||||
Enable publishing a delegated host other than ESP32.
|
||||
The example will also add a mock service for this host.
|
||||
|
||||
config MDNS_RESOLVE_TEST_SERVICES
|
||||
bool "Resolve test services"
|
||||
default n
|
||||
help
|
||||
Enable resolving test services on startup.
|
||||
These services are advertized and evaluated in automated tests.
|
||||
When executed locally, these will not be resolved and warnings appear in the log.
|
||||
Please set to false to disable initial querying to avoid warnings.
|
||||
|
||||
config MDNS_ADD_MAC_TO_HOSTNAME
|
||||
bool "Add mac suffix to hostname"
|
||||
default n
|
||||
help
|
||||
If enabled, a portion of MAC address is added to the hostname, this is used
|
||||
for evaluation of tests in CI
|
||||
|
||||
config MDNS_BUTTON_GPIO
|
||||
int "Button GPIO to trigger querries"
|
||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX
|
||||
default 0
|
||||
help
|
||||
Set the GPIO number used as mDNS test button
|
||||
|
||||
config MDNS_ADD_CUSTOM_NETIF
|
||||
bool "Add user netif to mdns service"
|
||||
default n
|
||||
help
|
||||
If enabled, we try to add a custom netif to mdns service.
|
||||
Note that for using with common connection example code, we have to disable
|
||||
all predefined interfaces in mdns component setup (since we're adding one
|
||||
of the default interfaces)
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,6 @@
|
||||
dependencies:
|
||||
espressif/mdns:
|
||||
version: ^1.0.0
|
||||
idf: '>=5.0'
|
||||
protocol_examples_common:
|
||||
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
|
||||
@@ -0,0 +1,423 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* MDNS-SD Query and advertise Example
|
||||
*/
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_netif_ip_addr.h"
|
||||
#include "esp_mac.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_netif.h"
|
||||
#include "protocol_examples_common.h"
|
||||
#include "mdns.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "netdb.h"
|
||||
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 1, 0)
|
||||
/* CONFIG_LWIP_IPV4 was introduced in IDF v5.1, set CONFIG_LWIP_IPV4 to 1 by default for IDF v5.0 */
|
||||
#ifndef CONFIG_LWIP_IPV4
|
||||
#define CONFIG_LWIP_IPV4 1
|
||||
#endif // CONFIG_LWIP_IPV4
|
||||
#endif // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 1, 0)
|
||||
|
||||
#define EXAMPLE_MDNS_INSTANCE CONFIG_MDNS_INSTANCE
|
||||
#define EXAMPLE_BUTTON_GPIO CONFIG_MDNS_BUTTON_GPIO
|
||||
|
||||
static const char *TAG = "mdns-test";
|
||||
static char *generate_hostname(void);
|
||||
|
||||
#if CONFIG_MDNS_RESOLVE_TEST_SERVICES == 1
|
||||
static void query_mdns_host_with_gethostbyname(char *host);
|
||||
static void query_mdns_host_with_getaddrinfo(char *host);
|
||||
#endif
|
||||
|
||||
static void initialise_mdns(void)
|
||||
{
|
||||
char *hostname = generate_hostname();
|
||||
|
||||
//initialize mDNS
|
||||
ESP_ERROR_CHECK(mdns_init());
|
||||
//set mDNS hostname (required if you want to advertise services)
|
||||
ESP_ERROR_CHECK(mdns_hostname_set(hostname));
|
||||
ESP_LOGI(TAG, "mdns hostname set to: [%s]", hostname);
|
||||
//set default mDNS instance name
|
||||
ESP_ERROR_CHECK(mdns_instance_name_set(EXAMPLE_MDNS_INSTANCE));
|
||||
|
||||
//structure with TXT records
|
||||
mdns_txt_item_t serviceTxtData[3] = {
|
||||
{"board", "esp32"},
|
||||
{"u", "user"},
|
||||
{"p", "password"}
|
||||
};
|
||||
|
||||
//initialize service
|
||||
ESP_ERROR_CHECK(mdns_service_add("ESP32-WebServer", "_http", "_tcp", 80, serviceTxtData, 3));
|
||||
ESP_ERROR_CHECK(mdns_service_subtype_add_for_host("ESP32-WebServer", "_http", "_tcp", NULL, "_server"));
|
||||
#if CONFIG_MDNS_MULTIPLE_INSTANCE
|
||||
ESP_ERROR_CHECK(mdns_service_add("ESP32-WebServer1", "_http", "_tcp", 80, NULL, 0));
|
||||
#endif
|
||||
|
||||
#if CONFIG_MDNS_PUBLISH_DELEGATE_HOST
|
||||
char *delegated_hostname;
|
||||
if (-1 == asprintf(&delegated_hostname, "%s-delegated", hostname)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
mdns_ip_addr_t addr4, addr6;
|
||||
esp_netif_str_to_ip4("10.0.0.1", &addr4.addr.u_addr.ip4);
|
||||
addr4.addr.type = ESP_IPADDR_TYPE_V4;
|
||||
esp_netif_str_to_ip6("fd11:22::1", &addr6.addr.u_addr.ip6);
|
||||
addr6.addr.type = ESP_IPADDR_TYPE_V6;
|
||||
addr4.next = &addr6;
|
||||
addr6.next = NULL;
|
||||
ESP_ERROR_CHECK(mdns_delegate_hostname_add(delegated_hostname, &addr4));
|
||||
ESP_ERROR_CHECK(mdns_service_add_for_host("test0", "_http", "_tcp", delegated_hostname, 1234, serviceTxtData, 3));
|
||||
free(delegated_hostname);
|
||||
#endif // CONFIG_MDNS_PUBLISH_DELEGATE_HOST
|
||||
|
||||
//add another TXT item
|
||||
ESP_ERROR_CHECK(mdns_service_txt_item_set("_http", "_tcp", "path", "/foobar"));
|
||||
//change TXT item value
|
||||
ESP_ERROR_CHECK(mdns_service_txt_item_set_with_explicit_value_len("_http", "_tcp", "u", "admin", strlen("admin")));
|
||||
free(hostname);
|
||||
}
|
||||
|
||||
/* these strings match mdns_ip_protocol_t enumeration */
|
||||
static const char *ip_protocol_str[] = {"V4", "V6", "MAX"};
|
||||
|
||||
static void mdns_print_results(mdns_result_t *results)
|
||||
{
|
||||
mdns_result_t *r = results;
|
||||
mdns_ip_addr_t *a = NULL;
|
||||
int i = 1, t;
|
||||
while (r) {
|
||||
if (r->esp_netif) {
|
||||
printf("%d: Interface: %s, Type: %s, TTL: %" PRIu32 "\n", i++, esp_netif_get_ifkey(r->esp_netif),
|
||||
ip_protocol_str[r->ip_protocol], r->ttl);
|
||||
}
|
||||
if (r->instance_name) {
|
||||
printf(" PTR : %s.%s.%s\n", r->instance_name, r->service_type, r->proto);
|
||||
}
|
||||
if (r->hostname) {
|
||||
printf(" SRV : %s.local:%u\n", r->hostname, r->port);
|
||||
}
|
||||
if (r->txt_count) {
|
||||
printf(" TXT : [%zu] ", r->txt_count);
|
||||
for (t = 0; t < r->txt_count; t++) {
|
||||
printf("%s=%s(%d); ", r->txt[t].key, r->txt[t].value ? r->txt[t].value : "NULL", r->txt_value_len[t]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
a = r->addr;
|
||||
while (a) {
|
||||
if (a->addr.type == ESP_IPADDR_TYPE_V6) {
|
||||
printf(" AAAA: " IPV6STR "\n", IPV62STR(a->addr.u_addr.ip6));
|
||||
} else {
|
||||
printf(" A : " IPSTR "\n", IP2STR(&(a->addr.u_addr.ip4)));
|
||||
}
|
||||
a = a->next;
|
||||
}
|
||||
r = r->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void query_mdns_service(const char *service_name, const char *proto)
|
||||
{
|
||||
ESP_LOGI(TAG, "Query PTR: %s.%s.local", service_name, proto);
|
||||
|
||||
mdns_result_t *results = NULL;
|
||||
esp_err_t err = mdns_query_ptr(service_name, proto, 3000, 20, &results);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Query Failed: %s", esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
if (!results) {
|
||||
ESP_LOGW(TAG, "No results found!");
|
||||
return;
|
||||
}
|
||||
|
||||
mdns_print_results(results);
|
||||
mdns_query_results_free(results);
|
||||
}
|
||||
|
||||
#if CONFIG_MDNS_PUBLISH_DELEGATE_HOST
|
||||
static void lookup_mdns_delegated_service(const char *service_name, const char *proto)
|
||||
{
|
||||
ESP_LOGI(TAG, "Lookup delegated service: %s.%s.local", service_name, proto);
|
||||
|
||||
mdns_result_t *results = NULL;
|
||||
esp_err_t err = mdns_lookup_delegated_service(NULL, service_name, proto, 20, &results);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Lookup Failed: %s", esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
if (!results) {
|
||||
ESP_LOGW(TAG, "No results found!");
|
||||
return;
|
||||
}
|
||||
|
||||
mdns_print_results(results);
|
||||
mdns_query_results_free(results);
|
||||
}
|
||||
#endif // CONFIG_MDNS_PUBLISH_DELEGATE_HOST
|
||||
|
||||
static void lookup_mdns_selfhosted_service(const char *service_name, const char *proto)
|
||||
{
|
||||
ESP_LOGI(TAG, "Lookup selfhosted service: %s.%s.local", service_name, proto);
|
||||
mdns_result_t *results = NULL;
|
||||
esp_err_t err = mdns_lookup_selfhosted_service(NULL, service_name, proto, 20, &results);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Lookup Failed: %s", esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
if (!results) {
|
||||
ESP_LOGW(TAG, "No results found!");
|
||||
return;
|
||||
}
|
||||
mdns_print_results(results);
|
||||
mdns_query_results_free(results);
|
||||
}
|
||||
|
||||
static bool check_and_print_result(mdns_search_once_t *search)
|
||||
{
|
||||
// Check if any result is available
|
||||
mdns_result_t *result = NULL;
|
||||
if (!mdns_query_async_get_results(search, 0, &result, NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!result) { // search timeout, but no result
|
||||
return true;
|
||||
}
|
||||
|
||||
// If yes, print the result
|
||||
mdns_ip_addr_t *a = result->addr;
|
||||
while (a) {
|
||||
if (a->addr.type == ESP_IPADDR_TYPE_V6) {
|
||||
printf(" AAAA: " IPV6STR "\n", IPV62STR(a->addr.u_addr.ip6));
|
||||
} else {
|
||||
printf(" A : " IPSTR "\n", IP2STR(&(a->addr.u_addr.ip4)));
|
||||
}
|
||||
a = a->next;
|
||||
}
|
||||
// and free the result
|
||||
mdns_query_results_free(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void query_mdns_hosts_async(const char *host_name)
|
||||
{
|
||||
ESP_LOGI(TAG, "Query both A and AAA: %s.local", host_name);
|
||||
|
||||
mdns_search_once_t *s_a = mdns_query_async_new(host_name, NULL, NULL, MDNS_TYPE_A, 1000, 1, NULL);
|
||||
mdns_search_once_t *s_aaaa = mdns_query_async_new(host_name, NULL, NULL, MDNS_TYPE_AAAA, 1000, 1, NULL);
|
||||
while (s_a || s_aaaa) {
|
||||
if (s_a && check_and_print_result(s_a)) {
|
||||
ESP_LOGI(TAG, "Query A %s.local finished", host_name);
|
||||
mdns_query_async_delete(s_a);
|
||||
s_a = NULL;
|
||||
}
|
||||
if (s_aaaa && check_and_print_result(s_aaaa)) {
|
||||
ESP_LOGI(TAG, "Query AAAA %s.local finished", host_name);
|
||||
mdns_query_async_delete(s_aaaa);
|
||||
s_aaaa = NULL;
|
||||
}
|
||||
vTaskDelay(50 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_LWIP_IPV4
|
||||
static void query_mdns_host(const char *host_name)
|
||||
{
|
||||
ESP_LOGI(TAG, "Query A: %s.local", host_name);
|
||||
|
||||
struct esp_ip4_addr addr;
|
||||
addr.addr = 0;
|
||||
|
||||
esp_err_t err = mdns_query_a(host_name, 2000, &addr);
|
||||
if (err) {
|
||||
if (err == ESP_ERR_NOT_FOUND) {
|
||||
ESP_LOGW(TAG, "%s: Host was not found!", esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
ESP_LOGE(TAG, "Query Failed: %s", esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Query A: %s.local resolved to: " IPSTR, host_name, IP2STR(&addr));
|
||||
}
|
||||
#endif // CONFIG_LWIP_IPV4
|
||||
|
||||
static void initialise_button(void)
|
||||
{
|
||||
gpio_config_t io_conf = {0};
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.pin_bit_mask = BIT64(EXAMPLE_BUTTON_GPIO);
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
io_conf.pull_up_en = 1;
|
||||
io_conf.pull_down_en = 0;
|
||||
gpio_config(&io_conf);
|
||||
}
|
||||
|
||||
static void check_button(void)
|
||||
{
|
||||
static bool old_level = true;
|
||||
bool new_level = gpio_get_level(EXAMPLE_BUTTON_GPIO);
|
||||
if (!new_level && old_level) {
|
||||
query_mdns_hosts_async("esp32-mdns");
|
||||
#ifdef CONFIG_LWIP_IPV4
|
||||
query_mdns_host("esp32");
|
||||
#endif
|
||||
query_mdns_service("_arduino", "_tcp");
|
||||
query_mdns_service("_http", "_tcp");
|
||||
query_mdns_service("_printer", "_tcp");
|
||||
query_mdns_service("_ipp", "_tcp");
|
||||
query_mdns_service("_afpovertcp", "_tcp");
|
||||
query_mdns_service("_smb", "_tcp");
|
||||
query_mdns_service("_ftp", "_tcp");
|
||||
query_mdns_service("_nfs", "_tcp");
|
||||
#if CONFIG_MDNS_PUBLISH_DELEGATE_HOST
|
||||
lookup_mdns_delegated_service("_http", "_tcp");
|
||||
#endif // CONFIG_MDNS_PUBLISH_DELEGATE_HOST
|
||||
lookup_mdns_selfhosted_service("_http", "_tcp");
|
||||
}
|
||||
old_level = new_level;
|
||||
}
|
||||
|
||||
static void mdns_example_task(void *pvParameters)
|
||||
{
|
||||
#if CONFIG_MDNS_RESOLVE_TEST_SERVICES == 1
|
||||
/* Send initial queries that are started by CI tester */
|
||||
#ifdef CONFIG_LWIP_IPV4
|
||||
query_mdns_host("tinytester");
|
||||
#endif
|
||||
query_mdns_host_with_gethostbyname("tinytester-lwip.local");
|
||||
query_mdns_host_with_getaddrinfo("tinytester-lwip.local");
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
check_button();
|
||||
vTaskDelay(50 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
ESP_LOGI(TAG, "mDNS Ver: %s", ESP_MDNS_VERSION_NUMBER);
|
||||
|
||||
initialise_mdns();
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
#if defined(CONFIG_MDNS_ADD_CUSTOM_NETIF) && !defined(CONFIG_MDNS_PREDEF_NETIF_STA) && !defined(CONFIG_MDNS_PREDEF_NETIF_ETH)
|
||||
/* Demonstration of adding a custom netif to mdns service, but we're adding the default example one,
|
||||
* so we must disable all predefined interfaces (PREDEF_NETIF_STA, AP and ETH) first
|
||||
*/
|
||||
ESP_ERROR_CHECK(mdns_register_netif(EXAMPLE_INTERFACE));
|
||||
/* It is not enough to just register the interface, we have to enable is manually.
|
||||
* This is typically performed in "GOT_IP" event handler, but we call it here directly
|
||||
* since the `EXAMPLE_INTERFACE` netif is connected already, to keep the example simple.
|
||||
*/
|
||||
ESP_ERROR_CHECK(mdns_netif_action(EXAMPLE_INTERFACE, MDNS_EVENT_ENABLE_IP4 | MDNS_EVENT_ENABLE_IP6));
|
||||
ESP_ERROR_CHECK(mdns_netif_action(EXAMPLE_INTERFACE, MDNS_EVENT_ANNOUNCE_IP4 | MDNS_EVENT_ANNOUNCE_IP6));
|
||||
|
||||
#if defined(CONFIG_MDNS_RESPOND_REVERSE_QUERIES)
|
||||
ESP_ERROR_CHECK(mdns_netif_action(EXAMPLE_INTERFACE, MDNS_EVENT_IP4_REVERSE_LOOKUP | MDNS_EVENT_IP6_REVERSE_LOOKUP));
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_MDNS_ADD_CUSTOM_NETIF
|
||||
|
||||
initialise_button();
|
||||
xTaskCreate(&mdns_example_task, "mdns_example_task", 2048, NULL, 5, NULL);
|
||||
}
|
||||
|
||||
/** Generate host name based on sdkconfig, optionally adding a portion of MAC address to it.
|
||||
* @return host name string allocated from the heap
|
||||
*/
|
||||
static char *generate_hostname(void)
|
||||
{
|
||||
#ifndef CONFIG_MDNS_ADD_MAC_TO_HOSTNAME
|
||||
return strdup(CONFIG_MDNS_HOSTNAME);
|
||||
#else
|
||||
uint8_t mac[6];
|
||||
char *hostname;
|
||||
esp_read_mac(mac, ESP_MAC_WIFI_STA);
|
||||
if (-1 == asprintf(&hostname, "%s-%02X%02X%02X", CONFIG_MDNS_HOSTNAME, mac[3], mac[4], mac[5])) {
|
||||
abort();
|
||||
}
|
||||
return hostname;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_MDNS_RESOLVE_TEST_SERVICES == 1
|
||||
/**
|
||||
* @brief Executes gethostbyname and displays list of resolved addresses.
|
||||
* Note: This function is used only to test advertised mdns hostnames resolution
|
||||
*/
|
||||
static void query_mdns_host_with_gethostbyname(char *host)
|
||||
{
|
||||
struct hostent *res = gethostbyname(host);
|
||||
if (res) {
|
||||
unsigned int i = 0;
|
||||
while (res->h_addr_list[i] != NULL) {
|
||||
ESP_LOGI(TAG, "gethostbyname: %s resolved to: %s", host,
|
||||
#if defined(CONFIG_LWIP_IPV6) && defined(CONFIG_LWIP_IPV4)
|
||||
res->h_addrtype == AF_INET ? inet_ntoa(*(struct in_addr *)(res->h_addr_list[i])) :
|
||||
inet6_ntoa(*(struct in6_addr *)(res->h_addr_list[i]))
|
||||
#elif defined(CONFIG_LWIP_IPV6)
|
||||
inet6_ntoa(*(struct in6_addr *)(res->h_addr_list[i]))
|
||||
#else
|
||||
inet_ntoa(*(struct in_addr *)(res->h_addr_list[i]))
|
||||
#endif
|
||||
);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Executes getaddrinfo and displays list of resolved addresses.
|
||||
* Note: This function is used only to test advertised mdns hostnames resolution
|
||||
*/
|
||||
static void query_mdns_host_with_getaddrinfo(char *host)
|
||||
{
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *res;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
if (!getaddrinfo(host, NULL, &hints, &res)) {
|
||||
while (res) {
|
||||
char *resolved_addr;
|
||||
#if defined(CONFIG_LWIP_IPV6) && defined(CONFIG_LWIP_IPV4)
|
||||
resolved_addr = res->ai_family == AF_INET ?
|
||||
inet_ntoa(((struct sockaddr_in *) res->ai_addr)->sin_addr) :
|
||||
inet6_ntoa(((struct sockaddr_in6 *) res->ai_addr)->sin6_addr);
|
||||
#elif defined(CONFIG_LWIP_IPV6)
|
||||
resolved_addr = inet6_ntoa(((struct sockaddr_in6 *) res->ai_addr)->sin6_addr);
|
||||
#else
|
||||
resolved_addr = inet_ntoa(((struct sockaddr_in *) res->ai_addr)->sin_addr);
|
||||
#endif // CONFIG_LWIP_IPV6
|
||||
ESP_LOGI(TAG, "getaddrinfo: %s resolved to: %s", host, resolved_addr);
|
||||
res = res->ai_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,203 @@
|
||||
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import re
|
||||
import select
|
||||
import socket
|
||||
import struct
|
||||
import subprocess
|
||||
import time
|
||||
from threading import Event, Thread
|
||||
|
||||
try:
|
||||
import dpkt
|
||||
import dpkt.dns
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
def get_dns_query_for_esp(esp_host):
|
||||
dns = dpkt.dns.DNS(
|
||||
b'\x00\x00\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01'
|
||||
)
|
||||
dns.qd[0].name = esp_host + u'.local'
|
||||
print('Created query for esp host: {} '.format(dns.__repr__()))
|
||||
return dns.pack()
|
||||
|
||||
|
||||
def get_dns_answer_to_mdns(tester_host):
|
||||
dns = dpkt.dns.DNS(
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
)
|
||||
dns.op = dpkt.dns.DNS_QR | dpkt.dns.DNS_AA
|
||||
dns.rcode = dpkt.dns.DNS_RCODE_NOERR
|
||||
arr = dpkt.dns.DNS.RR()
|
||||
arr.cls = dpkt.dns.DNS_IN
|
||||
arr.type = dpkt.dns.DNS_A
|
||||
arr.name = tester_host
|
||||
arr.ip = socket.inet_aton('127.0.0.1')
|
||||
dns.an.append(arr)
|
||||
print('Created answer to mdns query: {} '.format(dns.__repr__()))
|
||||
return dns.pack()
|
||||
|
||||
|
||||
def get_dns_answer_to_mdns_lwip(tester_host, id):
|
||||
dns = dpkt.dns.DNS(
|
||||
b'\x5e\x39\x84\x00\x00\x01\x00\x01\x00\x00\x00\x00\x0a\x64\x61\x76\x69\x64'
|
||||
b'\x2d\x63\x6f\x6d\x70\x05\x6c\x6f\x63\x61\x6c\x00\x00\x01\x00\x01\xc0\x0c'
|
||||
b'\x00\x01\x00\x01\x00\x00\x00\x0a\x00\x04\xc0\xa8\x0a\x6c')
|
||||
dns.qd[0].name = tester_host
|
||||
dns.an[0].name = tester_host
|
||||
dns.an[0].ip = socket.inet_aton('127.0.0.1')
|
||||
dns.an[0].rdata = socket.inet_aton('127.0.0.1')
|
||||
dns.id = id
|
||||
print('Created answer to mdns (lwip) query: {} '.format(dns.__repr__()))
|
||||
return dns.pack()
|
||||
|
||||
|
||||
def mdns_server(esp_host, events):
|
||||
UDP_IP = '0.0.0.0'
|
||||
UDP_PORT = 5353
|
||||
MCAST_GRP = '224.0.0.251'
|
||||
TESTER_NAME = u'tinytester.local'
|
||||
TESTER_NAME_LWIP = u'tinytester-lwip.local'
|
||||
QUERY_TIMEOUT = 0.2
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
|
||||
sock.setblocking(False)
|
||||
sock.bind((UDP_IP, UDP_PORT))
|
||||
mreq = struct.pack('4sl', socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
|
||||
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
|
||||
last_query_timepoint = time.time()
|
||||
while not events['stop'].is_set():
|
||||
try:
|
||||
current_time = time.time()
|
||||
if current_time - last_query_timepoint > QUERY_TIMEOUT:
|
||||
last_query_timepoint = current_time
|
||||
if not events['esp_answered'].is_set():
|
||||
sock.sendto(get_dns_query_for_esp(esp_host),
|
||||
(MCAST_GRP, UDP_PORT))
|
||||
if not events['esp_delegated_answered'].is_set():
|
||||
sock.sendto(get_dns_query_for_esp(esp_host + '-delegated'),
|
||||
(MCAST_GRP, UDP_PORT))
|
||||
timeout = max(
|
||||
0, QUERY_TIMEOUT - (current_time - last_query_timepoint))
|
||||
read_socks, _, _ = select.select([sock], [], [], timeout)
|
||||
if not read_socks:
|
||||
continue
|
||||
data, addr = sock.recvfrom(1024)
|
||||
dns = dpkt.dns.DNS(data)
|
||||
if len(dns.qd) > 0:
|
||||
for dns_query in dns.qd:
|
||||
if dns_query.type == dpkt.dns.DNS_A:
|
||||
if dns_query.name == TESTER_NAME:
|
||||
print('Received query: {} '.format(dns.__repr__()))
|
||||
sock.sendto(get_dns_answer_to_mdns(TESTER_NAME),
|
||||
(MCAST_GRP, UDP_PORT))
|
||||
elif dns_query.name == TESTER_NAME_LWIP:
|
||||
print('Received query: {} '.format(dns.__repr__()))
|
||||
sock.sendto(
|
||||
get_dns_answer_to_mdns_lwip(TESTER_NAME_LWIP, dns.id),
|
||||
addr)
|
||||
if len(dns.an) > 0:
|
||||
for dns_answer in dns.an:
|
||||
if dns_answer.type == dpkt.dns.DNS_A:
|
||||
print('Received answer from {}'.format(dns_answer.name))
|
||||
if dns_answer.name == esp_host + u'.local':
|
||||
print('Received answer to esp32-mdns query: {}'.format(
|
||||
dns.__repr__()))
|
||||
events['esp_answered'].set()
|
||||
if dns_answer.name == esp_host + u'-delegated.local':
|
||||
print('Received answer to esp32-mdns-delegate query: {}'.format(
|
||||
dns.__repr__()))
|
||||
events['esp_delegated_answered'].set()
|
||||
except socket.timeout:
|
||||
break
|
||||
except dpkt.UnpackError:
|
||||
continue
|
||||
|
||||
|
||||
def test_examples_protocol_mdns(dut):
|
||||
"""
|
||||
steps: |
|
||||
1. obtain IP address + init mdns example
|
||||
2. get the dut host name (and IP address)
|
||||
3. check the mdns name is accessible
|
||||
4. check DUT output if mdns advertized host is resolved
|
||||
5. check if DUT responds to dig
|
||||
6. check the DUT is searchable via reverse IP lookup
|
||||
"""
|
||||
|
||||
specific_host = dut.expect(r'mdns hostname set to: \[(.*?)\]')[1].decode()
|
||||
|
||||
mdns_server_events = {
|
||||
'stop': Event(),
|
||||
'esp_answered': Event(),
|
||||
'esp_delegated_answered': Event()
|
||||
}
|
||||
mdns_responder = Thread(target=mdns_server,
|
||||
args=(str(specific_host), mdns_server_events))
|
||||
ip_addresses = []
|
||||
if dut.app.sdkconfig.get('LWIP_IPV4') is True:
|
||||
ipv4 = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]',
|
||||
timeout=30)[1].decode()
|
||||
ip_addresses.append(ipv4)
|
||||
if dut.app.sdkconfig.get('LWIP_IPV6') is True:
|
||||
ipv6_r = r':'.join((r'[0-9a-fA-F]{4}', ) * 8)
|
||||
ipv6 = dut.expect(ipv6_r, timeout=30)[0].decode()
|
||||
ip_addresses.append(ipv6)
|
||||
print('Connected with IP addresses: {}'.format(','.join(ip_addresses)))
|
||||
try:
|
||||
# TODO: Add test for example disabling IPV4
|
||||
mdns_responder.start()
|
||||
if dut.app.sdkconfig.get('LWIP_IPV4') is True:
|
||||
# 3. check the mdns name is accessible.
|
||||
if not mdns_server_events['esp_answered'].wait(timeout=30):
|
||||
raise ValueError(
|
||||
'Test has failed: did not receive mdns answer within timeout')
|
||||
if not mdns_server_events['esp_delegated_answered'].wait(timeout=30):
|
||||
raise ValueError(
|
||||
'Test has failed: did not receive mdns answer for delegated host within timeout'
|
||||
)
|
||||
# 4. check DUT output if mdns advertized host is resolved
|
||||
dut.expect(
|
||||
re.compile(
|
||||
b'mdns-test: Query A: tinytester.local resolved to: 127.0.0.1')
|
||||
)
|
||||
dut.expect(
|
||||
re.compile(
|
||||
b'mdns-test: gethostbyname: tinytester-lwip.local resolved to: 127.0.0.1'
|
||||
))
|
||||
dut.expect(
|
||||
re.compile(
|
||||
b'mdns-test: getaddrinfo: tinytester-lwip.local resolved to: 127.0.0.1'
|
||||
))
|
||||
# 5. check the DUT answers to `dig` command
|
||||
dig_output = subprocess.check_output([
|
||||
'dig', '+short', '-p', '5353', '@224.0.0.251',
|
||||
'{}.local'.format(specific_host)
|
||||
])
|
||||
print('Resolving {} using "dig" succeeded with:\n{}'.format(
|
||||
specific_host, dig_output))
|
||||
if not ipv4.encode('utf-8') in dig_output:
|
||||
raise ValueError(
|
||||
'Test has failed: Incorrectly resolved DUT hostname using dig'
|
||||
"Output should've contained DUT's IP address:{}".format(ipv4))
|
||||
# 6. check the DUT reverse lookup
|
||||
if dut.app.sdkconfig.get('MDNS_RESPOND_REVERSE_QUERIES') is True:
|
||||
for ip_address in ip_addresses:
|
||||
dig_output = subprocess.check_output([
|
||||
'dig', '+short', '-p', '5353', '@224.0.0.251', '-x',
|
||||
'{}'.format(ip_address)
|
||||
])
|
||||
print('Reverse lookup for {} using "dig" succeeded with:\n{}'.
|
||||
format(ip_address, dig_output))
|
||||
if specific_host not in dig_output.decode():
|
||||
raise ValueError(
|
||||
'Test has failed: Incorrectly resolved DUT IP address using dig'
|
||||
"Output should've contained DUT's name:{}".format(
|
||||
specific_host))
|
||||
|
||||
finally:
|
||||
mdns_server_events['stop'].set()
|
||||
mdns_responder.join()
|
||||
@@ -0,0 +1,21 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_MDNS_RESOLVE_TEST_SERVICES=y
|
||||
CONFIG_MDNS_ADD_MAC_TO_HOSTNAME=y
|
||||
CONFIG_MDNS_PUBLISH_DELEGATE_HOST=y
|
||||
CONFIG_MDNS_PREDEF_NETIF_STA=n
|
||||
CONFIG_MDNS_PREDEF_NETIF_AP=n
|
||||
CONFIG_MDNS_PREDEF_NETIF_ETH=n
|
||||
CONFIG_MDNS_ADD_CUSTOM_NETIF=y
|
||||
CONFIG_MDNS_RESPOND_REVERSE_QUERIES=y
|
||||
CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_EXAMPLE_ETH_PHY_IP101=y
|
||||
CONFIG_EXAMPLE_ETH_PHY_GENERIC=y
|
||||
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
|
||||
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
|
||||
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
|
||||
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=y
|
||||
CONFIG_MDNS_BUTTON_GPIO=32
|
||||
@@ -0,0 +1,15 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_MDNS_RESOLVE_TEST_SERVICES=y
|
||||
CONFIG_MDNS_ADD_MAC_TO_HOSTNAME=y
|
||||
CONFIG_MDNS_PUBLISH_DELEGATE_HOST=y
|
||||
CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_EXAMPLE_ETH_PHY_IP101=y
|
||||
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
|
||||
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
|
||||
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
|
||||
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=y
|
||||
CONFIG_MDNS_BUTTON_GPIO=32
|
||||
@@ -0,0 +1,15 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_MDNS_RESOLVE_TEST_SERVICES=y
|
||||
CONFIG_MDNS_ADD_MAC_TO_HOSTNAME=y
|
||||
CONFIG_MDNS_PUBLISH_DELEGATE_HOST=y
|
||||
CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y
|
||||
CONFIG_LWIP_IPV4=n
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_EXAMPLE_ETH_PHY_IP101=y
|
||||
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
|
||||
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
|
||||
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
|
||||
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
|
||||
CONFIG_MDNS_BUTTON_GPIO=32
|
||||
@@ -0,0 +1,16 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_MDNS_RESOLVE_TEST_SERVICES=y
|
||||
CONFIG_MDNS_ADD_MAC_TO_HOSTNAME=y
|
||||
CONFIG_MDNS_PUBLISH_DELEGATE_HOST=y
|
||||
CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y
|
||||
CONFIG_LWIP_IPV6=n
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=n
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_EXAMPLE_ETH_PHY_IP101=y
|
||||
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
|
||||
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
|
||||
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
|
||||
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
|
||||
CONFIG_MDNS_BUTTON_GPIO=32
|
||||
@@ -0,0 +1,16 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_MDNS_RESOLVE_TEST_SERVICES=y
|
||||
CONFIG_MDNS_ADD_MAC_TO_HOSTNAME=y
|
||||
CONFIG_MDNS_PUBLISH_DELEGATE_HOST=y
|
||||
CONFIG_MDNS_NETWORKING_SOCKET=y
|
||||
CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_EXAMPLE_ETH_PHY_IP101=y
|
||||
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
|
||||
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
|
||||
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
|
||||
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=y
|
||||
CONFIG_MDNS_BUTTON_GPIO=32
|
||||
13
managed_components/espressif__mdns/idf_component.yml
Normal file
13
managed_components/espressif__mdns/idf_component.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
dependencies:
|
||||
idf:
|
||||
version: '>=5.0'
|
||||
description: Multicast UDP service used to provide local network service and host
|
||||
discovery.
|
||||
documentation: https://docs.espressif.com/projects/esp-protocols/mdns/docs/latest/en/index.html
|
||||
issues: https://github.com/espressif/esp-protocols/issues
|
||||
repository: git://github.com/espressif/esp-protocols.git
|
||||
repository_info:
|
||||
commit_sha: 3bfa00389de6f0d6d40efda8bea808380899a43d
|
||||
path: components/mdns
|
||||
url: https://github.com/espressif/esp-protocols/tree/master/components/mdns
|
||||
version: 1.9.1
|
||||
937
managed_components/espressif__mdns/include/mdns.h
Normal file
937
managed_components/espressif__mdns/include/mdns.h
Normal file
@@ -0,0 +1,937 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef ESP_MDNS_H_
|
||||
#define ESP_MDNS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include <esp_netif.h>
|
||||
|
||||
#define MDNS_TYPE_A 0x0001
|
||||
#define MDNS_TYPE_PTR 0x000C
|
||||
#define MDNS_TYPE_TXT 0x0010
|
||||
#define MDNS_TYPE_AAAA 0x001C
|
||||
#define MDNS_TYPE_SRV 0x0021
|
||||
#define MDNS_TYPE_OPT 0x0029
|
||||
#define MDNS_TYPE_NSEC 0x002F
|
||||
#define MDNS_TYPE_ANY 0x00FF
|
||||
|
||||
#if defined(CONFIG_LWIP_IPV6) && defined(CONFIG_MDNS_RESPOND_REVERSE_QUERIES)
|
||||
#define MDNS_NAME_MAX_LEN (64+4) // Need to account for IPv6 reverse queries (64 char address + ".ip6" )
|
||||
#else
|
||||
#define MDNS_NAME_MAX_LEN 64 // Maximum string length of hostname, instance, service and proto
|
||||
#endif
|
||||
#define MDNS_NAME_BUF_LEN (MDNS_NAME_MAX_LEN+1) // Maximum char buffer size to hold hostname, instance, service or proto
|
||||
|
||||
/**
|
||||
* @brief Asynchronous query handle
|
||||
*/
|
||||
typedef struct mdns_search_once_s mdns_search_once_t;
|
||||
|
||||
/**
|
||||
* @brief Daemon query handle
|
||||
*/
|
||||
typedef struct mdns_browse_s mdns_browse_t;
|
||||
|
||||
typedef enum {
|
||||
MDNS_EVENT_ENABLE_IP4 = 1 << 1,
|
||||
MDNS_EVENT_ENABLE_IP6 = 1 << 2,
|
||||
MDNS_EVENT_ANNOUNCE_IP4 = 1 << 3,
|
||||
MDNS_EVENT_ANNOUNCE_IP6 = 1 << 4,
|
||||
MDNS_EVENT_DISABLE_IP4 = 1 << 5,
|
||||
MDNS_EVENT_DISABLE_IP6 = 1 << 6,
|
||||
MDNS_EVENT_IP4_REVERSE_LOOKUP = 1 << 7,
|
||||
MDNS_EVENT_IP6_REVERSE_LOOKUP = 1 << 8,
|
||||
} mdns_event_actions_t;
|
||||
|
||||
/**
|
||||
* @brief mDNS enum to specify the ip_protocol type
|
||||
*/
|
||||
typedef enum {
|
||||
MDNS_IP_PROTOCOL_V4,
|
||||
MDNS_IP_PROTOCOL_V6,
|
||||
MDNS_IP_PROTOCOL_MAX
|
||||
} mdns_ip_protocol_t;
|
||||
|
||||
/**
|
||||
* @brief mDNS basic text item structure
|
||||
* Used in mdns_service_add()
|
||||
*/
|
||||
typedef struct {
|
||||
const char *key; /*!< item key name */
|
||||
const char *value; /*!< item value string */
|
||||
} mdns_txt_item_t;
|
||||
|
||||
/**
|
||||
* @brief mDNS basic subtype item structure
|
||||
* Used in mdns_service_subtype_xxx() APIs
|
||||
*/
|
||||
typedef struct {
|
||||
const char *subtype; /*!< subtype name */
|
||||
} mdns_subtype_item_t;
|
||||
|
||||
/**
|
||||
* @brief mDNS query linked list IP item
|
||||
*/
|
||||
typedef struct mdns_ip_addr_s {
|
||||
esp_ip_addr_t addr; /*!< IP address */
|
||||
struct mdns_ip_addr_s *next; /*!< next IP, or NULL for the last IP in the list */
|
||||
} mdns_ip_addr_t;
|
||||
|
||||
/**
|
||||
* @brief mDNS query type to be explicitly set to either Unicast or Multicast
|
||||
*/
|
||||
typedef enum {
|
||||
MDNS_QUERY_UNICAST,
|
||||
MDNS_QUERY_MULTICAST,
|
||||
} mdns_query_transmission_type_t;
|
||||
|
||||
/**
|
||||
* @brief mDNS query result structure
|
||||
*/
|
||||
typedef struct mdns_result_s {
|
||||
struct mdns_result_s *next; /*!< next result, or NULL for the last result in the list */
|
||||
|
||||
esp_netif_t *esp_netif; /*!< ptr to corresponding esp-netif */
|
||||
uint32_t ttl; /*!< time to live */
|
||||
|
||||
mdns_ip_protocol_t ip_protocol; /*!< ip_protocol type of the interface (v4/v6) */
|
||||
// PTR
|
||||
char *instance_name; /*!< instance name */
|
||||
char *service_type; /*!< service type */
|
||||
char *proto; /*!< srevice protocol */
|
||||
// SRV
|
||||
char *hostname; /*!< hostname */
|
||||
uint16_t port; /*!< service port */
|
||||
// TXT
|
||||
mdns_txt_item_t *txt; /*!< txt record */
|
||||
uint8_t *txt_value_len; /*!< array of txt value len of each record */
|
||||
size_t txt_count; /*!< number of txt items */
|
||||
// A and AAAA
|
||||
mdns_ip_addr_t *addr; /*!< linked list of IP addresses found */
|
||||
} mdns_result_t;
|
||||
|
||||
typedef void (*mdns_query_notify_t)(mdns_search_once_t *search);
|
||||
typedef void (*mdns_browse_notify_t)(mdns_result_t *result);
|
||||
|
||||
/**
|
||||
* @brief Initialize mDNS on given interface
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_INVALID_STATE when failed to register event handler
|
||||
* - ESP_ERR_NO_MEM on memory error
|
||||
* - ESP_FAIL when failed to start mdns task
|
||||
*/
|
||||
esp_err_t mdns_init(void);
|
||||
|
||||
/**
|
||||
* @brief Stop and free mDNS server
|
||||
*
|
||||
*/
|
||||
void mdns_free(void);
|
||||
|
||||
/**
|
||||
* @brief Set the hostname for mDNS server
|
||||
* required if you want to advertise services
|
||||
*
|
||||
* @param hostname Hostname to set
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*/
|
||||
esp_err_t mdns_hostname_set(const char *hostname);
|
||||
|
||||
/**
|
||||
* @brief Get the hostname for mDNS server
|
||||
*
|
||||
* @param hostname pointer to the hostname, it should be allocated
|
||||
* and hold at least MDNS_NAME_BUF_LEN chars
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_INVALID_STATE when mdns is not initialized
|
||||
*/
|
||||
esp_err_t mdns_hostname_get(char *hostname);
|
||||
|
||||
/**
|
||||
* @brief Adds a hostname and address to be delegated
|
||||
* A/AAAA queries will be replied for the hostname and
|
||||
* services can be added to this host.
|
||||
*
|
||||
* @param hostname Hostname to add
|
||||
* @param address_list The IP address list of the host
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_STATE mDNS is not running
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*
|
||||
*/
|
||||
esp_err_t mdns_delegate_hostname_add(const char *hostname, const mdns_ip_addr_t *address_list);
|
||||
|
||||
/**
|
||||
* @brief Set the address to a delegated hostname
|
||||
*
|
||||
* @param hostname Hostname to set
|
||||
* @param address_list The IP address list of the host
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_STATE mDNS is not running
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*
|
||||
*/
|
||||
esp_err_t mdns_delegate_hostname_set_address(const char *hostname, const mdns_ip_addr_t *address_list);
|
||||
|
||||
/**
|
||||
* @brief Remove a delegated hostname
|
||||
* All the services added to this host will also be removed.
|
||||
*
|
||||
* @param hostname Hostname to remove
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_STATE mDNS is not running
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*
|
||||
*/
|
||||
esp_err_t mdns_delegate_hostname_remove(const char *hostname);
|
||||
|
||||
/**
|
||||
* @brief Query whether a hostname has been added
|
||||
*
|
||||
* @param hostname Hostname to query
|
||||
*
|
||||
* @return
|
||||
* - true The hostname has been added.
|
||||
* - false The hostname has not been added.
|
||||
*
|
||||
*/
|
||||
bool mdns_hostname_exists(const char *hostname);
|
||||
|
||||
/**
|
||||
* @brief Set the default instance name for mDNS server
|
||||
*
|
||||
* @param instance_name Instance name to set
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*/
|
||||
esp_err_t mdns_instance_name_set(const char *instance_name);
|
||||
|
||||
/**
|
||||
* @brief Add service to mDNS server
|
||||
*
|
||||
* @note The value length of txt items will be automatically decided by strlen
|
||||
*
|
||||
* @param instance_name instance name to set. If NULL,
|
||||
* global instance name or hostname will be used.
|
||||
* Note that MDNS_MULTIPLE_INSTANCE config option
|
||||
* needs to be enabled for adding multiple instances
|
||||
* with the same instance type.
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param port service port
|
||||
* @param txt string array of TXT data (eg. {{"var","val"},{"other","2"}})
|
||||
* @param num_items number of items in TXT data
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
* - ESP_FAIL failed to add service
|
||||
*/
|
||||
esp_err_t mdns_service_add(const char *instance_name, const char *service_type, const char *proto, uint16_t port, mdns_txt_item_t txt[], size_t num_items);
|
||||
|
||||
/**
|
||||
* @brief Add service to mDNS server with a delegated hostname
|
||||
*
|
||||
* @note The value length of txt items will be automatically decided by strlen
|
||||
*
|
||||
* @param instance_name instance name to set. If NULL,
|
||||
* global instance name or hostname will be used
|
||||
* Note that MDNS_MULTIPLE_INSTANCE config option
|
||||
* needs to be enabled for adding multiple instances
|
||||
* with the same instance type.
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param hostname service hostname. If NULL, local hostname will be used.
|
||||
* @param port service port
|
||||
* @param txt string array of TXT data (eg. {{"var","val"},{"other","2"}})
|
||||
* @param num_items number of items in TXT data
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
* - ESP_FAIL failed to add service
|
||||
*/
|
||||
esp_err_t mdns_service_add_for_host(const char *instance_name, const char *service_type, const char *proto,
|
||||
const char *hostname, uint16_t port, mdns_txt_item_t txt[], size_t num_items);
|
||||
|
||||
/**
|
||||
* @brief Check whether a service has been added.
|
||||
*
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param hostname service hostname. If NULL, checks for the local hostname.
|
||||
*
|
||||
* @return
|
||||
* - true Correspondding service has been added.
|
||||
* - false Service not found.
|
||||
*/
|
||||
bool mdns_service_exists(const char *service_type, const char *proto, const char *hostname);
|
||||
|
||||
/**
|
||||
* @brief Check whether a service has been added.
|
||||
*
|
||||
* @param instance instance name
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param hostname service hostname. If NULL, checks for the local hostname.
|
||||
*
|
||||
* @return
|
||||
* - true Correspondding service has been added.
|
||||
* - false Service not found.
|
||||
*/
|
||||
bool mdns_service_exists_with_instance(const char *instance, const char *service_type, const char *proto,
|
||||
const char *hostname);
|
||||
|
||||
/**
|
||||
* @brief Remove service from mDNS server
|
||||
*
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NOT_FOUND Service not found
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*/
|
||||
esp_err_t mdns_service_remove(const char *service_type, const char *proto);
|
||||
|
||||
/**
|
||||
* @brief Remove service from mDNS server with hostname
|
||||
*
|
||||
* @param instance instance name
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param hostname service hostname. If NULL, local hostname will be used.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NOT_FOUND Service not found
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*/
|
||||
esp_err_t mdns_service_remove_for_host(const char *instance, const char *service_type, const char *proto, const char *hostname);
|
||||
|
||||
/**
|
||||
* @brief Set instance name for service
|
||||
*
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param instance_name instance name to set
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NOT_FOUND Service not found
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*/
|
||||
esp_err_t mdns_service_instance_name_set(const char *service_type, const char *proto, const char *instance_name);
|
||||
|
||||
/**
|
||||
* @brief Set instance name for service with hostname
|
||||
*
|
||||
* @param instance_old original instance name
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param hostname service hostname. If NULL, local hostname will be used.
|
||||
* @param instance_name instance name to set
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NOT_FOUND Service not found
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*/
|
||||
esp_err_t mdns_service_instance_name_set_for_host(const char *instance_old, const char *service_type, const char *proto, const char *hostname,
|
||||
const char *instance_name);
|
||||
|
||||
/**
|
||||
* @brief Set service port
|
||||
*
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param port service port
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NOT_FOUND Service not found
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*/
|
||||
esp_err_t mdns_service_port_set(const char *service_type, const char *proto, uint16_t port);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set service port with hostname
|
||||
*
|
||||
* @param instance instance name
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param hostname service hostname. If NULL, local hostname will be used.
|
||||
* @param port service port
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NOT_FOUND Service not found
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*/
|
||||
esp_err_t mdns_service_port_set_for_host(const char *instance, const char *service_type, const char *proto, const char *hostname,
|
||||
uint16_t port);
|
||||
|
||||
/**
|
||||
* @brief Replace all TXT items for service
|
||||
*
|
||||
* @note The value length of txt items will be automatically decided by strlen
|
||||
*
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param txt array of TXT data (eg. {{"var","val"},{"other","2"}})
|
||||
* @param num_items number of items in TXT data
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NOT_FOUND Service not found
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*/
|
||||
esp_err_t mdns_service_txt_set(const char *service_type, const char *proto, mdns_txt_item_t txt[], uint8_t num_items);
|
||||
|
||||
/**
|
||||
* @brief Replace all TXT items for service with hostname
|
||||
*
|
||||
* @note The value length of txt items will be automatically decided by strlen
|
||||
*
|
||||
* @param instance instance name
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param hostname service hostname. If NULL, local hostname will be used.
|
||||
* @param txt array of TXT data (eg. {{"var","val"},{"other","2"}})
|
||||
* @param num_items number of items in TXT data
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NOT_FOUND Service not found
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*/
|
||||
esp_err_t mdns_service_txt_set_for_host(const char *instance, const char *service_type, const char *proto, const char *hostname,
|
||||
mdns_txt_item_t txt[], uint8_t num_items);
|
||||
|
||||
/**
|
||||
* @brief Set/Add TXT item for service TXT record
|
||||
*
|
||||
* @note The value length will be automatically decided by strlen
|
||||
*
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param key the key that you want to add/update
|
||||
* @param value the new value of the key
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NOT_FOUND Service not found
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*/
|
||||
esp_err_t mdns_service_txt_item_set(const char *service_type, const char *proto, const char *key, const char *value);
|
||||
|
||||
/**
|
||||
* @brief Set/Add TXT item for service TXT record
|
||||
*
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param key the key that you want to add/update
|
||||
* @param value the new value of the key
|
||||
* @param value_len the length of the value
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NOT_FOUND Service not found
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*/
|
||||
esp_err_t mdns_service_txt_item_set_with_explicit_value_len(const char *service_type, const char *proto,
|
||||
const char *key, const char *value, uint8_t value_len);
|
||||
|
||||
/**
|
||||
* @brief Set/Add TXT item for service TXT record with hostname
|
||||
*
|
||||
* @note The value length will be automatically decided by strlen
|
||||
*
|
||||
* @param instance instance name
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param hostname service hostname. If NULL, local hostname will be used.
|
||||
* @param key the key that you want to add/update
|
||||
* @param value the new value of the key
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NOT_FOUND Service not found
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*/
|
||||
esp_err_t mdns_service_txt_item_set_for_host(const char *instance, const char *service_type, const char *proto, const char *hostname,
|
||||
const char *key, const char *value);
|
||||
|
||||
/**
|
||||
* @brief Set/Add TXT item for service TXT record with hostname and txt value length
|
||||
*
|
||||
* @param instance instance name
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param hostname service hostname. If NULL, local hostname will be used.
|
||||
* @param key the key that you want to add/update
|
||||
* @param value the new value of the key
|
||||
* @param value_len the length of the value
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NOT_FOUND Service not found
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*/
|
||||
esp_err_t mdns_service_txt_item_set_for_host_with_explicit_value_len(const char *instance, const char *service_type, const char *proto,
|
||||
const char *hostname, const char *key,
|
||||
const char *value, uint8_t value_len);
|
||||
|
||||
/**
|
||||
* @brief Remove TXT item for service TXT record
|
||||
*
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param key the key that you want to remove
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NOT_FOUND Service not found
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*/
|
||||
esp_err_t mdns_service_txt_item_remove(const char *service_type, const char *proto, const char *key);
|
||||
|
||||
/**
|
||||
* @brief Remove TXT item for service TXT record with hostname
|
||||
*
|
||||
* @param instance instance name
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param hostname service hostname. If NULL, local hostname will be used.
|
||||
* @param key the key that you want to remove
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NOT_FOUND Service not found
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*/
|
||||
esp_err_t mdns_service_txt_item_remove_for_host(const char *instance, const char *service_type, const char *proto, const char *hostname,
|
||||
const char *key);
|
||||
|
||||
/**
|
||||
* @brief Add a subtype for service.
|
||||
*
|
||||
* @param instance_name instance name. If NULL, will find the first service with the same service type and protocol.
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param hostname service hostname. If NULL, local hostname will be used.
|
||||
* @param subtype The subtype to add.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NOT_FOUND Service not found
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*/
|
||||
esp_err_t mdns_service_subtype_add_for_host(const char *instance_name, const char *service_type, const char *proto,
|
||||
const char *hostname, const char *subtype);
|
||||
|
||||
/**
|
||||
* @brief Remove a subtype for service.
|
||||
*
|
||||
* @param instance_name instance name. If NULL, will find the first service with the same service type and protocol.
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param hostname service hostname. If NULL, local hostname will be used.
|
||||
* @param subtype The subtype to remove.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NOT_FOUND Service not found
|
||||
*/
|
||||
esp_err_t mdns_service_subtype_remove_for_host(const char *instance_name, const char *service_type, const char *proto,
|
||||
const char *hostname, const char *subtype);
|
||||
|
||||
/**
|
||||
* @brief Add multiple subtypes for service at once.
|
||||
*
|
||||
* @param instance_name instance name. If NULL, will find the first service with the same service type and protocol.
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param hostname service hostname. If NULL, local hostname will be used.
|
||||
* @param subtype the pointer of subtype array to add.
|
||||
* @param num_items number of items in subtype array
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NOT_FOUND Service not found
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*/
|
||||
esp_err_t mdns_service_subtype_add_multiple_items_for_host(const char *instance_name, const char *service_type, const char *proto,
|
||||
const char *hostname, mdns_subtype_item_t subtype[], uint8_t num_items);
|
||||
|
||||
/**
|
||||
* @brief Update subtype for service.
|
||||
*
|
||||
* @param instance_name instance name. If NULL, will find the first service with the same service type and protocol.
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param hostname service hostname. If NULL, local hostname will be used.
|
||||
* @param subtype the pointer of subtype array to add.
|
||||
* @param num_items number of items in subtype array
|
||||
*
|
||||
* @note If `num_items` is 0, then remove all subtypes.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NOT_FOUND Service not found
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*/
|
||||
esp_err_t mdns_service_subtype_update_multiple_items_for_host(const char *instance_name, const char *service_type, const char *proto,
|
||||
const char *hostname, mdns_subtype_item_t subtype[], uint8_t num_items);
|
||||
/**
|
||||
* @brief Remove and free all services from mDNS server
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t mdns_service_remove_all(void);
|
||||
|
||||
/**
|
||||
* @brief Deletes the finished query. Call this only after the search has ended!
|
||||
*
|
||||
* @param search pointer to search object
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_STATE search has not finished
|
||||
* - ESP_ERR_INVALID_ARG pointer to search object is NULL
|
||||
*/
|
||||
esp_err_t mdns_query_async_delete(mdns_search_once_t *search);
|
||||
|
||||
/**
|
||||
* @brief Get results from search pointer. Results available as a pointer to the output parameter.
|
||||
* Pointer to search object has to be deleted via `mdns_query_async_delete` once the query has finished.
|
||||
* The results although have to be freed manually.
|
||||
*
|
||||
* @param search pointer to search object
|
||||
* @param timeout time in milliseconds to wait for answers
|
||||
* @param results pointer to the results of the query
|
||||
* @param num_results pointer to the number of the actual result items (set to NULL to ignore this return value)
|
||||
*
|
||||
* @return
|
||||
* True if search has finished before or at timeout
|
||||
* False if search timeout is over
|
||||
*/
|
||||
bool mdns_query_async_get_results(mdns_search_once_t *search, uint32_t timeout, mdns_result_t **results, uint8_t *num_results);
|
||||
|
||||
/**
|
||||
* @brief Query mDNS for host or service asynchronousely.
|
||||
* Search has to be tested for progress and deleted manually!
|
||||
*
|
||||
* @param name service instance or host name (NULL for PTR queries)
|
||||
* @param service_type service type (_http, _arduino, _ftp etc.) (NULL for host queries)
|
||||
* @param proto service protocol (_tcp, _udp, etc.) (NULL for host queries)
|
||||
* @param type type of query (MDNS_TYPE_*)
|
||||
* @param timeout time in milliseconds during which mDNS query is active
|
||||
* @param max_results maximum results to be collected
|
||||
* @param notifier Notification function to be called when the result is ready, can be NULL
|
||||
*
|
||||
* @return mdns_search_once_s pointer to new search object if query initiated successfully.
|
||||
* NULL otherwise.
|
||||
*/
|
||||
mdns_search_once_t *mdns_query_async_new(const char *name, const char *service_type, const char *proto, uint16_t type,
|
||||
uint32_t timeout, size_t max_results, mdns_query_notify_t notifier);
|
||||
|
||||
/**
|
||||
* @brief Generic mDNS query
|
||||
* All following query methods are derived from this one
|
||||
*
|
||||
* @param name service instance or host name (NULL for PTR queries)
|
||||
* @param service_type service type (_http, _arduino, _ftp etc.) (NULL for host queries)
|
||||
* @param proto service protocol (_tcp, _udp, etc.) (NULL for host queries)
|
||||
* @param type type of query (MDNS_TYPE_*)
|
||||
* @param transmission_type either Unicast query, or Multicast query
|
||||
* @param timeout time in milliseconds to wait for answers.
|
||||
* @param max_results maximum results to be collected
|
||||
* @param results pointer to the results of the query
|
||||
* results must be freed using mdns_query_results_free below
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_STATE mDNS is not running
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
* - ESP_ERR_INVALID_ARG timeout was not given
|
||||
*/
|
||||
esp_err_t mdns_query_generic(const char *name, const char *service_type, const char *proto, uint16_t type,
|
||||
mdns_query_transmission_type_t transmission_type, uint32_t timeout, size_t max_results, mdns_result_t **results);
|
||||
|
||||
/**
|
||||
* @brief Query mDNS for host or service
|
||||
*
|
||||
* Note that querying PTR types sends Multicast query, all other types send Unicast queries
|
||||
*
|
||||
* @param name service instance or host name (NULL for PTR queries)
|
||||
* @param service_type service type (_http, _arduino, _ftp etc.) (NULL for host queries)
|
||||
* @param proto service protocol (_tcp, _udp, etc.) (NULL for host queries)
|
||||
* @param type type of query (MDNS_TYPE_*)
|
||||
* @param timeout time in milliseconds to wait for answers.
|
||||
* @param max_results maximum results to be collected
|
||||
* @param results pointer to the results of the query
|
||||
* results must be freed using mdns_query_results_free below
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_STATE mDNS is not running
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
* - ESP_ERR_INVALID_ARG timeout was not given
|
||||
*/
|
||||
esp_err_t mdns_query(const char *name, const char *service_type, const char *proto, uint16_t type, uint32_t timeout, size_t max_results, mdns_result_t **results);
|
||||
|
||||
/**
|
||||
* @brief Free query results
|
||||
*
|
||||
* @param results linked list of results to be freed
|
||||
*/
|
||||
void mdns_query_results_free(mdns_result_t *results);
|
||||
|
||||
/**
|
||||
* @brief Query mDNS for service
|
||||
*
|
||||
* @param service_type service type (_http, _arduino, _ftp etc.)
|
||||
* @param proto service protocol (_tcp, _udp, etc.)
|
||||
* @param timeout time in milliseconds to wait for answer.
|
||||
* @param max_results maximum results to be collected
|
||||
* @param results pointer to the results of the query
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_STATE mDNS is not running
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
* - ESP_ERR_INVALID_ARG parameter error
|
||||
*/
|
||||
esp_err_t mdns_query_ptr(const char *service_type, const char *proto, uint32_t timeout, size_t max_results, mdns_result_t **results);
|
||||
|
||||
/**
|
||||
* @brief Query mDNS for SRV record
|
||||
*
|
||||
* @param instance_name service instance name
|
||||
* @param service_type service type (_http, _arduino, _ftp etc.)
|
||||
* @param proto service protocol (_tcp, _udp, etc.)
|
||||
* @param timeout time in milliseconds to wait for answer.
|
||||
* @param result pointer to the result of the query
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_STATE mDNS is not running
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
* - ESP_ERR_INVALID_ARG parameter error
|
||||
*/
|
||||
esp_err_t mdns_query_srv(const char *instance_name, const char *service_type, const char *proto, uint32_t timeout, mdns_result_t **result);
|
||||
|
||||
/**
|
||||
* @brief Query mDNS for TXT record
|
||||
*
|
||||
* @param instance_name service instance name
|
||||
* @param service_type service type (_http, _arduino, _ftp etc.)
|
||||
* @param proto service protocol (_tcp, _udp, etc.)
|
||||
* @param timeout time in milliseconds to wait for answer.
|
||||
* @param result pointer to the result of the query
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_STATE mDNS is not running
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
* - ESP_ERR_INVALID_ARG parameter error
|
||||
*/
|
||||
esp_err_t mdns_query_txt(const char *instance_name, const char *service_type, const char *proto, uint32_t timeout, mdns_result_t **result);
|
||||
|
||||
/**
|
||||
* @brief Look up delegated services.
|
||||
*
|
||||
* @param instance instance name (NULL for uncertain instance)
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param max_results maximum results to be collected
|
||||
* @param result pointer to the result of the search
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_STATE mDNS is not running
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
* - ESP_ERR_INVALID_ARG parameter error
|
||||
*/
|
||||
esp_err_t mdns_lookup_delegated_service(const char *instance, const char *service_type, const char *proto, size_t max_results,
|
||||
mdns_result_t **result);
|
||||
|
||||
/**
|
||||
* @brief Look up self hosted services.
|
||||
*
|
||||
* @param instance instance name (NULL for uncertain instance)
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param max_results maximum results to be collected
|
||||
* @param result pointer to the result of the search
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_STATE mDNS is not running
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
* - ESP_ERR_INVALID_ARG parameter error
|
||||
*/
|
||||
esp_err_t mdns_lookup_selfhosted_service(const char *instance, const char *service_type, const char *proto, size_t max_results,
|
||||
mdns_result_t **result);
|
||||
|
||||
/**
|
||||
* @brief Query mDNS for A record
|
||||
*
|
||||
* @param host_name host name to look for
|
||||
* @param timeout time in milliseconds to wait for answer.
|
||||
* @param addr pointer to the resulting IP4 address
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_STATE mDNS is not running
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
* - ESP_ERR_INVALID_ARG parameter error
|
||||
*/
|
||||
esp_err_t mdns_query_a(const char *host_name, uint32_t timeout, esp_ip4_addr_t *addr);
|
||||
|
||||
#if CONFIG_LWIP_IPV6
|
||||
/**
|
||||
* @brief Query mDNS for A record
|
||||
*
|
||||
* Please note that hostname must not contain domain name, as mDNS uses '.local' domain.
|
||||
*
|
||||
* @param host_name host name to look for
|
||||
* @param timeout time in milliseconds to wait for answer. If 0, max_results needs to be defined
|
||||
* @param addr pointer to the resulting IP6 address
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_STATE mDNS is not running
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
* - ESP_ERR_INVALID_ARG parameter error
|
||||
*/
|
||||
esp_err_t mdns_query_aaaa(const char *host_name, uint32_t timeout, esp_ip6_addr_t *addr);
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief Register custom esp_netif with mDNS functionality
|
||||
* mDNS service runs by default on preconfigured interfaces (STA, AP, ETH).
|
||||
* This API enables running the service on any customized interface,
|
||||
* either using standard WiFi or Ethernet driver or any kind of user defined driver.
|
||||
*
|
||||
* @param esp_netif Pointer to esp-netif interface
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_STATE mDNS is not running or this netif is already registered
|
||||
* - ESP_ERR_NO_MEM not enough memory for this in interface in the netif list (see CONFIG_MDNS_MAX_INTERFACES)
|
||||
*/
|
||||
esp_err_t mdns_register_netif(esp_netif_t *esp_netif);
|
||||
|
||||
/**
|
||||
* @brief Unregister esp-netif already registered in mDNS service
|
||||
*
|
||||
* @param esp_netif Pointer to esp-netif interface
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_STATE mDNS is not running
|
||||
* - ESP_ERR_NOT_FOUND this esp-netif was not registered in mDNS service
|
||||
*/
|
||||
esp_err_t mdns_unregister_netif(esp_netif_t *esp_netif);
|
||||
|
||||
/**
|
||||
* @brief Set esp_netif to a desired state, or perform a desired action, such as enable/disable this interface
|
||||
* or send announcement packets to this netif
|
||||
*
|
||||
* * This function is used to enable (probe, resolve conflicts and announce), announce, or disable (send bye) mDNS
|
||||
* services on the specified network interface.
|
||||
* * This function must be called if users registers a specific interface using mdns_register_netif()
|
||||
* to enable mDNS services on that interface.
|
||||
* * This function could be used in IP/connection event handlers to automatically enable/announce mDNS services
|
||||
* when network properties change and/or disable them on disconnection.
|
||||
*
|
||||
* @param esp_netif Pointer to esp-netif interface
|
||||
* @param event_action Disable/Enable/Announce on this interface over IPv4/IPv6 protocol.
|
||||
* Actions enumerated in mdns_event_actions_t type.
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_STATE mDNS is not running or this netif is not registered
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*/
|
||||
esp_err_t mdns_netif_action(esp_netif_t *esp_netif, mdns_event_actions_t event_action);
|
||||
|
||||
/**
|
||||
* @brief Browse mDNS for a service `_service._proto`.
|
||||
*
|
||||
* @param service Pointer to the `_service` which will be browsed.
|
||||
* @param proto Pointer to the `_proto` which will be browsed.
|
||||
* @param notifier The callback which will be called when the browsing service changed.
|
||||
* @return mdns_browse_t pointer to new browse object if initiated successfully.
|
||||
* NULL otherwise.
|
||||
*/
|
||||
mdns_browse_t *mdns_browse_new(const char *service, const char *proto, mdns_browse_notify_t notifier);
|
||||
|
||||
/**
|
||||
* @brief Stop the `_service._proto` browse.
|
||||
* @param service Pointer to the `_service` which will be browsed.
|
||||
* @param proto Pointer to the `_proto` which will be browsed.
|
||||
* @return
|
||||
* - ESP_OK success.
|
||||
* - ESP_ERR_FAIL mDNS is not running or the browsing of `_service._proto` is never started.
|
||||
* - ESP_ERR_NO_MEM memory error.
|
||||
*/
|
||||
esp_err_t mdns_browse_delete(const char *service, const char *proto);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ESP_MDNS_H_ */
|
||||
14
managed_components/espressif__mdns/include/mdns_console.h
Normal file
14
managed_components/espressif__mdns/include/mdns_console.h
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef _MDNS_CONSOLE_H_
|
||||
#define _MDNS_CONSOLE_H_
|
||||
|
||||
/**
|
||||
* @brief Register MDNS functions with the console component
|
||||
*/
|
||||
void mdns_console_register(void);
|
||||
|
||||
#endif /* _MDNS_CONSOLE_H_ */
|
||||
7869
managed_components/espressif__mdns/mdns.c
Normal file
7869
managed_components/espressif__mdns/mdns.c
Normal file
File diff suppressed because it is too large
Load Diff
1452
managed_components/espressif__mdns/mdns_console.c
Normal file
1452
managed_components/espressif__mdns/mdns_console.c
Normal file
File diff suppressed because it is too large
Load Diff
96
managed_components/espressif__mdns/mdns_mem_caps.c
Normal file
96
managed_components/espressif__mdns/mdns_mem_caps.c
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "mdns_private.h"
|
||||
#include "mdns_mem_caps.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#if CONFIG_MDNS_MEMORY_CUSTOM_IMPL
|
||||
#define ALLOW_WEAK __attribute__((weak))
|
||||
#else
|
||||
#define ALLOW_WEAK
|
||||
#endif
|
||||
|
||||
#if CONFIG_MDNS_TASK_CREATE_FROM_SPIRAM
|
||||
#define MDNS_TASK_MEMORY_CAPS (MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT)
|
||||
#define MDNS_TASK_MEMORY_LOG "SPIRAM"
|
||||
#endif
|
||||
#if CONFIG_MDNS_TASK_CREATE_FROM_INTERNAL
|
||||
#define MDNS_TASK_MEMORY_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||
#define MDNS_TASK_MEMORY_LOG "internal RAM"
|
||||
#endif
|
||||
|
||||
#if CONFIG_MDNS_MEMORY_ALLOC_SPIRAM
|
||||
#define MDNS_MEMORY_CAPS (MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT)
|
||||
#endif
|
||||
#if CONFIG_MDNS_MEMORY_ALLOC_INTERNAL
|
||||
#define MDNS_MEMORY_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||
#endif
|
||||
|
||||
// Allocate memory from internal heap as default.
|
||||
#ifndef MDNS_MEMORY_CAPS
|
||||
#warning "No memory allocation method defined, using internal memory"
|
||||
#define MDNS_MEMORY_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||
#endif
|
||||
#ifndef MDNS_TASK_MEMORY_CAPS
|
||||
#define MDNS_TASK_MEMORY_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||
#define MDNS_TASK_MEMORY_LOG "internal RAM"
|
||||
#endif
|
||||
|
||||
void ALLOW_WEAK *mdns_mem_malloc(size_t size)
|
||||
{
|
||||
return heap_caps_malloc(size, MDNS_MEMORY_CAPS);
|
||||
}
|
||||
|
||||
void ALLOW_WEAK *mdns_mem_calloc(size_t num, size_t size)
|
||||
{
|
||||
return heap_caps_calloc(num, size, MDNS_MEMORY_CAPS);
|
||||
}
|
||||
|
||||
void ALLOW_WEAK mdns_mem_free(void *ptr)
|
||||
{
|
||||
heap_caps_free(ptr);
|
||||
}
|
||||
|
||||
char ALLOW_WEAK *mdns_mem_strdup(const char *s)
|
||||
{
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
size_t len = strlen(s) + 1;
|
||||
char *copy = (char *)heap_caps_malloc(len, MDNS_MEMORY_CAPS);
|
||||
if (copy) {
|
||||
memcpy(copy, s, len);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
char ALLOW_WEAK *mdns_mem_strndup(const char *s, size_t n)
|
||||
{
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
size_t len = strnlen(s, n);
|
||||
char *copy = (char *)heap_caps_malloc(len + 1, MDNS_MEMORY_CAPS);
|
||||
if (copy) {
|
||||
memcpy(copy, s, len);
|
||||
copy[len] = '\0';
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
void ALLOW_WEAK *mdns_mem_task_malloc(size_t size)
|
||||
{
|
||||
ESP_LOGI("mdns_mem", "mDNS task will be created from %s", MDNS_TASK_MEMORY_LOG);
|
||||
return heap_caps_malloc(size, MDNS_TASK_MEMORY_CAPS);
|
||||
}
|
||||
|
||||
void ALLOW_WEAK mdns_mem_task_free(void *ptr)
|
||||
{
|
||||
heap_caps_free(ptr);
|
||||
}
|
||||
398
managed_components/espressif__mdns/mdns_networking_lwip.c
Normal file
398
managed_components/espressif__mdns/mdns_networking_lwip.c
Normal file
@@ -0,0 +1,398 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* MDNS Server Networking
|
||||
*
|
||||
*/
|
||||
#include <string.h>
|
||||
#include "esp_log.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/igmp.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/mld6.h"
|
||||
#include "lwip/priv/tcpip_priv.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_event.h"
|
||||
#include "mdns_networking.h"
|
||||
#include "esp_netif_net_stack.h"
|
||||
#include "mdns_mem_caps.h"
|
||||
|
||||
/*
|
||||
* MDNS Server Networking
|
||||
*
|
||||
*/
|
||||
enum interface_protocol {
|
||||
PROTO_IPV4 = 1 << MDNS_IP_PROTOCOL_V4,
|
||||
PROTO_IPV6 = 1 << MDNS_IP_PROTOCOL_V6
|
||||
};
|
||||
|
||||
typedef struct interfaces {
|
||||
bool ready;
|
||||
int proto;
|
||||
} interfaces_t;
|
||||
|
||||
static interfaces_t s_interfaces[MDNS_MAX_INTERFACES];
|
||||
|
||||
static struct udp_pcb *_pcb_main = NULL;
|
||||
|
||||
static const char *TAG = "mdns_networking";
|
||||
|
||||
static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip_addr_t *raddr, uint16_t rport);
|
||||
|
||||
/**
|
||||
* @brief Low level UDP PCB Initialize
|
||||
*/
|
||||
static esp_err_t _udp_pcb_main_init(void)
|
||||
{
|
||||
if (_pcb_main) {
|
||||
return ESP_OK;
|
||||
}
|
||||
_pcb_main = udp_new();
|
||||
if (!_pcb_main) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
if (udp_bind(_pcb_main, IP_ANY_TYPE, MDNS_SERVICE_PORT) != 0) {
|
||||
udp_remove(_pcb_main);
|
||||
_pcb_main = NULL;
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
_pcb_main->mcast_ttl = 255;
|
||||
_pcb_main->remote_port = MDNS_SERVICE_PORT;
|
||||
ip_addr_copy(_pcb_main->remote_ip, *(IP_ANY_TYPE));
|
||||
udp_recv(_pcb_main, &_udp_recv, NULL);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Low level UDP PCB Free
|
||||
*/
|
||||
static void _udp_pcb_main_deinit(void)
|
||||
{
|
||||
if (_pcb_main) {
|
||||
udp_recv(_pcb_main, NULL, NULL);
|
||||
udp_disconnect(_pcb_main);
|
||||
udp_remove(_pcb_main);
|
||||
_pcb_main = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Low level UDP Multicast membership control
|
||||
*/
|
||||
static esp_err_t _udp_join_group(mdns_if_t if_inx, mdns_ip_protocol_t ip_protocol, bool join)
|
||||
{
|
||||
struct netif *netif = NULL;
|
||||
esp_netif_t *tcpip_if = _mdns_get_esp_netif(if_inx);
|
||||
|
||||
if (!esp_netif_is_netif_up(tcpip_if)) {
|
||||
// Network interface went down before event propagated, skipping IGMP config
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
netif = esp_netif_get_netif_impl(tcpip_if);
|
||||
assert(netif);
|
||||
|
||||
#if LWIP_IPV4
|
||||
if (ip_protocol == MDNS_IP_PROTOCOL_V4) {
|
||||
ip4_addr_t multicast_addr;
|
||||
IP4_ADDR(&multicast_addr, 224, 0, 0, 251);
|
||||
|
||||
if (join) {
|
||||
if (igmp_joingroup_netif(netif, &multicast_addr)) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
} else {
|
||||
if (igmp_leavegroup_netif(netif, &multicast_addr)) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // LWIP_IPV4
|
||||
#if LWIP_IPV6
|
||||
if (ip_protocol == MDNS_IP_PROTOCOL_V6) {
|
||||
ip_addr_t multicast_addr = IPADDR6_INIT(0x000002ff, 0, 0, 0xfb000000);
|
||||
|
||||
if (join) {
|
||||
if (mld6_joingroup_netif(netif, ip_2_ip6(&multicast_addr))) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
} else {
|
||||
if (mld6_leavegroup_netif(netif, ip_2_ip6(&multicast_addr))) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // LWIP_IPV6
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief the receive callback of the raw udp api. Packets are received here
|
||||
*
|
||||
*/
|
||||
static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip_addr_t *raddr, uint16_t rport)
|
||||
{
|
||||
|
||||
uint8_t i;
|
||||
while (pb != NULL) {
|
||||
struct pbuf *this_pb = pb;
|
||||
pb = pb->next;
|
||||
this_pb->next = NULL;
|
||||
|
||||
mdns_rx_packet_t *packet = (mdns_rx_packet_t *)mdns_mem_malloc(sizeof(mdns_rx_packet_t));
|
||||
if (!packet) {
|
||||
HOOK_MALLOC_FAILED;
|
||||
//missed packet - no memory
|
||||
pbuf_free(this_pb);
|
||||
continue;
|
||||
}
|
||||
|
||||
packet->tcpip_if = MDNS_MAX_INTERFACES;
|
||||
packet->pb = this_pb;
|
||||
packet->src_port = rport;
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
packet->src.type = raddr->type;
|
||||
memcpy(&packet->src.u_addr, &raddr->u_addr, sizeof(raddr->u_addr));
|
||||
#elif LWIP_IPV4
|
||||
packet->src.type = IPADDR_TYPE_V4;
|
||||
packet->src.u_addr.ip4.addr = raddr->addr;
|
||||
#elif LWIP_IPV6
|
||||
packet->src.type = IPADDR_TYPE_V6;
|
||||
memcpy(&packet->src.u_addr.ip6, raddr, sizeof(ip_addr_t));
|
||||
#endif
|
||||
packet->dest.type = packet->src.type;
|
||||
|
||||
#if LWIP_IPV4
|
||||
if (packet->src.type == IPADDR_TYPE_V4) {
|
||||
packet->ip_protocol = MDNS_IP_PROTOCOL_V4;
|
||||
struct ip_hdr *iphdr = (struct ip_hdr *)(((uint8_t *)(packet->pb->payload)) - UDP_HLEN - IP_HLEN);
|
||||
packet->dest.u_addr.ip4.addr = iphdr->dest.addr;
|
||||
packet->multicast = ip4_addr_ismulticast(&(packet->dest.u_addr.ip4));
|
||||
}
|
||||
#endif // LWIP_IPV4
|
||||
#if LWIP_IPV6
|
||||
if (packet->src.type == IPADDR_TYPE_V6) {
|
||||
packet->ip_protocol = MDNS_IP_PROTOCOL_V6;
|
||||
struct ip6_hdr *ip6hdr = (struct ip6_hdr *)(((uint8_t *)(packet->pb->payload)) - UDP_HLEN - IP6_HLEN);
|
||||
memcpy(&packet->dest.u_addr.ip6.addr, (uint8_t *)ip6hdr->dest.addr, 16);
|
||||
packet->multicast = ip6_addr_ismulticast(&(packet->dest.u_addr.ip6));
|
||||
}
|
||||
#endif // LWIP_IPV6
|
||||
|
||||
//lwip does not return the proper pcb if you have more than one for the same multicast address (but different interfaces)
|
||||
struct netif *netif = NULL;
|
||||
bool found = false;
|
||||
for (i = 0; i < MDNS_MAX_INTERFACES; i++) {
|
||||
netif = esp_netif_get_netif_impl(_mdns_get_esp_netif(i));
|
||||
if (s_interfaces[i].proto && netif && netif == ip_current_input_netif()) {
|
||||
#if LWIP_IPV4
|
||||
if (packet->src.type == IPADDR_TYPE_V4) {
|
||||
if ((packet->src.u_addr.ip4.addr & ip_2_ip4(&netif->netmask)->addr) != (ip_2_ip4(&netif->ip_addr)->addr & ip_2_ip4(&netif->netmask)->addr)) {
|
||||
//packet source is not in the same subnet
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif // LWIP_IPV4
|
||||
packet->tcpip_if = i;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found || _mdns_send_rx_action(packet) != ESP_OK) {
|
||||
pbuf_free(this_pb);
|
||||
mdns_mem_free(packet);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool mdns_is_netif_ready(mdns_if_t netif, mdns_ip_protocol_t ip_proto)
|
||||
{
|
||||
return s_interfaces[netif].ready &&
|
||||
s_interfaces[netif].proto & (ip_proto == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if any of the interfaces is up
|
||||
*/
|
||||
static bool _udp_pcb_is_in_use(void)
|
||||
{
|
||||
int i, p;
|
||||
for (i = 0; i < MDNS_MAX_INTERFACES; i++) {
|
||||
for (p = 0; p < MDNS_IP_PROTOCOL_MAX; p++) {
|
||||
if (mdns_is_netif_ready(i, p)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop PCB Main code
|
||||
*/
|
||||
static void _udp_pcb_deinit(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
s_interfaces[tcpip_if].proto &= ~(ip_protocol == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6);
|
||||
if (s_interfaces[tcpip_if].proto == 0) {
|
||||
s_interfaces[tcpip_if].ready = false;
|
||||
_udp_join_group(tcpip_if, ip_protocol, false);
|
||||
if (!_udp_pcb_is_in_use()) {
|
||||
_udp_pcb_main_deinit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start PCB Main code
|
||||
*/
|
||||
static esp_err_t _udp_pcb_init(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
if (mdns_is_netif_ready(tcpip_if, ip_protocol)) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
esp_err_t err = _udp_join_group(tcpip_if, ip_protocol, true);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = _udp_pcb_main_init();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
s_interfaces[tcpip_if].proto |= (ip_protocol == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6);
|
||||
s_interfaces[tcpip_if].ready = true;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
struct tcpip_api_call_data call;
|
||||
mdns_if_t tcpip_if;
|
||||
mdns_ip_protocol_t ip_protocol;
|
||||
struct pbuf *pbt;
|
||||
const ip_addr_t *ip;
|
||||
uint16_t port;
|
||||
esp_err_t err;
|
||||
} mdns_api_call_t;
|
||||
|
||||
/**
|
||||
* @brief Start PCB from LwIP thread
|
||||
*/
|
||||
static err_t _mdns_pcb_init_api(struct tcpip_api_call_data *api_call_msg)
|
||||
{
|
||||
mdns_api_call_t *msg = (mdns_api_call_t *)api_call_msg;
|
||||
msg->err = _udp_pcb_init(msg->tcpip_if, msg->ip_protocol) == ESP_OK ? ERR_OK : ERR_IF;
|
||||
return msg->err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop PCB from LwIP thread
|
||||
*/
|
||||
static err_t _mdns_pcb_deinit_api(struct tcpip_api_call_data *api_call_msg)
|
||||
{
|
||||
mdns_api_call_t *msg = (mdns_api_call_t *)api_call_msg;
|
||||
_udp_pcb_deinit(msg->tcpip_if, msg->ip_protocol);
|
||||
msg->err = ESP_OK;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Non-static functions below are
|
||||
* - _mdns prefixed
|
||||
* - commented in mdns_networking.h header
|
||||
*/
|
||||
esp_err_t _mdns_pcb_init(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
mdns_api_call_t msg = {
|
||||
.tcpip_if = tcpip_if,
|
||||
.ip_protocol = ip_protocol
|
||||
};
|
||||
tcpip_api_call(_mdns_pcb_init_api, &msg.call);
|
||||
return msg.err;
|
||||
}
|
||||
|
||||
esp_err_t _mdns_pcb_deinit(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
mdns_api_call_t msg = {
|
||||
.tcpip_if = tcpip_if,
|
||||
.ip_protocol = ip_protocol
|
||||
};
|
||||
tcpip_api_call(_mdns_pcb_deinit_api, &msg.call);
|
||||
return msg.err;
|
||||
}
|
||||
|
||||
static err_t _mdns_udp_pcb_write_api(struct tcpip_api_call_data *api_call_msg)
|
||||
{
|
||||
void *nif = NULL;
|
||||
mdns_api_call_t *msg = (mdns_api_call_t *)api_call_msg;
|
||||
nif = esp_netif_get_netif_impl(_mdns_get_esp_netif(msg->tcpip_if));
|
||||
if (!nif || !mdns_is_netif_ready(msg->tcpip_if, msg->ip_protocol) || _pcb_main == NULL) {
|
||||
pbuf_free(msg->pbt);
|
||||
msg->err = ERR_IF;
|
||||
return ERR_IF;
|
||||
}
|
||||
esp_err_t err = udp_sendto_if(_pcb_main, msg->pbt, msg->ip, msg->port, (struct netif *)nif);
|
||||
pbuf_free(msg->pbt);
|
||||
msg->err = err;
|
||||
return err;
|
||||
}
|
||||
|
||||
size_t _mdns_udp_pcb_write(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, const esp_ip_addr_t *ip, uint16_t port, uint8_t *data, size_t len)
|
||||
{
|
||||
struct pbuf *pbt = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
|
||||
if (pbt == NULL) {
|
||||
return 0;
|
||||
}
|
||||
memcpy((uint8_t *)pbt->payload, data, len);
|
||||
|
||||
ip_addr_t ip_add_copy;
|
||||
#if LWIP_IPV6 && LWIP_IPV4
|
||||
ip_add_copy.type = ip->type;
|
||||
memcpy(&(ip_add_copy.u_addr), &(ip->u_addr), sizeof(ip_add_copy.u_addr));
|
||||
#elif LWIP_IPV4
|
||||
ip_add_copy.addr = ip->u_addr.ip4.addr;
|
||||
#elif LWIP_IPV6
|
||||
#if LWIP_IPV6_SCOPES
|
||||
ip_add_copy.zone = ip->u_addr.ip6.zone;
|
||||
#endif // LWIP_IPV6_SCOPES
|
||||
memcpy(ip_add_copy.addr, ip->u_addr.ip6.addr, sizeof(ip_add_copy.addr));
|
||||
#endif
|
||||
|
||||
mdns_api_call_t msg = {
|
||||
.tcpip_if = tcpip_if,
|
||||
.ip_protocol = ip_protocol,
|
||||
.pbt = pbt,
|
||||
.ip = &ip_add_copy,
|
||||
.port = port
|
||||
};
|
||||
tcpip_api_call(_mdns_udp_pcb_write_api, &msg.call);
|
||||
|
||||
if (msg.err) {
|
||||
return 0;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
void *_mdns_get_packet_data(mdns_rx_packet_t *packet)
|
||||
{
|
||||
return packet->pb->payload;
|
||||
}
|
||||
|
||||
size_t _mdns_get_packet_len(mdns_rx_packet_t *packet)
|
||||
{
|
||||
return packet->pb->len;
|
||||
}
|
||||
|
||||
void _mdns_packet_free(mdns_rx_packet_t *packet)
|
||||
{
|
||||
pbuf_free(packet->pb);
|
||||
mdns_mem_free(packet);
|
||||
}
|
||||
499
managed_components/espressif__mdns/mdns_networking_socket.c
Normal file
499
managed_components/espressif__mdns/mdns_networking_socket.c
Normal file
@@ -0,0 +1,499 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief MDNS Server Networking module implemented using BSD sockets
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "esp_event.h"
|
||||
#include "mdns_networking.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#include "esp_log.h"
|
||||
#include "mdns_mem_caps.h"
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_LINUX)
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
enum interface_protocol {
|
||||
PROTO_IPV4 = 1 << MDNS_IP_PROTOCOL_V4,
|
||||
PROTO_IPV6 = 1 << MDNS_IP_PROTOCOL_V6
|
||||
};
|
||||
|
||||
typedef struct interfaces {
|
||||
int sock;
|
||||
int proto;
|
||||
} interfaces_t;
|
||||
|
||||
static interfaces_t s_interfaces[MDNS_MAX_INTERFACES];
|
||||
|
||||
static const char *TAG = "mdns_networking";
|
||||
static bool s_run_sock_recv_task = false;
|
||||
static int create_socket(esp_netif_t *netif);
|
||||
static int join_mdns_multicast_group(int sock, esp_netif_t *netif, mdns_ip_protocol_t ip_protocol);
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_LINUX)
|
||||
// Need to define packet buffer struct on linux
|
||||
struct pbuf {
|
||||
struct pbuf *next;
|
||||
void *payload;
|
||||
size_t tot_len;
|
||||
size_t len;
|
||||
};
|
||||
#else
|
||||
// Compatibility define to access sock-addr struct the same way for lwip and linux
|
||||
#define s6_addr32 un.u32_addr
|
||||
#endif // CONFIG_IDF_TARGET_LINUX
|
||||
|
||||
static void __attribute__((constructor)) ctor_networking_socket(void)
|
||||
{
|
||||
for (int i = 0; i < sizeof(s_interfaces) / sizeof(s_interfaces[0]); ++i) {
|
||||
s_interfaces[i].sock = -1;
|
||||
s_interfaces[i].proto = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void delete_socket(int sock)
|
||||
{
|
||||
close(sock);
|
||||
}
|
||||
|
||||
bool mdns_is_netif_ready(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
return s_interfaces[tcpip_if].proto & (ip_protocol == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6);
|
||||
}
|
||||
|
||||
void *_mdns_get_packet_data(mdns_rx_packet_t *packet)
|
||||
{
|
||||
return packet->pb->payload;
|
||||
}
|
||||
|
||||
size_t _mdns_get_packet_len(mdns_rx_packet_t *packet)
|
||||
{
|
||||
return packet->pb->len;
|
||||
}
|
||||
|
||||
void _mdns_packet_free(mdns_rx_packet_t *packet)
|
||||
{
|
||||
mdns_mem_free(packet->pb->payload);
|
||||
mdns_mem_free(packet->pb);
|
||||
mdns_mem_free(packet);
|
||||
}
|
||||
|
||||
esp_err_t _mdns_pcb_deinit(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
s_interfaces[tcpip_if].proto &= ~(ip_protocol == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6);
|
||||
if (s_interfaces[tcpip_if].proto == 0) {
|
||||
// if the interface for both protocols uninitialized, close the interface socket
|
||||
if (s_interfaces[tcpip_if].sock >= 0) {
|
||||
delete_socket(s_interfaces[tcpip_if].sock);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < MDNS_MAX_INTERFACES; i++) {
|
||||
if (s_interfaces[i].sock >= 0) {
|
||||
// If any of the interfaces initialized
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// no interface alive, stop the rx task
|
||||
s_run_sock_recv_task = false;
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_LINUX)
|
||||
#ifdef CONFIG_LWIP_IPV6
|
||||
static char *inet6_ntoa_r(struct in6_addr addr, char *ptr, size_t size)
|
||||
{
|
||||
inet_ntop(AF_INET6, &(addr.s6_addr32[0]), ptr, size);
|
||||
return ptr;
|
||||
}
|
||||
#endif // CONFIG_LWIP_IPV6
|
||||
static char *inet_ntoa_r(struct in_addr addr, char *ptr, size_t size)
|
||||
{
|
||||
char *res = inet_ntoa(addr);
|
||||
if (res && strlen(res) < size) {
|
||||
strcpy(ptr, res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif // CONFIG_IDF_TARGET_LINUX
|
||||
|
||||
static inline char *get_string_address(struct sockaddr_storage *source_addr)
|
||||
{
|
||||
static char address_str[40]; // 40=(8*4+7+term) is the max size of ascii IPv6 addr "XXXX:XX...XX:XXXX"
|
||||
char *res = NULL;
|
||||
// Convert ip address to string
|
||||
#ifdef CONFIG_LWIP_IPV4
|
||||
if (source_addr->ss_family == PF_INET) {
|
||||
res = inet_ntoa_r(((struct sockaddr_in *)source_addr)->sin_addr, address_str, sizeof(address_str));
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_LWIP_IPV6
|
||||
if (source_addr->ss_family == PF_INET6) {
|
||||
res = inet6_ntoa_r(((struct sockaddr_in6 *)source_addr)->sin6_addr, address_str, sizeof(address_str));
|
||||
}
|
||||
#endif
|
||||
if (!res) {
|
||||
address_str[0] = '\0'; // Returns empty string if conversion didn't succeed
|
||||
}
|
||||
return address_str;
|
||||
}
|
||||
|
||||
|
||||
static inline size_t espaddr_to_inet(const esp_ip_addr_t *addr, const uint16_t port, const mdns_ip_protocol_t ip_protocol, struct sockaddr_storage *in_addr)
|
||||
{
|
||||
size_t ss_addr_len = 0;
|
||||
memset(in_addr, 0, sizeof(struct sockaddr_storage));
|
||||
#ifdef CONFIG_LWIP_IPV4
|
||||
if (ip_protocol == MDNS_IP_PROTOCOL_V4 && addr->type == ESP_IPADDR_TYPE_V4) {
|
||||
in_addr->ss_family = PF_INET;
|
||||
#if !defined(CONFIG_IDF_TARGET_LINUX)
|
||||
in_addr->s2_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
ss_addr_len = sizeof(struct sockaddr_in);
|
||||
struct sockaddr_in *in_addr_ip4 = (struct sockaddr_in *) in_addr;
|
||||
in_addr_ip4->sin_port = port;
|
||||
in_addr_ip4->sin_addr.s_addr = addr->u_addr.ip4.addr;
|
||||
}
|
||||
#endif // CONFIG_LWIP_IPV4
|
||||
#ifdef CONFIG_LWIP_IPV6
|
||||
if (ip_protocol == MDNS_IP_PROTOCOL_V6 && addr->type == ESP_IPADDR_TYPE_V6) {
|
||||
memset(in_addr, 0, sizeof(struct sockaddr_storage));
|
||||
in_addr->ss_family = PF_INET6;
|
||||
#if !defined(CONFIG_IDF_TARGET_LINUX)
|
||||
in_addr->s2_len = sizeof(struct sockaddr_in6);
|
||||
#endif
|
||||
ss_addr_len = sizeof(struct sockaddr_in6);
|
||||
struct sockaddr_in6 *in_addr_ip6 = (struct sockaddr_in6 *)in_addr;
|
||||
uint32_t *u32_addr = in_addr_ip6->sin6_addr.s6_addr32;
|
||||
in_addr_ip6->sin6_port = port;
|
||||
u32_addr[0] = addr->u_addr.ip6.addr[0];
|
||||
u32_addr[1] = addr->u_addr.ip6.addr[1];
|
||||
u32_addr[2] = addr->u_addr.ip6.addr[2];
|
||||
u32_addr[3] = addr->u_addr.ip6.addr[3];
|
||||
}
|
||||
#endif // CONFIG_LWIP_IPV6
|
||||
return ss_addr_len;
|
||||
}
|
||||
|
||||
size_t _mdns_udp_pcb_write(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, const esp_ip_addr_t *ip, uint16_t port, uint8_t *data, size_t len)
|
||||
{
|
||||
if (!(s_interfaces[tcpip_if].proto & (ip_protocol == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6))) {
|
||||
return 0;
|
||||
}
|
||||
int sock = s_interfaces[tcpip_if].sock;
|
||||
if (sock < 0) {
|
||||
return 0;
|
||||
}
|
||||
struct sockaddr_storage in_addr;
|
||||
size_t ss_size = espaddr_to_inet(ip, htons(port), ip_protocol, &in_addr);
|
||||
if (!ss_size) {
|
||||
ESP_LOGE(TAG, "espaddr_to_inet() failed: Mismatch of IP protocols");
|
||||
return 0;
|
||||
}
|
||||
ESP_LOGD(TAG, "[sock=%d]: Sending to IP %s port %d", sock, get_string_address(&in_addr), port);
|
||||
ssize_t actual_len = sendto(sock, data, len, 0, (struct sockaddr *)&in_addr, ss_size);
|
||||
if (actual_len < 0) {
|
||||
ESP_LOGE(TAG, "[sock=%d]: _mdns_udp_pcb_write sendto() has failed\n errno=%d: %s", sock, errno, strerror(errno));
|
||||
}
|
||||
return actual_len;
|
||||
}
|
||||
|
||||
static inline void inet_to_espaddr(const struct sockaddr_storage *in_addr, esp_ip_addr_t *addr, uint16_t *port)
|
||||
{
|
||||
#ifdef CONFIG_LWIP_IPV4
|
||||
if (in_addr->ss_family == PF_INET) {
|
||||
struct sockaddr_in *in_addr_ip4 = (struct sockaddr_in *)in_addr;
|
||||
memset(addr, 0, sizeof(esp_ip_addr_t));
|
||||
*port = in_addr_ip4->sin_port;
|
||||
addr->u_addr.ip4.addr = in_addr_ip4->sin_addr.s_addr;
|
||||
addr->type = ESP_IPADDR_TYPE_V4;
|
||||
}
|
||||
#endif /* CONFIG_LWIP_IPV4 */
|
||||
#ifdef CONFIG_LWIP_IPV6
|
||||
if (in_addr->ss_family == PF_INET6) {
|
||||
struct sockaddr_in6 *in_addr_ip6 = (struct sockaddr_in6 *)in_addr;
|
||||
memset(addr, 0, sizeof(esp_ip_addr_t));
|
||||
*port = in_addr_ip6->sin6_port;
|
||||
uint32_t *u32_addr = in_addr_ip6->sin6_addr.s6_addr32;
|
||||
if (u32_addr[0] == 0 && u32_addr[1] == 0 && u32_addr[2] == esp_netif_htonl(0x0000FFFFUL)) {
|
||||
// Mapped IPv4 address, convert directly to IPv4
|
||||
addr->type = ESP_IPADDR_TYPE_V4;
|
||||
addr->u_addr.ip4.addr = u32_addr[3];
|
||||
} else {
|
||||
addr->type = ESP_IPADDR_TYPE_V6;
|
||||
addr->u_addr.ip6.addr[0] = u32_addr[0];
|
||||
addr->u_addr.ip6.addr[1] = u32_addr[1];
|
||||
addr->u_addr.ip6.addr[2] = u32_addr[2];
|
||||
addr->u_addr.ip6.addr[3] = u32_addr[3];
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_LWIP_IPV6
|
||||
}
|
||||
|
||||
void sock_recv_task(void *arg)
|
||||
{
|
||||
while (s_run_sock_recv_task) {
|
||||
struct timeval tv = {
|
||||
.tv_sec = 1,
|
||||
.tv_usec = 0,
|
||||
};
|
||||
fd_set rfds;
|
||||
FD_ZERO(&rfds);
|
||||
int max_sock = -1;
|
||||
for (int i = 0; i < MDNS_MAX_INTERFACES; i++) {
|
||||
int sock = s_interfaces[i].sock;
|
||||
if (sock >= 0) {
|
||||
FD_SET(sock, &rfds);
|
||||
max_sock = MAX(max_sock, sock);
|
||||
}
|
||||
}
|
||||
if (max_sock < 0) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
ESP_LOGI(TAG, "No sock!");
|
||||
continue;
|
||||
}
|
||||
|
||||
int s = select(max_sock + 1, &rfds, NULL, NULL, &tv);
|
||||
if (s < 0) {
|
||||
ESP_LOGE(TAG, "Select failed. errno=%d: %s", errno, strerror(errno));
|
||||
break;
|
||||
} else if (s > 0) {
|
||||
for (int tcpip_if = 0; tcpip_if < MDNS_MAX_INTERFACES; tcpip_if++) {
|
||||
int sock = s_interfaces[tcpip_if].sock;
|
||||
if (sock < 0) {
|
||||
continue;
|
||||
}
|
||||
if (FD_ISSET(sock, &rfds)) {
|
||||
static char recvbuf[MDNS_MAX_PACKET_SIZE];
|
||||
uint16_t port = 0;
|
||||
|
||||
struct sockaddr_storage raddr; // Large enough for both IPv4 or IPv6
|
||||
socklen_t socklen = sizeof(struct sockaddr_storage);
|
||||
esp_ip_addr_t addr = {0};
|
||||
int len = recvfrom(sock, recvbuf, sizeof(recvbuf), 0,
|
||||
(struct sockaddr *) &raddr, &socklen);
|
||||
if (len < 0) {
|
||||
ESP_LOGE(TAG, "multicast recvfrom failed. errno=%d: %s", errno, strerror(errno));
|
||||
break;
|
||||
}
|
||||
ESP_LOGD(TAG, "[sock=%d]: Received from IP:%s", sock, get_string_address(&raddr));
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, recvbuf, len, ESP_LOG_VERBOSE);
|
||||
inet_to_espaddr(&raddr, &addr, &port);
|
||||
|
||||
// Allocate the packet structure and pass it to the mdns main engine
|
||||
mdns_rx_packet_t *packet = (mdns_rx_packet_t *) mdns_mem_calloc(1, sizeof(mdns_rx_packet_t));
|
||||
struct pbuf *packet_pbuf = mdns_mem_calloc(1, sizeof(struct pbuf));
|
||||
uint8_t *buf = mdns_mem_malloc(len);
|
||||
if (packet == NULL || packet_pbuf == NULL || buf == NULL) {
|
||||
mdns_mem_free(buf);
|
||||
mdns_mem_free(packet_pbuf);
|
||||
mdns_mem_free(packet);
|
||||
HOOK_MALLOC_FAILED;
|
||||
ESP_LOGE(TAG, "Failed to allocate the mdns packet");
|
||||
continue;
|
||||
}
|
||||
memcpy(buf, recvbuf, len);
|
||||
packet_pbuf->next = NULL;
|
||||
packet_pbuf->payload = buf;
|
||||
packet_pbuf->tot_len = len;
|
||||
packet_pbuf->len = len;
|
||||
packet->tcpip_if = tcpip_if;
|
||||
packet->pb = packet_pbuf;
|
||||
packet->src_port = ntohs(port);
|
||||
memcpy(&packet->src, &addr, sizeof(esp_ip_addr_t));
|
||||
// TODO(IDF-3651): Add the correct dest addr -- for mdns to decide multicast/unicast
|
||||
// Currently it's enough to assume the packet is multicast and mdns to check the source port of the packet
|
||||
memset(&packet->dest, 0, sizeof(esp_ip_addr_t));
|
||||
packet->multicast = 1;
|
||||
packet->dest.type = packet->src.type;
|
||||
packet->ip_protocol =
|
||||
packet->src.type == ESP_IPADDR_TYPE_V4 ? MDNS_IP_PROTOCOL_V4 : MDNS_IP_PROTOCOL_V6;
|
||||
if (_mdns_send_rx_action(packet) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "_mdns_send_rx_action failed!");
|
||||
mdns_mem_free(packet->pb->payload);
|
||||
mdns_mem_free(packet->pb);
|
||||
mdns_mem_free(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void mdns_networking_init(void)
|
||||
{
|
||||
if (s_run_sock_recv_task == false) {
|
||||
s_run_sock_recv_task = true;
|
||||
xTaskCreate(sock_recv_task, "mdns recv task", 3 * 1024, NULL, 5, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static bool create_pcb(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
if (s_interfaces[tcpip_if].proto & (ip_protocol == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6)) {
|
||||
return true;
|
||||
}
|
||||
int sock = s_interfaces[tcpip_if].sock;
|
||||
esp_netif_t *netif = _mdns_get_esp_netif(tcpip_if);
|
||||
if (sock < 0) {
|
||||
sock = create_socket(netif);
|
||||
}
|
||||
if (sock < 0) {
|
||||
ESP_LOGE(TAG, "Failed to create the socket!");
|
||||
return false;
|
||||
}
|
||||
int err = join_mdns_multicast_group(sock, netif, ip_protocol);
|
||||
if (err < 0) {
|
||||
ESP_LOGE(TAG, "Failed to add ipv6 multicast group for protocol %d", ip_protocol);
|
||||
}
|
||||
s_interfaces[tcpip_if].proto |= (ip_protocol == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6);
|
||||
s_interfaces[tcpip_if].sock = sock;
|
||||
return true;
|
||||
}
|
||||
|
||||
esp_err_t _mdns_pcb_init(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
ESP_LOGI(TAG, "_mdns_pcb_init(tcpip_if=%lu, ip_protocol=%lu)", (unsigned long)tcpip_if, (unsigned long)ip_protocol);
|
||||
if (!create_pcb(tcpip_if, ip_protocol)) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
mdns_networking_init();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static int create_socket(esp_netif_t *netif)
|
||||
{
|
||||
#ifdef CONFIG_LWIP_IPV6
|
||||
int sock = socket(PF_INET6, SOCK_DGRAM, 0);
|
||||
#else
|
||||
int sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
#endif
|
||||
if (sock < 0) {
|
||||
ESP_LOGE(TAG, "Failed to create socket. errno=%d: %s", errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
int on = 1;
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
|
||||
ESP_LOGE(TAG, "Failed setsockopt() to set SO_REUSEADDR. errno=%d: %s\n", errno, strerror(errno));
|
||||
}
|
||||
// Bind the socket to any address
|
||||
#ifdef CONFIG_LWIP_IPV6
|
||||
struct sockaddr_in6 saddr = { INADDR_ANY };
|
||||
saddr.sin6_family = AF_INET6;
|
||||
saddr.sin6_port = htons(5353);
|
||||
bzero(&saddr.sin6_addr.s6_addr, sizeof(saddr.sin6_addr.s6_addr));
|
||||
int err = bind(sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in6));
|
||||
if (err < 0) {
|
||||
ESP_LOGE(TAG, "Failed to bind socket. errno=%d: %s", errno, strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
#else
|
||||
struct sockaddr_in saddr = { 0 };
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_port = htons(5353);
|
||||
bzero(&saddr.sin_addr.s_addr, sizeof(saddr.sin_addr.s_addr));
|
||||
int err = bind(sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in));
|
||||
if (err < 0) {
|
||||
ESP_LOGE(TAG, "Failed to bind socket. errno=%d: %s", errno, strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
#endif // CONFIG_LWIP_IPV6
|
||||
struct ifreq ifr;
|
||||
esp_netif_get_netif_impl_name(netif, ifr.ifr_name);
|
||||
int ret = setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(struct ifreq));
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "\"%s\" Unable to bind socket to specified interface. errno=%d: %s", esp_netif_get_desc(netif), errno, strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
|
||||
return sock;
|
||||
|
||||
err:
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LWIP_IPV6
|
||||
static int socket_add_ipv6_multicast_group(int sock, esp_netif_t *netif)
|
||||
{
|
||||
int ifindex = esp_netif_get_netif_impl_index(netif);
|
||||
int err = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex));
|
||||
if (err < 0) {
|
||||
ESP_LOGE(TAG, "Failed to set IPV6_MULTICAST_IF. errno=%d: %s", errno, strerror(errno));
|
||||
return err;
|
||||
}
|
||||
|
||||
struct ipv6_mreq v6imreq = { 0 };
|
||||
esp_ip_addr_t multi_addr = ESP_IP6ADDR_INIT(0x000002ff, 0, 0, 0xfb000000);
|
||||
memcpy(&v6imreq.ipv6mr_multiaddr, &multi_addr.u_addr.ip6.addr, sizeof(v6imreq.ipv6mr_multiaddr));
|
||||
v6imreq.ipv6mr_interface = ifindex;
|
||||
err = setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &v6imreq, sizeof(struct ipv6_mreq));
|
||||
if (err < 0) {
|
||||
ESP_LOGE(TAG, "Failed to set IPV6_ADD_MEMBERSHIP. errno=%d: %s", errno, strerror(errno));
|
||||
return err;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
#endif // CONFIG_LWIP_IPV6
|
||||
|
||||
#ifdef CONFIG_LWIP_IPV4
|
||||
static int socket_add_ipv4_multicast_group(int sock, esp_netif_t *netif)
|
||||
{
|
||||
struct ip_mreq imreq = { 0 };
|
||||
int err = 0;
|
||||
esp_netif_ip_info_t ip_info = { 0 };
|
||||
|
||||
if (esp_netif_get_ip_info(netif, &ip_info) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to esp_netif_get_ip_info()");
|
||||
goto err;
|
||||
}
|
||||
imreq.imr_interface.s_addr = ip_info.ip.addr;
|
||||
|
||||
esp_ip_addr_t multicast_addr = ESP_IP4ADDR_INIT(224, 0, 0, 251);
|
||||
imreq.imr_multiaddr.s_addr = multicast_addr.u_addr.ip4.addr;
|
||||
|
||||
err = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imreq, sizeof(struct ip_mreq));
|
||||
if (err < 0) {
|
||||
ESP_LOGE(TAG, "[sock=%d] Failed to set IP_ADD_MEMBERSHIP. errno=%d: %s", sock, errno, strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
|
||||
err:
|
||||
return err;
|
||||
}
|
||||
#endif // CONFIG_LWIP_IPV4
|
||||
|
||||
static int join_mdns_multicast_group(int sock, esp_netif_t *netif, mdns_ip_protocol_t ip_protocol)
|
||||
{
|
||||
#ifdef CONFIG_LWIP_IPV4
|
||||
if (ip_protocol == MDNS_IP_PROTOCOL_V4) {
|
||||
return socket_add_ipv4_multicast_group(sock, netif);
|
||||
}
|
||||
#endif // CONFIG_LWIP_IPV4
|
||||
#ifdef CONFIG_LWIP_IPV6
|
||||
if (ip_protocol == MDNS_IP_PROTOCOL_V6) {
|
||||
return socket_add_ipv6_multicast_group(sock, netif);
|
||||
}
|
||||
#endif // CONFIG_LWIP_IPV6
|
||||
return -1;
|
||||
}
|
||||
54
managed_components/espressif__mdns/mem_prefix_script.py
Normal file
54
managed_components/espressif__mdns/mem_prefix_script.py
Normal file
@@ -0,0 +1,54 @@
|
||||
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
import re
|
||||
import sys
|
||||
|
||||
# Configurable prefix for memory functions
|
||||
MDNS_MEM_PREFIX = 'mdns_mem_' # Change this to modify the prefix
|
||||
|
||||
|
||||
def add_prefix_to_mem_funcs(content):
|
||||
# List of memory functions to prefix
|
||||
mem_funcs = [
|
||||
'malloc',
|
||||
'calloc',
|
||||
'free',
|
||||
'strdup',
|
||||
'strndup'
|
||||
]
|
||||
|
||||
# Create regex pattern matching the memory functions but not already prefixed ones
|
||||
pattern = fr'(?<!{MDNS_MEM_PREFIX})(?<![\w])(' + '|'.join(mem_funcs) + r')(?=\s*\()'
|
||||
|
||||
# Replace all occurrences with configured prefix
|
||||
modified = re.sub(pattern, fr'{MDNS_MEM_PREFIX}\1', content)
|
||||
|
||||
return modified
|
||||
|
||||
|
||||
def process_file(filename):
|
||||
try:
|
||||
# Read the file
|
||||
with open(filename, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
# Add prefixes
|
||||
modified = add_prefix_to_mem_funcs(content)
|
||||
|
||||
# Write back to file
|
||||
with open(filename, 'w') as f:
|
||||
f.write(modified)
|
||||
|
||||
print(f'Successfully processed {filename}')
|
||||
|
||||
except Exception as e:
|
||||
print(f'Error processing {filename}: {str(e)}')
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) != 2:
|
||||
print('Usage: python script.py <filename>')
|
||||
sys.exit(1)
|
||||
|
||||
process_file(sys.argv[1])
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Allocate memory.
|
||||
* @param size Number of bytes to allocate.
|
||||
* @return Pointer to allocated memory, or NULL on failure.
|
||||
*/
|
||||
void *mdns_mem_malloc(size_t size);
|
||||
|
||||
/**
|
||||
* @brief Allocate and zero memory.
|
||||
* @param num Number of elements.
|
||||
* @param size Size of each element.
|
||||
* @return Pointer to allocated memory, or NULL on failure.
|
||||
*/
|
||||
void *mdns_mem_calloc(size_t num, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Free allocated memory.
|
||||
* @param ptr Pointer to memory to free.
|
||||
*/
|
||||
void mdns_mem_free(void *ptr);
|
||||
|
||||
/**
|
||||
* @brief Duplicate a string.
|
||||
* @param s String to duplicate.
|
||||
* @return Pointer to duplicated string, or NULL on failure.
|
||||
*/
|
||||
char *mdns_mem_strdup(const char *s);
|
||||
|
||||
/**
|
||||
* @brief Duplicate a string with length limit.
|
||||
* @param s String to duplicate.
|
||||
* @param n Maximum number of characters to copy.
|
||||
* @return Pointer to duplicated string, or NULL on failure.
|
||||
*/
|
||||
char *mdns_mem_strndup(const char *s, size_t n);
|
||||
|
||||
/**
|
||||
* @brief Allocate memory for mDNS task.
|
||||
* @param size Number of bytes to allocate.
|
||||
* @return Pointer to allocated memory, or NULL on failure.
|
||||
*/
|
||||
void *mdns_mem_task_malloc(size_t size);
|
||||
|
||||
/**
|
||||
* @brief Free allocated memory for mDNS task.
|
||||
* @param ptr Pointer to memory to free.
|
||||
*/
|
||||
void mdns_mem_task_free(void *ptr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef ESP_MDNS_NETWORKING_H_
|
||||
#define ESP_MDNS_NETWORKING_H_
|
||||
|
||||
/*
|
||||
* MDNS Server Networking -- private include
|
||||
*
|
||||
*/
|
||||
#include "mdns.h"
|
||||
#include "mdns_private.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief Queue RX packet action
|
||||
*/
|
||||
esp_err_t _mdns_send_rx_action(mdns_rx_packet_t *packet);
|
||||
|
||||
bool mdns_is_netif_ready(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol);
|
||||
|
||||
/**
|
||||
* @brief Start PCB
|
||||
*/
|
||||
esp_err_t _mdns_pcb_init(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol);
|
||||
|
||||
/**
|
||||
* @brief Stop PCB
|
||||
*/
|
||||
esp_err_t _mdns_pcb_deinit(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol);
|
||||
|
||||
/**
|
||||
* @brief send packet over UDP
|
||||
*
|
||||
* @param server The server
|
||||
* @param data byte array containing the packet data
|
||||
* @param len length of the packet data
|
||||
*
|
||||
* @return length of sent packet or 0 on error
|
||||
*/
|
||||
size_t _mdns_udp_pcb_write(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, const esp_ip_addr_t *ip, uint16_t port, uint8_t *data, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Gets data pointer to the mDNS packet
|
||||
*/
|
||||
void *_mdns_get_packet_data(mdns_rx_packet_t *packet);
|
||||
|
||||
/**
|
||||
* @brief Gets data length of c
|
||||
*/
|
||||
size_t _mdns_get_packet_len(mdns_rx_packet_t *packet);
|
||||
|
||||
/**
|
||||
* @brief Free the mDNS packet
|
||||
*/
|
||||
void _mdns_packet_free(mdns_rx_packet_t *packet);
|
||||
|
||||
#endif /* ESP_MDNS_NETWORKING_H_ */
|
||||
@@ -0,0 +1,468 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef MDNS_PRIVATE_H_
|
||||
#define MDNS_PRIVATE_H_
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "mdns.h"
|
||||
#include "esp_task.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_timer.h"
|
||||
#include "esp_system.h"
|
||||
|
||||
#ifdef CONFIG_MDNS_ENABLE_DEBUG_PRINTS
|
||||
#define MDNS_ENABLE_DEBUG
|
||||
#define _mdns_dbg_printf(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/** Number of predefined interfaces */
|
||||
#ifndef CONFIG_MDNS_PREDEF_NETIF_STA
|
||||
#define CONFIG_MDNS_PREDEF_NETIF_STA 0
|
||||
#endif
|
||||
#ifndef CONFIG_MDNS_PREDEF_NETIF_AP
|
||||
#define CONFIG_MDNS_PREDEF_NETIF_AP 0
|
||||
#endif
|
||||
#ifndef CONFIG_MDNS_PREDEF_NETIF_ETH
|
||||
#define CONFIG_MDNS_PREDEF_NETIF_ETH 0
|
||||
#endif
|
||||
#define MDNS_MAX_PREDEF_INTERFACES (CONFIG_MDNS_PREDEF_NETIF_STA + CONFIG_MDNS_PREDEF_NETIF_AP + CONFIG_MDNS_PREDEF_NETIF_ETH)
|
||||
|
||||
#ifdef CONFIG_LWIP_IPV6_NUM_ADDRESSES
|
||||
#define NETIF_IPV6_MAX_NUMS CONFIG_LWIP_IPV6_NUM_ADDRESSES
|
||||
#else
|
||||
#define NETIF_IPV6_MAX_NUMS 3
|
||||
#endif
|
||||
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 1, 0)
|
||||
/* CONFIG_LWIP_IPV4 was introduced in IDF v5.1 */
|
||||
/* For IDF v5.0, set CONFIG_LWIP_IPV4 to 1 by default */
|
||||
#ifndef CONFIG_LWIP_IPV4
|
||||
#define CONFIG_LWIP_IPV4 1
|
||||
#endif // CONFIG_LWIP_IPV4
|
||||
#endif // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 1, 0)
|
||||
|
||||
/** Number of configured interfaces */
|
||||
#if MDNS_MAX_PREDEF_INTERFACES > CONFIG_MDNS_MAX_INTERFACES
|
||||
#warning Number of configured interfaces is less then number of predefined interfaces. Please update CONFIG_MDNS_MAX_INTERFACES.
|
||||
#define MDNS_MAX_INTERFACES (MDNS_MAX_PREDEF_INTERFACES)
|
||||
#else
|
||||
#define MDNS_MAX_INTERFACES (CONFIG_MDNS_MAX_INTERFACES)
|
||||
#endif
|
||||
|
||||
/** The maximum number of services */
|
||||
#define MDNS_MAX_SERVICES CONFIG_MDNS_MAX_SERVICES
|
||||
|
||||
#define MDNS_ANSWER_PTR_TTL 4500
|
||||
#define MDNS_ANSWER_TXT_TTL 4500
|
||||
#define MDNS_ANSWER_SRV_TTL 120
|
||||
#define MDNS_ANSWER_A_TTL 120
|
||||
#define MDNS_ANSWER_AAAA_TTL 120
|
||||
|
||||
#define MDNS_FLAGS_QUERY_REPSONSE 0x8000
|
||||
#define MDNS_FLAGS_AUTHORITATIVE 0x0400
|
||||
#define MDNS_FLAGS_QR_AUTHORITATIVE (MDNS_FLAGS_QUERY_REPSONSE | MDNS_FLAGS_AUTHORITATIVE)
|
||||
#define MDNS_FLAGS_DISTRIBUTED 0x0200
|
||||
|
||||
#define MDNS_NAME_REF 0xC000
|
||||
|
||||
//custom type! only used by this implementation
|
||||
//to help manage service discovery handling
|
||||
#define MDNS_TYPE_SDPTR 0x0032
|
||||
|
||||
#define MDNS_CLASS_IN 0x0001
|
||||
#define MDNS_CLASS_ANY 0x00FF
|
||||
#define MDNS_CLASS_IN_FLUSH_CACHE 0x8001
|
||||
|
||||
#define MDNS_ANSWER_ALL 0x3F
|
||||
#define MDNS_ANSWER_PTR 0x08
|
||||
#define MDNS_ANSWER_TXT 0x04
|
||||
#define MDNS_ANSWER_SRV 0x02
|
||||
#define MDNS_ANSWER_A 0x01
|
||||
#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 CONFIG_MDNS_TASK_STACK_SIZE
|
||||
#define MDNS_TASK_PRIORITY CONFIG_MDNS_TASK_PRIORITY
|
||||
#if (MDNS_TASK_PRIORITY > ESP_TASK_PRIO_MAX)
|
||||
#error "mDNS task priority is higher than ESP_TASK_PRIO_MAX"
|
||||
#elif (MDNS_TASK_PRIORITY > ESP_TASKD_EVENT_PRIO)
|
||||
#warning "mDNS task priority is higher than ESP_TASKD_EVENT_PRIO, mDNS library might not work correctly"
|
||||
#endif
|
||||
#define MDNS_TASK_AFFINITY CONFIG_MDNS_TASK_AFFINITY
|
||||
#define MDNS_SERVICE_ADD_TIMEOUT_MS CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS
|
||||
|
||||
#define MDNS_PACKET_QUEUE_LEN 16 // Maximum packets that can be queued for parsing
|
||||
#define MDNS_ACTION_QUEUE_LEN CONFIG_MDNS_ACTION_QUEUE_LEN // Maximum actions pending to the server
|
||||
#define MDNS_TXT_MAX_LEN 1024 // Maximum string length of text data in TXT record
|
||||
#define MDNS_MAX_PACKET_SIZE 1460 // Maximum size of mDNS outgoing packet
|
||||
|
||||
#define MDNS_HEAD_LEN 12
|
||||
#define MDNS_HEAD_ID_OFFSET 0
|
||||
#define MDNS_HEAD_FLAGS_OFFSET 2
|
||||
#define MDNS_HEAD_QUESTIONS_OFFSET 4
|
||||
#define MDNS_HEAD_ANSWERS_OFFSET 6
|
||||
#define MDNS_HEAD_SERVERS_OFFSET 8
|
||||
#define MDNS_HEAD_ADDITIONAL_OFFSET 10
|
||||
|
||||
#define MDNS_TYPE_OFFSET 0
|
||||
#define MDNS_CLASS_OFFSET 2
|
||||
#define MDNS_TTL_OFFSET 4
|
||||
#define MDNS_LEN_OFFSET 8
|
||||
#define MDNS_DATA_OFFSET 10
|
||||
|
||||
#define MDNS_SRV_PRIORITY_OFFSET 0
|
||||
#define MDNS_SRV_WEIGHT_OFFSET 2
|
||||
#define MDNS_SRV_PORT_OFFSET 4
|
||||
#define MDNS_SRV_FQDN_OFFSET 6
|
||||
|
||||
#define MDNS_TIMER_PERIOD_US (CONFIG_MDNS_TIMER_PERIOD_MS*1000)
|
||||
|
||||
#define MDNS_SERVICE_LOCK() xSemaphoreTake(_mdns_service_semaphore, portMAX_DELAY)
|
||||
#define MDNS_SERVICE_UNLOCK() xSemaphoreGive(_mdns_service_semaphore)
|
||||
|
||||
#define queueToEnd(type, queue, item) \
|
||||
if (!queue) { \
|
||||
queue = item; \
|
||||
} else { \
|
||||
type * _q = queue; \
|
||||
while (_q->next) { _q = _q->next; } \
|
||||
_q->next = item; \
|
||||
}
|
||||
|
||||
#define queueDetach(type, queue, item) \
|
||||
if (queue) { \
|
||||
if (queue == item) { \
|
||||
queue = queue->next; \
|
||||
} else { \
|
||||
type * _q = queue; \
|
||||
while (_q->next && _q->next != item) { \
|
||||
_q = _q->next; \
|
||||
} \
|
||||
if (_q->next == item) { \
|
||||
_q->next = item->next; \
|
||||
item->next = NULL; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define queueFree(type, queue) while (queue) { type * _q = queue; queue = queue->next; mdns_mem_free(_q); }
|
||||
|
||||
#define PCB_STATE_IS_PROBING(s) (s->state > PCB_OFF && s->state < PCB_ANNOUNCE_1)
|
||||
#define PCB_STATE_IS_ANNOUNCING(s) (s->state > PCB_PROBE_3 && s->state < PCB_RUNNING)
|
||||
#define PCB_STATE_IS_RUNNING(s) (s->state == PCB_RUNNING)
|
||||
|
||||
#ifndef HOOK_MALLOC_FAILED
|
||||
#define HOOK_MALLOC_FAILED ESP_LOGE(TAG, "Cannot allocate memory (line: %d, free heap: %" PRIu32 " bytes)", __LINE__, esp_get_free_heap_size());
|
||||
#endif
|
||||
|
||||
typedef size_t mdns_if_t;
|
||||
|
||||
typedef enum {
|
||||
PCB_OFF, PCB_DUP, PCB_INIT,
|
||||
PCB_PROBE_1, PCB_PROBE_2, PCB_PROBE_3,
|
||||
PCB_ANNOUNCE_1, PCB_ANNOUNCE_2, PCB_ANNOUNCE_3,
|
||||
PCB_RUNNING
|
||||
} mdns_pcb_state_t;
|
||||
|
||||
typedef enum {
|
||||
MDNS_ANSWER, MDNS_NS, MDNS_EXTRA
|
||||
} mdns_parsed_record_type_t;
|
||||
|
||||
typedef enum {
|
||||
ACTION_SYSTEM_EVENT,
|
||||
ACTION_HOSTNAME_SET,
|
||||
ACTION_INSTANCE_SET,
|
||||
ACTION_SEARCH_ADD,
|
||||
ACTION_SEARCH_SEND,
|
||||
ACTION_SEARCH_END,
|
||||
ACTION_BROWSE_ADD,
|
||||
ACTION_BROWSE_SYNC,
|
||||
ACTION_BROWSE_END,
|
||||
ACTION_TX_HANDLE,
|
||||
ACTION_RX_HANDLE,
|
||||
ACTION_TASK_STOP,
|
||||
ACTION_DELEGATE_HOSTNAME_ADD,
|
||||
ACTION_DELEGATE_HOSTNAME_REMOVE,
|
||||
ACTION_DELEGATE_HOSTNAME_SET_ADDR,
|
||||
ACTION_MAX
|
||||
} mdns_action_type_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint16_t id;
|
||||
uint16_t flags;
|
||||
uint16_t questions; //QDCOUNT
|
||||
uint16_t answers; //ANCOUNT
|
||||
uint16_t servers; //NSCOUNT
|
||||
uint16_t additional;//ARCOUNT
|
||||
} mdns_header_t;
|
||||
|
||||
typedef struct {
|
||||
char host[MDNS_NAME_BUF_LEN]; // hostname for A/AAAA records, instance name for SRV records
|
||||
char service[MDNS_NAME_BUF_LEN];
|
||||
char proto[MDNS_NAME_BUF_LEN];
|
||||
char domain[MDNS_NAME_BUF_LEN];
|
||||
uint8_t parts;
|
||||
uint8_t sub;
|
||||
bool invalid;
|
||||
} mdns_name_t;
|
||||
|
||||
typedef struct mdns_parsed_question_s {
|
||||
struct mdns_parsed_question_s *next;
|
||||
uint16_t type;
|
||||
bool sub;
|
||||
bool unicast;
|
||||
char *host;
|
||||
char *service;
|
||||
char *proto;
|
||||
char *domain;
|
||||
} mdns_parsed_question_t;
|
||||
|
||||
typedef struct mdns_parsed_record_s {
|
||||
struct mdns_parsed_record_s *next;
|
||||
mdns_parsed_record_type_t record_type;
|
||||
uint16_t type;
|
||||
uint16_t clas;
|
||||
uint8_t flush;
|
||||
uint32_t ttl;
|
||||
char *host;
|
||||
char *service;
|
||||
char *proto;
|
||||
char *domain;
|
||||
uint16_t data_len;
|
||||
uint8_t *data;
|
||||
} mdns_parsed_record_t;
|
||||
|
||||
typedef struct {
|
||||
mdns_if_t tcpip_if;
|
||||
mdns_ip_protocol_t ip_protocol;
|
||||
esp_ip_addr_t src;
|
||||
uint16_t src_port;
|
||||
uint8_t multicast;
|
||||
uint8_t authoritative;
|
||||
uint8_t probe;
|
||||
uint8_t discovery;
|
||||
uint8_t distributed;
|
||||
mdns_parsed_question_t *questions;
|
||||
mdns_parsed_record_t *records;
|
||||
uint16_t id;
|
||||
} mdns_parsed_packet_t;
|
||||
|
||||
typedef struct {
|
||||
mdns_if_t tcpip_if;
|
||||
mdns_ip_protocol_t ip_protocol;
|
||||
struct pbuf *pb;
|
||||
esp_ip_addr_t src;
|
||||
esp_ip_addr_t dest;
|
||||
uint16_t src_port;
|
||||
uint8_t multicast;
|
||||
} mdns_rx_packet_t;
|
||||
|
||||
typedef struct mdns_txt_linked_item_s {
|
||||
const char *key; /*!< item key name */
|
||||
char *value; /*!< item value string */
|
||||
uint8_t value_len; /*!< item value length */
|
||||
struct mdns_txt_linked_item_s *next; /*!< next result, or NULL for the last result in the list */
|
||||
} mdns_txt_linked_item_t;
|
||||
|
||||
typedef struct mdns_subtype_s {
|
||||
const char *subtype; /*!< subtype */
|
||||
struct mdns_subtype_s *next; /*!< next result, or NULL for the last result in the list */
|
||||
} mdns_subtype_t;
|
||||
|
||||
typedef struct {
|
||||
const char *instance;
|
||||
const char *service;
|
||||
const char *proto;
|
||||
const char *hostname;
|
||||
uint16_t priority;
|
||||
uint16_t weight;
|
||||
uint16_t port;
|
||||
mdns_txt_linked_item_t *txt;
|
||||
mdns_subtype_t *subtype;
|
||||
} mdns_service_t;
|
||||
|
||||
typedef struct mdns_srv_item_s {
|
||||
struct mdns_srv_item_s *next;
|
||||
mdns_service_t *service;
|
||||
} mdns_srv_item_t;
|
||||
|
||||
typedef struct mdns_out_question_s {
|
||||
struct mdns_out_question_s *next;
|
||||
uint16_t type;
|
||||
bool unicast;
|
||||
const char *host;
|
||||
const char *service;
|
||||
const char *proto;
|
||||
const char *domain;
|
||||
bool own_dynamic_memory;
|
||||
} mdns_out_question_t;
|
||||
|
||||
typedef struct mdns_host_item_t {
|
||||
const char *hostname;
|
||||
mdns_ip_addr_t *address_list;
|
||||
struct mdns_host_item_t *next;
|
||||
} mdns_host_item_t;
|
||||
|
||||
typedef struct mdns_out_answer_s {
|
||||
struct mdns_out_answer_s *next;
|
||||
uint16_t type;
|
||||
uint8_t bye;
|
||||
uint8_t flush;
|
||||
mdns_service_t *service;
|
||||
mdns_host_item_t *host;
|
||||
const char *custom_instance;
|
||||
const char *custom_service;
|
||||
const char *custom_proto;
|
||||
} mdns_out_answer_t;
|
||||
|
||||
typedef struct mdns_tx_packet_s {
|
||||
struct mdns_tx_packet_s *next;
|
||||
uint32_t send_at;
|
||||
mdns_if_t tcpip_if;
|
||||
mdns_ip_protocol_t ip_protocol;
|
||||
esp_ip_addr_t dst;
|
||||
uint16_t port;
|
||||
uint16_t flags;
|
||||
uint8_t distributed;
|
||||
mdns_out_question_t *questions;
|
||||
mdns_out_answer_t *answers;
|
||||
mdns_out_answer_t *servers;
|
||||
mdns_out_answer_t *additional;
|
||||
bool queued;
|
||||
uint16_t id;
|
||||
} mdns_tx_packet_t;
|
||||
|
||||
typedef struct {
|
||||
mdns_pcb_state_t state;
|
||||
mdns_srv_item_t **probe_services;
|
||||
uint8_t probe_services_len;
|
||||
uint8_t probe_ip;
|
||||
uint8_t probe_running;
|
||||
uint16_t failed_probes;
|
||||
} mdns_pcb_t;
|
||||
|
||||
typedef enum {
|
||||
SEARCH_OFF,
|
||||
SEARCH_INIT,
|
||||
SEARCH_RUNNING,
|
||||
SEARCH_MAX
|
||||
} mdns_search_once_state_t;
|
||||
|
||||
typedef enum {
|
||||
BROWSE_OFF,
|
||||
BROWSE_INIT,
|
||||
BROWSE_RUNNING,
|
||||
BROWSE_MAX
|
||||
} mdns_browse_state_t;
|
||||
|
||||
typedef struct mdns_search_once_s {
|
||||
struct mdns_search_once_s *next;
|
||||
|
||||
mdns_search_once_state_t state;
|
||||
uint32_t started_at;
|
||||
uint32_t sent_at;
|
||||
uint32_t timeout;
|
||||
mdns_query_notify_t notifier;
|
||||
SemaphoreHandle_t done_semaphore;
|
||||
uint16_t type;
|
||||
bool unicast;
|
||||
uint8_t max_results;
|
||||
uint8_t num_results;
|
||||
char *instance;
|
||||
char *service;
|
||||
char *proto;
|
||||
mdns_result_t *result;
|
||||
} mdns_search_once_t;
|
||||
|
||||
typedef struct mdns_browse_s {
|
||||
struct mdns_browse_s *next;
|
||||
|
||||
mdns_browse_state_t state;
|
||||
mdns_browse_notify_t notifier;
|
||||
|
||||
char *service;
|
||||
char *proto;
|
||||
mdns_result_t *result;
|
||||
} mdns_browse_t;
|
||||
|
||||
typedef struct mdns_browse_result_sync_t {
|
||||
mdns_result_t *result;
|
||||
struct mdns_browse_result_sync_t *next;
|
||||
} mdns_browse_result_sync_t;
|
||||
|
||||
typedef struct mdns_browse_sync {
|
||||
mdns_browse_t *browse;
|
||||
mdns_browse_result_sync_t *sync_result;
|
||||
} mdns_browse_sync_t;
|
||||
|
||||
typedef struct mdns_server_s {
|
||||
struct {
|
||||
mdns_pcb_t pcbs[MDNS_IP_PROTOCOL_MAX];
|
||||
} interfaces[MDNS_MAX_INTERFACES];
|
||||
const char *hostname;
|
||||
const char *instance;
|
||||
mdns_srv_item_t *services;
|
||||
QueueHandle_t action_queue;
|
||||
SemaphoreHandle_t action_sema;
|
||||
mdns_tx_packet_t *tx_queue_head;
|
||||
mdns_search_once_t *search_once;
|
||||
esp_timer_handle_t timer_handle;
|
||||
mdns_browse_t *browse;
|
||||
} mdns_server_t;
|
||||
|
||||
typedef struct {
|
||||
mdns_action_type_t type;
|
||||
union {
|
||||
struct {
|
||||
char *hostname;
|
||||
} hostname_set;
|
||||
char *instance;
|
||||
struct {
|
||||
mdns_if_t interface;
|
||||
mdns_event_actions_t event_action;
|
||||
} sys_event;
|
||||
struct {
|
||||
mdns_search_once_t *search;
|
||||
} search_add;
|
||||
struct {
|
||||
mdns_tx_packet_t *packet;
|
||||
} tx_handle;
|
||||
struct {
|
||||
mdns_rx_packet_t *packet;
|
||||
} rx_handle;
|
||||
struct {
|
||||
const char *hostname;
|
||||
mdns_ip_addr_t *address_list;
|
||||
} delegate_hostname;
|
||||
struct {
|
||||
mdns_browse_t *browse;
|
||||
} browse_add;
|
||||
struct {
|
||||
mdns_browse_sync_t *browse_sync;
|
||||
} browse_sync;
|
||||
} data;
|
||||
} mdns_action_t;
|
||||
|
||||
/*
|
||||
* @brief Convert mnds if to esp-netif handle
|
||||
*
|
||||
* @param tcpip_if mdns supported interface as internal enum
|
||||
*
|
||||
* @return
|
||||
* - ptr to esp-netif on success
|
||||
* - NULL if no available netif for current interface index
|
||||
*/
|
||||
esp_netif_t *_mdns_get_esp_netif(mdns_if_t tcpip_if);
|
||||
|
||||
|
||||
#endif /* MDNS_PRIVATE_H_ */
|
||||
@@ -0,0 +1,16 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
if(${IDF_TARGET} STREQUAL "linux")
|
||||
set(EXTRA_COMPONENT_DIRS "../../../../common_components/linux_compat")
|
||||
set(COMPONENTS main)
|
||||
endif()
|
||||
|
||||
project(mdns_host)
|
||||
|
||||
# Enable sanitizers only without console (we'd see some leaks on argtable when console exits)
|
||||
if(NOT CONFIG_TEST_CONSOLE AND CONFIG_IDF_TARGET_LINUX)
|
||||
idf_component_get_property(mdns mdns COMPONENT_LIB)
|
||||
target_link_options(${mdns} INTERFACE -fsanitize=address -fsanitize=undefined)
|
||||
endif()
|
||||
33
managed_components/espressif__mdns/tests/host_test/README.md
Normal file
33
managed_components/espressif__mdns/tests/host_test/README.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Setup dummy network interfaces
|
||||
|
||||
Note: Set two addresses so we could use one as source and another as destination
|
||||
```
|
||||
sudo ip link add eth2 type dummy
|
||||
sudo ip addr add 192.168.1.200/24 dev eth2
|
||||
sudo ip addr add 192.168.1.201/24 dev eth2
|
||||
sudo ip link set eth2 up
|
||||
sudo ifconfig eth2 multicast
|
||||
```
|
||||
|
||||
# Dig on a specified interface
|
||||
|
||||
```
|
||||
dig +short -b 192.168.1.200 -p 5353 @224.0.0.251 myesp.local
|
||||
```
|
||||
|
||||
or a reverse query:
|
||||
```
|
||||
dig +short -b 192.168.2.200 -p 5353 @224.0.0.251 -x 192.168.1.200
|
||||
```
|
||||
|
||||
# Run avahi to browse services
|
||||
|
||||
Avahi needs the netif to have the "multicast" flag set
|
||||
|
||||
```bash
|
||||
david@david-comp:~/esp/idf (feature/mdns_networking_socket)$ avahi-browse -a -r -p
|
||||
+;eth2;IPv6;myesp-service2;Web Site;local
|
||||
+;eth2;IPv4;myesp-service2;Web Site;local
|
||||
=;eth2;IPv6;myesp-service2;Web Site;local;myesp.local;192.168.1.200;80;"board=esp32" "u=user" "p=password"
|
||||
=;eth2;IPv4;myesp-service2;Web Site;local;myesp.local;192.168.1.200;80;"board=esp32" "u=user" "p=password"
|
||||
```
|
||||
@@ -0,0 +1,8 @@
|
||||
idf_build_get_property(idf_target IDF_TARGET)
|
||||
if(${IDF_TARGET} STREQUAL "linux")
|
||||
idf_component_register(SRCS esp_netif_linux.c
|
||||
INCLUDE_DIRS include $ENV{IDF_PATH}/components/esp_netif/include
|
||||
REQUIRES esp_event)
|
||||
else()
|
||||
idf_component_register()
|
||||
endif()
|
||||
@@ -0,0 +1,15 @@
|
||||
menu "LWIP-MOCK-CONFIG"
|
||||
|
||||
config LWIP_IPV6
|
||||
bool "Enable IPv6"
|
||||
default y
|
||||
help
|
||||
Enable/disable IPv6
|
||||
|
||||
config LWIP_IPV4
|
||||
bool "Enable IPv4"
|
||||
default y
|
||||
help
|
||||
Enable/disable IPv4
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include<stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "esp_netif.h"
|
||||
#include "esp_err.h"
|
||||
#include <string.h> //strlen
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h> //inet_addr
|
||||
#include <sys/types.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
#include "esp_netif_types.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#define MAX_NETIFS 4
|
||||
|
||||
static const char *TAG = "esp_netif_linux";
|
||||
|
||||
static esp_netif_t *s_netif_list[MAX_NETIFS] = { 0 };
|
||||
|
||||
struct esp_netif_obj {
|
||||
const char *if_key;
|
||||
const char *if_desc;
|
||||
};
|
||||
|
||||
esp_netif_t *esp_netif_get_handle_from_ifkey(const char *if_key)
|
||||
{
|
||||
for (int i = 0; i < MAX_NETIFS; ++i) {
|
||||
if (s_netif_list[i] && strcmp(s_netif_list[i]->if_key, if_key) == 0) {
|
||||
return s_netif_list[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
esp_err_t esp_netif_get_ip_info(esp_netif_t *esp_netif, esp_netif_ip_info_t *ip_info)
|
||||
{
|
||||
if (esp_netif == NULL) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
struct ifaddrs *addrs, *tmp;
|
||||
getifaddrs(&addrs);
|
||||
tmp = addrs;
|
||||
|
||||
while (tmp) {
|
||||
if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET) {
|
||||
char addr[20];
|
||||
struct sockaddr_in *pAddr = (struct sockaddr_in *) tmp->ifa_addr;
|
||||
inet_ntop(AF_INET, &pAddr->sin_addr, addr, sizeof(addr));
|
||||
if (strcmp(esp_netif->if_desc, tmp->ifa_name) == 0) {
|
||||
ESP_LOGD(TAG, "AF_INET4: %s: %s\n", tmp->ifa_name, addr);
|
||||
memcpy(&ip_info->ip.addr, &pAddr->sin_addr, 4);
|
||||
}
|
||||
}
|
||||
tmp = tmp->ifa_next;
|
||||
}
|
||||
freeifaddrs(addrs);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_netif_dhcpc_get_status(esp_netif_t *esp_netif, esp_netif_dhcp_status_t *status)
|
||||
{
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int esp_netif_get_all_ip6(esp_netif_t *esp_netif, esp_ip6_addr_t if_ip6[])
|
||||
{
|
||||
if (esp_netif == NULL) {
|
||||
return 0;
|
||||
}
|
||||
struct ifaddrs *addrs, *tmp;
|
||||
int addr_count = 0;
|
||||
getifaddrs(&addrs);
|
||||
tmp = addrs;
|
||||
|
||||
while (tmp) {
|
||||
if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 *pAddr = (struct sockaddr_in6 *)tmp->ifa_addr;
|
||||
if (strcmp(esp_netif->if_desc, tmp->ifa_name) == 0) {
|
||||
memcpy(&if_ip6[addr_count++], &pAddr->sin6_addr, 4 * 4);
|
||||
}
|
||||
}
|
||||
tmp = tmp->ifa_next;
|
||||
}
|
||||
|
||||
freeifaddrs(addrs);
|
||||
return addr_count;
|
||||
}
|
||||
|
||||
esp_err_t esp_netif_get_ip6_linklocal(esp_netif_t *esp_netif, esp_ip6_addr_t *if_ip6)
|
||||
{
|
||||
if (esp_netif == NULL) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
struct ifaddrs *addrs, *tmp;
|
||||
getifaddrs(&addrs);
|
||||
tmp = addrs;
|
||||
|
||||
while (tmp) {
|
||||
if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET6) {
|
||||
char addr[64];
|
||||
struct sockaddr_in6 *pAddr = (struct sockaddr_in6 *)tmp->ifa_addr;
|
||||
inet_ntop(AF_INET6, &pAddr->sin6_addr, addr, sizeof(addr));
|
||||
if (strcmp(esp_netif->if_desc, tmp->ifa_name) == 0) {
|
||||
ESP_LOGD(TAG, "AF_INET6: %s: %s\n", tmp->ifa_name, addr);
|
||||
memcpy(if_ip6->addr, &pAddr->sin6_addr, 4 * 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
tmp = tmp->ifa_next;
|
||||
}
|
||||
|
||||
freeifaddrs(addrs);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
int esp_netif_get_netif_impl_index(esp_netif_t *esp_netif)
|
||||
{
|
||||
if (esp_netif == NULL) {
|
||||
return -1;
|
||||
}
|
||||
uint32_t interfaceIndex = if_nametoindex(esp_netif->if_desc);
|
||||
return interfaceIndex;
|
||||
}
|
||||
|
||||
esp_err_t esp_netif_get_netif_impl_name(esp_netif_t *esp_netif, char *name)
|
||||
{
|
||||
if (esp_netif == NULL) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
strcpy(name, esp_netif->if_desc);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
const char *esp_netif_get_desc(esp_netif_t *esp_netif)
|
||||
{
|
||||
if (esp_netif == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return esp_netif->if_desc;
|
||||
}
|
||||
|
||||
esp_netif_t *esp_netif_new(const esp_netif_config_t *config)
|
||||
{
|
||||
if (esp_netif_get_handle_from_ifkey(config->base->if_key)) {
|
||||
return NULL;
|
||||
}
|
||||
esp_netif_t *netif = calloc(1, sizeof(struct esp_netif_obj));
|
||||
if (netif) {
|
||||
netif->if_desc = config->base->if_desc;
|
||||
netif->if_key = config->base->if_key;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_NETIFS; ++i) {
|
||||
if (s_netif_list[i] == NULL) {
|
||||
s_netif_list[i] = netif;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return netif;
|
||||
}
|
||||
|
||||
void esp_netif_destroy(esp_netif_t *esp_netif)
|
||||
{
|
||||
for (int i = 0; i < MAX_NETIFS; ++i) {
|
||||
if (s_netif_list[i] == esp_netif) {
|
||||
s_netif_list[i] = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(esp_netif);
|
||||
}
|
||||
|
||||
const char *esp_netif_get_ifkey(esp_netif_t *esp_netif)
|
||||
{
|
||||
return esp_netif->if_key;
|
||||
}
|
||||
|
||||
esp_err_t esp_netif_str_to_ip4(const char *src, esp_ip4_addr_t *dst)
|
||||
{
|
||||
if (src == NULL || dst == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
struct in_addr addr;
|
||||
if (inet_pton(AF_INET, src, &addr) != 1) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
dst->addr = addr.s_addr;
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
#include "esp_event.h"
|
||||
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include_next "endian.h"
|
||||
178
managed_components/espressif__mdns/tests/host_test/dnsfixture.py
Normal file
178
managed_components/espressif__mdns/tests/host_test/dnsfixture.py
Normal file
@@ -0,0 +1,178 @@
|
||||
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import logging
|
||||
import re
|
||||
import socket
|
||||
import sys
|
||||
|
||||
import dns.message
|
||||
import dns.query
|
||||
import dns.rdataclass
|
||||
import dns.rdatatype
|
||||
import dns.resolver
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DnsPythonWrapper:
|
||||
def __init__(self, server='224.0.0.251', port=5353, retries=3):
|
||||
self.server = server
|
||||
self.port = port
|
||||
self.retries = retries
|
||||
|
||||
def send_and_receive_query(self, query, timeout=3):
|
||||
logger.info(f'Sending DNS query to {self.server}:{self.port}')
|
||||
try:
|
||||
# Create a UDP socket
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
|
||||
sock.settimeout(timeout)
|
||||
|
||||
# Send the DNS query
|
||||
query_data = query.to_wire()
|
||||
sock.sendto(query_data, (self.server, self.port))
|
||||
|
||||
# Receive the DNS response
|
||||
response_data, _ = sock.recvfrom(512) # 512 bytes is the typical size for a DNS response
|
||||
|
||||
# Parse the response
|
||||
response = dns.message.from_wire(response_data)
|
||||
|
||||
return response
|
||||
|
||||
except socket.timeout as e:
|
||||
logger.warning(f'DNS query timed out: {e}')
|
||||
return None
|
||||
except dns.exception.DNSException as e:
|
||||
logger.error(f'DNS query failed: {e}')
|
||||
return None
|
||||
|
||||
def run_query(self, name, query_type='PTR', timeout=3):
|
||||
logger.info(f'Running DNS query for {name} with type {query_type}')
|
||||
query = dns.message.make_query(name, dns.rdatatype.from_text(query_type), dns.rdataclass.IN)
|
||||
|
||||
# Print the DNS question section
|
||||
logger.info(f'DNS question section: {query.question}')
|
||||
|
||||
# Send and receive the DNS query
|
||||
response = None
|
||||
for attempt in range(1, self.retries + 1):
|
||||
logger.info(f'Attempt {attempt}/{self.retries}')
|
||||
response = self.send_and_receive_query(query, timeout)
|
||||
if response:
|
||||
break
|
||||
|
||||
if response:
|
||||
logger.info(f'DNS query response:\n{response}')
|
||||
else:
|
||||
logger.warning('No response received or response was invalid.')
|
||||
|
||||
return response
|
||||
|
||||
def parse_answer_section(self, response, query_type):
|
||||
answers = []
|
||||
if response:
|
||||
for answer in response.answer:
|
||||
if dns.rdatatype.to_text(answer.rdtype) == query_type:
|
||||
for item in answer.items:
|
||||
full_answer = (
|
||||
f'{answer.name} {answer.ttl} '
|
||||
f'{dns.rdataclass.to_text(answer.rdclass)} '
|
||||
f'{dns.rdatatype.to_text(answer.rdtype)} '
|
||||
f'{item.to_text()}'
|
||||
)
|
||||
answers.append(full_answer)
|
||||
return answers
|
||||
|
||||
def check_record(self, name, query_type, expected=True, expect=None):
|
||||
output = self.run_query(name, query_type=query_type)
|
||||
answers = self.parse_answer_section(output, query_type)
|
||||
logger.info(f'answers: {answers}')
|
||||
if expect is None:
|
||||
expect = name
|
||||
if expected:
|
||||
assert any(expect in answer for answer in answers), f"Expected record '{expect}' not in answer section"
|
||||
else:
|
||||
assert not any(expect in answer for answer in answers), f"Unexpected record '{expect}' found in answer section"
|
||||
|
||||
def parse_section(self, response, section: str, rdtype_text: str):
|
||||
"""Parse a specific response section (answer, authority, additional) for given rdtype.
|
||||
|
||||
Returns list of textual records for that rdtype.
|
||||
"""
|
||||
out = []
|
||||
if not response:
|
||||
return out
|
||||
rrsets = []
|
||||
if section == 'answer':
|
||||
rrsets = response.answer
|
||||
elif section == 'authority':
|
||||
rrsets = response.authority
|
||||
elif section == 'additional':
|
||||
rrsets = response.additional
|
||||
else:
|
||||
raise ValueError('invalid section')
|
||||
for rr in rrsets:
|
||||
if dns.rdatatype.to_text(rr.rdtype) != rdtype_text:
|
||||
continue
|
||||
for item in rr.items:
|
||||
full = (
|
||||
f'{rr.name} {rr.ttl} '
|
||||
f'{dns.rdataclass.to_text(rr.rdclass)} '
|
||||
f'{dns.rdatatype.to_text(rr.rdtype)} '
|
||||
f'{item.to_text()}'
|
||||
)
|
||||
out.append(full)
|
||||
return out
|
||||
|
||||
def check_additional(self, response, rdtype_text: str, owner_contains: str, expected: bool = True, expect_substr: str | None = None):
|
||||
"""Check Additional section for an RR of type rdtype_text whose owner includes owner_contains.
|
||||
|
||||
If expect_substr is provided, also require it to appear in the textual RR.
|
||||
"""
|
||||
records = self.parse_section(response, 'additional', rdtype_text)
|
||||
logger.info(f'additional({rdtype_text}): {records}')
|
||||
|
||||
def _matches(line: str) -> bool:
|
||||
in_owner = owner_contains in line
|
||||
has_val = (expect_substr in line) if expect_substr else True
|
||||
return in_owner and has_val
|
||||
found = any(_matches(r) for r in records)
|
||||
if expected:
|
||||
assert found, f"Expected {rdtype_text} for {owner_contains} in Additional not found"
|
||||
else:
|
||||
assert not found, f"Unexpected {rdtype_text} for {owner_contains} found in Additional"
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 3:
|
||||
print('Usage: python dns_fixture.py <query_type> <name>')
|
||||
sys.exit(1)
|
||||
|
||||
query_type = sys.argv[1]
|
||||
name = sys.argv[2]
|
||||
ip_only = len(sys.argv) > 3 and sys.argv[3] == '--ip_only'
|
||||
if ip_only:
|
||||
logger.setLevel(logging.WARNING)
|
||||
|
||||
dns_wrapper = DnsPythonWrapper()
|
||||
if query_type == 'X' and '.' in name:
|
||||
# Sends an IPv4 reverse query
|
||||
reversed_ip = '.'.join(reversed(name.split('.')))
|
||||
name = f'{reversed_ip}.in-addr.arpa'
|
||||
query_type = 'PTR'
|
||||
response = dns_wrapper.run_query(name, query_type=query_type)
|
||||
answers = dns_wrapper.parse_answer_section(response, query_type)
|
||||
|
||||
if answers:
|
||||
for answer in answers:
|
||||
logger.info(f'DNS query response: {answer}')
|
||||
if ip_only:
|
||||
ipv4_pattern = re.compile(r'\b(?:\d{1,3}\.){3}\d{1,3}\b')
|
||||
ipv4_addresses = ipv4_pattern.findall(answer)
|
||||
if ipv4_addresses:
|
||||
print(f"{', '.join(ipv4_addresses)}")
|
||||
else:
|
||||
logger.info(f'No response for {name} with query type {query_type}')
|
||||
exit(9) # Same as dig timeout
|
||||
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRCS "main.c"
|
||||
INCLUDE_DIRS
|
||||
"."
|
||||
REQUIRES mdns console nvs_flash)
|
||||
@@ -0,0 +1,21 @@
|
||||
menu "Test Configuration"
|
||||
|
||||
config TEST_HOSTNAME
|
||||
string "mDNS Hostname"
|
||||
default "esp32-mdns"
|
||||
help
|
||||
mDNS Hostname for example to use
|
||||
|
||||
config TEST_NETIF_NAME
|
||||
string "Network interface name"
|
||||
default "eth2"
|
||||
help
|
||||
Name/ID if the network interface on which we run the mDNS host test
|
||||
|
||||
config TEST_CONSOLE
|
||||
bool "Start console"
|
||||
default n
|
||||
help
|
||||
Test uses esp_console for interactive testing.
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,7 @@
|
||||
dependencies:
|
||||
idf: ">=5.0"
|
||||
espressif/mdns:
|
||||
version: "^1.0.0"
|
||||
override_path: "../../.."
|
||||
protocol_examples_common:
|
||||
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
|
||||
126
managed_components/espressif__mdns/tests/host_test/main/main.c
Normal file
126
managed_components/espressif__mdns/tests/host_test/main/main.c
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_console.h"
|
||||
#include "mdns.h"
|
||||
#include "mdns_console.h"
|
||||
|
||||
static const char *TAG = "mdns-test";
|
||||
|
||||
static void mdns_test_app(esp_netif_t *interface);
|
||||
|
||||
#ifdef CONFIG_TEST_CONSOLE
|
||||
static EventGroupHandle_t s_exit_signal = NULL;
|
||||
|
||||
static int exit_console(int argc, char **argv)
|
||||
{
|
||||
xEventGroupSetBits(s_exit_signal, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
static void query_mdns_host(const char *host_name)
|
||||
{
|
||||
ESP_LOGI(TAG, "Query A: %s.local", host_name);
|
||||
|
||||
struct esp_ip4_addr addr;
|
||||
addr.addr = 0;
|
||||
|
||||
esp_err_t err = mdns_query_a(host_name, 2000, &addr);
|
||||
if (err) {
|
||||
if (err == ESP_ERR_NOT_FOUND) {
|
||||
ESP_LOGW(TAG, "%x: Host was not found!", (err));
|
||||
return;
|
||||
}
|
||||
ESP_LOGE(TAG, "Query Failed: %x", (err));
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Query A: %s.local resolved to: " IPSTR, host_name, IP2STR(&addr));
|
||||
}
|
||||
#endif // TEST_CONSOLE
|
||||
|
||||
#ifndef CONFIG_IDF_TARGET_LINUX
|
||||
#include "protocol_examples_common.h"
|
||||
#include "esp_event.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
/**
|
||||
* @brief This is an entry point for the real target device,
|
||||
* need to init few components and connect to a network interface
|
||||
*/
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
mdns_test_app(EXAMPLE_INTERFACE);
|
||||
|
||||
ESP_ERROR_CHECK(example_disconnect());
|
||||
}
|
||||
#else
|
||||
|
||||
/**
|
||||
* @brief This is an entry point for the linux target (simulator on host)
|
||||
* need to create a dummy WiFi station and use it as mdns network interface
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
const esp_netif_inherent_config_t base_cg = { .if_key = "WIFI_STA_DEF", .if_desc = CONFIG_TEST_NETIF_NAME };
|
||||
esp_netif_config_t cfg = { .base = &base_cg };
|
||||
esp_netif_t *sta = esp_netif_new(&cfg);
|
||||
|
||||
mdns_test_app(sta);
|
||||
|
||||
esp_netif_destroy(sta);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void mdns_test_app(esp_netif_t *interface)
|
||||
{
|
||||
ESP_ERROR_CHECK(mdns_init());
|
||||
ESP_ERROR_CHECK(mdns_hostname_set(CONFIG_TEST_HOSTNAME));
|
||||
ESP_LOGI(TAG, "mdns hostname set to: [%s]", CONFIG_TEST_HOSTNAME);
|
||||
ESP_ERROR_CHECK(mdns_register_netif(interface));
|
||||
ESP_ERROR_CHECK(mdns_netif_action(interface, MDNS_EVENT_ENABLE_IP4 /*| MDNS_EVENT_ENABLE_IP6 */ | MDNS_EVENT_IP4_REVERSE_LOOKUP | MDNS_EVENT_IP6_REVERSE_LOOKUP));
|
||||
|
||||
#ifdef CONFIG_TEST_CONSOLE
|
||||
esp_console_repl_t *repl = NULL;
|
||||
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
|
||||
esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
|
||||
s_exit_signal = xEventGroupCreate();
|
||||
|
||||
repl_config.prompt = "mdns>";
|
||||
// init console REPL environment
|
||||
ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &repl));
|
||||
|
||||
const esp_console_cmd_t cmd_exit = {
|
||||
.command = "exit",
|
||||
.help = "exit mDNS console application",
|
||||
.hint = NULL,
|
||||
.func = exit_console,
|
||||
.argtable = NULL
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_exit));
|
||||
mdns_console_register();
|
||||
ESP_ERROR_CHECK(esp_console_start_repl(repl));
|
||||
xEventGroupWaitBits(s_exit_signal, 1, pdTRUE, pdFALSE, portMAX_DELAY);
|
||||
repl->del(repl);
|
||||
#else
|
||||
vTaskDelay(pdMS_TO_TICKS(10000));
|
||||
query_mdns_host("david-work");
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
#endif
|
||||
mdns_free();
|
||||
ESP_LOGI(TAG, "Exit");
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import logging
|
||||
|
||||
import pexpect
|
||||
import pytest
|
||||
from dnsfixture import DnsPythonWrapper
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
ipv6_enabled = False
|
||||
|
||||
|
||||
class MdnsConsole:
|
||||
def __init__(self, command):
|
||||
self.process = pexpect.spawn(command, encoding='utf-8')
|
||||
self.process.logfile = open('mdns_interaction.log', 'w') # Log all interactions
|
||||
self.process.expect('mdns> ', timeout=10)
|
||||
|
||||
def send_input(self, input_data):
|
||||
logger.info(f'Sending to stdin: {input_data}')
|
||||
self.process.sendline(input_data)
|
||||
|
||||
def get_output(self, expected_data):
|
||||
logger.info(f'Expecting: {expected_data}')
|
||||
self.process.expect(expected_data, timeout=10)
|
||||
output = self.process.before.strip()
|
||||
logger.info(f'Received from stdout: {output}')
|
||||
return output
|
||||
|
||||
def terminate(self):
|
||||
self.send_input('exit')
|
||||
self.get_output('Exit')
|
||||
self.process.wait()
|
||||
self.process.close()
|
||||
assert self.process.exitstatus == 0
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def mdns_console():
|
||||
app = MdnsConsole('./build_linux_console/mdns_host.elf')
|
||||
yield app
|
||||
app.terminate()
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def dig_app():
|
||||
return DnsPythonWrapper()
|
||||
|
||||
|
||||
def test_mdns_init(mdns_console, dig_app):
|
||||
mdns_console.send_input('mdns_init -h hostname')
|
||||
mdns_console.get_output('MDNS: Hostname: hostname')
|
||||
dig_app.check_record('hostname.local', query_type='A', expected=True)
|
||||
if ipv6_enabled:
|
||||
dig_app.check_record('hostname.local', query_type='AAAA', expected=True)
|
||||
|
||||
|
||||
def test_add_service(mdns_console, dig_app):
|
||||
mdns_console.send_input('mdns_service_add _http _tcp 80 -i test_service')
|
||||
mdns_console.get_output('MDNS: Service Instance: test_service')
|
||||
mdns_console.send_input('mdns_service_lookup _http _tcp')
|
||||
mdns_console.get_output('PTR : test_service')
|
||||
dig_app.check_record('_http._tcp.local', query_type='PTR', expected=True)
|
||||
|
||||
|
||||
def test_ptr_additional_records_for_service(dig_app):
|
||||
# Query PTR for the service type and ensure SRV/TXT are in Additional (RFC 6763 §12.1)
|
||||
resp = dig_app.run_query('_http._tcp.local', query_type='PTR')
|
||||
# Answer section should have at least one PTR to the instance
|
||||
answers = dig_app.parse_answer_section(resp, 'PTR')
|
||||
assert any('test_service._http._tcp.local' in a for a in answers)
|
||||
# Additional section should include SRV and TXT for the same instance
|
||||
dig_app.check_additional(resp, 'SRV', 'test_service._http._tcp.local', expected=True)
|
||||
dig_app.check_additional(resp, 'TXT', 'test_service._http._tcp.local', expected=True)
|
||||
|
||||
|
||||
def test_remove_service(mdns_console, dig_app):
|
||||
mdns_console.send_input('mdns_service_remove _http _tcp')
|
||||
mdns_console.send_input('mdns_service_lookup _http _tcp')
|
||||
mdns_console.get_output('No results found!')
|
||||
dig_app.check_record('_http._tcp.local', query_type='PTR', expected=False)
|
||||
|
||||
|
||||
def test_delegate_host(mdns_console, dig_app):
|
||||
mdns_console.send_input('mdns_delegate_host delegated 1.2.3.4')
|
||||
dig_app.check_record('delegated.local', query_type='A', expected=True)
|
||||
|
||||
|
||||
def test_undelegate_host(mdns_console, dig_app):
|
||||
mdns_console.send_input('mdns_undelegate_host delegated')
|
||||
dig_app.check_record('delegated.local', query_type='A', expected=False)
|
||||
|
||||
|
||||
def test_add_delegated_service(mdns_console, dig_app):
|
||||
mdns_console.send_input('mdns_delegate_host delegated 1.2.3.4')
|
||||
dig_app.check_record('delegated.local', query_type='A', expected=True)
|
||||
mdns_console.send_input('mdns_service_add _test _tcp 80 -i local')
|
||||
mdns_console.get_output('MDNS: Service Instance: local')
|
||||
mdns_console.send_input('mdns_service_add _test2 _tcp 80 -i extern -h delegated')
|
||||
mdns_console.get_output('MDNS: Service Instance: extern')
|
||||
mdns_console.send_input('mdns_service_lookup _test _tcp')
|
||||
mdns_console.get_output('PTR : local')
|
||||
mdns_console.send_input('mdns_service_lookup _test2 _tcp -d')
|
||||
mdns_console.get_output('PTR : extern')
|
||||
dig_app.check_record('_test2._tcp.local', query_type='PTR', expected=True)
|
||||
dig_app.check_record('extern._test2._tcp.local', query_type='SRV', expected=True)
|
||||
|
||||
|
||||
def test_remove_delegated_service(mdns_console, dig_app):
|
||||
mdns_console.send_input('mdns_service_remove _test2 _tcp -h delegated')
|
||||
mdns_console.send_input('mdns_service_lookup _test2 _tcp -d')
|
||||
mdns_console.get_output('No results found!')
|
||||
dig_app.check_record('_test2._tcp.local', query_type='PTR', expected=False)
|
||||
# add the delegated service again, would be used in the TXT test
|
||||
mdns_console.send_input('mdns_service_add _test2 _tcp 80 -i extern -h delegated')
|
||||
mdns_console.get_output('MDNS: Service Instance: extern')
|
||||
|
||||
|
||||
def check_txt_for_service(instance, service, proto, mdns_console, dig_app, host=None, with_inst=False):
|
||||
for_host_arg = f'-h {host}' if host is not None else ''
|
||||
for_inst_arg = f'-i {instance}' if with_inst else ''
|
||||
mdns_console.send_input(f'mdns_service_txt_set {service} {proto} {for_host_arg} {for_inst_arg} key1 value1')
|
||||
dig_app.check_record(f'{instance}.{service}.{proto}.local', query_type='SRV', expected=True)
|
||||
dig_app.check_record(f'{service}.{proto}.local', query_type='TXT', expected=True, expect='key1=value1')
|
||||
mdns_console.send_input(f'mdns_service_txt_set {service} {proto} {for_host_arg} {for_inst_arg} key2 value2')
|
||||
dig_app.check_record(f'{service}.{proto}.local', query_type='TXT', expected=True, expect='key2=value2')
|
||||
mdns_console.send_input(f'mdns_service_txt_remove {service} {proto} {for_host_arg} {for_inst_arg} key2')
|
||||
dig_app.check_record(f'{service}.{proto}.local', query_type='TXT', expected=False, expect='key2=value2')
|
||||
dig_app.check_record(f'{service}.{proto}.local', query_type='TXT', expected=True, expect='key1=value1')
|
||||
mdns_console.send_input(f'mdns_service_txt_replace {service} {proto} {for_host_arg} {for_inst_arg} key3=value3 key4=value4')
|
||||
dig_app.check_record(f'{service}.{proto}.local', query_type='TXT', expected=False, expect='key1=value1')
|
||||
dig_app.check_record(f'{service}.{proto}.local', query_type='TXT', expected=True, expect='key3=value3')
|
||||
dig_app.check_record(f'{service}.{proto}.local', query_type='TXT', expected=True, expect='key4=value4')
|
||||
|
||||
|
||||
def test_update_txt(mdns_console, dig_app):
|
||||
check_txt_for_service('local', '_test', '_tcp', mdns_console=mdns_console, dig_app=dig_app)
|
||||
check_txt_for_service('local', '_test', '_tcp', mdns_console=mdns_console, dig_app=dig_app, with_inst=True)
|
||||
|
||||
|
||||
def test_update_delegated_txt(mdns_console, dig_app):
|
||||
check_txt_for_service('extern', '_test2', '_tcp', mdns_console=mdns_console, dig_app=dig_app, host='delegated')
|
||||
check_txt_for_service('extern', '_test2', '_tcp', mdns_console=mdns_console, dig_app=dig_app, host='delegated', with_inst=True)
|
||||
|
||||
|
||||
def test_service_port_set(mdns_console, dig_app):
|
||||
dig_app.check_record('local._test._tcp.local', query_type='SRV', expected=True, expect='80')
|
||||
mdns_console.send_input('mdns_service_port_set _test _tcp 81')
|
||||
dig_app.check_record('local._test._tcp.local', query_type='SRV', expected=True, expect='81')
|
||||
mdns_console.send_input('mdns_service_port_set _test2 _tcp -h delegated 82')
|
||||
dig_app.check_record('extern._test2._tcp.local', query_type='SRV', expected=True, expect='82')
|
||||
mdns_console.send_input('mdns_service_port_set _test2 _tcp -h delegated -i extern 83')
|
||||
dig_app.check_record('extern._test2._tcp.local', query_type='SRV', expected=True, expect='83')
|
||||
mdns_console.send_input('mdns_service_port_set _test2 _tcp -h delegated -i invalid_inst 84')
|
||||
mdns_console.get_output('ESP_ERR_NOT_FOUND')
|
||||
dig_app.check_record('extern._test2._tcp.local', query_type='SRV', expected=True, expect='83')
|
||||
|
||||
|
||||
def test_service_subtype(mdns_console, dig_app):
|
||||
dig_app.check_record('local._test._tcp.local', query_type='SRV', expected=True)
|
||||
mdns_console.send_input('mdns_service_subtype _test _tcp _subtest -i local')
|
||||
dig_app.check_record('_subtest._sub._test._tcp.local', query_type='PTR', expected=True)
|
||||
mdns_console.send_input('mdns_service_subtype _test2 _tcp _subtest2 -i extern -h delegated')
|
||||
dig_app.check_record('_subtest2._sub._test2._tcp.local', query_type='PTR', expected=True)
|
||||
|
||||
|
||||
def test_service_set_instance(mdns_console, dig_app):
|
||||
dig_app.check_record('local._test._tcp.local', query_type='SRV', expected=True)
|
||||
mdns_console.send_input('mdns_service_instance_set _test _tcp local2')
|
||||
dig_app.check_record('local2._test._tcp.local', query_type='SRV', expected=True)
|
||||
mdns_console.send_input('mdns_service_instance_set _test2 _tcp extern2 -h delegated')
|
||||
mdns_console.send_input('mdns_service_lookup _test2 _tcp -d')
|
||||
mdns_console.get_output('PTR : extern2')
|
||||
dig_app.check_record('extern2._test2._tcp.local', query_type='SRV', expected=True)
|
||||
mdns_console.send_input('mdns_service_instance_set _test2 _tcp extern3 -h delegated -i extern')
|
||||
mdns_console.get_output('ESP_ERR_NOT_FOUND')
|
||||
|
||||
|
||||
def test_service_remove_all(mdns_console, dig_app):
|
||||
mdns_console.send_input('mdns_service_remove_all')
|
||||
mdns_console.send_input('mdns_service_lookup _test2 _tcp -d')
|
||||
mdns_console.get_output('No results found!')
|
||||
mdns_console.send_input('mdns_service_lookup _test _tcp')
|
||||
mdns_console.get_output('No results found!')
|
||||
dig_app.check_record('_test._tcp.local', query_type='PTR', expected=False)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main(['-s', 'test_mdns.py'])
|
||||
@@ -0,0 +1,4 @@
|
||||
CONFIG_IDF_TARGET="linux"
|
||||
CONFIG_ESP_EVENT_POST_FROM_ISR=n
|
||||
CONFIG_MDNS_ENABLE_CONSOLE_CLI=y
|
||||
CONFIG_TEST_CONSOLE=y
|
||||
@@ -0,0 +1 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
@@ -0,0 +1,6 @@
|
||||
CONFIG_TEST_NETIF_NAME="eth0"
|
||||
CONFIG_ESP_EVENT_POST_FROM_ISR=n
|
||||
CONFIG_MDNS_NETWORKING_SOCKET=y
|
||||
CONFIG_MDNS_SKIP_SUPPRESSING_OWN_QUERIES=y
|
||||
CONFIG_MDNS_PREDEF_NETIF_STA=n
|
||||
CONFIG_MDNS_PREDEF_NETIF_AP=n
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user