diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 2491f2df3b..59f50a7753 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -9,7 +9,7 @@ variables:
check_version:
stage: pre_check
- image: ${CI_DOCKER_REGISTRY}/esp-env-v5.4:1
+ image: ${CI_DOCKER_REGISTRY}/esp-env-v5.5:3
script:
- export HOSTED_NG_PATH=$PWD/esp_hosted_ng
- .gitlab/ci/check_hosted_ng_version.sh
@@ -20,7 +20,7 @@ check_version:
build_fw_esp32_sdio:
stage: build_firmware
- image: $CI_DOCKER_REGISTRY/esp-env-v5.4:1
+ image: $CI_DOCKER_REGISTRY/esp-env-v5.5:3
variables:
IDF_TARGET: esp32
script:
@@ -33,7 +33,7 @@ build_fw_esp32_sdio:
build_fw_esp32_spi:
stage: build_firmware
- image: $CI_DOCKER_REGISTRY/esp-env-v5.4:1
+ image: $CI_DOCKER_REGISTRY/esp-env-v5.5:3
variables:
IDF_TARGET: esp32
script:
@@ -46,7 +46,7 @@ build_fw_esp32_spi:
build_fw_esp32s2_spi:
stage: build_firmware
- image: $CI_DOCKER_REGISTRY/esp-env-v5.4:1
+ image: $CI_DOCKER_REGISTRY/esp-env-v5.5:3
variables:
IDF_TARGET: esp32s2
script:
@@ -59,7 +59,7 @@ build_fw_esp32s2_spi:
build_fw_esp32s3_spi:
stage: build_firmware
- image: $CI_DOCKER_REGISTRY/esp-env-v5.4:1
+ image: $CI_DOCKER_REGISTRY/esp-env-v5.5:3
variables:
IDF_TARGET: esp32s3
script:
@@ -72,7 +72,7 @@ build_fw_esp32s3_spi:
build_fw_esp32c2_spi:
stage: build_firmware
- image: $CI_DOCKER_REGISTRY/esp-env-v5.4:1
+ image: $CI_DOCKER_REGISTRY/esp-env-v5.5:3
variables:
IDF_TARGET: esp32c2
script:
@@ -85,7 +85,7 @@ build_fw_esp32c2_spi:
build_fw_esp32c3_spi:
stage: build_firmware
- image: $CI_DOCKER_REGISTRY/esp-env-v5.4:1
+ image: $CI_DOCKER_REGISTRY/esp-env-v5.5:3
variables:
IDF_TARGET: esp32c3
script:
@@ -98,7 +98,7 @@ build_fw_esp32c3_spi:
build_fw_esp32c6_sdio:
stage: build_firmware
- image: $CI_DOCKER_REGISTRY/esp-env-v5.4:1
+ image: $CI_DOCKER_REGISTRY/esp-env-v5.5:3
variables:
IDF_TARGET: esp32c6
script:
@@ -111,9 +111,22 @@ build_fw_esp32c6_sdio:
build_fw_esp32c6_spi:
stage: build_firmware
- image: $CI_DOCKER_REGISTRY/esp-env-v5.4:1
+ image: $CI_DOCKER_REGISTRY/esp-env-v5.5:3
variables:
IDF_TARGET: esp32c6
+ script:
+ - .gitlab/ci/build_firmware.sh $IDF_TARGET
+ rules:
+ - changes:
+ - esp_hosted_ng/esp/esp_driver/network_adapter/**/*
+ tags:
+ - build_fw
+
+build_fw_esp32c5_spi:
+ stage: build_firmware
+ image: $CI_DOCKER_REGISTRY/esp-env-v5.5:3
+ variables:
+ IDF_TARGET: esp32c5
script:
- .gitlab/ci/build_firmware.sh $IDF_TARGET spi
rules:
@@ -122,6 +135,20 @@ build_fw_esp32c6_spi:
tags:
- build_fw
+build_fw_esp32c5_sdio:
+ stage: build_firmware
+ image: $CI_DOCKER_REGISTRY/esp-env-v5.5:3
+ allow_failure: true
+ variables:
+ IDF_TARGET: esp32c5
+ script:
+ - .gitlab/ci/build_firmware.sh $IDF_TARGET sdio
+ rules:
+ - changes:
+ - esp_hosted_ng/esp/esp_driver/network_adapter/**/*
+ tags:
+ - build_fw
+
build_host_sdio_linux_6.8.0:
stage: build_host
script:
@@ -133,6 +160,17 @@ build_host_sdio_linux_6.8.0:
tags:
- hosted_runner_4
+build_host_sdio_linux_6.14.0:
+ stage: build_host
+ script:
+ - cd esp_hosted_ng/host
+ - make
+ rules:
+ - changes:
+ - esp_hosted_ng/host/**/*
+ tags:
+ - hosted_runner6
+
build_host_sdio_linux_5.15.0:
stage: build_host
script:
@@ -205,4 +243,3 @@ deploy_master_github:
- git remote remove github &>/dev/null || true
- git remote add github git@github.com:espressif/esp-hosted.git
- git push github "${CI_COMMIT_SHA}:refs/heads/${CI_COMMIT_REF_NAME}"
-
diff --git a/.gitlab/ci/build_firmware.sh b/.gitlab/ci/build_firmware.sh
index 918dc3918f..3617fcdd5f 100755
--- a/.gitlab/ci/build_firmware.sh
+++ b/.gitlab/ci/build_firmware.sh
@@ -31,7 +31,11 @@ if [ "$2" = "spi" ]; then
fi
echo "Setting target as $TGT_NAME"
-idf.py set-target $TGT_NAME
+if [ "$TGT_NAME" = "esp32c5" ]; then
+ idf.py --preview set-target "$TGT_NAME"
+else
+ idf.py set-target "$TGT_NAME"
+fi
idf.py build
# Check if the build was successful
diff --git a/README.md b/README.md
index 32a721dac6..29d5addd8a 100644
--- a/README.md
+++ b/README.md
@@ -1,133 +1,114 @@
# ESP-Hosted
-ESP-Hosted is an open source solution that provides a way to use Espressif SoCs and modules as a communication co-processor. This solution provides wireless connectivity (Wi-Fi and BT/BLE) to the host microprocessor or microcontroller, allowing it to communicate with other devices.
+**ESP-Hosted** is an open-source solution that enables Espressif SoCs/modules (like ESP32) to act as **wireless communication co-processors** for external host systems.
-Following is the high level block diagram for ESP-Hosted. Detailed block diagram is available in subsequent sections.
+It allows **host devices** (Linux-based systems or microcontrollers, MCUs) to add Wi-Fi and Bluetooth/BLE capabilities via **standard interfaces** like SPI, SDIO, or UART.
-
+### 🔑 Key Features
+* **Flexible Connectivity**: Wi-Fi + Bluetooth/BLE
+* **Broad Host Support**: Works with Linux and MCU-based systems
+* **Multiple Interfaces**: SPI, SDIO, UART
+* **Shared Networking**: ESP and host can share the same IP address
+* **Power Efficient**: Low power modes for battery-powered use cases
-## 1. ESP-Hosted Flavours
+### 📦 High-Level Architecture
-The ESP-Hosted solution is available in two flavours as mentioned below. The differentiation factor here is the type of network interface presented to host and the way Wi-Fi on ESP SoC/module is configured/controlled. Both the flavours have their respective host and firmware software.
+
+---
-### 1.1 ESP-Hosted-NG
+## 🧩 ESP-Hosted Variants
-This is the Next-Generation ESP-Hosted solution specifically designed for hosts that run Linux operating system. This flavour of the solution takes a standard approach while providing a network interface to the host. This allows usage of standard Wi-Fi applications such as wpa_supplicant to be used with ESP SoCs/modules.
+ESP-Hosted is available in three main variants:
-This solution offers following:
+### 🔹 [ESP-Hosted-NG (Next Gen)](esp_hosted_ng/README.md)
-* 802.11 network interface which is a standard Wi-Fi interface on Linux host
-* Configuration of Wi-Fi is supported through standard cfg80211 interface of Linux
-* A standard HCI interface
+Best for **Linux hosts** needing standard Wi-Fi and Bluetooth integration:
-This flavour is available in [esp_hosted_ng](esp_hosted_ng)
+* Acts as a native 802.11 wireless device
+* Configurable via `cfg80211` / `wpa_supplicant`
+* Supports `NetworkManager`
+* Bluetooth via standard HCI interface
-Please proceed with the [detailed documentation](esp_hosted_ng/README.md) for setup and usage instructions.
+---
+### 🔹 [ESP-Hosted-FG (First Gen)](esp_hosted_fg/README.md)
+Designed for **Linux hosts**, with custom lightweight RPC-based control:
-### 1.2 ESP-Hosted-FG
+* Ethernet 802.3 interface
+* Wi-Fi configuration via protobuf-based RPC
+* Fully customizable APIs
+* Bluetooth via standard HCI
+* Python or C integration
+* ESP maintains network when the host is powered off
-This is a first generation ESP-Hosted solution. This is a flavour, which provides a standard 802.3 (Ethernet) network interface to the host. Thought process behind this solution is to keep the host software simple while providing suite of connectivity features.
+---
-In order to achieve this, the host is presented with following:
+### 🔹 [ESP-Hosted-MCU](https://github.com/espressif/esp-hosted-mcu)
-* A standard 802.3 network interface which essentially is an Ethernet interface
-* A light weight control interface to configure Wi-Fi on ESP board
-* A standard HCI interface
+Optimized for **resource-constrained MCUs**:
-Although this flavour supports Linux host, the nature of this solution makes it ideal to be used with MCU hosts which do not have complex communication interfaces such as Ethernet, Wi-Fi, BT/BLE etc.
+* Minimal memory footprint
+* Wi-Fi configuration via protobuf-based RPC
+* Power-efficient operation
+* Ready port of ESP and STM32 as host
+* Bluetooth via standard HCI
+* ESP stays connected even when the host is in deep sleep or powered off
-This flavour is available in [esp_hosted_fg](esp_hosted_fg)
-Please proceed with the [detailed documentation](esp_hosted_fg/README.md) for setup and usage instructions.
+---
+## 📊 Variant Comparison
-## 2. ESP-Hosted-FG vs ESP-Hosted-NG
+| Feature | ESP-Hosted-NG | ESP-Hosted-FG | ESP-Hosted-MCU |
+| :-------------------------------- | :------------------------------: | :-------------: | :--------------: |
+| **Target Host** | Linux | Linux / MCU | MCU |
+| **Wi-Fi Configuration** | `cfg80211` | RPC (protobuf) | RPC (protobuf) |
+| **Network Interface** | 802.11 Wi-Fi | 802.3 Ethernet | 802.3 Ethernet |
+| **Same IP for ESP & Host** | ❌ | ✅ | ✅ |
+| **Power Management** | ✅ | :hourglass: Planned | ✅ |
+| **Wi-Fi Modes** | STA, AP | STA, AP, STA+AP | STA, AP, STA+AP |
+| **Bus Interfaces** | SPI, SDIO, UART (and combos) | Same | Same |
+| **Wi-Fi Security** | WPA, WPA2, WPA3, Open | Same | Same |
+| **Standards** | 802.11 b/g/n/ax, BLE 4.2/5.0/5.3 | Same | Same |
+| **Supported ESP Chips** | ESP32, C2/C3/C6, S2/S3 | ESP32, C2/C3/C5/C6, S2/S3 | ESP32, C2/C5/C3/C6, S2/S3 |
-Now that we offer two flavours of this solution, it could cause a little confusion. This section will try to explains similarities and differences in both the flavours and help you make a choice.
+---
-### 2.1 Similarities
+## 🤔 Choosing the Right Variant
-- Both the flavours share the same aim, to conveniently use ESP's Wi-Fi and Bluetooth/BLE capabilities from host
-- Both the flavours aim to support same set of ESP SoCs/modules and same set of transports like SPI/SDIO/UART for connectivity needs
+| Use Case | Recommended Variant |
+| ---------------------------------------------------------------- | ------------------- |
+| Standard Linux Wi-Fi config (`NetworkManager`, `wpa_supplicant`) | **ESP-Hosted-NG** |
+| Linux with custom/proprietary control over Wi-Fi | **ESP-Hosted-FG** |
+| Embedded Linux platforms (e.g. Raspberry Pi, BeagleBone) | **NG** or **FG** |
+| Minimal resource devices (low RAM/CPU MCUs) | **ESP-Hosted-MCU** |
+| Custom networking or duplicate stack (same IP on host & ESP) | **FG** or **MCU** |
+| IoT use cases requiring both BLE and Wi-Fi | **Any** |
+| Need for protocol customization / Deep Packet Inspection | **FG** or **MCU** |
+| Classic Bluetooth support | **All Variants** |
-### 2.2 Key Differences
+---
-- ESP-Hosted-FG supports both Linux and MCU hosts. ESP-Hosted-NG supports only Linux host.
-- ESP-Hosted-FG exposes 802.3 network interface (Ethernet) to the host. Where as, ESP-Hosted-NG exposes 802.11 interface (Wi-Fi).
-- ESP-Hosted-FG uses custom control path to configure Wi-Fi as opposed to ESP-Hosted-NG which uses standard nl80211/cfg80211 configuration.
+## 📚 Documentation & Resources
+### ESP-Hosted-NG
-Following table summarizes this entire discussion.
+* 📄 [Documentation](https://github.com/espressif/esp-hosted/blob/master/esp_hosted_ng/README.md)
+* 🐞 [Issues](https://github.com/espressif/esp-hosted/issues)
+* 📈 [Throughput Benchmarks](https://github.com/espressif/esp-hosted/blob/master/esp_hosted_ng/README.md#5-throughput-performance)
-
-
-
Features
-
ESP-HostedFirstGeneration
-
ESP-HostedNextGeneration
-
-
-
Supported platforms
-
MCU & Linux host
-
Linux only host
-
-
-
Wi-Fi Configuration mechanism
-
Custom control interface
-
nl80211 / cfg80211
-
-
-
Network Interface available
-
802.3 Ethernet Interface
-
802.11 Wi-Fi interface
-
-
-
Recommended Host Type
-
MCU Host
-
Linux Host
-
-
-
Wi-Fi features
-
802.11 b/g/n
-
-
-
Transport Layer
-
SDIO, SPI, UART
-
-
-
Usable transport combinations
-
SPI only, SPI+UART, SDIO only, SDIO+UART
-
-
-
Wi-Fi Mode
-
Station, SoftAP
-
Station, SoftAP
-
-
-
Wi-Fi Security Protocols
-
Open / WPA / WPA2 / WPA3
-
-
-
Bluetooth features
-
BLE 4.2, BLE 5.0, BLE 5.3
-
-
-
Chipsets supported
-
ESP32, ESP32-C2/C3/C5/C6/S2/S3
-
ESP32, ESP32-C2/C3/C5/C6/S2/S3
-
-
-
-- **Iperf Throughput**
- - [ESP-Hosted-FG](esp_hosted_fg/README.md#5-throughput-performance)
- - [ESP-Hosted-NG](esp_hosted_ng/README.md#4-throughput-performance)
-
-## 3. Our Recommendation
-
-* If you are using MCU host, you do not have choice but to use ESP-Hosted-FG
-* If you are using Linux host, we recommend ESP-Hosted-NG since it takes a standard approach which makes it compatible with widely used user space applications/services such as wpa_supplicant, Network Manager etc.
+### ESP-Hosted-FG
+* 📄 [Documentation](https://github.com/espressif/esp-hosted/blob/master/esp_hosted_fg/README.md)
+* 🐞 [Issues](https://github.com/espressif/esp-hosted/issues)
+* 📈 [Throughput Benchmarks](https://github.com/espressif/esp-hosted/blob/master/esp_hosted_fg/README.md#5-throughput-performance)
+
+### ESP-Hosted-MCU
+
+* 📄 [Documentation](https://github.com/espressif/esp-hosted-mcu/blob/main/README.md)
+* 🐞 [Issues](https://github.com/espressif/esp-hosted-mcu/issues)
+* 📈 [Throughput Benchmarks](https://github.com/espressif/esp-hosted-mcu/tree/main?tab=readme-ov-file#hosted-transports-table)
diff --git a/esp_hosted_fg/README.md b/esp_hosted_fg/README.md
index 0b1b056517..6e6a2f7ca5 100644
--- a/esp_hosted_fg/README.md
+++ b/esp_hosted_fg/README.md
@@ -89,17 +89,24 @@ The below table explains which feature is supported on which transport interface
| -------: | :-------: | :-------: |
|  |     |    |
|  |     |   |
+|  |   |    |
|  |  |  |
|    |   |   |
-Note:
-- ESP-Hosted-FG related BR/EDR 4.2 and BLE 4.2 functionalities are tested with bluez 5.43+. Whereas, BLE 5.0 functionalities are tested with bluez 5.45+.
-- We suggest the latest stable bluez version to be used. Any other Bluetooth stack instead of bluez also could be used.
-- bluez 5.45 on-wards BLE 5.0 HCI commands are supported.
-- BLE 5.0 has backward compatibility of BLE 4.2.
+> [!NOTE]
+> - ESP-Hosted-FG related BR/EDR 4.2 and BLE 4.2 functionalities are tested with bluez 5.43+. Whereas, BLE 5.0 functionalities are tested with bluez 5.45+.
+> - Suggested to use latest stable bluez version.
+> - bluez 5.45 on-wards BLE 5.0 HCI commands are supported.
+> - BLE 5.0 has backward compatibility of BLE 4.2.
+> - ESP32-C5 SDIO and SDIO+UART support is coming soon!
##### 1.5.2 MCU Host
+
+> [!CAUTION]
+>
+> MCU support in ESP-Hosted-FG is now deprecated. For all MCU-based applications, please use the dedicated [ESP-Hosted-MCU repository](https://github.com/espressif/esp-hosted-mcu) instead. The information below is kept for backward compatibility only.
+
The below table explains which feature is supported on which transport interface for MCU based host.
| ESP Chipset | Transport options | MCU Features supported |
@@ -130,12 +137,6 @@ Note:
- Linux hosts support OTA update (Over The Air ESP firmware update) in C and python
- MCU hosts can refer to the same for their development
- For detailed documentation, please read [ota_update.md](docs/Linux_based_host/ota_update.md).
-- Features awaiting:
- - ESP32-C6 support for MCU
- - SDIO support with MCU host
- - LWIP integration at MCU host
- - Bluetooth stack at MCU host
- - ESP chipsets acting as MCU host (ESP as slave <----> ESP as host)
---
@@ -147,6 +148,11 @@ This section describes how to set up and use ESP-Hosted-FG solution. Since ESP-H
Please refer to the [Setup Guide](docs/Linux_based_host/Linux_based_readme.md) for Linux host.
### 2.2 Setup With MCU Host
+
+> [!CAUTION]
+>
+> MCU support in ESP-Hosted-FG is now deprecated. For all MCU-based applications, please use the dedicated [ESP-Hosted-MCU repository](https://github.com/espressif/esp-hosted-mcu) instead. The information below is kept for reference purposes only.
+
Please refer to the [Setup Guide](docs/MCU_based_host/MCU_based_readme.md) for MCU host.
In addition to [Control path APIs](#31-control-path-apis) listed below, APIs for MCU specific solution are explained [here](docs/MCU_based_host/mcu_api.md)
diff --git a/esp_hosted_fg/common/esp_hosted_config.pb-c.c b/esp_hosted_fg/common/esp_hosted_config.pb-c.c
index 88f7956396..d27e8608a3 100644
--- a/esp_hosted_fg/common/esp_hosted_config.pb-c.c
+++ b/esp_hosted_fg/common/esp_hosted_config.pb-c.c
@@ -2122,6 +2122,186 @@ void ctrl_msg__resp__get_country_code__free_unpacked
assert(message->base.descriptor == &ctrl_msg__resp__get_country_code__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
+void ctrl_msg__req__set_dhcp_dns_status__init
+ (CtrlMsgReqSetDhcpDnsStatus *message)
+{
+ static const CtrlMsgReqSetDhcpDnsStatus init_value = CTRL_MSG__REQ__SET_DHCP_DNS_STATUS__INIT;
+ *message = init_value;
+}
+size_t ctrl_msg__req__set_dhcp_dns_status__get_packed_size
+ (const CtrlMsgReqSetDhcpDnsStatus *message)
+{
+ assert(message->base.descriptor == &ctrl_msg__req__set_dhcp_dns_status__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t ctrl_msg__req__set_dhcp_dns_status__pack
+ (const CtrlMsgReqSetDhcpDnsStatus *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &ctrl_msg__req__set_dhcp_dns_status__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t ctrl_msg__req__set_dhcp_dns_status__pack_to_buffer
+ (const CtrlMsgReqSetDhcpDnsStatus *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &ctrl_msg__req__set_dhcp_dns_status__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+CtrlMsgReqSetDhcpDnsStatus *
+ ctrl_msg__req__set_dhcp_dns_status__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (CtrlMsgReqSetDhcpDnsStatus *)
+ protobuf_c_message_unpack (&ctrl_msg__req__set_dhcp_dns_status__descriptor,
+ allocator, len, data);
+}
+void ctrl_msg__req__set_dhcp_dns_status__free_unpacked
+ (CtrlMsgReqSetDhcpDnsStatus *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &ctrl_msg__req__set_dhcp_dns_status__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+void ctrl_msg__resp__set_dhcp_dns_status__init
+ (CtrlMsgRespSetDhcpDnsStatus *message)
+{
+ static const CtrlMsgRespSetDhcpDnsStatus init_value = CTRL_MSG__RESP__SET_DHCP_DNS_STATUS__INIT;
+ *message = init_value;
+}
+size_t ctrl_msg__resp__set_dhcp_dns_status__get_packed_size
+ (const CtrlMsgRespSetDhcpDnsStatus *message)
+{
+ assert(message->base.descriptor == &ctrl_msg__resp__set_dhcp_dns_status__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t ctrl_msg__resp__set_dhcp_dns_status__pack
+ (const CtrlMsgRespSetDhcpDnsStatus *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &ctrl_msg__resp__set_dhcp_dns_status__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t ctrl_msg__resp__set_dhcp_dns_status__pack_to_buffer
+ (const CtrlMsgRespSetDhcpDnsStatus *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &ctrl_msg__resp__set_dhcp_dns_status__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+CtrlMsgRespSetDhcpDnsStatus *
+ ctrl_msg__resp__set_dhcp_dns_status__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (CtrlMsgRespSetDhcpDnsStatus *)
+ protobuf_c_message_unpack (&ctrl_msg__resp__set_dhcp_dns_status__descriptor,
+ allocator, len, data);
+}
+void ctrl_msg__resp__set_dhcp_dns_status__free_unpacked
+ (CtrlMsgRespSetDhcpDnsStatus *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &ctrl_msg__resp__set_dhcp_dns_status__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+void ctrl_msg__req__get_dhcp_dns_status__init
+ (CtrlMsgReqGetDhcpDnsStatus *message)
+{
+ static const CtrlMsgReqGetDhcpDnsStatus init_value = CTRL_MSG__REQ__GET_DHCP_DNS_STATUS__INIT;
+ *message = init_value;
+}
+size_t ctrl_msg__req__get_dhcp_dns_status__get_packed_size
+ (const CtrlMsgReqGetDhcpDnsStatus *message)
+{
+ assert(message->base.descriptor == &ctrl_msg__req__get_dhcp_dns_status__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t ctrl_msg__req__get_dhcp_dns_status__pack
+ (const CtrlMsgReqGetDhcpDnsStatus *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &ctrl_msg__req__get_dhcp_dns_status__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t ctrl_msg__req__get_dhcp_dns_status__pack_to_buffer
+ (const CtrlMsgReqGetDhcpDnsStatus *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &ctrl_msg__req__get_dhcp_dns_status__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+CtrlMsgReqGetDhcpDnsStatus *
+ ctrl_msg__req__get_dhcp_dns_status__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (CtrlMsgReqGetDhcpDnsStatus *)
+ protobuf_c_message_unpack (&ctrl_msg__req__get_dhcp_dns_status__descriptor,
+ allocator, len, data);
+}
+void ctrl_msg__req__get_dhcp_dns_status__free_unpacked
+ (CtrlMsgReqGetDhcpDnsStatus *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &ctrl_msg__req__get_dhcp_dns_status__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+void ctrl_msg__resp__get_dhcp_dns_status__init
+ (CtrlMsgRespGetDhcpDnsStatus *message)
+{
+ static const CtrlMsgRespGetDhcpDnsStatus init_value = CTRL_MSG__RESP__GET_DHCP_DNS_STATUS__INIT;
+ *message = init_value;
+}
+size_t ctrl_msg__resp__get_dhcp_dns_status__get_packed_size
+ (const CtrlMsgRespGetDhcpDnsStatus *message)
+{
+ assert(message->base.descriptor == &ctrl_msg__resp__get_dhcp_dns_status__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t ctrl_msg__resp__get_dhcp_dns_status__pack
+ (const CtrlMsgRespGetDhcpDnsStatus *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &ctrl_msg__resp__get_dhcp_dns_status__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t ctrl_msg__resp__get_dhcp_dns_status__pack_to_buffer
+ (const CtrlMsgRespGetDhcpDnsStatus *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &ctrl_msg__resp__get_dhcp_dns_status__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+CtrlMsgRespGetDhcpDnsStatus *
+ ctrl_msg__resp__get_dhcp_dns_status__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (CtrlMsgRespGetDhcpDnsStatus *)
+ protobuf_c_message_unpack (&ctrl_msg__resp__get_dhcp_dns_status__descriptor,
+ allocator, len, data);
+}
+void ctrl_msg__resp__get_dhcp_dns_status__free_unpacked
+ (CtrlMsgRespGetDhcpDnsStatus *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &ctrl_msg__resp__get_dhcp_dns_status__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
void ctrl_msg__event__espinit__init
(CtrlMsgEventESPInit *message)
{
@@ -2392,6 +2572,186 @@ void ctrl_msg__event__station_connected_to_espsoft_ap__free_unpacked
assert(message->base.descriptor == &ctrl_msg__event__station_connected_to_espsoft_ap__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
+void ctrl_msg__event__set_dhcp_dns_status__init
+ (CtrlMsgEventSetDhcpDnsStatus *message)
+{
+ static const CtrlMsgEventSetDhcpDnsStatus init_value = CTRL_MSG__EVENT__SET_DHCP_DNS_STATUS__INIT;
+ *message = init_value;
+}
+size_t ctrl_msg__event__set_dhcp_dns_status__get_packed_size
+ (const CtrlMsgEventSetDhcpDnsStatus *message)
+{
+ assert(message->base.descriptor == &ctrl_msg__event__set_dhcp_dns_status__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t ctrl_msg__event__set_dhcp_dns_status__pack
+ (const CtrlMsgEventSetDhcpDnsStatus *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &ctrl_msg__event__set_dhcp_dns_status__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t ctrl_msg__event__set_dhcp_dns_status__pack_to_buffer
+ (const CtrlMsgEventSetDhcpDnsStatus *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &ctrl_msg__event__set_dhcp_dns_status__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+CtrlMsgEventSetDhcpDnsStatus *
+ ctrl_msg__event__set_dhcp_dns_status__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (CtrlMsgEventSetDhcpDnsStatus *)
+ protobuf_c_message_unpack (&ctrl_msg__event__set_dhcp_dns_status__descriptor,
+ allocator, len, data);
+}
+void ctrl_msg__event__set_dhcp_dns_status__free_unpacked
+ (CtrlMsgEventSetDhcpDnsStatus *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &ctrl_msg__event__set_dhcp_dns_status__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+void ctrl_msg__req__custom_rpc_unserialised_msg__init
+ (CtrlMsgReqCustomRpcUnserialisedMsg *message)
+{
+ static const CtrlMsgReqCustomRpcUnserialisedMsg init_value = CTRL_MSG__REQ__CUSTOM_RPC_UNSERIALISED_MSG__INIT;
+ *message = init_value;
+}
+size_t ctrl_msg__req__custom_rpc_unserialised_msg__get_packed_size
+ (const CtrlMsgReqCustomRpcUnserialisedMsg *message)
+{
+ assert(message->base.descriptor == &ctrl_msg__req__custom_rpc_unserialised_msg__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t ctrl_msg__req__custom_rpc_unserialised_msg__pack
+ (const CtrlMsgReqCustomRpcUnserialisedMsg *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &ctrl_msg__req__custom_rpc_unserialised_msg__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t ctrl_msg__req__custom_rpc_unserialised_msg__pack_to_buffer
+ (const CtrlMsgReqCustomRpcUnserialisedMsg *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &ctrl_msg__req__custom_rpc_unserialised_msg__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+CtrlMsgReqCustomRpcUnserialisedMsg *
+ ctrl_msg__req__custom_rpc_unserialised_msg__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (CtrlMsgReqCustomRpcUnserialisedMsg *)
+ protobuf_c_message_unpack (&ctrl_msg__req__custom_rpc_unserialised_msg__descriptor,
+ allocator, len, data);
+}
+void ctrl_msg__req__custom_rpc_unserialised_msg__free_unpacked
+ (CtrlMsgReqCustomRpcUnserialisedMsg *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &ctrl_msg__req__custom_rpc_unserialised_msg__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+void ctrl_msg__resp__custom_rpc_unserialised_msg__init
+ (CtrlMsgRespCustomRpcUnserialisedMsg *message)
+{
+ static const CtrlMsgRespCustomRpcUnserialisedMsg init_value = CTRL_MSG__RESP__CUSTOM_RPC_UNSERIALISED_MSG__INIT;
+ *message = init_value;
+}
+size_t ctrl_msg__resp__custom_rpc_unserialised_msg__get_packed_size
+ (const CtrlMsgRespCustomRpcUnserialisedMsg *message)
+{
+ assert(message->base.descriptor == &ctrl_msg__resp__custom_rpc_unserialised_msg__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t ctrl_msg__resp__custom_rpc_unserialised_msg__pack
+ (const CtrlMsgRespCustomRpcUnserialisedMsg *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &ctrl_msg__resp__custom_rpc_unserialised_msg__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t ctrl_msg__resp__custom_rpc_unserialised_msg__pack_to_buffer
+ (const CtrlMsgRespCustomRpcUnserialisedMsg *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &ctrl_msg__resp__custom_rpc_unserialised_msg__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+CtrlMsgRespCustomRpcUnserialisedMsg *
+ ctrl_msg__resp__custom_rpc_unserialised_msg__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (CtrlMsgRespCustomRpcUnserialisedMsg *)
+ protobuf_c_message_unpack (&ctrl_msg__resp__custom_rpc_unserialised_msg__descriptor,
+ allocator, len, data);
+}
+void ctrl_msg__resp__custom_rpc_unserialised_msg__free_unpacked
+ (CtrlMsgRespCustomRpcUnserialisedMsg *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &ctrl_msg__resp__custom_rpc_unserialised_msg__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
+void ctrl_msg__event__custom_rpc_unserialised_msg__init
+ (CtrlMsgEventCustomRpcUnserialisedMsg *message)
+{
+ static const CtrlMsgEventCustomRpcUnserialisedMsg init_value = CTRL_MSG__EVENT__CUSTOM_RPC_UNSERIALISED_MSG__INIT;
+ *message = init_value;
+}
+size_t ctrl_msg__event__custom_rpc_unserialised_msg__get_packed_size
+ (const CtrlMsgEventCustomRpcUnserialisedMsg *message)
+{
+ assert(message->base.descriptor == &ctrl_msg__event__custom_rpc_unserialised_msg__descriptor);
+ return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
+}
+size_t ctrl_msg__event__custom_rpc_unserialised_msg__pack
+ (const CtrlMsgEventCustomRpcUnserialisedMsg *message,
+ uint8_t *out)
+{
+ assert(message->base.descriptor == &ctrl_msg__event__custom_rpc_unserialised_msg__descriptor);
+ return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
+}
+size_t ctrl_msg__event__custom_rpc_unserialised_msg__pack_to_buffer
+ (const CtrlMsgEventCustomRpcUnserialisedMsg *message,
+ ProtobufCBuffer *buffer)
+{
+ assert(message->base.descriptor == &ctrl_msg__event__custom_rpc_unserialised_msg__descriptor);
+ return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
+}
+CtrlMsgEventCustomRpcUnserialisedMsg *
+ ctrl_msg__event__custom_rpc_unserialised_msg__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data)
+{
+ return (CtrlMsgEventCustomRpcUnserialisedMsg *)
+ protobuf_c_message_unpack (&ctrl_msg__event__custom_rpc_unserialised_msg__descriptor,
+ allocator, len, data);
+}
+void ctrl_msg__event__custom_rpc_unserialised_msg__free_unpacked
+ (CtrlMsgEventCustomRpcUnserialisedMsg *message,
+ ProtobufCAllocator *allocator)
+{
+ if(!message)
+ return;
+ assert(message->base.descriptor == &ctrl_msg__event__custom_rpc_unserialised_msg__descriptor);
+ protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
+}
void ctrl_msg__init
(CtrlMsg *message)
{
@@ -4783,83 +5143,539 @@ const ProtobufCMessageDescriptor ctrl_msg__resp__get_country_code__descriptor =
(ProtobufCMessageInit) ctrl_msg__resp__get_country_code__init,
NULL,NULL,NULL /* reserved[123] */
};
-static const ProtobufCFieldDescriptor ctrl_msg__event__espinit__field_descriptors[1] =
+static const ProtobufCFieldDescriptor ctrl_msg__req__set_dhcp_dns_status__field_descriptors[9] =
{
{
- "init_data",
+ "iface",
1,
PROTOBUF_C_LABEL_NONE,
- PROTOBUF_C_TYPE_BYTES,
+ PROTOBUF_C_TYPE_INT32,
0, /* quantifier_offset */
- offsetof(CtrlMsgEventESPInit, init_data),
+ offsetof(CtrlMsgReqSetDhcpDnsStatus, iface),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
-};
-static const unsigned ctrl_msg__event__espinit__field_indices_by_name[] = {
- 0, /* field[0] = init_data */
-};
-static const ProtobufCIntRange ctrl_msg__event__espinit__number_ranges[1 + 1] =
-{
- { 1, 0 },
- { 0, 1 }
-};
-const ProtobufCMessageDescriptor ctrl_msg__event__espinit__descriptor =
-{
- PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
- "CtrlMsg_Event_ESPInit",
- "CtrlMsgEventESPInit",
- "CtrlMsgEventESPInit",
- "",
- sizeof(CtrlMsgEventESPInit),
- 1,
- ctrl_msg__event__espinit__field_descriptors,
- ctrl_msg__event__espinit__field_indices_by_name,
- 1, ctrl_msg__event__espinit__number_ranges,
- (ProtobufCMessageInit) ctrl_msg__event__espinit__init,
- NULL,NULL,NULL /* reserved[123] */
-};
-static const ProtobufCFieldDescriptor ctrl_msg__event__heartbeat__field_descriptors[1] =
-{
{
- "hb_num",
- 1,
+ "net_link_up",
+ 2,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_INT32,
0, /* quantifier_offset */
- offsetof(CtrlMsgEventHeartbeat, hb_num),
+ offsetof(CtrlMsgReqSetDhcpDnsStatus, net_link_up),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
-};
-static const unsigned ctrl_msg__event__heartbeat__field_indices_by_name[] = {
- 0, /* field[0] = hb_num */
-};
-static const ProtobufCIntRange ctrl_msg__event__heartbeat__number_ranges[1 + 1] =
-{
- { 1, 0 },
- { 0, 1 }
-};
-const ProtobufCMessageDescriptor ctrl_msg__event__heartbeat__descriptor =
-{
- PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
- "CtrlMsg_Event_Heartbeat",
+ {
+ "dhcp_up",
+ 3,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_INT32,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgReqSetDhcpDnsStatus, dhcp_up),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "dhcp_ip",
+ 4,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_BYTES,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgReqSetDhcpDnsStatus, dhcp_ip),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "dhcp_nm",
+ 5,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_BYTES,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgReqSetDhcpDnsStatus, dhcp_nm),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "dhcp_gw",
+ 6,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_BYTES,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgReqSetDhcpDnsStatus, dhcp_gw),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "dns_up",
+ 7,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_INT32,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgReqSetDhcpDnsStatus, dns_up),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "dns_ip",
+ 8,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_BYTES,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgReqSetDhcpDnsStatus, dns_ip),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "dns_type",
+ 9,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_INT32,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgReqSetDhcpDnsStatus, dns_type),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned ctrl_msg__req__set_dhcp_dns_status__field_indices_by_name[] = {
+ 5, /* field[5] = dhcp_gw */
+ 3, /* field[3] = dhcp_ip */
+ 4, /* field[4] = dhcp_nm */
+ 2, /* field[2] = dhcp_up */
+ 7, /* field[7] = dns_ip */
+ 8, /* field[8] = dns_type */
+ 6, /* field[6] = dns_up */
+ 0, /* field[0] = iface */
+ 1, /* field[1] = net_link_up */
+};
+static const ProtobufCIntRange ctrl_msg__req__set_dhcp_dns_status__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 9 }
+};
+const ProtobufCMessageDescriptor ctrl_msg__req__set_dhcp_dns_status__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "CtrlMsg_Req_SetDhcpDnsStatus",
+ "CtrlMsgReqSetDhcpDnsStatus",
+ "CtrlMsgReqSetDhcpDnsStatus",
+ "",
+ sizeof(CtrlMsgReqSetDhcpDnsStatus),
+ 9,
+ ctrl_msg__req__set_dhcp_dns_status__field_descriptors,
+ ctrl_msg__req__set_dhcp_dns_status__field_indices_by_name,
+ 1, ctrl_msg__req__set_dhcp_dns_status__number_ranges,
+ (ProtobufCMessageInit) ctrl_msg__req__set_dhcp_dns_status__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
+static const ProtobufCFieldDescriptor ctrl_msg__resp__set_dhcp_dns_status__field_descriptors[1] =
+{
+ {
+ "resp",
+ 1,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_INT32,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgRespSetDhcpDnsStatus, resp),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned ctrl_msg__resp__set_dhcp_dns_status__field_indices_by_name[] = {
+ 0, /* field[0] = resp */
+};
+static const ProtobufCIntRange ctrl_msg__resp__set_dhcp_dns_status__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 1 }
+};
+const ProtobufCMessageDescriptor ctrl_msg__resp__set_dhcp_dns_status__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "CtrlMsg_Resp_SetDhcpDnsStatus",
+ "CtrlMsgRespSetDhcpDnsStatus",
+ "CtrlMsgRespSetDhcpDnsStatus",
+ "",
+ sizeof(CtrlMsgRespSetDhcpDnsStatus),
+ 1,
+ ctrl_msg__resp__set_dhcp_dns_status__field_descriptors,
+ ctrl_msg__resp__set_dhcp_dns_status__field_indices_by_name,
+ 1, ctrl_msg__resp__set_dhcp_dns_status__number_ranges,
+ (ProtobufCMessageInit) ctrl_msg__resp__set_dhcp_dns_status__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
+#define ctrl_msg__req__get_dhcp_dns_status__field_descriptors NULL
+#define ctrl_msg__req__get_dhcp_dns_status__field_indices_by_name NULL
+#define ctrl_msg__req__get_dhcp_dns_status__number_ranges NULL
+const ProtobufCMessageDescriptor ctrl_msg__req__get_dhcp_dns_status__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "CtrlMsg_Req_GetDhcpDnsStatus",
+ "CtrlMsgReqGetDhcpDnsStatus",
+ "CtrlMsgReqGetDhcpDnsStatus",
+ "",
+ sizeof(CtrlMsgReqGetDhcpDnsStatus),
+ 0,
+ ctrl_msg__req__get_dhcp_dns_status__field_descriptors,
+ ctrl_msg__req__get_dhcp_dns_status__field_indices_by_name,
+ 0, ctrl_msg__req__get_dhcp_dns_status__number_ranges,
+ (ProtobufCMessageInit) ctrl_msg__req__get_dhcp_dns_status__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
+static const ProtobufCFieldDescriptor ctrl_msg__resp__get_dhcp_dns_status__field_descriptors[10] =
+{
+ {
+ "resp",
+ 1,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_INT32,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgRespGetDhcpDnsStatus, resp),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "iface",
+ 2,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_INT32,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgRespGetDhcpDnsStatus, iface),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "net_link_up",
+ 3,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_INT32,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgRespGetDhcpDnsStatus, net_link_up),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "dhcp_up",
+ 4,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_INT32,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgRespGetDhcpDnsStatus, dhcp_up),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "dhcp_ip",
+ 5,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_BYTES,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgRespGetDhcpDnsStatus, dhcp_ip),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "dhcp_nm",
+ 6,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_BYTES,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgRespGetDhcpDnsStatus, dhcp_nm),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "dhcp_gw",
+ 7,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_BYTES,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgRespGetDhcpDnsStatus, dhcp_gw),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "dns_up",
+ 8,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_INT32,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgRespGetDhcpDnsStatus, dns_up),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "dns_ip",
+ 9,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_BYTES,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgRespGetDhcpDnsStatus, dns_ip),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "dns_type",
+ 10,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_INT32,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgRespGetDhcpDnsStatus, dns_type),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned ctrl_msg__resp__get_dhcp_dns_status__field_indices_by_name[] = {
+ 6, /* field[6] = dhcp_gw */
+ 4, /* field[4] = dhcp_ip */
+ 5, /* field[5] = dhcp_nm */
+ 3, /* field[3] = dhcp_up */
+ 8, /* field[8] = dns_ip */
+ 9, /* field[9] = dns_type */
+ 7, /* field[7] = dns_up */
+ 1, /* field[1] = iface */
+ 2, /* field[2] = net_link_up */
+ 0, /* field[0] = resp */
+};
+static const ProtobufCIntRange ctrl_msg__resp__get_dhcp_dns_status__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 10 }
+};
+const ProtobufCMessageDescriptor ctrl_msg__resp__get_dhcp_dns_status__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "CtrlMsg_Resp_GetDhcpDnsStatus",
+ "CtrlMsgRespGetDhcpDnsStatus",
+ "CtrlMsgRespGetDhcpDnsStatus",
+ "",
+ sizeof(CtrlMsgRespGetDhcpDnsStatus),
+ 10,
+ ctrl_msg__resp__get_dhcp_dns_status__field_descriptors,
+ ctrl_msg__resp__get_dhcp_dns_status__field_indices_by_name,
+ 1, ctrl_msg__resp__get_dhcp_dns_status__number_ranges,
+ (ProtobufCMessageInit) ctrl_msg__resp__get_dhcp_dns_status__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
+static const ProtobufCFieldDescriptor ctrl_msg__event__espinit__field_descriptors[1] =
+{
+ {
+ "init_data",
+ 1,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_BYTES,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgEventESPInit, init_data),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned ctrl_msg__event__espinit__field_indices_by_name[] = {
+ 0, /* field[0] = init_data */
+};
+static const ProtobufCIntRange ctrl_msg__event__espinit__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 1 }
+};
+const ProtobufCMessageDescriptor ctrl_msg__event__espinit__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "CtrlMsg_Event_ESPInit",
+ "CtrlMsgEventESPInit",
+ "CtrlMsgEventESPInit",
+ "",
+ sizeof(CtrlMsgEventESPInit),
+ 1,
+ ctrl_msg__event__espinit__field_descriptors,
+ ctrl_msg__event__espinit__field_indices_by_name,
+ 1, ctrl_msg__event__espinit__number_ranges,
+ (ProtobufCMessageInit) ctrl_msg__event__espinit__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
+static const ProtobufCFieldDescriptor ctrl_msg__event__heartbeat__field_descriptors[1] =
+{
+ {
+ "hb_num",
+ 1,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_INT32,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgEventHeartbeat, hb_num),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned ctrl_msg__event__heartbeat__field_indices_by_name[] = {
+ 0, /* field[0] = hb_num */
+};
+static const ProtobufCIntRange ctrl_msg__event__heartbeat__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 1 }
+};
+const ProtobufCMessageDescriptor ctrl_msg__event__heartbeat__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "CtrlMsg_Event_Heartbeat",
"CtrlMsgEventHeartbeat",
"CtrlMsgEventHeartbeat",
"",
- sizeof(CtrlMsgEventHeartbeat),
- 1,
- ctrl_msg__event__heartbeat__field_descriptors,
- ctrl_msg__event__heartbeat__field_indices_by_name,
- 1, ctrl_msg__event__heartbeat__number_ranges,
- (ProtobufCMessageInit) ctrl_msg__event__heartbeat__init,
+ sizeof(CtrlMsgEventHeartbeat),
+ 1,
+ ctrl_msg__event__heartbeat__field_descriptors,
+ ctrl_msg__event__heartbeat__field_indices_by_name,
+ 1, ctrl_msg__event__heartbeat__number_ranges,
+ (ProtobufCMessageInit) ctrl_msg__event__heartbeat__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
+static const ProtobufCFieldDescriptor ctrl_msg__event__station_disconnect_from_ap__field_descriptors[6] =
+{
+ {
+ "resp",
+ 1,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_INT32,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgEventStationDisconnectFromAP, resp),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ssid",
+ 2,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_BYTES,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgEventStationDisconnectFromAP, ssid),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "ssid_len",
+ 3,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_UINT32,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgEventStationDisconnectFromAP, ssid_len),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "bssid",
+ 4,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_BYTES,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgEventStationDisconnectFromAP, bssid),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "reason",
+ 5,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_UINT32,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgEventStationDisconnectFromAP, reason),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "rssi",
+ 6,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_INT32,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgEventStationDisconnectFromAP, rssi),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned ctrl_msg__event__station_disconnect_from_ap__field_indices_by_name[] = {
+ 3, /* field[3] = bssid */
+ 4, /* field[4] = reason */
+ 0, /* field[0] = resp */
+ 5, /* field[5] = rssi */
+ 1, /* field[1] = ssid */
+ 2, /* field[2] = ssid_len */
+};
+static const ProtobufCIntRange ctrl_msg__event__station_disconnect_from_ap__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 6 }
+};
+const ProtobufCMessageDescriptor ctrl_msg__event__station_disconnect_from_ap__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "CtrlMsg_Event_StationDisconnectFromAP",
+ "CtrlMsgEventStationDisconnectFromAP",
+ "CtrlMsgEventStationDisconnectFromAP",
+ "",
+ sizeof(CtrlMsgEventStationDisconnectFromAP),
+ 6,
+ ctrl_msg__event__station_disconnect_from_ap__field_descriptors,
+ ctrl_msg__event__station_disconnect_from_ap__field_indices_by_name,
+ 1, ctrl_msg__event__station_disconnect_from_ap__number_ranges,
+ (ProtobufCMessageInit) ctrl_msg__event__station_disconnect_from_ap__init,
NULL,NULL,NULL /* reserved[123] */
};
-static const ProtobufCFieldDescriptor ctrl_msg__event__station_disconnect_from_ap__field_descriptors[6] =
+static const ProtobufCFieldDescriptor ctrl_msg__event__station_connected_to_ap__field_descriptors[7] =
{
{
"resp",
@@ -4867,7 +5683,7 @@ static const ProtobufCFieldDescriptor ctrl_msg__event__station_disconnect_from_a
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_INT32,
0, /* quantifier_offset */
- offsetof(CtrlMsgEventStationDisconnectFromAP, resp),
+ offsetof(CtrlMsgEventStationConnectedToAP, resp),
NULL,
NULL,
0, /* flags */
@@ -4879,7 +5695,7 @@ static const ProtobufCFieldDescriptor ctrl_msg__event__station_disconnect_from_a
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_BYTES,
0, /* quantifier_offset */
- offsetof(CtrlMsgEventStationDisconnectFromAP, ssid),
+ offsetof(CtrlMsgEventStationConnectedToAP, ssid),
NULL,
NULL,
0, /* flags */
@@ -4891,7 +5707,7 @@ static const ProtobufCFieldDescriptor ctrl_msg__event__station_disconnect_from_a
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_UINT32,
0, /* quantifier_offset */
- offsetof(CtrlMsgEventStationDisconnectFromAP, ssid_len),
+ offsetof(CtrlMsgEventStationConnectedToAP, ssid_len),
NULL,
NULL,
0, /* flags */
@@ -4903,272 +5719,516 @@ static const ProtobufCFieldDescriptor ctrl_msg__event__station_disconnect_from_a
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_BYTES,
0, /* quantifier_offset */
- offsetof(CtrlMsgEventStationDisconnectFromAP, bssid),
+ offsetof(CtrlMsgEventStationConnectedToAP, bssid),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
- "reason",
+ "channel",
5,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_UINT32,
0, /* quantifier_offset */
- offsetof(CtrlMsgEventStationDisconnectFromAP, reason),
+ offsetof(CtrlMsgEventStationConnectedToAP, channel),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
- "rssi",
+ "authmode",
6,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_INT32,
0, /* quantifier_offset */
- offsetof(CtrlMsgEventStationDisconnectFromAP, rssi),
+ offsetof(CtrlMsgEventStationConnectedToAP, authmode),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "aid",
+ 7,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_INT32,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgEventStationConnectedToAP, aid),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
-static const unsigned ctrl_msg__event__station_disconnect_from_ap__field_indices_by_name[] = {
+static const unsigned ctrl_msg__event__station_connected_to_ap__field_indices_by_name[] = {
+ 6, /* field[6] = aid */
+ 5, /* field[5] = authmode */
3, /* field[3] = bssid */
- 4, /* field[4] = reason */
+ 4, /* field[4] = channel */
0, /* field[0] = resp */
- 5, /* field[5] = rssi */
1, /* field[1] = ssid */
2, /* field[2] = ssid_len */
};
-static const ProtobufCIntRange ctrl_msg__event__station_disconnect_from_ap__number_ranges[1 + 1] =
+static const ProtobufCIntRange ctrl_msg__event__station_connected_to_ap__number_ranges[1 + 1] =
{
{ 1, 0 },
- { 0, 6 }
+ { 0, 7 }
};
-const ProtobufCMessageDescriptor ctrl_msg__event__station_disconnect_from_ap__descriptor =
+const ProtobufCMessageDescriptor ctrl_msg__event__station_connected_to_ap__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
- "CtrlMsg_Event_StationDisconnectFromAP",
- "CtrlMsgEventStationDisconnectFromAP",
- "CtrlMsgEventStationDisconnectFromAP",
+ "CtrlMsg_Event_StationConnectedToAP",
+ "CtrlMsgEventStationConnectedToAP",
+ "CtrlMsgEventStationConnectedToAP",
"",
- sizeof(CtrlMsgEventStationDisconnectFromAP),
- 6,
- ctrl_msg__event__station_disconnect_from_ap__field_descriptors,
- ctrl_msg__event__station_disconnect_from_ap__field_indices_by_name,
- 1, ctrl_msg__event__station_disconnect_from_ap__number_ranges,
- (ProtobufCMessageInit) ctrl_msg__event__station_disconnect_from_ap__init,
+ sizeof(CtrlMsgEventStationConnectedToAP),
+ 7,
+ ctrl_msg__event__station_connected_to_ap__field_descriptors,
+ ctrl_msg__event__station_connected_to_ap__field_indices_by_name,
+ 1, ctrl_msg__event__station_connected_to_ap__number_ranges,
+ (ProtobufCMessageInit) ctrl_msg__event__station_connected_to_ap__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
+static const ProtobufCFieldDescriptor ctrl_msg__event__station_disconnect_from_espsoft_ap__field_descriptors[5] =
+{
+ {
+ "resp",
+ 1,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_INT32,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgEventStationDisconnectFromESPSoftAP, resp),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "mac",
+ 2,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_BYTES,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgEventStationDisconnectFromESPSoftAP, mac),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "aid",
+ 3,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_UINT32,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgEventStationDisconnectFromESPSoftAP, aid),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "is_mesh_child",
+ 4,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_BOOL,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgEventStationDisconnectFromESPSoftAP, is_mesh_child),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "reason",
+ 5,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_UINT32,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgEventStationDisconnectFromESPSoftAP, reason),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned ctrl_msg__event__station_disconnect_from_espsoft_ap__field_indices_by_name[] = {
+ 2, /* field[2] = aid */
+ 3, /* field[3] = is_mesh_child */
+ 1, /* field[1] = mac */
+ 4, /* field[4] = reason */
+ 0, /* field[0] = resp */
+};
+static const ProtobufCIntRange ctrl_msg__event__station_disconnect_from_espsoft_ap__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 5 }
+};
+const ProtobufCMessageDescriptor ctrl_msg__event__station_disconnect_from_espsoft_ap__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "CtrlMsg_Event_StationDisconnectFromESPSoftAP",
+ "CtrlMsgEventStationDisconnectFromESPSoftAP",
+ "CtrlMsgEventStationDisconnectFromESPSoftAP",
+ "",
+ sizeof(CtrlMsgEventStationDisconnectFromESPSoftAP),
+ 5,
+ ctrl_msg__event__station_disconnect_from_espsoft_ap__field_descriptors,
+ ctrl_msg__event__station_disconnect_from_espsoft_ap__field_indices_by_name,
+ 1, ctrl_msg__event__station_disconnect_from_espsoft_ap__number_ranges,
+ (ProtobufCMessageInit) ctrl_msg__event__station_disconnect_from_espsoft_ap__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
+static const ProtobufCFieldDescriptor ctrl_msg__event__station_connected_to_espsoft_ap__field_descriptors[4] =
+{
+ {
+ "resp",
+ 1,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_INT32,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgEventStationConnectedToESPSoftAP, resp),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "mac",
+ 2,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_BYTES,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgEventStationConnectedToESPSoftAP, mac),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "aid",
+ 3,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_UINT32,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgEventStationConnectedToESPSoftAP, aid),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "is_mesh_child",
+ 4,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_BOOL,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgEventStationConnectedToESPSoftAP, is_mesh_child),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+};
+static const unsigned ctrl_msg__event__station_connected_to_espsoft_ap__field_indices_by_name[] = {
+ 2, /* field[2] = aid */
+ 3, /* field[3] = is_mesh_child */
+ 1, /* field[1] = mac */
+ 0, /* field[0] = resp */
+};
+static const ProtobufCIntRange ctrl_msg__event__station_connected_to_espsoft_ap__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 4 }
+};
+const ProtobufCMessageDescriptor ctrl_msg__event__station_connected_to_espsoft_ap__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "CtrlMsg_Event_StationConnectedToESPSoftAP",
+ "CtrlMsgEventStationConnectedToESPSoftAP",
+ "CtrlMsgEventStationConnectedToESPSoftAP",
+ "",
+ sizeof(CtrlMsgEventStationConnectedToESPSoftAP),
+ 4,
+ ctrl_msg__event__station_connected_to_espsoft_ap__field_descriptors,
+ ctrl_msg__event__station_connected_to_espsoft_ap__field_indices_by_name,
+ 1, ctrl_msg__event__station_connected_to_espsoft_ap__number_ranges,
+ (ProtobufCMessageInit) ctrl_msg__event__station_connected_to_espsoft_ap__init,
NULL,NULL,NULL /* reserved[123] */
};
-static const ProtobufCFieldDescriptor ctrl_msg__event__station_connected_to_ap__field_descriptors[7] =
+static const ProtobufCFieldDescriptor ctrl_msg__event__set_dhcp_dns_status__field_descriptors[10] =
{
{
- "resp",
+ "iface",
1,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_INT32,
0, /* quantifier_offset */
- offsetof(CtrlMsgEventStationConnectedToAP, resp),
+ offsetof(CtrlMsgEventSetDhcpDnsStatus, iface),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
- "ssid",
+ "net_link_up",
2,
PROTOBUF_C_LABEL_NONE,
- PROTOBUF_C_TYPE_BYTES,
+ PROTOBUF_C_TYPE_INT32,
0, /* quantifier_offset */
- offsetof(CtrlMsgEventStationConnectedToAP, ssid),
+ offsetof(CtrlMsgEventSetDhcpDnsStatus, net_link_up),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
- "ssid_len",
+ "dhcp_up",
3,
PROTOBUF_C_LABEL_NONE,
- PROTOBUF_C_TYPE_UINT32,
+ PROTOBUF_C_TYPE_INT32,
0, /* quantifier_offset */
- offsetof(CtrlMsgEventStationConnectedToAP, ssid_len),
+ offsetof(CtrlMsgEventSetDhcpDnsStatus, dhcp_up),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
- "bssid",
+ "dhcp_ip",
4,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_BYTES,
0, /* quantifier_offset */
- offsetof(CtrlMsgEventStationConnectedToAP, bssid),
+ offsetof(CtrlMsgEventSetDhcpDnsStatus, dhcp_ip),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
- "channel",
+ "dhcp_nm",
5,
PROTOBUF_C_LABEL_NONE,
- PROTOBUF_C_TYPE_UINT32,
+ PROTOBUF_C_TYPE_BYTES,
0, /* quantifier_offset */
- offsetof(CtrlMsgEventStationConnectedToAP, channel),
+ offsetof(CtrlMsgEventSetDhcpDnsStatus, dhcp_nm),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
- "authmode",
+ "dhcp_gw",
6,
PROTOBUF_C_LABEL_NONE,
- PROTOBUF_C_TYPE_INT32,
+ PROTOBUF_C_TYPE_BYTES,
0, /* quantifier_offset */
- offsetof(CtrlMsgEventStationConnectedToAP, authmode),
+ offsetof(CtrlMsgEventSetDhcpDnsStatus, dhcp_gw),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
- "aid",
+ "dns_up",
7,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_INT32,
0, /* quantifier_offset */
- offsetof(CtrlMsgEventStationConnectedToAP, aid),
+ offsetof(CtrlMsgEventSetDhcpDnsStatus, dns_up),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "dns_ip",
+ 8,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_BYTES,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgEventSetDhcpDnsStatus, dns_ip),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "dns_type",
+ 9,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_INT32,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgEventSetDhcpDnsStatus, dns_type),
+ NULL,
+ NULL,
+ 0, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "resp",
+ 10,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_INT32,
+ 0, /* quantifier_offset */
+ offsetof(CtrlMsgEventSetDhcpDnsStatus, resp),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
-static const unsigned ctrl_msg__event__station_connected_to_ap__field_indices_by_name[] = {
- 6, /* field[6] = aid */
- 5, /* field[5] = authmode */
- 3, /* field[3] = bssid */
- 4, /* field[4] = channel */
- 0, /* field[0] = resp */
- 1, /* field[1] = ssid */
- 2, /* field[2] = ssid_len */
+static const unsigned ctrl_msg__event__set_dhcp_dns_status__field_indices_by_name[] = {
+ 5, /* field[5] = dhcp_gw */
+ 3, /* field[3] = dhcp_ip */
+ 4, /* field[4] = dhcp_nm */
+ 2, /* field[2] = dhcp_up */
+ 7, /* field[7] = dns_ip */
+ 8, /* field[8] = dns_type */
+ 6, /* field[6] = dns_up */
+ 0, /* field[0] = iface */
+ 1, /* field[1] = net_link_up */
+ 9, /* field[9] = resp */
};
-static const ProtobufCIntRange ctrl_msg__event__station_connected_to_ap__number_ranges[1 + 1] =
+static const ProtobufCIntRange ctrl_msg__event__set_dhcp_dns_status__number_ranges[1 + 1] =
{
{ 1, 0 },
- { 0, 7 }
+ { 0, 10 }
};
-const ProtobufCMessageDescriptor ctrl_msg__event__station_connected_to_ap__descriptor =
+const ProtobufCMessageDescriptor ctrl_msg__event__set_dhcp_dns_status__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
- "CtrlMsg_Event_StationConnectedToAP",
- "CtrlMsgEventStationConnectedToAP",
- "CtrlMsgEventStationConnectedToAP",
+ "CtrlMsg_Event_SetDhcpDnsStatus",
+ "CtrlMsgEventSetDhcpDnsStatus",
+ "CtrlMsgEventSetDhcpDnsStatus",
"",
- sizeof(CtrlMsgEventStationConnectedToAP),
- 7,
- ctrl_msg__event__station_connected_to_ap__field_descriptors,
- ctrl_msg__event__station_connected_to_ap__field_indices_by_name,
- 1, ctrl_msg__event__station_connected_to_ap__number_ranges,
- (ProtobufCMessageInit) ctrl_msg__event__station_connected_to_ap__init,
+ sizeof(CtrlMsgEventSetDhcpDnsStatus),
+ 10,
+ ctrl_msg__event__set_dhcp_dns_status__field_descriptors,
+ ctrl_msg__event__set_dhcp_dns_status__field_indices_by_name,
+ 1, ctrl_msg__event__set_dhcp_dns_status__number_ranges,
+ (ProtobufCMessageInit) ctrl_msg__event__set_dhcp_dns_status__init,
NULL,NULL,NULL /* reserved[123] */
};
-static const ProtobufCFieldDescriptor ctrl_msg__event__station_disconnect_from_espsoft_ap__field_descriptors[5] =
+static const ProtobufCFieldDescriptor ctrl_msg__req__custom_rpc_unserialised_msg__field_descriptors[2] =
{
{
- "resp",
+ "custom_msg_id",
1,
PROTOBUF_C_LABEL_NONE,
- PROTOBUF_C_TYPE_INT32,
+ PROTOBUF_C_TYPE_UINT32,
0, /* quantifier_offset */
- offsetof(CtrlMsgEventStationDisconnectFromESPSoftAP, resp),
+ offsetof(CtrlMsgReqCustomRpcUnserialisedMsg, custom_msg_id),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
- "mac",
+ "data",
2,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_BYTES,
0, /* quantifier_offset */
- offsetof(CtrlMsgEventStationDisconnectFromESPSoftAP, mac),
+ offsetof(CtrlMsgReqCustomRpcUnserialisedMsg, data),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
+};
+static const unsigned ctrl_msg__req__custom_rpc_unserialised_msg__field_indices_by_name[] = {
+ 0, /* field[0] = custom_msg_id */
+ 1, /* field[1] = data */
+};
+static const ProtobufCIntRange ctrl_msg__req__custom_rpc_unserialised_msg__number_ranges[1 + 1] =
+{
+ { 1, 0 },
+ { 0, 2 }
+};
+const ProtobufCMessageDescriptor ctrl_msg__req__custom_rpc_unserialised_msg__descriptor =
+{
+ PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
+ "CtrlMsg_Req_CustomRpcUnserialisedMsg",
+ "CtrlMsgReqCustomRpcUnserialisedMsg",
+ "CtrlMsgReqCustomRpcUnserialisedMsg",
+ "",
+ sizeof(CtrlMsgReqCustomRpcUnserialisedMsg),
+ 2,
+ ctrl_msg__req__custom_rpc_unserialised_msg__field_descriptors,
+ ctrl_msg__req__custom_rpc_unserialised_msg__field_indices_by_name,
+ 1, ctrl_msg__req__custom_rpc_unserialised_msg__number_ranges,
+ (ProtobufCMessageInit) ctrl_msg__req__custom_rpc_unserialised_msg__init,
+ NULL,NULL,NULL /* reserved[123] */
+};
+static const ProtobufCFieldDescriptor ctrl_msg__resp__custom_rpc_unserialised_msg__field_descriptors[3] =
+{
{
- "aid",
- 3,
+ "resp",
+ 1,
PROTOBUF_C_LABEL_NONE,
- PROTOBUF_C_TYPE_UINT32,
+ PROTOBUF_C_TYPE_INT32,
0, /* quantifier_offset */
- offsetof(CtrlMsgEventStationDisconnectFromESPSoftAP, aid),
+ offsetof(CtrlMsgRespCustomRpcUnserialisedMsg, resp),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
- "is_mesh_child",
- 4,
+ "custom_msg_id",
+ 2,
PROTOBUF_C_LABEL_NONE,
- PROTOBUF_C_TYPE_BOOL,
+ PROTOBUF_C_TYPE_UINT32,
0, /* quantifier_offset */
- offsetof(CtrlMsgEventStationDisconnectFromESPSoftAP, is_mesh_child),
+ offsetof(CtrlMsgRespCustomRpcUnserialisedMsg, custom_msg_id),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
- "reason",
- 5,
+ "data",
+ 3,
PROTOBUF_C_LABEL_NONE,
- PROTOBUF_C_TYPE_UINT32,
+ PROTOBUF_C_TYPE_BYTES,
0, /* quantifier_offset */
- offsetof(CtrlMsgEventStationDisconnectFromESPSoftAP, reason),
+ offsetof(CtrlMsgRespCustomRpcUnserialisedMsg, data),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
-static const unsigned ctrl_msg__event__station_disconnect_from_espsoft_ap__field_indices_by_name[] = {
- 2, /* field[2] = aid */
- 3, /* field[3] = is_mesh_child */
- 1, /* field[1] = mac */
- 4, /* field[4] = reason */
+static const unsigned ctrl_msg__resp__custom_rpc_unserialised_msg__field_indices_by_name[] = {
+ 1, /* field[1] = custom_msg_id */
+ 2, /* field[2] = data */
0, /* field[0] = resp */
};
-static const ProtobufCIntRange ctrl_msg__event__station_disconnect_from_espsoft_ap__number_ranges[1 + 1] =
+static const ProtobufCIntRange ctrl_msg__resp__custom_rpc_unserialised_msg__number_ranges[1 + 1] =
{
{ 1, 0 },
- { 0, 5 }
+ { 0, 3 }
};
-const ProtobufCMessageDescriptor ctrl_msg__event__station_disconnect_from_espsoft_ap__descriptor =
+const ProtobufCMessageDescriptor ctrl_msg__resp__custom_rpc_unserialised_msg__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
- "CtrlMsg_Event_StationDisconnectFromESPSoftAP",
- "CtrlMsgEventStationDisconnectFromESPSoftAP",
- "CtrlMsgEventStationDisconnectFromESPSoftAP",
+ "CtrlMsg_Resp_CustomRpcUnserialisedMsg",
+ "CtrlMsgRespCustomRpcUnserialisedMsg",
+ "CtrlMsgRespCustomRpcUnserialisedMsg",
"",
- sizeof(CtrlMsgEventStationDisconnectFromESPSoftAP),
- 5,
- ctrl_msg__event__station_disconnect_from_espsoft_ap__field_descriptors,
- ctrl_msg__event__station_disconnect_from_espsoft_ap__field_indices_by_name,
- 1, ctrl_msg__event__station_disconnect_from_espsoft_ap__number_ranges,
- (ProtobufCMessageInit) ctrl_msg__event__station_disconnect_from_espsoft_ap__init,
+ sizeof(CtrlMsgRespCustomRpcUnserialisedMsg),
+ 3,
+ ctrl_msg__resp__custom_rpc_unserialised_msg__field_descriptors,
+ ctrl_msg__resp__custom_rpc_unserialised_msg__field_indices_by_name,
+ 1, ctrl_msg__resp__custom_rpc_unserialised_msg__number_ranges,
+ (ProtobufCMessageInit) ctrl_msg__resp__custom_rpc_unserialised_msg__init,
NULL,NULL,NULL /* reserved[123] */
};
-static const ProtobufCFieldDescriptor ctrl_msg__event__station_connected_to_espsoft_ap__field_descriptors[4] =
+static const ProtobufCFieldDescriptor ctrl_msg__event__custom_rpc_unserialised_msg__field_descriptors[3] =
{
{
"resp",
@@ -5176,76 +6236,63 @@ static const ProtobufCFieldDescriptor ctrl_msg__event__station_connected_to_esps
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_INT32,
0, /* quantifier_offset */
- offsetof(CtrlMsgEventStationConnectedToESPSoftAP, resp),
+ offsetof(CtrlMsgEventCustomRpcUnserialisedMsg, resp),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
- "mac",
+ "custom_evt_id",
2,
PROTOBUF_C_LABEL_NONE,
- PROTOBUF_C_TYPE_BYTES,
- 0, /* quantifier_offset */
- offsetof(CtrlMsgEventStationConnectedToESPSoftAP, mac),
- NULL,
- NULL,
- 0, /* flags */
- 0,NULL,NULL /* reserved1,reserved2, etc */
- },
- {
- "aid",
- 3,
- PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_UINT32,
0, /* quantifier_offset */
- offsetof(CtrlMsgEventStationConnectedToESPSoftAP, aid),
+ offsetof(CtrlMsgEventCustomRpcUnserialisedMsg, custom_evt_id),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
- "is_mesh_child",
- 4,
+ "data",
+ 3,
PROTOBUF_C_LABEL_NONE,
- PROTOBUF_C_TYPE_BOOL,
+ PROTOBUF_C_TYPE_BYTES,
0, /* quantifier_offset */
- offsetof(CtrlMsgEventStationConnectedToESPSoftAP, is_mesh_child),
+ offsetof(CtrlMsgEventCustomRpcUnserialisedMsg, data),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
-static const unsigned ctrl_msg__event__station_connected_to_espsoft_ap__field_indices_by_name[] = {
- 2, /* field[2] = aid */
- 3, /* field[3] = is_mesh_child */
- 1, /* field[1] = mac */
+static const unsigned ctrl_msg__event__custom_rpc_unserialised_msg__field_indices_by_name[] = {
+ 1, /* field[1] = custom_evt_id */
+ 2, /* field[2] = data */
0, /* field[0] = resp */
};
-static const ProtobufCIntRange ctrl_msg__event__station_connected_to_espsoft_ap__number_ranges[1 + 1] =
+static const ProtobufCIntRange ctrl_msg__event__custom_rpc_unserialised_msg__number_ranges[1 + 1] =
{
{ 1, 0 },
- { 0, 4 }
+ { 0, 3 }
};
-const ProtobufCMessageDescriptor ctrl_msg__event__station_connected_to_espsoft_ap__descriptor =
+const ProtobufCMessageDescriptor ctrl_msg__event__custom_rpc_unserialised_msg__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
- "CtrlMsg_Event_StationConnectedToESPSoftAP",
- "CtrlMsgEventStationConnectedToESPSoftAP",
- "CtrlMsgEventStationConnectedToESPSoftAP",
+ "CtrlMsg_Event_CustomRpcUnserialisedMsg",
+ "CtrlMsgEventCustomRpcUnserialisedMsg",
+ "CtrlMsgEventCustomRpcUnserialisedMsg",
"",
- sizeof(CtrlMsgEventStationConnectedToESPSoftAP),
- 4,
- ctrl_msg__event__station_connected_to_espsoft_ap__field_descriptors,
- ctrl_msg__event__station_connected_to_espsoft_ap__field_indices_by_name,
- 1, ctrl_msg__event__station_connected_to_espsoft_ap__number_ranges,
- (ProtobufCMessageInit) ctrl_msg__event__station_connected_to_espsoft_ap__init,
+ sizeof(CtrlMsgEventCustomRpcUnserialisedMsg),
+ 3,
+ ctrl_msg__event__custom_rpc_unserialised_msg__field_descriptors,
+ ctrl_msg__event__custom_rpc_unserialised_msg__field_indices_by_name,
+ 1, ctrl_msg__event__custom_rpc_unserialised_msg__number_ranges,
+ (ProtobufCMessageInit) ctrl_msg__event__custom_rpc_unserialised_msg__init,
NULL,NULL,NULL /* reserved[123] */
};
-static const ProtobufCFieldDescriptor ctrl_msg__field_descriptors[60] =
+static const ProtobufCFieldDescriptor ctrl_msg__field_descriptors[68] =
{
{
"msg_type",
@@ -5595,6 +6642,42 @@ static const ProtobufCFieldDescriptor ctrl_msg__field_descriptors[60] =
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
+ {
+ "req_set_dhcp_dns_status",
+ 126,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(CtrlMsg, payload_case),
+ offsetof(CtrlMsg, req_set_dhcp_dns_status),
+ &ctrl_msg__req__set_dhcp_dns_status__descriptor,
+ NULL,
+ 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "req_get_dhcp_dns_status",
+ 127,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(CtrlMsg, payload_case),
+ offsetof(CtrlMsg, req_get_dhcp_dns_status),
+ &ctrl_msg__req__get_dhcp_dns_status__descriptor,
+ NULL,
+ 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "req_custom_rpc_unserialised_msg",
+ 128,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(CtrlMsg, payload_case),
+ offsetof(CtrlMsg, req_custom_rpc_unserialised_msg),
+ &ctrl_msg__req__custom_rpc_unserialised_msg__descriptor,
+ NULL,
+ 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
{
"resp_get_mac_address",
201,
@@ -5895,6 +6978,42 @@ static const ProtobufCFieldDescriptor ctrl_msg__field_descriptors[60] =
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
+ {
+ "resp_set_dhcp_dns_status",
+ 226,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(CtrlMsg, payload_case),
+ offsetof(CtrlMsg, resp_set_dhcp_dns_status),
+ &ctrl_msg__resp__set_dhcp_dns_status__descriptor,
+ NULL,
+ 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "resp_get_dhcp_dns_status",
+ 227,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(CtrlMsg, payload_case),
+ offsetof(CtrlMsg, resp_get_dhcp_dns_status),
+ &ctrl_msg__resp__get_dhcp_dns_status__descriptor,
+ NULL,
+ 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "resp_custom_rpc_unserialised_msg",
+ 228,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(CtrlMsg, payload_case),
+ offsetof(CtrlMsg, resp_custom_rpc_unserialised_msg),
+ &ctrl_msg__resp__custom_rpc_unserialised_msg__descriptor,
+ NULL,
+ 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
{
"event_esp_init",
301,
@@ -5967,22 +7086,50 @@ static const ProtobufCFieldDescriptor ctrl_msg__field_descriptors[60] =
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
+ {
+ "event_set_dhcp_dns_status",
+ 307,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(CtrlMsg, payload_case),
+ offsetof(CtrlMsg, event_set_dhcp_dns_status),
+ &ctrl_msg__event__set_dhcp_dns_status__descriptor,
+ NULL,
+ 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
+ {
+ "event_custom_rpc_unserialised_msg",
+ 308,
+ PROTOBUF_C_LABEL_NONE,
+ PROTOBUF_C_TYPE_MESSAGE,
+ offsetof(CtrlMsg, payload_case),
+ offsetof(CtrlMsg, event_custom_rpc_unserialised_msg),
+ &ctrl_msg__event__custom_rpc_unserialised_msg__descriptor,
+ NULL,
+ 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
+ 0,NULL,NULL /* reserved1,reserved2, etc */
+ },
};
static const unsigned ctrl_msg__field_indices_by_name[] = {
- 54, /* field[54] = event_esp_init */
- 55, /* field[55] = event_heartbeat */
- 58, /* field[58] = event_station_connected_to_AP */
- 59, /* field[59] = event_station_connected_to_ESP_SoftAP */
- 56, /* field[56] = event_station_disconnect_from_AP */
- 57, /* field[57] = event_station_disconnect_from_ESP_SoftAP */
+ 67, /* field[67] = event_custom_rpc_unserialised_msg */
+ 60, /* field[60] = event_esp_init */
+ 61, /* field[61] = event_heartbeat */
+ 66, /* field[66] = event_set_dhcp_dns_status */
+ 64, /* field[64] = event_station_connected_to_AP */
+ 65, /* field[65] = event_station_connected_to_ESP_SoftAP */
+ 62, /* field[62] = event_station_disconnect_from_AP */
+ 63, /* field[63] = event_station_disconnect_from_ESP_SoftAP */
1, /* field[1] = msg_id */
0, /* field[0] = msg_type */
24, /* field[24] = req_config_heartbeat */
10, /* field[10] = req_connect_ap */
+ 31, /* field[31] = req_custom_rpc_unserialised_msg */
11, /* field[11] = req_disconnect_ap */
25, /* field[25] = req_enable_disable_feat */
9, /* field[9] = req_get_ap_config */
28, /* field[28] = req_get_country_code */
+ 30, /* field[30] = req_get_dhcp_dns_status */
26, /* field[26] = req_get_fw_version */
4, /* field[4] = req_get_mac_address */
18, /* field[18] = req_get_power_save_mode */
@@ -5995,6 +7142,7 @@ static const unsigned ctrl_msg__field_indices_by_name[] = {
3, /* field[3] = req_resp_type */
8, /* field[8] = req_scan_ap_list */
27, /* field[27] = req_set_country_code */
+ 29, /* field[29] = req_set_dhcp_dns_status */
5, /* field[5] = req_set_mac_address */
17, /* field[17] = req_set_power_save_mode */
13, /* field[13] = req_set_softap_vendor_specific_ie */
@@ -6003,40 +7151,43 @@ static const unsigned ctrl_msg__field_indices_by_name[] = {
15, /* field[15] = req_softap_connected_stas_list */
14, /* field[14] = req_start_softap */
16, /* field[16] = req_stop_softap */
- 49, /* field[49] = resp_config_heartbeat */
- 35, /* field[35] = resp_connect_ap */
- 36, /* field[36] = resp_disconnect_ap */
- 50, /* field[50] = resp_enable_disable_feat */
- 34, /* field[34] = resp_get_ap_config */
- 53, /* field[53] = resp_get_country_code */
- 51, /* field[51] = resp_get_fw_version */
- 29, /* field[29] = resp_get_mac_address */
- 43, /* field[43] = resp_get_power_save_mode */
- 37, /* field[37] = resp_get_softap_config */
- 48, /* field[48] = resp_get_wifi_curr_tx_power */
- 31, /* field[31] = resp_get_wifi_mode */
- 44, /* field[44] = resp_ota_begin */
- 46, /* field[46] = resp_ota_end */
- 45, /* field[45] = resp_ota_write */
- 33, /* field[33] = resp_scan_ap_list */
- 52, /* field[52] = resp_set_country_code */
- 30, /* field[30] = resp_set_mac_address */
- 42, /* field[42] = resp_set_power_save_mode */
- 38, /* field[38] = resp_set_softap_vendor_specific_ie */
- 47, /* field[47] = resp_set_wifi_max_tx_power */
- 32, /* field[32] = resp_set_wifi_mode */
- 40, /* field[40] = resp_softap_connected_stas_list */
- 39, /* field[39] = resp_start_softap */
- 41, /* field[41] = resp_stop_softap */
+ 52, /* field[52] = resp_config_heartbeat */
+ 38, /* field[38] = resp_connect_ap */
+ 59, /* field[59] = resp_custom_rpc_unserialised_msg */
+ 39, /* field[39] = resp_disconnect_ap */
+ 53, /* field[53] = resp_enable_disable_feat */
+ 37, /* field[37] = resp_get_ap_config */
+ 56, /* field[56] = resp_get_country_code */
+ 58, /* field[58] = resp_get_dhcp_dns_status */
+ 54, /* field[54] = resp_get_fw_version */
+ 32, /* field[32] = resp_get_mac_address */
+ 46, /* field[46] = resp_get_power_save_mode */
+ 40, /* field[40] = resp_get_softap_config */
+ 51, /* field[51] = resp_get_wifi_curr_tx_power */
+ 34, /* field[34] = resp_get_wifi_mode */
+ 47, /* field[47] = resp_ota_begin */
+ 49, /* field[49] = resp_ota_end */
+ 48, /* field[48] = resp_ota_write */
+ 36, /* field[36] = resp_scan_ap_list */
+ 55, /* field[55] = resp_set_country_code */
+ 57, /* field[57] = resp_set_dhcp_dns_status */
+ 33, /* field[33] = resp_set_mac_address */
+ 45, /* field[45] = resp_set_power_save_mode */
+ 41, /* field[41] = resp_set_softap_vendor_specific_ie */
+ 50, /* field[50] = resp_set_wifi_max_tx_power */
+ 35, /* field[35] = resp_set_wifi_mode */
+ 43, /* field[43] = resp_softap_connected_stas_list */
+ 42, /* field[42] = resp_start_softap */
+ 44, /* field[44] = resp_stop_softap */
2, /* field[2] = uid */
};
static const ProtobufCIntRange ctrl_msg__number_ranges[4 + 1] =
{
{ 1, 0 },
{ 101, 4 },
- { 201, 29 },
- { 301, 54 },
- { 0, 60 }
+ { 201, 32 },
+ { 301, 60 },
+ { 0, 68 }
};
const ProtobufCMessageDescriptor ctrl_msg__descriptor =
{
@@ -6046,7 +7197,7 @@ const ProtobufCMessageDescriptor ctrl_msg__descriptor =
"CtrlMsg",
"",
sizeof(CtrlMsg),
- 60,
+ 68,
ctrl_msg__field_descriptors,
ctrl_msg__field_indices_by_name,
4, ctrl_msg__number_ranges,
@@ -6177,20 +7328,22 @@ const ProtobufCEnumDescriptor ctrl__wifi_bw__descriptor =
ctrl__wifi_bw__value_ranges,
NULL,NULL,NULL,NULL /* reserved[1234] */
};
-static const ProtobufCEnumValue ctrl__wifi_power_save__enum_values_by_number[3] =
+static const ProtobufCEnumValue ctrl__wifi_power_save__enum_values_by_number[4] =
{
- { "PS_Invalid", "CTRL__WIFI_POWER_SAVE__PS_Invalid", 0 },
+ { "NO_PS", "CTRL__WIFI_POWER_SAVE__NO_PS", 0 },
{ "MIN_MODEM", "CTRL__WIFI_POWER_SAVE__MIN_MODEM", 1 },
{ "MAX_MODEM", "CTRL__WIFI_POWER_SAVE__MAX_MODEM", 2 },
+ { "PS_Invalid", "CTRL__WIFI_POWER_SAVE__PS_Invalid", 3 },
};
static const ProtobufCIntRange ctrl__wifi_power_save__value_ranges[] = {
-{0, 0},{0, 3}
+{0, 0},{0, 4}
};
-static const ProtobufCEnumValueIndex ctrl__wifi_power_save__enum_values_by_name[3] =
+static const ProtobufCEnumValueIndex ctrl__wifi_power_save__enum_values_by_name[4] =
{
{ "MAX_MODEM", 2 },
{ "MIN_MODEM", 1 },
- { "PS_Invalid", 0 },
+ { "NO_PS", 0 },
+ { "PS_Invalid", 3 },
};
const ProtobufCEnumDescriptor ctrl__wifi_power_save__descriptor =
{
@@ -6199,9 +7352,9 @@ const ProtobufCEnumDescriptor ctrl__wifi_power_save__descriptor =
"Ctrl_WifiPowerSave",
"CtrlWifiPowerSave",
"",
- 3,
+ 4,
ctrl__wifi_power_save__enum_values_by_number,
- 3,
+ 4,
ctrl__wifi_power_save__enum_values_by_name,
1,
ctrl__wifi_power_save__value_ranges,
@@ -6317,7 +7470,7 @@ const ProtobufCEnumDescriptor ctrl_msg_type__descriptor =
ctrl_msg_type__value_ranges,
NULL,NULL,NULL,NULL /* reserved[1234] */
};
-static const ProtobufCEnumValue ctrl_msg_id__enum_values_by_number[63] =
+static const ProtobufCEnumValue ctrl_msg_id__enum_values_by_number[71] =
{
{ "MsgId_Invalid", "CTRL_MSG_ID__MsgId_Invalid", 0 },
{ "Req_Base", "CTRL_MSG_ID__Req_Base", 100 },
@@ -6346,7 +7499,10 @@ static const ProtobufCEnumValue ctrl_msg_id__enum_values_by_number[63] =
{ "Req_GetFwVersion", "CTRL_MSG_ID__Req_GetFwVersion", 123 },
{ "Req_SetCountryCode", "CTRL_MSG_ID__Req_SetCountryCode", 124 },
{ "Req_GetCountryCode", "CTRL_MSG_ID__Req_GetCountryCode", 125 },
- { "Req_Max", "CTRL_MSG_ID__Req_Max", 126 },
+ { "Req_SetDhcpDnsStatus", "CTRL_MSG_ID__Req_SetDhcpDnsStatus", 126 },
+ { "Req_GetDhcpDnsStatus", "CTRL_MSG_ID__Req_GetDhcpDnsStatus", 127 },
+ { "Req_Custom_RPC_Unserialised_Msg", "CTRL_MSG_ID__Req_Custom_RPC_Unserialised_Msg", 128 },
+ { "Req_Max", "CTRL_MSG_ID__Req_Max", 129 },
{ "Resp_Base", "CTRL_MSG_ID__Resp_Base", 200 },
{ "Resp_GetMACAddress", "CTRL_MSG_ID__Resp_GetMACAddress", 201 },
{ "Resp_SetMacAddress", "CTRL_MSG_ID__Resp_SetMacAddress", 202 },
@@ -6373,7 +7529,10 @@ static const ProtobufCEnumValue ctrl_msg_id__enum_values_by_number[63] =
{ "Resp_GetFwVersion", "CTRL_MSG_ID__Resp_GetFwVersion", 223 },
{ "Resp_SetCountryCode", "CTRL_MSG_ID__Resp_SetCountryCode", 224 },
{ "Resp_GetCountryCode", "CTRL_MSG_ID__Resp_GetCountryCode", 225 },
- { "Resp_Max", "CTRL_MSG_ID__Resp_Max", 226 },
+ { "Resp_SetDhcpDnsStatus", "CTRL_MSG_ID__Resp_SetDhcpDnsStatus", 226 },
+ { "Resp_GetDhcpDnsStatus", "CTRL_MSG_ID__Resp_GetDhcpDnsStatus", 227 },
+ { "Resp_Custom_RPC_Unserialised_Msg", "CTRL_MSG_ID__Resp_Custom_RPC_Unserialised_Msg", 228 },
+ { "Resp_Max", "CTRL_MSG_ID__Resp_Max", 229 },
{ "Event_Base", "CTRL_MSG_ID__Event_Base", 300 },
{ "Event_ESPInit", "CTRL_MSG_ID__Event_ESPInit", 301 },
{ "Event_Heartbeat", "CTRL_MSG_ID__Event_Heartbeat", 302 },
@@ -6381,30 +7540,36 @@ static const ProtobufCEnumValue ctrl_msg_id__enum_values_by_number[63] =
{ "Event_StationDisconnectFromESPSoftAP", "CTRL_MSG_ID__Event_StationDisconnectFromESPSoftAP", 304 },
{ "Event_StationConnectedToAP", "CTRL_MSG_ID__Event_StationConnectedToAP", 305 },
{ "Event_StationConnectedToESPSoftAP", "CTRL_MSG_ID__Event_StationConnectedToESPSoftAP", 306 },
- { "Event_Max", "CTRL_MSG_ID__Event_Max", 307 },
+ { "Event_SetDhcpDnsStatus", "CTRL_MSG_ID__Event_SetDhcpDnsStatus", 307 },
+ { "Event_Custom_RPC_Unserialised_Msg", "CTRL_MSG_ID__Event_Custom_RPC_Unserialised_Msg", 308 },
+ { "Event_Max", "CTRL_MSG_ID__Event_Max", 309 },
};
static const ProtobufCIntRange ctrl_msg_id__value_ranges[] = {
-{0, 0},{100, 1},{200, 28},{300, 55},{0, 63}
-};
-static const ProtobufCEnumValueIndex ctrl_msg_id__enum_values_by_name[63] =
-{
- { "Event_Base", 55 },
- { "Event_ESPInit", 56 },
- { "Event_Heartbeat", 57 },
- { "Event_Max", 62 },
- { "Event_StationConnectedToAP", 60 },
- { "Event_StationConnectedToESPSoftAP", 61 },
- { "Event_StationDisconnectFromAP", 58 },
- { "Event_StationDisconnectFromESPSoftAP", 59 },
+{0, 0},{100, 1},{200, 31},{300, 61},{0, 71}
+};
+static const ProtobufCEnumValueIndex ctrl_msg_id__enum_values_by_name[71] =
+{
+ { "Event_Base", 61 },
+ { "Event_Custom_RPC_Unserialised_Msg", 69 },
+ { "Event_ESPInit", 62 },
+ { "Event_Heartbeat", 63 },
+ { "Event_Max", 70 },
+ { "Event_SetDhcpDnsStatus", 68 },
+ { "Event_StationConnectedToAP", 66 },
+ { "Event_StationConnectedToESPSoftAP", 67 },
+ { "Event_StationDisconnectFromAP", 64 },
+ { "Event_StationDisconnectFromESPSoftAP", 65 },
{ "MsgId_Invalid", 0 },
{ "Req_Base", 1 },
{ "Req_ConfigHeartbeat", 22 },
{ "Req_ConnectAP", 8 },
+ { "Req_Custom_RPC_Unserialised_Msg", 29 },
{ "Req_DisconnectAP", 9 },
{ "Req_EnableDisable", 23 },
{ "Req_GetAPConfig", 7 },
{ "Req_GetAPScanList", 6 },
{ "Req_GetCountryCode", 26 },
+ { "Req_GetDhcpDnsStatus", 28 },
{ "Req_GetFwVersion", 24 },
{ "Req_GetMACAddress", 2 },
{ "Req_GetPowerSaveMode", 16 },
@@ -6412,11 +7577,12 @@ static const ProtobufCEnumValueIndex ctrl_msg_id__enum_values_by_name[63] =
{ "Req_GetSoftAPConnectedSTAList", 13 },
{ "Req_GetWifiCurrTxPower", 21 },
{ "Req_GetWifiMode", 4 },
- { "Req_Max", 27 },
+ { "Req_Max", 30 },
{ "Req_OTABegin", 17 },
{ "Req_OTAEnd", 19 },
{ "Req_OTAWrite", 18 },
{ "Req_SetCountryCode", 25 },
+ { "Req_SetDhcpDnsStatus", 27 },
{ "Req_SetMacAddress", 3 },
{ "Req_SetPowerSaveMode", 15 },
{ "Req_SetSoftAPVendorSpecificIE", 11 },
@@ -6424,33 +7590,36 @@ static const ProtobufCEnumValueIndex ctrl_msg_id__enum_values_by_name[63] =
{ "Req_SetWifiMode", 5 },
{ "Req_StartSoftAP", 12 },
{ "Req_StopSoftAP", 14 },
- { "Resp_Base", 28 },
- { "Resp_ConfigHeartbeat", 49 },
- { "Resp_ConnectAP", 35 },
- { "Resp_DisconnectAP", 36 },
- { "Resp_EnableDisable", 50 },
- { "Resp_GetAPConfig", 34 },
- { "Resp_GetAPScanList", 33 },
- { "Resp_GetCountryCode", 53 },
- { "Resp_GetFwVersion", 51 },
- { "Resp_GetMACAddress", 29 },
- { "Resp_GetPowerSaveMode", 43 },
- { "Resp_GetSoftAPConfig", 37 },
- { "Resp_GetSoftAPConnectedSTAList", 40 },
- { "Resp_GetWifiCurrTxPower", 48 },
- { "Resp_GetWifiMode", 31 },
- { "Resp_Max", 54 },
- { "Resp_OTABegin", 44 },
- { "Resp_OTAEnd", 46 },
- { "Resp_OTAWrite", 45 },
- { "Resp_SetCountryCode", 52 },
- { "Resp_SetMacAddress", 30 },
- { "Resp_SetPowerSaveMode", 42 },
- { "Resp_SetSoftAPVendorSpecificIE", 38 },
- { "Resp_SetWifiMaxTxPower", 47 },
- { "Resp_SetWifiMode", 32 },
- { "Resp_StartSoftAP", 39 },
- { "Resp_StopSoftAP", 41 },
+ { "Resp_Base", 31 },
+ { "Resp_ConfigHeartbeat", 52 },
+ { "Resp_ConnectAP", 38 },
+ { "Resp_Custom_RPC_Unserialised_Msg", 59 },
+ { "Resp_DisconnectAP", 39 },
+ { "Resp_EnableDisable", 53 },
+ { "Resp_GetAPConfig", 37 },
+ { "Resp_GetAPScanList", 36 },
+ { "Resp_GetCountryCode", 56 },
+ { "Resp_GetDhcpDnsStatus", 58 },
+ { "Resp_GetFwVersion", 54 },
+ { "Resp_GetMACAddress", 32 },
+ { "Resp_GetPowerSaveMode", 46 },
+ { "Resp_GetSoftAPConfig", 40 },
+ { "Resp_GetSoftAPConnectedSTAList", 43 },
+ { "Resp_GetWifiCurrTxPower", 51 },
+ { "Resp_GetWifiMode", 34 },
+ { "Resp_Max", 60 },
+ { "Resp_OTABegin", 47 },
+ { "Resp_OTAEnd", 49 },
+ { "Resp_OTAWrite", 48 },
+ { "Resp_SetCountryCode", 55 },
+ { "Resp_SetDhcpDnsStatus", 57 },
+ { "Resp_SetMacAddress", 33 },
+ { "Resp_SetPowerSaveMode", 45 },
+ { "Resp_SetSoftAPVendorSpecificIE", 41 },
+ { "Resp_SetWifiMaxTxPower", 50 },
+ { "Resp_SetWifiMode", 35 },
+ { "Resp_StartSoftAP", 42 },
+ { "Resp_StopSoftAP", 44 },
};
const ProtobufCEnumDescriptor ctrl_msg_id__descriptor =
{
@@ -6459,27 +7628,29 @@ const ProtobufCEnumDescriptor ctrl_msg_id__descriptor =
"CtrlMsgId",
"CtrlMsgId",
"",
- 63,
+ 71,
ctrl_msg_id__enum_values_by_number,
- 63,
+ 71,
ctrl_msg_id__enum_values_by_name,
4,
ctrl_msg_id__value_ranges,
NULL,NULL,NULL,NULL /* reserved[1234] */
};
-static const ProtobufCEnumValue hosted_feature__enum_values_by_number[3] =
+static const ProtobufCEnumValue hosted_feature__enum_values_by_number[4] =
{
{ "Hosted_InvalidFeature", "HOSTED_FEATURE__Hosted_InvalidFeature", 0 },
{ "Hosted_Wifi", "HOSTED_FEATURE__Hosted_Wifi", 1 },
{ "Hosted_Bluetooth", "HOSTED_FEATURE__Hosted_Bluetooth", 2 },
+ { "Hosted_Is_Network_Split_On", "HOSTED_FEATURE__Hosted_Is_Network_Split_On", 3 },
};
static const ProtobufCIntRange hosted_feature__value_ranges[] = {
-{0, 0},{0, 3}
+{0, 0},{0, 4}
};
-static const ProtobufCEnumValueIndex hosted_feature__enum_values_by_name[3] =
+static const ProtobufCEnumValueIndex hosted_feature__enum_values_by_name[4] =
{
{ "Hosted_Bluetooth", 2 },
{ "Hosted_InvalidFeature", 0 },
+ { "Hosted_Is_Network_Split_On", 3 },
{ "Hosted_Wifi", 1 },
};
const ProtobufCEnumDescriptor hosted_feature__descriptor =
@@ -6489,9 +7660,9 @@ const ProtobufCEnumDescriptor hosted_feature__descriptor =
"HostedFeature",
"HostedFeature",
"",
- 3,
+ 4,
hosted_feature__enum_values_by_number,
- 3,
+ 4,
hosted_feature__enum_values_by_name,
1,
hosted_feature__value_ranges,
diff --git a/esp_hosted_fg/common/include/adapter.h b/esp_hosted_fg/common/include/adapter.h
index afb192c7de..d5dd1f73e4 100644
--- a/esp_hosted_fg/common/include/adapter.h
+++ b/esp_hosted_fg/common/include/adapter.h
@@ -4,6 +4,14 @@
#ifndef __ESP_NETWORK_ADAPTER__H
#define __ESP_NETWORK_ADAPTER__H
+#ifdef __KERNEL__
+ #include
+#else
+ #include
+#endif
+
+#define ESP_PKT_NUM_DEBUG (0)
+
#define PRIO_Q_SERIAL 0
#define PRIO_Q_BT 1
#define PRIO_Q_OTHERS 2
@@ -11,6 +19,9 @@
/* ESP Payload Header Flags */
#define MORE_FRAGMENT (1 << 0)
+#define FLAG_WAKEUP_PKT (1 << 1)
+#define FLAG_POWER_SAVE_STARTED (1 << 2)
+#define FLAG_POWER_SAVE_STOPPED (1 << 3)
/* Serial interface */
#define SERIAL_IF_FILE "/dev/esps0"
@@ -29,6 +40,9 @@ struct esp_payload_header {
uint16_t checksum;
uint16_t seq_num;
uint8_t reserved2;
+ #if ESP_PKT_NUM_DEBUG
+ uint16_t pkt_num;
+ #endif
/* Position of union field has to always be last,
* this is required for hci_pkt_type */
union {
@@ -39,6 +53,8 @@ struct esp_payload_header {
/* Do no add anything here */
} __attribute__((packed));
+#define H_ESP_PAYLOAD_HEADER_OFFSET sizeof(struct esp_payload_header)
+
typedef enum {
ESP_STA_IF,
ESP_AP_IF,
@@ -53,6 +69,8 @@ typedef enum {
ESP_OPEN_DATA_PATH,
ESP_CLOSE_DATA_PATH,
ESP_RESET,
+ ESP_POWER_SAVE_ON,
+ ESP_POWER_SAVE_OFF,
ESP_MAX_HOST_INTERRUPT,
} ESP_HOST_INTERRUPT;
@@ -117,4 +135,38 @@ static inline uint16_t compute_checksum(uint8_t *buf, uint16_t len)
return checksum;
}
+#if ESP_PKT_NUM_DEBUG
+struct dbg_stats_t {
+ uint16_t tx_pkt_num;
+ uint16_t exp_rx_pkt_num;
+};
+
+#ifdef __KERNEL__
+#define le16toh(x) le16_to_cpu(x)
+#define htole16(x) cpu_to_le16(x)
+#define debug(fmt, ...) printk(KERN_INFO fmt, ##__VA_ARGS__)
+#else
+#define debug(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#endif
+
+extern struct dbg_stats_t dbg_stats;
+#define UPDATE_HEADER_TX_PKT_NO(h) h->pkt_num = htole16(dbg_stats.tx_pkt_num++)
+#define UPDATE_HEADER_RX_PKT_NO(h) \
+ do { \
+ uint16_t rcvd_pkt_num = le16toh(h->pkt_num); \
+ if (dbg_stats.exp_rx_pkt_num != rcvd_pkt_num) { \
+ debug("exp_pkt_num[%u], rx_pkt_num[%u]\n", \
+ dbg_stats.exp_rx_pkt_num, rcvd_pkt_num); \
+ dbg_stats.exp_rx_pkt_num = rcvd_pkt_num; \
+ } \
+ dbg_stats.exp_rx_pkt_num++; \
+ } while(0);
+
+#else /*ESP_PKT_NUM_DEBUG*/
+
+ #define UPDATE_HEADER_TX_PKT_NO(h)
+ #define UPDATE_HEADER_RX_PKT_NO(h)
+
+#endif /*ESP_PKT_NUM_DEBUG*/
+
#endif
diff --git a/esp_hosted_fg/common/include/esp_fw_version.h b/esp_hosted_fg/common/include/esp_fw_version.h
index 3f7fb75a3a..c9eb174235 100644
--- a/esp_hosted_fg/common/include/esp_fw_version.h
+++ b/esp_hosted_fg/common/include/esp_fw_version.h
@@ -5,9 +5,9 @@
#define __ESP_FW_VERSION__H
#define PROJECT_NAME "FG"
-#define PROJECT_VERSION_MAJOR_1 0
+#define PROJECT_VERSION_MAJOR_1 1
#define PROJECT_VERSION_MAJOR_2 0
-#define PROJECT_VERSION_MINOR 6
+#define PROJECT_VERSION_MINOR 0
#define PROJECT_REVISION_PATCH_1 0
#define PROJECT_REVISION_PATCH_2 0
diff --git a/esp_hosted_fg/common/include/esp_hosted_config.pb-c.h b/esp_hosted_fg/common/include/esp_hosted_config.pb-c.h
index 9003eff4b0..e15ac98531 100644
--- a/esp_hosted_fg/common/include/esp_hosted_config.pb-c.h
+++ b/esp_hosted_fg/common/include/esp_hosted_config.pb-c.h
@@ -62,12 +62,20 @@ typedef struct CtrlMsgReqSetCountryCode CtrlMsgReqSetCountryCode;
typedef struct CtrlMsgRespSetCountryCode CtrlMsgRespSetCountryCode;
typedef struct CtrlMsgReqGetCountryCode CtrlMsgReqGetCountryCode;
typedef struct CtrlMsgRespGetCountryCode CtrlMsgRespGetCountryCode;
+typedef struct CtrlMsgReqSetDhcpDnsStatus CtrlMsgReqSetDhcpDnsStatus;
+typedef struct CtrlMsgRespSetDhcpDnsStatus CtrlMsgRespSetDhcpDnsStatus;
+typedef struct CtrlMsgReqGetDhcpDnsStatus CtrlMsgReqGetDhcpDnsStatus;
+typedef struct CtrlMsgRespGetDhcpDnsStatus CtrlMsgRespGetDhcpDnsStatus;
typedef struct CtrlMsgEventESPInit CtrlMsgEventESPInit;
typedef struct CtrlMsgEventHeartbeat CtrlMsgEventHeartbeat;
typedef struct CtrlMsgEventStationDisconnectFromAP CtrlMsgEventStationDisconnectFromAP;
typedef struct CtrlMsgEventStationConnectedToAP CtrlMsgEventStationConnectedToAP;
typedef struct CtrlMsgEventStationDisconnectFromESPSoftAP CtrlMsgEventStationDisconnectFromESPSoftAP;
typedef struct CtrlMsgEventStationConnectedToESPSoftAP CtrlMsgEventStationConnectedToESPSoftAP;
+typedef struct CtrlMsgEventSetDhcpDnsStatus CtrlMsgEventSetDhcpDnsStatus;
+typedef struct CtrlMsgReqCustomRpcUnserialisedMsg CtrlMsgReqCustomRpcUnserialisedMsg;
+typedef struct CtrlMsgRespCustomRpcUnserialisedMsg CtrlMsgRespCustomRpcUnserialisedMsg;
+typedef struct CtrlMsgEventCustomRpcUnserialisedMsg CtrlMsgEventCustomRpcUnserialisedMsg;
typedef struct CtrlMsg CtrlMsg;
@@ -103,9 +111,10 @@ typedef enum _CtrlWifiBw {
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(CTRL__WIFI_BW)
} CtrlWifiBw;
typedef enum _CtrlWifiPowerSave {
- CTRL__WIFI_POWER_SAVE__PS_Invalid = 0,
+ CTRL__WIFI_POWER_SAVE__NO_PS = 0,
CTRL__WIFI_POWER_SAVE__MIN_MODEM = 1,
- CTRL__WIFI_POWER_SAVE__MAX_MODEM = 2
+ CTRL__WIFI_POWER_SAVE__MAX_MODEM = 2,
+ CTRL__WIFI_POWER_SAVE__PS_Invalid = 3
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(CTRL__WIFI_POWER_SAVE)
} CtrlWifiPowerSave;
typedef enum _CtrlWifiSecProt {
@@ -170,11 +179,14 @@ typedef enum _CtrlMsgId {
CTRL_MSG_ID__Req_GetFwVersion = 123,
CTRL_MSG_ID__Req_SetCountryCode = 124,
CTRL_MSG_ID__Req_GetCountryCode = 125,
+ CTRL_MSG_ID__Req_SetDhcpDnsStatus = 126,
+ CTRL_MSG_ID__Req_GetDhcpDnsStatus = 127,
+ CTRL_MSG_ID__Req_Custom_RPC_Unserialised_Msg = 128,
/*
* Add new control path command response before Req_Max
* and update Req_Max
*/
- CTRL_MSG_ID__Req_Max = 126,
+ CTRL_MSG_ID__Req_Max = 129,
/*
** Response Msgs *
*/
@@ -204,11 +216,14 @@ typedef enum _CtrlMsgId {
CTRL_MSG_ID__Resp_GetFwVersion = 223,
CTRL_MSG_ID__Resp_SetCountryCode = 224,
CTRL_MSG_ID__Resp_GetCountryCode = 225,
+ CTRL_MSG_ID__Resp_SetDhcpDnsStatus = 226,
+ CTRL_MSG_ID__Resp_GetDhcpDnsStatus = 227,
+ CTRL_MSG_ID__Resp_Custom_RPC_Unserialised_Msg = 228,
/*
* Add new control path command response before Resp_Max
* and update Resp_Max
*/
- CTRL_MSG_ID__Resp_Max = 226,
+ CTRL_MSG_ID__Resp_Max = 229,
/*
** Event Msgs *
*/
@@ -219,17 +234,20 @@ typedef enum _CtrlMsgId {
CTRL_MSG_ID__Event_StationDisconnectFromESPSoftAP = 304,
CTRL_MSG_ID__Event_StationConnectedToAP = 305,
CTRL_MSG_ID__Event_StationConnectedToESPSoftAP = 306,
+ CTRL_MSG_ID__Event_SetDhcpDnsStatus = 307,
+ CTRL_MSG_ID__Event_Custom_RPC_Unserialised_Msg = 308,
/*
* Add new control path command notification before Event_Max
* and update Event_Max
*/
- CTRL_MSG_ID__Event_Max = 307
+ CTRL_MSG_ID__Event_Max = 309
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(CTRL_MSG_ID)
} CtrlMsgId;
typedef enum _HostedFeature {
HOSTED_FEATURE__Hosted_InvalidFeature = 0,
HOSTED_FEATURE__Hosted_Wifi = 1,
- HOSTED_FEATURE__Hosted_Bluetooth = 2
+ HOSTED_FEATURE__Hosted_Bluetooth = 2,
+ HOSTED_FEATURE__Hosted_Is_Network_Split_On = 3
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(HOSTED_FEATURE)
} HostedFeature;
@@ -762,6 +780,62 @@ struct CtrlMsgRespGetCountryCode
, 0, {0,NULL} }
+struct CtrlMsgReqSetDhcpDnsStatus
+{
+ ProtobufCMessage base;
+ int32_t iface;
+ int32_t net_link_up;
+ int32_t dhcp_up;
+ ProtobufCBinaryData dhcp_ip;
+ ProtobufCBinaryData dhcp_nm;
+ ProtobufCBinaryData dhcp_gw;
+ int32_t dns_up;
+ ProtobufCBinaryData dns_ip;
+ int32_t dns_type;
+};
+#define CTRL_MSG__REQ__SET_DHCP_DNS_STATUS__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&ctrl_msg__req__set_dhcp_dns_status__descriptor) \
+ , 0, 0, 0, {0,NULL}, {0,NULL}, {0,NULL}, 0, {0,NULL}, 0 }
+
+
+struct CtrlMsgRespSetDhcpDnsStatus
+{
+ ProtobufCMessage base;
+ int32_t resp;
+};
+#define CTRL_MSG__RESP__SET_DHCP_DNS_STATUS__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&ctrl_msg__resp__set_dhcp_dns_status__descriptor) \
+ , 0 }
+
+
+struct CtrlMsgReqGetDhcpDnsStatus
+{
+ ProtobufCMessage base;
+};
+#define CTRL_MSG__REQ__GET_DHCP_DNS_STATUS__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&ctrl_msg__req__get_dhcp_dns_status__descriptor) \
+ }
+
+
+struct CtrlMsgRespGetDhcpDnsStatus
+{
+ ProtobufCMessage base;
+ int32_t resp;
+ int32_t iface;
+ int32_t net_link_up;
+ int32_t dhcp_up;
+ ProtobufCBinaryData dhcp_ip;
+ ProtobufCBinaryData dhcp_nm;
+ ProtobufCBinaryData dhcp_gw;
+ int32_t dns_up;
+ ProtobufCBinaryData dns_ip;
+ int32_t dns_type;
+};
+#define CTRL_MSG__RESP__GET_DHCP_DNS_STATUS__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&ctrl_msg__resp__get_dhcp_dns_status__descriptor) \
+ , 0, 0, 0, 0, {0,NULL}, {0,NULL}, {0,NULL}, 0, {0,NULL}, 0 }
+
+
/*
** Event structure *
*/
@@ -843,6 +917,63 @@ struct CtrlMsgEventStationConnectedToESPSoftAP
, 0, {0,NULL}, 0, 0 }
+struct CtrlMsgEventSetDhcpDnsStatus
+{
+ ProtobufCMessage base;
+ int32_t iface;
+ int32_t net_link_up;
+ int32_t dhcp_up;
+ ProtobufCBinaryData dhcp_ip;
+ ProtobufCBinaryData dhcp_nm;
+ ProtobufCBinaryData dhcp_gw;
+ int32_t dns_up;
+ ProtobufCBinaryData dns_ip;
+ int32_t dns_type;
+ int32_t resp;
+};
+#define CTRL_MSG__EVENT__SET_DHCP_DNS_STATUS__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&ctrl_msg__event__set_dhcp_dns_status__descriptor) \
+ , 0, 0, 0, {0,NULL}, {0,NULL}, {0,NULL}, 0, {0,NULL}, 0, 0 }
+
+
+/*
+ * Add Custom RPC message structures after existing message structures to make it easily notice
+ */
+struct CtrlMsgReqCustomRpcUnserialisedMsg
+{
+ ProtobufCMessage base;
+ uint32_t custom_msg_id;
+ ProtobufCBinaryData data;
+};
+#define CTRL_MSG__REQ__CUSTOM_RPC_UNSERIALISED_MSG__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&ctrl_msg__req__custom_rpc_unserialised_msg__descriptor) \
+ , 0, {0,NULL} }
+
+
+struct CtrlMsgRespCustomRpcUnserialisedMsg
+{
+ ProtobufCMessage base;
+ int32_t resp;
+ uint32_t custom_msg_id;
+ ProtobufCBinaryData data;
+};
+#define CTRL_MSG__RESP__CUSTOM_RPC_UNSERIALISED_MSG__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&ctrl_msg__resp__custom_rpc_unserialised_msg__descriptor) \
+ , 0, 0, {0,NULL} }
+
+
+struct CtrlMsgEventCustomRpcUnserialisedMsg
+{
+ ProtobufCMessage base;
+ int32_t resp;
+ uint32_t custom_evt_id;
+ ProtobufCBinaryData data;
+};
+#define CTRL_MSG__EVENT__CUSTOM_RPC_UNSERIALISED_MSG__INIT \
+ { PROTOBUF_C_MESSAGE_INIT (&ctrl_msg__event__custom_rpc_unserialised_msg__descriptor) \
+ , 0, 0, {0,NULL} }
+
+
typedef enum {
CTRL_MSG__PAYLOAD__NOT_SET = 0,
CTRL_MSG__PAYLOAD_REQ_GET_MAC_ADDRESS = 101,
@@ -870,6 +1001,9 @@ typedef enum {
CTRL_MSG__PAYLOAD_REQ_GET_FW_VERSION = 123,
CTRL_MSG__PAYLOAD_REQ_SET_COUNTRY_CODE = 124,
CTRL_MSG__PAYLOAD_REQ_GET_COUNTRY_CODE = 125,
+ CTRL_MSG__PAYLOAD_REQ_SET_DHCP_DNS_STATUS = 126,
+ CTRL_MSG__PAYLOAD_REQ_GET_DHCP_DNS_STATUS = 127,
+ CTRL_MSG__PAYLOAD_REQ_CUSTOM_RPC_UNSERIALISED_MSG = 128,
CTRL_MSG__PAYLOAD_RESP_GET_MAC_ADDRESS = 201,
CTRL_MSG__PAYLOAD_RESP_SET_MAC_ADDRESS = 202,
CTRL_MSG__PAYLOAD_RESP_GET_WIFI_MODE = 203,
@@ -895,12 +1029,17 @@ typedef enum {
CTRL_MSG__PAYLOAD_RESP_GET_FW_VERSION = 223,
CTRL_MSG__PAYLOAD_RESP_SET_COUNTRY_CODE = 224,
CTRL_MSG__PAYLOAD_RESP_GET_COUNTRY_CODE = 225,
+ CTRL_MSG__PAYLOAD_RESP_SET_DHCP_DNS_STATUS = 226,
+ CTRL_MSG__PAYLOAD_RESP_GET_DHCP_DNS_STATUS = 227,
+ CTRL_MSG__PAYLOAD_RESP_CUSTOM_RPC_UNSERIALISED_MSG = 228,
CTRL_MSG__PAYLOAD_EVENT_ESP_INIT = 301,
CTRL_MSG__PAYLOAD_EVENT_HEARTBEAT = 302,
CTRL_MSG__PAYLOAD_EVENT_STATION_DISCONNECT_FROM__AP = 303,
CTRL_MSG__PAYLOAD_EVENT_STATION_DISCONNECT_FROM__ESP__SOFT_AP = 304,
CTRL_MSG__PAYLOAD_EVENT_STATION_CONNECTED_TO__AP = 305,
- CTRL_MSG__PAYLOAD_EVENT_STATION_CONNECTED_TO__ESP__SOFT_AP = 306
+ CTRL_MSG__PAYLOAD_EVENT_STATION_CONNECTED_TO__ESP__SOFT_AP = 306,
+ CTRL_MSG__PAYLOAD_EVENT_SET_DHCP_DNS_STATUS = 307,
+ CTRL_MSG__PAYLOAD_EVENT_CUSTOM_RPC_UNSERIALISED_MSG = 308
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(CTRL_MSG__PAYLOAD__CASE)
} CtrlMsg__PayloadCase;
@@ -953,6 +1092,9 @@ struct CtrlMsg
CtrlMsgReqGetFwVersion *req_get_fw_version;
CtrlMsgReqSetCountryCode *req_set_country_code;
CtrlMsgReqGetCountryCode *req_get_country_code;
+ CtrlMsgReqSetDhcpDnsStatus *req_set_dhcp_dns_status;
+ CtrlMsgReqGetDhcpDnsStatus *req_get_dhcp_dns_status;
+ CtrlMsgReqCustomRpcUnserialisedMsg *req_custom_rpc_unserialised_msg;
/*
** Responses *
*/
@@ -981,6 +1123,9 @@ struct CtrlMsg
CtrlMsgRespGetFwVersion *resp_get_fw_version;
CtrlMsgRespSetCountryCode *resp_set_country_code;
CtrlMsgRespGetCountryCode *resp_get_country_code;
+ CtrlMsgRespSetDhcpDnsStatus *resp_set_dhcp_dns_status;
+ CtrlMsgRespGetDhcpDnsStatus *resp_get_dhcp_dns_status;
+ CtrlMsgRespCustomRpcUnserialisedMsg *resp_custom_rpc_unserialised_msg;
/*
** Notifications *
*/
@@ -990,6 +1135,8 @@ struct CtrlMsg
CtrlMsgEventStationDisconnectFromESPSoftAP *event_station_disconnect_from_esp_softap;
CtrlMsgEventStationConnectedToAP *event_station_connected_to_ap;
CtrlMsgEventStationConnectedToESPSoftAP *event_station_connected_to_esp_softap;
+ CtrlMsgEventSetDhcpDnsStatus *event_set_dhcp_dns_status;
+ CtrlMsgEventCustomRpcUnserialisedMsg *event_custom_rpc_unserialised_msg;
};
};
#define CTRL_MSG__INIT \
@@ -1890,6 +2037,82 @@ CtrlMsgRespGetCountryCode *
void ctrl_msg__resp__get_country_code__free_unpacked
(CtrlMsgRespGetCountryCode *message,
ProtobufCAllocator *allocator);
+/* CtrlMsgReqSetDhcpDnsStatus methods */
+void ctrl_msg__req__set_dhcp_dns_status__init
+ (CtrlMsgReqSetDhcpDnsStatus *message);
+size_t ctrl_msg__req__set_dhcp_dns_status__get_packed_size
+ (const CtrlMsgReqSetDhcpDnsStatus *message);
+size_t ctrl_msg__req__set_dhcp_dns_status__pack
+ (const CtrlMsgReqSetDhcpDnsStatus *message,
+ uint8_t *out);
+size_t ctrl_msg__req__set_dhcp_dns_status__pack_to_buffer
+ (const CtrlMsgReqSetDhcpDnsStatus *message,
+ ProtobufCBuffer *buffer);
+CtrlMsgReqSetDhcpDnsStatus *
+ ctrl_msg__req__set_dhcp_dns_status__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void ctrl_msg__req__set_dhcp_dns_status__free_unpacked
+ (CtrlMsgReqSetDhcpDnsStatus *message,
+ ProtobufCAllocator *allocator);
+/* CtrlMsgRespSetDhcpDnsStatus methods */
+void ctrl_msg__resp__set_dhcp_dns_status__init
+ (CtrlMsgRespSetDhcpDnsStatus *message);
+size_t ctrl_msg__resp__set_dhcp_dns_status__get_packed_size
+ (const CtrlMsgRespSetDhcpDnsStatus *message);
+size_t ctrl_msg__resp__set_dhcp_dns_status__pack
+ (const CtrlMsgRespSetDhcpDnsStatus *message,
+ uint8_t *out);
+size_t ctrl_msg__resp__set_dhcp_dns_status__pack_to_buffer
+ (const CtrlMsgRespSetDhcpDnsStatus *message,
+ ProtobufCBuffer *buffer);
+CtrlMsgRespSetDhcpDnsStatus *
+ ctrl_msg__resp__set_dhcp_dns_status__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void ctrl_msg__resp__set_dhcp_dns_status__free_unpacked
+ (CtrlMsgRespSetDhcpDnsStatus *message,
+ ProtobufCAllocator *allocator);
+/* CtrlMsgReqGetDhcpDnsStatus methods */
+void ctrl_msg__req__get_dhcp_dns_status__init
+ (CtrlMsgReqGetDhcpDnsStatus *message);
+size_t ctrl_msg__req__get_dhcp_dns_status__get_packed_size
+ (const CtrlMsgReqGetDhcpDnsStatus *message);
+size_t ctrl_msg__req__get_dhcp_dns_status__pack
+ (const CtrlMsgReqGetDhcpDnsStatus *message,
+ uint8_t *out);
+size_t ctrl_msg__req__get_dhcp_dns_status__pack_to_buffer
+ (const CtrlMsgReqGetDhcpDnsStatus *message,
+ ProtobufCBuffer *buffer);
+CtrlMsgReqGetDhcpDnsStatus *
+ ctrl_msg__req__get_dhcp_dns_status__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void ctrl_msg__req__get_dhcp_dns_status__free_unpacked
+ (CtrlMsgReqGetDhcpDnsStatus *message,
+ ProtobufCAllocator *allocator);
+/* CtrlMsgRespGetDhcpDnsStatus methods */
+void ctrl_msg__resp__get_dhcp_dns_status__init
+ (CtrlMsgRespGetDhcpDnsStatus *message);
+size_t ctrl_msg__resp__get_dhcp_dns_status__get_packed_size
+ (const CtrlMsgRespGetDhcpDnsStatus *message);
+size_t ctrl_msg__resp__get_dhcp_dns_status__pack
+ (const CtrlMsgRespGetDhcpDnsStatus *message,
+ uint8_t *out);
+size_t ctrl_msg__resp__get_dhcp_dns_status__pack_to_buffer
+ (const CtrlMsgRespGetDhcpDnsStatus *message,
+ ProtobufCBuffer *buffer);
+CtrlMsgRespGetDhcpDnsStatus *
+ ctrl_msg__resp__get_dhcp_dns_status__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void ctrl_msg__resp__get_dhcp_dns_status__free_unpacked
+ (CtrlMsgRespGetDhcpDnsStatus *message,
+ ProtobufCAllocator *allocator);
/* CtrlMsgEventESPInit methods */
void ctrl_msg__event__espinit__init
(CtrlMsgEventESPInit *message);
@@ -2004,6 +2227,82 @@ CtrlMsgEventStationConnectedToESPSoftAP *
void ctrl_msg__event__station_connected_to_espsoft_ap__free_unpacked
(CtrlMsgEventStationConnectedToESPSoftAP *message,
ProtobufCAllocator *allocator);
+/* CtrlMsgEventSetDhcpDnsStatus methods */
+void ctrl_msg__event__set_dhcp_dns_status__init
+ (CtrlMsgEventSetDhcpDnsStatus *message);
+size_t ctrl_msg__event__set_dhcp_dns_status__get_packed_size
+ (const CtrlMsgEventSetDhcpDnsStatus *message);
+size_t ctrl_msg__event__set_dhcp_dns_status__pack
+ (const CtrlMsgEventSetDhcpDnsStatus *message,
+ uint8_t *out);
+size_t ctrl_msg__event__set_dhcp_dns_status__pack_to_buffer
+ (const CtrlMsgEventSetDhcpDnsStatus *message,
+ ProtobufCBuffer *buffer);
+CtrlMsgEventSetDhcpDnsStatus *
+ ctrl_msg__event__set_dhcp_dns_status__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void ctrl_msg__event__set_dhcp_dns_status__free_unpacked
+ (CtrlMsgEventSetDhcpDnsStatus *message,
+ ProtobufCAllocator *allocator);
+/* CtrlMsgReqCustomRpcUnserialisedMsg methods */
+void ctrl_msg__req__custom_rpc_unserialised_msg__init
+ (CtrlMsgReqCustomRpcUnserialisedMsg *message);
+size_t ctrl_msg__req__custom_rpc_unserialised_msg__get_packed_size
+ (const CtrlMsgReqCustomRpcUnserialisedMsg *message);
+size_t ctrl_msg__req__custom_rpc_unserialised_msg__pack
+ (const CtrlMsgReqCustomRpcUnserialisedMsg *message,
+ uint8_t *out);
+size_t ctrl_msg__req__custom_rpc_unserialised_msg__pack_to_buffer
+ (const CtrlMsgReqCustomRpcUnserialisedMsg *message,
+ ProtobufCBuffer *buffer);
+CtrlMsgReqCustomRpcUnserialisedMsg *
+ ctrl_msg__req__custom_rpc_unserialised_msg__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void ctrl_msg__req__custom_rpc_unserialised_msg__free_unpacked
+ (CtrlMsgReqCustomRpcUnserialisedMsg *message,
+ ProtobufCAllocator *allocator);
+/* CtrlMsgRespCustomRpcUnserialisedMsg methods */
+void ctrl_msg__resp__custom_rpc_unserialised_msg__init
+ (CtrlMsgRespCustomRpcUnserialisedMsg *message);
+size_t ctrl_msg__resp__custom_rpc_unserialised_msg__get_packed_size
+ (const CtrlMsgRespCustomRpcUnserialisedMsg *message);
+size_t ctrl_msg__resp__custom_rpc_unserialised_msg__pack
+ (const CtrlMsgRespCustomRpcUnserialisedMsg *message,
+ uint8_t *out);
+size_t ctrl_msg__resp__custom_rpc_unserialised_msg__pack_to_buffer
+ (const CtrlMsgRespCustomRpcUnserialisedMsg *message,
+ ProtobufCBuffer *buffer);
+CtrlMsgRespCustomRpcUnserialisedMsg *
+ ctrl_msg__resp__custom_rpc_unserialised_msg__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void ctrl_msg__resp__custom_rpc_unserialised_msg__free_unpacked
+ (CtrlMsgRespCustomRpcUnserialisedMsg *message,
+ ProtobufCAllocator *allocator);
+/* CtrlMsgEventCustomRpcUnserialisedMsg methods */
+void ctrl_msg__event__custom_rpc_unserialised_msg__init
+ (CtrlMsgEventCustomRpcUnserialisedMsg *message);
+size_t ctrl_msg__event__custom_rpc_unserialised_msg__get_packed_size
+ (const CtrlMsgEventCustomRpcUnserialisedMsg *message);
+size_t ctrl_msg__event__custom_rpc_unserialised_msg__pack
+ (const CtrlMsgEventCustomRpcUnserialisedMsg *message,
+ uint8_t *out);
+size_t ctrl_msg__event__custom_rpc_unserialised_msg__pack_to_buffer
+ (const CtrlMsgEventCustomRpcUnserialisedMsg *message,
+ ProtobufCBuffer *buffer);
+CtrlMsgEventCustomRpcUnserialisedMsg *
+ ctrl_msg__event__custom_rpc_unserialised_msg__unpack
+ (ProtobufCAllocator *allocator,
+ size_t len,
+ const uint8_t *data);
+void ctrl_msg__event__custom_rpc_unserialised_msg__free_unpacked
+ (CtrlMsgEventCustomRpcUnserialisedMsg *message,
+ ProtobufCAllocator *allocator);
/* CtrlMsg methods */
void ctrl_msg__init
(CtrlMsg *message);
@@ -2166,6 +2465,18 @@ typedef void (*CtrlMsgReqGetCountryCode_Closure)
typedef void (*CtrlMsgRespGetCountryCode_Closure)
(const CtrlMsgRespGetCountryCode *message,
void *closure_data);
+typedef void (*CtrlMsgReqSetDhcpDnsStatus_Closure)
+ (const CtrlMsgReqSetDhcpDnsStatus *message,
+ void *closure_data);
+typedef void (*CtrlMsgRespSetDhcpDnsStatus_Closure)
+ (const CtrlMsgRespSetDhcpDnsStatus *message,
+ void *closure_data);
+typedef void (*CtrlMsgReqGetDhcpDnsStatus_Closure)
+ (const CtrlMsgReqGetDhcpDnsStatus *message,
+ void *closure_data);
+typedef void (*CtrlMsgRespGetDhcpDnsStatus_Closure)
+ (const CtrlMsgRespGetDhcpDnsStatus *message,
+ void *closure_data);
typedef void (*CtrlMsgEventESPInit_Closure)
(const CtrlMsgEventESPInit *message,
void *closure_data);
@@ -2184,6 +2495,18 @@ typedef void (*CtrlMsgEventStationDisconnectFromESPSoftAP_Closure)
typedef void (*CtrlMsgEventStationConnectedToESPSoftAP_Closure)
(const CtrlMsgEventStationConnectedToESPSoftAP *message,
void *closure_data);
+typedef void (*CtrlMsgEventSetDhcpDnsStatus_Closure)
+ (const CtrlMsgEventSetDhcpDnsStatus *message,
+ void *closure_data);
+typedef void (*CtrlMsgReqCustomRpcUnserialisedMsg_Closure)
+ (const CtrlMsgReqCustomRpcUnserialisedMsg *message,
+ void *closure_data);
+typedef void (*CtrlMsgRespCustomRpcUnserialisedMsg_Closure)
+ (const CtrlMsgRespCustomRpcUnserialisedMsg *message,
+ void *closure_data);
+typedef void (*CtrlMsgEventCustomRpcUnserialisedMsg_Closure)
+ (const CtrlMsgEventCustomRpcUnserialisedMsg *message,
+ void *closure_data);
typedef void (*CtrlMsg_Closure)
(const CtrlMsg *message,
void *closure_data);
@@ -2250,12 +2573,20 @@ extern const ProtobufCMessageDescriptor ctrl_msg__req__set_country_code__descrip
extern const ProtobufCMessageDescriptor ctrl_msg__resp__set_country_code__descriptor;
extern const ProtobufCMessageDescriptor ctrl_msg__req__get_country_code__descriptor;
extern const ProtobufCMessageDescriptor ctrl_msg__resp__get_country_code__descriptor;
+extern const ProtobufCMessageDescriptor ctrl_msg__req__set_dhcp_dns_status__descriptor;
+extern const ProtobufCMessageDescriptor ctrl_msg__resp__set_dhcp_dns_status__descriptor;
+extern const ProtobufCMessageDescriptor ctrl_msg__req__get_dhcp_dns_status__descriptor;
+extern const ProtobufCMessageDescriptor ctrl_msg__resp__get_dhcp_dns_status__descriptor;
extern const ProtobufCMessageDescriptor ctrl_msg__event__espinit__descriptor;
extern const ProtobufCMessageDescriptor ctrl_msg__event__heartbeat__descriptor;
extern const ProtobufCMessageDescriptor ctrl_msg__event__station_disconnect_from_ap__descriptor;
extern const ProtobufCMessageDescriptor ctrl_msg__event__station_connected_to_ap__descriptor;
extern const ProtobufCMessageDescriptor ctrl_msg__event__station_disconnect_from_espsoft_ap__descriptor;
extern const ProtobufCMessageDescriptor ctrl_msg__event__station_connected_to_espsoft_ap__descriptor;
+extern const ProtobufCMessageDescriptor ctrl_msg__event__set_dhcp_dns_status__descriptor;
+extern const ProtobufCMessageDescriptor ctrl_msg__req__custom_rpc_unserialised_msg__descriptor;
+extern const ProtobufCMessageDescriptor ctrl_msg__resp__custom_rpc_unserialised_msg__descriptor;
+extern const ProtobufCMessageDescriptor ctrl_msg__event__custom_rpc_unserialised_msg__descriptor;
extern const ProtobufCMessageDescriptor ctrl_msg__descriptor;
PROTOBUF_C__END_DECLS
diff --git a/esp_hosted_fg/common/include/esp_hosted_custom_rpc.h b/esp_hosted_fg/common/include/esp_hosted_custom_rpc.h
new file mode 100644
index 0000000000..3765df7819
--- /dev/null
+++ b/esp_hosted_fg/common/include/esp_hosted_custom_rpc.h
@@ -0,0 +1,28 @@
+#ifndef __ESP_HOSTED_RPC_H__
+#define __ESP_HOSTED_RPC_H__
+
+#include
+#include
+#include
+
+/* This file contains the custom RPC message IDs shared between the ESP Firmware and the Host side Protobuf Application.
+
+ * These IDs are just demonstration purpose. You can customize them as per your application requirements.
+ */
+
+
+enum custom_rpc_req_id {
+ CUSTOM_RPC_REQ_ID__ONLY_ACK = 1,
+ CUSTOM_RPC_REQ_ID__ECHO_BACK_RESPONSE = 2,
+ CUSTOM_RPC_REQ_ID__ECHO_BACK_AS_EVENT = 3,
+ /* Add more request IDs as needed */
+};
+
+enum custom_rpc_event_id {
+ /* Slave use this event to send back data received in CUSTOM_RPC_REQ_ID__ECHO_BACK_AS_EVENT */
+ CUSTOM_RPC_EVENT_ID__DEMO_ECHO_BACK_REQUEST = 100,
+ CUSTOM_RPC_EVENT_ID__DEMO_SIMPLE_EVENT = 101,
+ /* Add more event IDs as needed */
+};
+
+#endif /* __ESP_HOSTED_RPC_H__ */
diff --git a/esp_hosted_fg/common/include/esp_hosted_log.h b/esp_hosted_fg/common/include/esp_hosted_log.h
new file mode 100644
index 0000000000..1ac572c51c
--- /dev/null
+++ b/esp_hosted_fg/common/include/esp_hosted_log.h
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef __ESP_HOSTED_LOG_H
+#define __ESP_HOSTED_LOG_H
+#include "esp_log.h"
+
+#define ESP_PRIV_HEXDUMP(tag1, tag2, buff, buf_len, display_len, curr_level) \
+ if ( LOG_LOCAL_LEVEL >= curr_level) { \
+ int len_to_print = 0; \
+ len_to_print = display_len
+#include
+#include
+#include
+#include
+#ifdef CONFIG_HEAP_TRACING
+#include
+#endif
+#include
+#include
+#include
+#include "lwip/sockets.h"
+
+/* This should be agnostic, later */
+#ifdef CONFIG_ESP_HOSTED_COPROCESSOR
+#include "iperf.h"
+#include "wifi_cmd.h"
+#include "iperf_cmd.h"
+#include "ping_cmd.h"
+
+#define CLI_NEW_INSTANCE 1
+#endif
+
+static const char *TAG = "esp_cli";
+
+static int task_dump_cli_handler(int argc, char *argv[])
+{
+ /* Just to go to the next line */
+ printf("\n");
+#ifndef CONFIG_FREERTOS_USE_TRACE_FACILITY
+ printf("%s: To use this utility enable: Component config > FreeRTOS > Kernel > configUSE_TRACEFACILITY\n", TAG);
+#else
+ int num_of_tasks = uxTaskGetNumberOfTasks();
+ TaskStatus_t *task_array = calloc(1, num_of_tasks * sizeof(TaskStatus_t));
+ if (!task_array) {
+ ESP_LOGE(TAG, "Memory not allocated for task list.");
+ return 0;
+ }
+ num_of_tasks = uxTaskGetSystemState(task_array, num_of_tasks, NULL);
+ printf("\tName\tNumber\tPriority\tStackWaterMark\n");
+ for (int i = 0; i < num_of_tasks; i++) {
+ printf("%16s\t%u\t%u\t%u\n",
+ task_array[i].pcTaskName,
+ (unsigned) task_array[i].xTaskNumber,
+ (unsigned) task_array[i].uxCurrentPriority,
+ (unsigned) task_array[i].usStackHighWaterMark);
+ }
+ free(task_array);
+#endif
+ return 0;
+}
+
+static int cpu_dump_cli_handler(int argc, char *argv[])
+{
+ /* Just to go to the next line */
+ printf("\n");
+#ifndef CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
+ printf("%s: To use this utility enable: Component config > FreeRTOS > Kernel > configGENERATE_RUN_TIME_STATS\n", TAG);
+#else
+ char *buf = calloc(1, 2 * 1024);
+ vTaskGetRunTimeStats(buf);
+ printf("%s: Run Time Stats:\n%s\n", TAG, buf);
+ free(buf);
+#endif
+ return 0;
+}
+
+static void print_heap_stats()
+{
+ uint32_t freeSize = esp_get_free_heap_size();
+ printf("The available total size of heap:%" PRIu32 "\n", freeSize);
+
+ printf("\tDescription\tInternal\tSPIRAM\n");
+ printf("Current Free Memory\t%d\t\t%d\n",
+ heap_caps_get_free_size(MALLOC_CAP_8BIT) - heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
+ heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
+ printf("Largest Free Block\t%d\t\t%d\n",
+ heap_caps_get_largest_free_block(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL),
+ heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM));
+ printf("Min. Ever Free Size\t%d\t\t%d\n",
+ heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL),
+ heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM));
+}
+
+static int mem_dump_cli_handler(int argc, char *argv[])
+{
+ /* Just to go to the next line */
+ printf("\n");
+ print_heap_stats();
+ return 0;
+}
+
+#ifdef CONFIG_HEAP_TRACING
+static int heap_trace_records;
+static heap_trace_record_t *heap_trace_records_buf;
+static void cli_heap_trace_start()
+{
+ /* Just to go to the next line */
+ printf("\n");
+ if (!heap_trace_records_buf) {
+ heap_trace_records_buf = malloc(heap_trace_records * sizeof(heap_trace_record_t));
+ if (!heap_trace_records_buf) {
+ printf("%s: Failed to allocate records buffer\n", TAG);
+ return;
+ }
+ if (heap_trace_init_standalone(heap_trace_records_buf, heap_trace_records) != ESP_OK) {
+ printf("%s: Failed to initialise tracing\n", TAG);
+ goto error1;
+ }
+ }
+ if (heap_trace_start(HEAP_TRACE_LEAKS) != ESP_OK) {
+ printf("%s: Failed to start heap trace\n", TAG);
+ goto error2;
+ }
+ return;
+error2:
+ heap_trace_init_standalone(NULL, 0);
+error1:
+ free(heap_trace_records_buf);
+ heap_trace_records_buf = NULL;
+ return;
+}
+
+static void cli_heap_trace_stop()
+{
+ /* Just to go to the next line */
+ printf("\n");
+ if (!heap_trace_records_buf) {
+ printf("%s: Tracing not started?\n", TAG);
+ return;
+ }
+ heap_trace_stop();
+ heap_trace_dump();
+ heap_trace_init_standalone(NULL, 0);
+ free(heap_trace_records_buf);
+ heap_trace_records_buf = NULL;
+}
+#endif
+
+static int heap_trace_cli_handler(int argc, char *argv[])
+{
+ /* Just to go to the next line */
+ printf("\n");
+#ifndef CONFIG_HEAP_TRACING
+ printf("%s: To use this utility enable: Component config --> Heap memory debugging --> Enable heap tracing\n", TAG);
+#else
+ if (argc < 2) {
+ printf("%s: Incorrect arguments\n", TAG);
+ return 0;
+ }
+ if (strcmp(argv[1], "start") == 0) {
+#define DEFAULT_HEAP_TRACE_RECORDS 200
+ if (argc != 3) {
+ heap_trace_records = DEFAULT_HEAP_TRACE_RECORDS;
+ } else {
+ heap_trace_records = atoi(argv[2]);
+ }
+ printf("%s: Using a buffer to trace %d records\n", TAG, heap_trace_records);
+ cli_heap_trace_start();
+ } else if (strcmp(argv[1], "stop") == 0) {
+ cli_heap_trace_stop();
+ } else {
+ printf("%s: Invalid argument:%s:\n", TAG, argv[1]);
+ }
+#endif
+ return 0;
+}
+
+static int reboot_cli_handler(int argc, char *argv[])
+{
+ /* Just to go to the next line */
+ printf("\n");
+ esp_restart();
+ return 0;
+}
+
+static int crash_device_handler(int argc, char** argv)
+{
+ printf("Crashing the device now...\n");
+
+ // Writing at invalid address
+ *(volatile int *) (0x0) = 0;
+ return ESP_OK;
+}
+
+static int sock_dump_cli_handler(int argc, char *argv[])
+{
+ printf("\n");
+ int i, ret, used_sockets = 0;
+
+ struct sockaddr_in local_sock, peer_sock;
+ socklen_t local_sock_len = sizeof(struct sockaddr_in), peer_sock_len = sizeof(struct sockaddr_in);
+ char local_ip_addr[16], peer_ip_addr[16];
+ unsigned int local_port, peer_port;
+
+ int sock_type;
+ socklen_t sock_type_len;
+
+#define TOTAL_NUM_SOCKETS MEMP_NUM_NETCONN
+ printf("sock_fd\tprotocol\tlocal_addr\t\tpeer_addr\n");
+ for (i = LWIP_SOCKET_OFFSET; i < LWIP_SOCKET_OFFSET + TOTAL_NUM_SOCKETS; i++) {
+ memset(&local_sock, 0, sizeof(struct sockaddr_in));
+ memset(&peer_sock, 0, sizeof(struct sockaddr_in));
+ local_sock_len = sizeof(struct sockaddr);
+ peer_sock_len = sizeof(struct sockaddr);
+ memset(local_ip_addr, 0, sizeof(local_ip_addr));
+ memset(peer_ip_addr, 0, sizeof(peer_ip_addr));
+ local_port = 0;
+ peer_port = 0;
+ sock_type = 0;
+ sock_type_len = sizeof(int);
+
+ ret = getsockname(i, (struct sockaddr *)&local_sock, &local_sock_len);
+ if (ret >= 0) {
+ used_sockets++;
+ inet_ntop(AF_INET, &local_sock.sin_addr, local_ip_addr, sizeof(local_ip_addr));
+ local_port = ntohs(local_sock.sin_port);
+ getsockopt(i, SOL_SOCKET, SO_TYPE, &sock_type, &sock_type_len);
+ printf("%d\t%d:%s\t%16s:%d", i, sock_type, sock_type == SOCK_STREAM ? "tcp" : sock_type == SOCK_DGRAM ? "udp" : "raw", local_ip_addr, local_port);
+
+ ret = getpeername(i, (struct sockaddr *)&peer_sock, &peer_sock_len);
+ if (ret >= 0) {
+ inet_ntop(AF_INET, &peer_sock.sin_addr, peer_ip_addr, sizeof(peer_ip_addr));
+ peer_port = ntohs(peer_sock.sin_port);
+ printf("\t%16s:%d", peer_ip_addr, peer_port);
+ }
+ printf("\n");
+ }
+ }
+ printf("Remaining sockets: %d\n", TOTAL_NUM_SOCKETS - used_sockets);
+ return 0;
+}
+
+#if 0
+static bool wifi_is_provisioned(void)
+{
+ wifi_config_t wifi_cfg = {0};
+
+ if (esp_wifi_get_config(WIFI_IF_STA, &wifi_cfg) != ESP_OK) {
+ ESP_LOGI(TAG, "Wifi get config failed");
+ return false;
+ }
+
+ ESP_LOGI(TAG, "SSID: %s", wifi_cfg.sta.ssid);
+
+ if (strlen((const char *) wifi_cfg.sta.ssid)) {
+ ESP_LOGI(TAG, "Wifi provisioned");
+ return true;
+ }
+ ESP_LOGI(TAG, "Wifi not provisioned, Fallback to example config");
+
+ return false;
+}
+
+
+static int wifi_set_cli_handler(int argc, char *argv[])
+{
+ /* Just to go to the next line */
+ printf("\n");
+ if (argc != 3) {
+ printf("%s: Incorrect arguments\n", TAG);
+ return 0;
+ }
+
+ wifi_config_t wifi_cfg = {
+ .sta = {
+ /* Setting a password implies station will connect to all security modes including WEP/WPA.
+ * However these modes are deprecated and not advisable to be used. Incase your Access point
+ * doesn't support WPA2, these mode can be enabled by commenting below line */
+ .threshold.authmode = WIFI_AUTH_WPA2_PSK,
+
+ .pmf_cfg = {
+ .capable = true,
+ .required = false
+ },
+ },
+ };
+
+ snprintf((char*)wifi_cfg.sta.ssid, sizeof(wifi_cfg.sta.ssid), "%s", argv[1]);
+ snprintf((char*)wifi_cfg.sta.password, sizeof(wifi_cfg.sta.password), "%s", argv[2]);
+
+ /* Configure WiFi station with provided host credentials */
+ if (esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_cfg) != ESP_OK) {
+ printf("%s: Failed to set WiFi configuration\n", TAG);
+ return 0;
+ }
+
+ if (wifi_is_provisioned()) {
+ ESP_LOGI(TAG, "Wifi Provisioned");
+ }
+
+ ESP_LOGI(TAG, "Rebooting with new wi-fi configuration...");
+ vTaskDelay(pdMS_TO_TICKS(2 * 1000));
+ esp_restart(); // for now we simply re-start the device
+
+ return 0;
+}
+#endif
+
+#if defined(H_HOST_PS_ALLOWED) || defined(CONFIG_HOST_DEEP_SLEEP_ALLOWED)
+#ifdef H_ESP_HOSTED_HOST
+static int deep_sleep_cli_handler(int argc, char *argv[])
+{
+ ESP_LOGI(TAG, "Putting ESP32-P4 into deep sleep...");
+ start_host_power_save();
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_ESP_HOSTED_COPROCESSOR
+static int wakeup_cli_handler(int argc, char *argv[])
+{
+ ESP_LOGI(TAG, "Asking P4 to wake-up...");
+ wakeup_host(1000);
+ return 0;
+}
+#endif
+#endif
+
+static esp_console_cmd_t diag_cmds[] = {
+ {
+ .command = "crash",
+ .help = "Crash the device writing at invalid address",
+ .func = &crash_device_handler,
+ },
+ {
+ .command = "reboot",
+ .help = "Reboot the device",
+ .func = reboot_cli_handler,
+ },
+ {
+ .command = "mem-dump",
+ .help = "Prints memory stats",
+ .func = mem_dump_cli_handler,
+ },
+ {
+ .command = "task-dump",
+ .help = "Print task snapshots",
+ .func = task_dump_cli_handler,
+ },
+ {
+ .command = "cpu-dump",
+ .help = "Print CPU consumption data at the moment",
+ .func = cpu_dump_cli_handler,
+ },
+ {
+ .command = "heap-trace",
+ .help = " [trace-buf-size]",
+ .func = heap_trace_cli_handler,
+ },
+ {
+ .command = "sock-dump",
+ .help = "",
+ .func = sock_dump_cli_handler,
+ },
+#if 0
+ {
+ .command = "wifi-set",
+ .help = "wifi-set ",
+ .func = wifi_set_cli_handler,
+ },
+#endif
+
+#if defined(H_HOST_PS_ALLOWED) || defined(CONFIG_HOST_DEEP_SLEEP_ALLOWED)
+#ifdef H_ESP_HOSTED_HOST
+ {
+ .command = "deep-sleep",
+ .help = "Put P4 into deep sleep",
+ .func = deep_sleep_cli_handler,
+ },
+#endif
+#ifdef CONFIG_ESP_HOSTED_COPROCESSOR
+ {
+ .command = "wake-up",
+ .help = "Wake-up P4 from deep sleep",
+ .func = wakeup_cli_handler,
+ },
+#endif
+#endif
+};
+
+#ifdef CONFIG_ESP_HOSTED_COPROCESSOR
+#if CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS || CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS
+#include "esp_wifi_he.h"
+#endif
+#if CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS
+extern int wifi_cmd_get_tx_statistics(int argc, char **argv);
+extern int wifi_cmd_clr_tx_statistics(int argc, char **argv);
+#endif
+#if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS
+extern int wifi_cmd_get_rx_statistics(int argc, char **argv);
+extern int wifi_cmd_clr_rx_statistics(int argc, char **argv);
+#endif
+
+void iperf_hook_show_wifi_stats(iperf_traffic_type_t type, iperf_status_t status)
+{
+ if (status == IPERF_STARTED) {
+#if CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS
+ if (type != IPERF_UDP_SERVER) {
+ wifi_cmd_clr_tx_statistics(0, NULL);
+ }
+#endif
+#if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS
+ if (type != IPERF_UDP_CLIENT) {
+ wifi_cmd_clr_rx_statistics(0, NULL);
+ }
+#endif
+ }
+
+ if (status == IPERF_STOPPED) {
+#if CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS
+ if (type != IPERF_UDP_SERVER) {
+ wifi_cmd_get_tx_statistics(0, NULL);
+ }
+#endif
+#if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS
+ if (type != IPERF_UDP_CLIENT) {
+ wifi_cmd_get_rx_statistics(0, NULL);
+ }
+#endif
+ }
+
+}
+#endif
+
+int esp_cli_register_cmds()
+{
+ int cmds_num = sizeof(diag_cmds) / sizeof(esp_console_cmd_t);
+ int i;
+ const char* remove_cmd = "deep_sleep";
+
+ ESP_LOGI(TAG, "Remove any existing deep_sleep cmd in cli");
+ esp_console_cmd_deregister(remove_cmd);
+
+ for (i = 0; i < cmds_num; i++) {
+ ESP_LOGI(TAG, "Registering command: %s", diag_cmds[i].command);
+ esp_console_cmd_register(&diag_cmds[i]);
+ }
+
+#ifdef CONFIG_ESP_HOSTED_COPROCESSOR
+#ifdef CONFIG_SLAVE_MANAGES_WIFI
+ app_register_all_wifi_commands();
+ app_register_iperf_commands();
+ app_register_ping_commands();
+ app_register_iperf_hook_func(iperf_hook_show_wifi_stats);
+#endif
+#endif
+ return 0;
+}
+
+
+#if defined(CLI_NEW_INSTANCE) && CLI_NEW_INSTANCE
+int esp_hosted_cli_start()
+{
+ static int cli_started;
+ if (cli_started) {
+ return 0;
+ }
+
+ ESP_LOGI(TAG, "Starting CLI at slave");
+ esp_console_repl_t *repl = NULL;
+ esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
+#ifdef CONFIG_ESP_HOSTED_COPROCESSOR
+ repl_config.prompt = "coprocessor> ";
+#elif H_ESP_HOSTED_HOST
+ repl_config.prompt = "host> ";
+#endif
+ esp_console_register_help_command();
+ esp_cli_register_cmds();
+#if defined(CONFIG_ESP_CONSOLE_UART_DEFAULT) || defined(CONFIG_ESP_CONSOLE_UART_CUSTOM)
+ esp_console_dev_uart_config_t hw_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
+ ESP_ERROR_CHECK(esp_console_new_repl_uart(&hw_config, &repl_config, &repl));
+
+#elif defined(CONFIG_ESP_CONSOLE_USB_CDC)
+ esp_console_dev_usb_cdc_config_t hw_config = ESP_CONSOLE_DEV_CDC_CONFIG_DEFAULT();
+ ESP_ERROR_CHECK(esp_console_new_repl_usb_cdc(&hw_config, &repl_config, &repl));
+
+#elif defined(CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG)
+ esp_console_dev_usb_serial_jtag_config_t hw_config = ESP_CONSOLE_DEV_USB_SERIAL_JTAG_CONFIG_DEFAULT();
+ ESP_ERROR_CHECK(esp_console_new_repl_usb_serial_jtag(&hw_config, &repl_config, &repl));
+
+#else
+#error Unsupported console type
+#endif
+ ESP_ERROR_CHECK(esp_console_start_repl(repl));
+ cli_started = 1;
+ return 0;
+}
+#else
+int esp_hosted_cli_start()
+{
+ return esp_cli_register_cmds();
+}
+#endif
+#endif /*ESP_HOSTED_CLI_ENABLED*/
diff --git a/esp_hosted_fg/common/utils/esp_hosted_cli.h b/esp_hosted_fg/common/utils/esp_hosted_cli.h
new file mode 100644
index 0000000000..ce28066c66
--- /dev/null
+++ b/esp_hosted_fg/common/utils/esp_hosted_cli.h
@@ -0,0 +1,35 @@
+/*
+ * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef _ESP_HOSTED_CLI_H_
+#define _ESP_HOSTED_CLI_H_
+
+#include "sdkconfig.h"
+
+/* host */
+#ifdef CONFIG_ESP_HOSTED_HOST
+#include "esp_hosted_config.h"
+#include "power_save_drv.h"
+#endif
+
+/* coprocessor */
+#ifdef CONFIG_ESP_HOSTED_COPROCESSOR
+ #ifdef CONFIG_ESP_HOSTED_CLI_ENABLED
+ #include "host_power_save.h"
+ #define H_ESP_HOSTED_CLI_ENABLED 1
+ #endif /*CONFIG_ESP_HOSTED_CLI_ENABLED*/
+
+ #ifdef CONFIG_SLAVE_MANAGES_WIFI
+ #define H_SLAVE_MANAGES_WIFI 1
+ #endif
+#endif /*CONFIG_ESP_HOSTED_COPROCESSOR*/
+
+
+#ifdef H_ESP_HOSTED_CLI_ENABLED
+int esp_hosted_cli_start();
+#endif
+
+#endif /* _ESP_HOSTED_CLI_H_ */
diff --git a/esp_hosted_fg/docs/Linux_based_host/Auto_Network_Setup.md b/esp_hosted_fg/docs/Linux_based_host/Auto_Network_Setup.md
new file mode 100644
index 0000000000..2b30ace4bd
--- /dev/null
+++ b/esp_hosted_fg/docs/Linux_based_host/Auto_Network_Setup.md
@@ -0,0 +1,245 @@
+# Auto Network Setup
+
+Auto IP Restore ensures seamless collaboration between your ESP device and host system by automating network configuration — ideal for both development and deployment scenarios.
+
+
+Index
+
+1. [Overview](#1-overview)
+ - [1.1. What is Auto IP Restore?](#11-what-is-auto-ip-restore)
+ - [1.2. How It Works](#12-how-it-works)
+
+2. [Getting Started](#2-getting-started)
+ - [2.1. ESP Wi-Fi Setup](#21-esp-wi-fi-setup)
+ - [2.2. Running the Host Application](#22-running-the-host-application)
+
+3. [System Components](#3-system-components)
+ - [3.1. Host Kernel Module](#31-host-kernel-module)
+ - [3.2. User-Space Applications](#32-user-space-applications)
+ - [3.3. Host System Configuration](#33-host-system-configuration)
+
+4. [Implementation Details](#4-implementation-details)
+
+5. [Future Enhancements](#5-future-enhancements)
+
+
+
+---
+
+## 1. Overview
+
+### 1.1 What is Auto IP Restore?
+
+Auto IP Restore allows the host system to retrieve and apply network configuration from a connected ESP device. It simplifies Wi-Fi restoration after reboot or sleep cycles.
+
+#### ✨ Key Benefits
+
+- ✅ No manual IP setup required
+- ✅ Blazingly Fast connectivity on boot or wake-up from power saving
+- ✅ Background daemon supported
+- ✅ Extremely easy for user
+
+---
+
+### 1.2 How It Works
+
+Auto IP Restore involves tight integration between the host (Linux) and the ESP device:
+
+```mermaid
+sequenceDiagram
+ participant Host
+ participant KMod as Kernel Module
+ participant Daemon
+ participant ESP
+
+ participant Router as WiFi Router
+ Note over Host,Router: System Bootup
+ Note over ESP: ESP Bootup
+ ESP->>Router: Auto-connect to Wi-Fi
+ Router-->>ESP: DHCP IP assigned
+
+ Note over Host,Daemon: Host Bootup
+ Host->>KMod: Load Kernel Module
+ KMod->>ESP: Set-up ESP-Hosted transport
+ ESP-->>KMod: Transport Up
+
+ Note over Host,Router: IP Recovery
+ Note over Daemon: Start User Space App
+ Daemon->>ESP: Query MAC Address
+ ESP-->>Daemon: Return MAC
+ Daemon->>ESP: Query IP Config
+ ESP-->>Daemon: Return IP/DNS Info
+ Daemon->>Host: Configure ethsta0 interface
+ Daemon->>Host: Update resolv.conf
+ Daemon->>Host: Update default route
+
+ Note over Host,Router: Network Ready
+ Host<<->>Router: Traffic begins
+
+ Daemon->>Daemon: Subscribe network change event
+ Router-->>ESP: Change in DHCP or Wi-Fi
+ ESP-->>Daemon: Send network change Event
+ Daemon->>Host: Update IP / Router / DNS / Network accordingly
+
+````
+
+The ESP fetches IP configuration from the router and stores it in flash. On host boot, the daemon queries the ESP and sets the host interface (`ethsta0`) accordingly.
+
+---
+
+## 2. Getting Started
+
+### 2.1 ESP Wi-Fi Setup
+
+You can configure the ESP via:
+
+* 📦 **Stored Config**: Automatically connects using credentials in flash
+* 🛠 **CLI**:
+
+ ```sh
+ coprocessor> sta
+ ```
+* ⚙️ **Kconfig**: Default Wi-Fi set in [Kconfig.projbuild](../../../esp_hosted_fg/esp/esp_driver/network_adapter/main/Kconfig.projbuild)
+* 💻 **Host App**: Configure via `hosted_shell.out` or other RPC-capable tools
+
+Once configured, the ESP uses its DHCP client to get IP/gateway/DNS from the router.
+
+---
+
+### 2.2 Running the Host Application
+
+Two main user-space options exist:
+
+#### Option A: Development (Interactive Shell)
+
+```bash
+sudo ./hosted_shell.out
+```
+
+Provides interactive CLI with tab completion and command help.
+
+#### Option B: Production (Daemon)
+
+1. Install daemon:
+
+ ```bash
+ sudo cp hosted_daemon.out /usr/local/bin/
+ ```
+
+2. Create a systemd service:
+
+ ```bash
+ sudo nano /etc/systemd/system/hosted-daemon.service
+ ```
+
+ ```ini
+ [Unit]
+ Description=ESP Hosted Auto IP Restore Daemon
+ After=network.target
+
+ [Service]
+ Type=forking
+ ExecStart=/usr/local/bin/hosted_daemon.out
+ Restart=always
+ StandardOutput=syslog
+ StandardError=syslog
+ SyslogIdentifier=hosted-daemon
+
+ [Install]
+ WantedBy=multi-user.target
+ ```
+
+3. Enable and start the service:
+
+ ```bash
+ sudo systemctl enable hosted-daemon
+ sudo systemctl start hosted-daemon
+ ```
+
+4. Monitor logs:
+
+ ```bash
+ journalctl -u hosted-daemon -f
+ ```
+
+---
+
+## 3. System Components
+
+### 3.1 Host Kernel Module
+
+**Path**: [esp_hosted_fg/host/linux/host_driver/esp32](../../../esp_hosted_fg/host/linux/host_driver/esp32)
+
+* Initializes ESP transport (SPI or SDIO)
+* Creates the virtual `ethsta0` interface
+* Triggers ESP power-up sequence
+* Kernel mode cannot/should not configure IP directly (done via user-space)
+
+---
+
+### 3.2 User-Space Applications
+
+**Path**: [esp_hosted_fg/host/linux/host_control/c_support/](../../../esp_hosted_fg/host/linux/host_control/c_support/)
+
+#### A. Hosted Daemon (`hosted_daemon.out`)
+
+* Background service for IP sync
+* Key files:
+ - [hosted_daemon.c](../../../esp_hosted_fg/host/linux/host_control/c_support/hosted_daemon.c)
+ - [Makefile](../../../esp_hosted_fg/host/linux/host_control/c_support/Makefile)
+
+#### B. Hosted CLI (`hosted_shell.out`)
+
+* Interactive CLI
+* Uses replxx for tab completion
+* Good for testing or scripting
+* Key files:
+ - Install replxx library from https://github.com/AmokHuginnsson/replxx
+ - [hosted_shell.c](../../../esp_hosted_fg/host/linux/host_control/c_support/hosted_shell.c)
+ - [Makefile](../../../esp_hosted_fg/host/linux/host_control/c_support/Makefile)
+
+---
+
+### 3.3 Host System Configuration
+
+Configuration changes made by user-space apps include:
+
+* `/etc/resolv.conf` — sets DNS from ESP
+* Routing table — sets default gateway
+* `ethsta0` IP — applies ESP-provided IP
+
+These use helper functions from:
+ - [nw_helper_func.c](../../../esp_hosted_fg/host/linux/host_control/c_support/nw_helper_func.c)
+
+---
+
+## 4. Implementation Details
+
+Daemon on boot-up, calls function to fetch IP from ESP:
+
+```c
+static int fetch_ip_addr_from_slave(void) {
+ ctrl_cmd_t *resp = get_dhcp_dns_status(req);
+ if (resp->resp_event_status == SUCCESS) {
+ strncpy(sta_ip_str, resp->u.dhcp_dns_status.dhcp_ip, MAC_ADDR_LENGTH);
+ // Set IP, DNS, and route on ethsta0
+ }
+ return resp_cb(resp);
+}
+```
+
+Also subscribes to DHCP-DNS events, when received, automatically brings network up and down
+Key Points:
+
+* ESP sends `CTRL_EVENT_DHCP_DNS_STATUS` when IP changes
+* Daemon auto-applies new settings
+* Host DHCP client optional (can override daemon config)
+
+> ℹ️ Make sure a user-space app (daemon or shell) is running to handle events.
+
+---
+
+## 5. Future Enhancements
+
+* 🔋 Power management integration
+* 🌐 IPv6 support
diff --git a/esp_hosted_fg/docs/Linux_based_host/Getting_started.md b/esp_hosted_fg/docs/Linux_based_host/Getting_started.md
index 5773574af0..e7de10dfb7 100644
--- a/esp_hosted_fg/docs/Linux_based_host/Getting_started.md
+++ b/esp_hosted_fg/docs/Linux_based_host/Getting_started.md
@@ -1,17 +1,45 @@
# User Guide for ESP-Hosted with Linux Host (Raspberry-Pi)
-This section elaborates about setting up control path, Wi-Fi and Bluetooth/BLE connectivity on Linux host using ESP-Hosted solution.
+
+Index
+
+- [1. Control Path](#1-control-path)
+- [2. Wi-Fi Connectivity](#2-wi-fi-connectivity)
+ - [2.1 Control/Configure Wi-Fi Interface](#21-controlconfigure-wi-fi-interface)
+ - [2.1.1 Wi-Fi Station Mode Operations](#211-wi-fi-station-mode-operations)
+ - [2.1.2 Wi-Fi softAP Mode Operations](#212-wi-fi-softap-mode-operations)
+ - [2.1.3 Other Wi-Fi commands](#213-other-wi-fi-commands)
+- [3. Bluetooth/BLE Connectivity](#3-bluetoothble-connectivity)
+ - [3.1 BT/BLE Test procedure](#31-btble-test-procedure)
+ - [3.1.1 GATT server](#311-gatt-server)
+ - [3.1.2 GATT Client](#312-gatt-client)
+ - [3.1.3 BT scan](#313-bt-scan)
+ - [3.1.4 BLE scan](#314-ble-scan)
+ - [3.2 BLE 5.X testing](#32-ble-5x-testing)
+ - [3.2.1 Basic scan, pair, connect](#321-basic-scan-pair-connect)
+ - [3.2.2 GATT Server](#322-gatt-server)
+ - [3.2.3 GATT client](#323-gatt-client)
+ - [3.2.4 1M, 2M, CODED phy for LE](#324-1m-2m-coded-phy-for-le)
+- [4. OTA operation](#4-ota-operation)
+- [5. Troubleshoot Instructions](#5-troubleshoot-instructions)
+- [6. Network Split](#6-network-split)
+- [7. Auto Network Setup](#7-auto-network-setup)
+
+
+\
+This section elaborates how to get you onboard to establish Wi-Fi and Bluetooth/BLE connectivity on Linux host using ESP-Hosted solution.
## 1. Control Path
-* Control path is intended to setup all configurations at ESP side. These configurations could be related to services like
- - Connect host with external AP (Wi-Fi router)
- - Get configurations of external AP which host is connected
- - Set maximum Wi-Fi transmit power of ESP
- - Find out current Wi-Fi power of ESP
-* Control path command could be considered as first step before you can establish data path
-* It is way to verify if ESP-Hosted transport like SPI,SDIO is setup correctly
-* Overall [control path design](../common/contrl_path.md#3-design) and easy setup of control path using [demo application](../common/contrl_path.md#5-kick-start-using-control-path) is explained in [Control Path documentation](../common/contrl_path.md)
+* Control path is a lightweight RPC (Remote Procedure Call) user space library that uses Google Protobuf to configure the ESP device
+* It allows you to:
+ - Connect to Wi-Fi networks
+ - Get information about connected networks
+ - Configure Wi-Fi transmit power
+ - And other ESP settings
+* You need to use control path before establishing data connections
+* It's a good way to verify your SPI/SDIO transport is working correctly
+* The [Control Path documentation](../common/contrl_path.md) explains the [design architecture](../common/contrl_path.md#3-design) and provides a [quick start guide](../common/contrl_path.md#5-kick-start-using-control-path) with demo applications
## 2. Wi-Fi Connectivity
@@ -30,10 +58,10 @@ Wi-Fi can be configured as either as `STATION` mode or `SOFTAP` mode or `STATION
- This section explains how one can configure and control Wi-Fi interface using provided [python demo app](../common/python_demo.md)
- Python demo app can be used in two modes, shell mode *i.e.* command line mode and CLI mode. In following sections, only shell mode is detailed, just to enough to kick-start
- User can make use of easy and intuitive mode by referring [here](../common/python_demo.md#modes-supported)
-- C based solution also could be used from [C based demo app](../common/c_demo.md). For simplicity,
+- C based demo user space apps could be used from [C based demo app](../common/c_demo.md).
+- Python based demo user space app could be used from [Python based demo app](../common/python_demo.md)
-
-Python App is placed in [esp_hosted_fg/host/linux/host_control/python_support/](../../host/linux/host_control/python_support/) directory. Use below command to navigate to this directory.
+For simplicity, python app is used here.
```sh
$ cd esp_hosted_fg/host/linux/host_control/python_support/
```
@@ -295,3 +323,26 @@ Please follow [OTA update documentation](ota_update.md) for further details.
Please refer following for troubleshoot instructions if something goes wrong.
* [Troubleshooting Guide](./Troubleshoot.md)
+
+
+## 6. Network Split
+
+Network Split enables host and ESP to share an IP address while handling traffic based on port ranges. Users benefit from continued ESP connectivity during host sleep/power-down and can customize network configuration between slave and host.
+
+Key features:
+- Port-based traffic splitting (host: 49152-61439, ESP: 61440-65535)
+- Intelligent packet filtering with Deep Packet Inspection
+- Special handling for wake-up events
+
+For details, see [Network Split documentation](Network_Split.md).
+
+## 7. Auto Network Setup
+
+Auto Network Setup automatically retrieves and applies network settings from ESP to host, eliminating manual reconfiguration after reboots or sleep cycles and saving users time with seamless connectivity.
+
+Key benefits:
+- No manual IP setup required
+- Fast connectivity on boot or wake-up
+- Background daemon support
+
+For details, see [Auto Network Setup documentation](Auto_Network_Setup.md).
diff --git a/esp_hosted_fg/docs/Linux_based_host/Linux_based_readme.md b/esp_hosted_fg/docs/Linux_based_host/Linux_based_readme.md
index b660790a70..d50f874fa7 100644
--- a/esp_hosted_fg/docs/Linux_based_host/Linux_based_readme.md
+++ b/esp_hosted_fg/docs/Linux_based_host/Linux_based_readme.md
@@ -19,7 +19,7 @@
### 1.1 Hardware Requirements
* Raspberry-Pi model 3 Model B/B+ or Raspberry-Pi 4 model B
-* ESP32/ESP32-S2/S3/C2/C3/C6 board
+* ESP32/ESP32-S2/S3/C2/C3/C5/C6 board
* 8-12 jumper wires of length < 10cm
### 1.2 Host Setup
@@ -88,6 +88,7 @@ Prepare connections based on interface requirements and setup host as below.
* After loading ESP firmware, execute below command to create `hci0` interface
```sh
$ sudo hciattach -s 921600 /dev/serial0 any 921600 flow
+ ```
* **Wi-Fi over SPI and Bluetooth over UART**
* Connection Setup
@@ -235,4 +236,4 @@ Following guide explains how to use ESP-Hosted solution.
# 4. ESP-Hosted Porting Guide to other Linux Platforms
Following document explains guidelines for porting solution to othe Linux platforms
-* [Porting Guide](./porting_guide.md)
+* [Porting Guide](./porting_guide.md)
\ No newline at end of file
diff --git a/esp_hosted_fg/docs/Linux_based_host/Network_Split.md b/esp_hosted_fg/docs/Linux_based_host/Network_Split.md
new file mode 100644
index 0000000000..4ab92fca01
--- /dev/null
+++ b/esp_hosted_fg/docs/Linux_based_host/Network_Split.md
@@ -0,0 +1,345 @@
+
+# Network Split Feature
+
+
+Index
+
+1. [Introduction](#1-introduction)
+2. [Network Architecture](#2-network-architecture)
+ - [2.1. High-level Overview](#21-high-level-overview)
+ - [Packet routing entry](#packet-routing-entry)
+ - [TCP Packets](#tcp-packets)
+ - [UDP Packets](#udp-packets)
+ - [ICMP & ARP Packets](#icmp--arp-packets)
+ - [2.2. Packet Routing Summary](#22-packet-routing-summary)
+3. [Enable Network Split](#3-enable-network-split)
+ - [3.1. Configure the ESP Firmware](#31-configure-the-esp-firmware-for-linux-host)
+ - [3.2. Configure the Linux Host System](#32-configure-the-linux-host-system)
+4. [Troubleshooting](#4-troubleshooting)
+
+
+
+## 1. Introduction
+
+**Network Split** allows a **Linux Host** and an **ESP32 Slave** to share a single IP address and intelligently split network traffic between them. This means the ESP can continue handling selected network activity (like MQTT or DNS) even when the host is in a low-power "sleep" state, conserving energy without interrupting essential connectivity.
+
+**Highlights:**
+
+ * Port-based traffic splitting between the host and slave.
+ * Shared IP address with intelligent packet routing.
+ * Deep Packet Inspection (DPI) for custom handling and routing of packets.
+
+##### Co-Processor Supported
+
+| Supported Slave Targets | ESP32-C5 | ESP32-C6/C61 | ESP32-S2 | ESP32-S3 | ESP32 |
+| :---------------------- | :------: | :----------: | :------: | :------: | :---: |
+
+##### Communication Bus Supported
+
+| Transports Supported | SPI | SDIO |
+| :-------------------: | :-: | :--: |
+
+-----
+
+## 2. Network Architecture
+
+The Network Split architecture divides incoming network traffic based on destination port ranges. By default:
+
+ * The **Host** handles ports **49152-61439**.
+ * The **Slave** handles ports **61440-65535**.
+
+This port-based routing is transparent to remote endpoints, making it appear as a single device with one IP address.
+
+### 2.1. High-level Overview
+
+The core packet routing logic resides in `lwip_filter.c` and `lwip_filter.h` on the slave side, managing all packet routing decisions. The packet routing logic implementation:
+
+https://github.com/espressif/esp-hosted/blob/ba39e6392f4f1c2e9ace3c5fa463bab34a42cb31/esp_hosted_fg/esp/esp_driver/network_adapter/main/lwip_filter.c#L347-L520
+
+The routing logic includes special handling for:
+
+ * **Priority ports** (e.g., SSH, HTTP, RTSP, DNS, NTP).
+ * **MQTT messages** containing "wakeup-host" content.
+ * **iPerf** performance testing traffic.
+ * **DHCP client** traffic.
+ * **ARP** and **ICMP** protocols.
+
+The diagrams below illustrate the packet classification and routing logic:
+
+#### Packet routing entry
+
+```mermaid
+%% Main Packet Classification
+flowchart TD
+ A[New Packet] --> B{MAC Broadcast?}
+ B -->|Yes| C[Send to Slave Network]
+ B -->|No| D{IP Packet?}
+ D -->|Yes| E[Protocol Processing]
+ D -->|No| F[ARP Processing]
+
+ E --> G{TCP?}
+ E --> H{UDP?}
+ E --> I{ICMP?}
+
+ classDef slaveNode fill:#d9f7be,stroke:#389e0d
+ classDef hostNode fill:#d6e4ff,stroke:#1d39c4
+ classDef invalidNode fill:#ffccc7,stroke:#cf1322
+ classDef bothNode fill:#fff1b8,stroke:#d4b106
+ classDef defaultNode fill:#fff,stroke:#333
+
+ class C slaveNode
+```
+
+#### TCP Packets
+
+```mermaid
+%% TCP Processing
+flowchart TD
+ G[TCP Packet] --> G1{Priority Port? SSH, RTSP, etc.}
+ G1 -->|Yes| K[Send to Host Network]
+
+ G1 -->|No| G2{Dest Port == iPerf 5001?}
+ G2 -->|Yes| G3{Local TCP Port Open?}
+ G3 -->|Yes| C[Send to Slave Network]
+ G3 -->|No| G4{Host Sleeping?}
+ G4 -->|No| K
+ G4 -->|Yes| C
+
+ G2 -->|No| G5{Is Remote TCP Port?}
+ G5 -->|Yes| G6{Host Sleeping?}
+ G6 -->|Yes| G7{Source Port == MQTT 1883?}
+ G7 -->|Yes| G8{"Contains 'wakeup-host'?"}
+ G8 -->|Yes| K
+ G8 -->|No| L[Drop Packet]
+ G7 -->|No| L
+ G6 -->|No| K
+
+ G5 -->|No| G9{Is Local TCP Port?}
+ G9 -->|Yes| C
+ G9 -->|No| D[Slave's Internal LWIP Stack]
+
+ classDef slaveNode fill:#d9f7be,stroke:#389e0d
+ classDef hostNode fill:#d6e4ff,stroke:#1d39c4
+ classDef invalidNode fill:#ffccc7,stroke:#cf1322
+ classDef defaultNode fill:#fff,stroke:#333
+
+ class K hostNode
+ class C slaveNode
+ class L invalidNode
+ class D defaultNode
+```
+
+#### UDP Packets
+
+```mermaid
+%% UDP Processing
+flowchart TD
+ H[UDP Packet] --> H1{Priority Port? DNS, NTP, etc.}
+ H1 -->|Yes| K[Send to Host Network]
+
+ H1 -->|No| H2{Dest Port == iPerf 5001?}
+ H2 -->|Yes| H3{Local UDP Port Open?}
+ H3 -->|Yes| C[Send to Slave Network]
+ H3 -->|No| H4{Host Sleeping?}
+ H4 -->|No| K
+ H4 -->|Yes| C
+
+ H2 -->|No| H5{DHCP Client Port?}
+ H5 -->|Yes| H6["Send to DHCP Handler (Host or Slave)"]
+
+ H5 -->|No| H7{Is Remote UDP Port?}
+ H7 -->|Yes| H8{Host Sleeping?}
+ H8 -->|Yes| L[Drop Packet]
+ H8 -->|No| K
+
+ H7 -->|No| H9{Is Local UDP Port?}
+ H9 -->|Yes| C
+ H9 -->|No| D[Slave's Internal LWIP Stack]
+
+ classDef slaveNode fill:#d9f7be,stroke:#389e0d
+ classDef hostNode fill:#d6e4ff,stroke:#1d39c4
+ classDef invalidNode fill:#ffccc7,stroke:#cf1322
+ classDef defaultNode fill:#fff,stroke:#333
+
+ class K hostNode
+ class C slaveNode
+ class L invalidNode
+ class D defaultNode
+ class H6 defaultNode
+```
+
+#### ICMP & ARP Packets
+
+```mermaid
+%% ICMP & ARP Processing
+flowchart TD
+ subgraph ICMP
+ I[ICMP Packet] --> I1{Ping Request?}
+ I1 -->|Yes| C[Send to Slave Network]
+ I1 -->|No| I2{Ping Response?}
+ I2 -->|Yes| I3{Host Sleeping?}
+ I3 -->|Yes| C
+ I3 -->|No| N[Send to Both Networks]
+ end
+
+ subgraph ARP
+ F[ARP Packet] --> F1{ARP Request?}
+ F1 -->|Yes| C
+ F1 -->|No| F2{Host Sleeping?}
+ F2 -->|Yes| C
+ F2 -->|No| N
+ end
+
+ classDef slaveNode fill:#d9f7be,stroke:#389e0d
+ classDef bothNode fill:#fff1b8,stroke:#d4b106
+
+ class C slaveNode
+ class N bothNode
+```
+
+The slave determines if the host is "sleeping" by monitoring the host's activity or a dedicated control signal, ensuring packets are routed appropriately to wake the host when necessary or handled by the slave directly.
+
+### 2.2. Packet Routing Summary
+
+All incoming packets are evaluated by `lwip_filter.c`. The slave routes packets based on these rules:
+
+| Packet Type | Destination Port Condition | Routed To |
+| :------------------------------------ | :----------------------------------------- | :--------------------------------- |
+| Broadcast, ARP Request, ICMP Request | N/A | Slave Network Stack |
+| TCP/UDP | Listed in Static Port Forwarding | Host Network Stack |
+| TCP/UDP | Within Host Port Range (49152-61439) | Host Network Stack |
+| TCP/UDP | Within Slave Port Range (61440-65535) | Slave Network Stack |
+| Others | Not matched by any rule | Default Destination (as configured)|
+| iperf (-p 5001 default port) | If 5001 is open at slave | Slave Network Stack. Else Host Network Stack |
+
+-----
+
+## 3. Enable Network Split
+
+### 3.1. Configure the ESP Firmware (for Linux Host)
+
+The firmware source is located at: [esp\_hosted\_fg/esp/esp\_driver/network\_adapter](https://github.com/espressif/esp-hosted/tree/master/esp_hosted_fg/esp/esp_driver/network_adapter)
+
+##### SDK Setup
+
+ * **Linux / Mac users:**
+ ```bash
+ bash setup-idf.sh
+ ```
+ * **Windows users:**
+ Refer to [setup\_windows11.md](https://github.com/espressif/esp-hosted/blob/master/esp_hosted_fg/esp/esp_driver/setup_windows11.md).
+
+##### Configure Network Split Mode
+
+Run `idf.py menuconfig` from your firmware directory.
+
+Enable the feature:
+
+```
+Example Configuration
+└── [*] Allow Network Split using packet port number
+```
+
+(Optional) Customize under `Network Split Configuration`:
+
+```
+├── Extra port forwarding to host (static)
+│ ├── TCP dst: 22,8554 (e.g., SSH, RTSP)
+│ └── UDP dst: 53,123 (e.g., DNS, NTP)
+├── Port Ranges
+│ ├── Host: 49152–61439
+│ └── Slave: 61440–65535
+└── Default Destination: slave / host / both
+```
+
+##### Build and Flash ESP Firmware
+
+```bash
+idf.py -p /dev/ttyUSBx build flash monitor
+```
+
+(Replace `/dev/ttyUSBx` with your ESP device’s serial port.)
+
+-----
+
+### 3.2. Configure the Linux Host System
+
+The Linux host code is located at: [esp\_hosted\_fg/host/linux](https://www.google.com/search?q=https://github.com/espressif/esp-hosted/tree/master/esp_hosted_fg/host/linux)
+
+##### Sysctl Configuration
+
+Edit `/etc/sysctl.conf`:
+
+```bash
+net.ipv4.ip_local_port_range = 49152 61439
+```
+
+Apply the changes:
+
+```bash
+sudo sysctl -p
+```
+
+> [!TIP]
+> The port ranges configured on the host and slave **must match exactly** to avoid routing issues.
+
+##### Setup Linux Host Driver and Application
+
+ * **Kernel Module:**
+ Build using the [Makefile](https://github.com/espressif/esp-hosted/blob/master/esp_hosted_fg/host/linux/host_driver/esp32/Makefile) or the [helper script](https://github.com/espressif/esp-hosted/blob/master/esp_hosted_fg/host/linux/host_control/rpi_init.sh) (`rpi_init.sh`) for Raspberry Pi.
+
+ * **User Application:**
+ Build:
+
+ ```bash
+ cd esp_hosted_fg/host/linux/host_control
+ make hosted_shell
+ ```
+
+ Run:
+
+ ```bash
+ sudo ./hosted_shell.out
+ ```
+
+ Connect the ESP to Wi-Fi:
+
+ ```bash
+ connect_ap
+ ```
+
+ This command creates the `ethsta0` network interface, which is then ready for standard socket-based tools like `iperf`.
+
+-----
+
+## 4. Troubleshooting
+
+**Debug Logging:**
+To enable verbose logging for the packet routing logic on the slave:
+
+```c
+esp_log_level_set("lwip_filter", ESP_LOG_VERBOSE);
+```
+
+**Network Monitoring:**
+Use `tcpdump` to monitor traffic on the host interface:
+
+```bash
+sudo tcpdump -i ethsta0 port 80
+```
+
+Check the configured local port range on the host:
+
+```bash
+cat /proc/sys/net/ipv4/ip_local_port_range
+```
+
+**Common Issues:**
+
+ * **Packets not getting delivered to host or slave:**
+ * Check if the socket being opened is using reserved port ranges.
+ * If so, you can either handle the packet within the existing packet routing logic or add the destination port to the `Extra port forwarding to host` configuration in `menuconfig`.
+ * **DHCP not completing:**
+ * Verify where the DHCP packet is destined by checking the `lwip_filter.c` logic related to DHCP (refer to lines [38-42 here](https://github.com/espressif/esp-hosted/blob/ba39e6392f4f1c2e9ace3c5fa463bab34a42cb31/esp_hosted_fg/esp/esp_driver/network_adapter/main/lwip_filter.c#L38-L42)).
+ * **Same port needing to be used by both slave and host:**
+ * This is already supported for iperf on port 5001. You can amend the packet routing logic in `lwip_filter.c` to handle other specific ports similarly if needed.
diff --git a/esp_hosted_fg/docs/Linux_based_host/Raw_TP_Testing.md b/esp_hosted_fg/docs/Linux_based_host/Raw_TP_Testing.md
index f766617207..2c1bd49201 100644
--- a/esp_hosted_fg/docs/Linux_based_host/Raw_TP_Testing.md
+++ b/esp_hosted_fg/docs/Linux_based_host/Raw_TP_Testing.md
@@ -12,7 +12,7 @@
- e.g if you are setting Wi-Fi over SDIO and you want to test raw TP over SDIO interface, then compile and load host driver as below:
```sh
$ cd esp_hosted_fg/host/linux/host_control/
- $ ./rpi_init.sh sdio rawtp
+ $ ./rpi_init.sh wifi=sdio rawtp
```
- On ESP side:
@@ -23,5 +23,34 @@
- Host to ESP : For this, make `TEST_RAW_TP__ESP_TO_HOST` value to 0
4. Build and flash ESP firmware again.
-**Note**
-Please revert these configurations once raw throughput testing is done
+> [!Note]
+> Please revert these configurations once raw throughput testing is done
+
+## Raw Throughput Benchmarks
+
+### For SDIO with ESP32-C6 or C5
+
+Before starting the test, check your SDMMC CLK frequency and bus width. On a Raspberry Pi, this is done via `/sys/kernel/debug/mmc1/ios`:
+
+```sh
+$ sudo cat /sys/kernel/debug/mmc1/ios
+clock 50000000 Hz
+actual clock: 41666667 Hz
+[...]
+bus width: 2 (4 bits)
+```
+
+This shows the SDMMC clock is running at 41 MHz and SDIO is using 4 data lines. For other linux based SOCs, check your documentation on how to display similar SDMMC info.
+
+To change the clock frequency, add the `clockspeed` parameter when running `rpi_init.sh`:
+
+```sh
+$ ./rpi_init.sh wifi=sdio clockspeed=50 rawtp
+```
+
+With the SDMMC clock at 41 MHz, here are the raw throughput numbers:
+
+| Data Transfer | Throughput (Mbits/s) |
+| ------------- | -------------------: |
+| C6/C5 to RPi | 40 |
+| RPi to C6/C5 | 60 |
diff --git a/esp_hosted_fg/docs/Linux_based_host/SDIO_setup.md b/esp_hosted_fg/docs/Linux_based_host/SDIO_setup.md
index 1a1f41ffd9..b6ddeea5a4 100644
--- a/esp_hosted_fg/docs/Linux_based_host/SDIO_setup.md
+++ b/esp_hosted_fg/docs/Linux_based_host/SDIO_setup.md
@@ -1,38 +1,41 @@
# Wi-Fi and BT/BLE connectivity Setup over SDIO
-| Supported Targets | ESP32 | ESP32-C6 |
-| ----------------- | ----- | -------- |
+| Supported Targets | ESP32 | ESP32-C6 | ESP32-C5 |
+| ----------------- | ----- | -------- | -------- |
+
+> [!NOTE]
+> SDIO support for ESP32-C5 is currently in BETA. It is available as a `--preview` release in the `master` branch of ESP-IDF.
## 1. Setup
### 1.1 Hardware Setup
-In this setup, ESP board acts as a SDIO peripheral and provides Wi-Fi capabilities to host. Please connect ESP board to Raspberry-Pi with jumper cables as mentioned below.
+In this setup, ESP board acts as a SDIO peripheral and provides Wi-Fi capabilities to host. Please connect ESP board to Raspberry-Pi as mentioned below.
Raspberry Pi should be powered with correct incoming power rating.
ESP can be powered through PC using micro-USB/USB-C cable.
-| Raspberry-Pi Pin | ESP32 Pin | ESP32-C6 Pin | Function |
-|:-------:|:---------:|:--------:|:--------:|
-| 13 | IO13+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/sd_pullup_requirements.html)| IO23+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/api-reference/peripherals/sd_pullup_requirements.html) | DAT3 |
-| 15 | IO14 | IO19 | CLK |
-| 16 | IO15+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/sd_pullup_requirements.html) | IO18+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/api-reference/peripherals/sd_pullup_requirements.html) | CMD |
-| 18 | IO2+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/sd_pullup_requirements.html)| IO20+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/api-reference/peripherals/sd_pullup_requirements.html) | DAT0 |
-| 22 | IO4+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/sd_pullup_requirements.html)| IO21+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/api-reference/peripherals/sd_pullup_requirements.html) | DAT1 |
-| 31 | EN | ESP Reset |
-| 37 | IO12+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/sd_pullup_requirements.html)| IO22+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/api-reference/peripherals/sd_pullup_requirements.html) | DAT2 |
-| 39 | GND | GND | GND|
+| Raspberry-Pi Pin | ESP32 Pin | ESP32-C6 Pin | ESP32-C5 | Function |
+| :--------------: | :-------: | :----------: | :------: | :------: |
+| 13 | IO13+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/sd_pullup_requirements.html) | IO23+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/api-reference/peripherals/sd_pullup_requirements.html) | IO13+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/sd_pullup_requirements.html) | DAT3 |
+| 15 | IO14 | IO19 | IO9 | CLK |
+| 16 | IO15+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/sd_pullup_requirements.html) | IO18+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/api-reference/peripherals/sd_pullup_requirements.html) | IO10+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/sd_pullup_requirements.html) | CMD |
+| 18 | IO2+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/sd_pullup_requirements.html) | IO20+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/api-reference/peripherals/sd_pullup_requirements.html) | IO8+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/api-reference/peripherals/sd_pullup_requirements.html) | DAT0 |
+| 22 | IO4+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/sd_pullup_requirements.html) | IO21+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/api-reference/peripherals/sd_pullup_requirements.html) | IO7+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/api-reference/peripherals/sd_pullup_requirements.html) | DAT1 |
+| 31 | EN | ESP Reset | ESP Reset | Reset |
+| 37 | IO12+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/sd_pullup_requirements.html)| IO22+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/api-reference/peripherals/sd_pullup_requirements.html) | IO14+[pull-up](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/api-reference/peripherals/sd_pullup_requirements.html) | DAT2 |
+| 39 | GND | GND | GND | GND |
Raspberry-Pi pinout can be found [here!](https://pinout.xyz/pinout/sdio)
-Sample setup image of ESP32 SDIO with RPi looks like:
-
-
+Sample setup image of ESP32-C6 SDIO with RPi looks like:
-:warning: Note:
-As SDIO faces signal integrity issues over jumper wires, we strongly recommend to **Design PCB boards with above connections.**
-If that is not possible
- - Use good quality extremely small (smaller than 5cm) jumper wires, all equal length
- - Join all possible grounds interconnected to lower noise
- - Add at least, 10k Ohm external pull-up resistors on 5 lines: CMD, DAT0-4. We use 51k Ohm resistors in our set-up.
+
+> [!WARNING]
+> As SDIO faces signal integrity issues over jumper wires, we strongly recommend to **Design PCB boards with above connections.**
+>
+> If that is not possible
+> - Use good quality extremely small (smaller than 5cm) jumper wires, all equal length
+> - Join all possible grounds interconnected to lower noise
+> - Add at least, 10k Ohm external pull-up resistors on 5 lines: CMD, DAT0-4. We use 51k Ohm resistors in our set-up.
### 1.2 Raspberry-Pi Software Setup
By default, the SDIO pins of Raspberry-pi are not configured and are internally used for the built-in Wi-Fi interface. Please enable SDIO pins by appending the following line to the _/boot/firmware/config.txt_ file (prior to _Bookworm_, the file is at _/boot/config.txt_):
@@ -48,13 +51,41 @@ Also, it is recommended to download (any) software needed (like iperf etc) befor
## 2. Load ESP-Hosted Solution
### 2.1 Host Software
-* Execute following commands in root directory of cloned ESP-Hosted repository on Raspberry-Pi
+* Execute following commands in root directory of cloned ESP-Hosted repository on Raspberry-Pi:
+
```sh
$ cd esp_hosted_fg/host/linux/host_control/
-$ ./rpi_init.sh sdio
+$ ./rpi_init.sh wifi=sdio bt=sdio
```
+
* This script compiles and loads host driver on Raspberry-Pi. It also creates virtual serial interface `/dev/esps0` which is used as a control interface for Wi-Fi on ESP peripheral
+Execute `./rpi_init.sh --help` to see the list of options.
+
+> [!NOTE]
+> For SDIO+UART, use `bt=uart_2pins` or `bt=uart_4pins` for 2/4 pin UART. For wifi only support, exclude the `bt` parameter.
+
+#### 2.1.1 Manually loading and unloading the Kernel Module
+
+Once built, the kernel module `esp32_sdio.ko` can be found in `esp_hosted_fg/host/linux/host_driver/esp32`. You can manualy load/unload the module as needed.
+
+To add the module:
+
+`$ sudo insmod esp_hosted_fg/host/linux/host_driver/esp32/esp32_sdio.ko resetpin=518 clockspeed=50`
+
+##### Module Parameters
+
+| Parameter | Meaning |
+| --- | --- |
+| `resetpin` | GPIO to reset the ESP peripheral |
+| `clockspeed` | SDIO CLK frequency (in MHz: maximum 50) |
+
+Note: `clockspeed` is optional. Default is to use the default SDIO clock speed.
+
+To remove the module:
+
+`$ sudo rmmod esp32_sdio`
+
### 2.2 ESP Peripheral Firmware
One can load pre-built release binaries on ESP peripheral or compile those from source. Below subsection explains both these methods.
diff --git a/esp_hosted_fg/docs/Linux_based_host/SPI_setup.md b/esp_hosted_fg/docs/Linux_based_host/SPI_setup.md
index 8f915a0daa..eef9948a76 100644
--- a/esp_hosted_fg/docs/Linux_based_host/SPI_setup.md
+++ b/esp_hosted_fg/docs/Linux_based_host/SPI_setup.md
@@ -57,13 +57,47 @@ Every packet would be passed through the ESP-Hosted Wi-Fi interface and not the
## 2. Load ESP-Hosted Solution
### 2.1 Host Software
-* Execute following commands in root directory of cloned ESP-Hosted repository on Raspberry-Pi
+* Execute following commands in root directory of cloned ESP-Hosted repository on Raspberry-Pi.
+
```sh
$ cd esp_hosted_fg/host/linux/host_control/
-$ ./rpi_init.sh spi
+$ ./rpi_init.sh wifi=spi bt=spi spi_mode=3
```
+
* This script compiles and loads host driver on Raspberry-Pi. It also creates virtual serial interface `/dev/esps0` which is used as a control interface for Wi-Fi on ESP peripheral
+Execute `./rpi_init.sh --help` to see the list of options.
+
+> [!NOTE]
+> For SPI+UART, use `bt=uart_2pins` or `bt=uart_4pins` for 2/4 pin UART. For wifi only support, exclude the `bt` parameter.
+
+> [!NOTE]
+> For ESP32 peripheral, use `spi_mode=2`. For other ESP SOCs, use `spi_mode=3`.
+
+#### 2.1.1 Manually loading and unloading the Kernel Module
+
+Once built, the kernel module `esp32_spi.ko` can be found in `esp_hosted_fg/host/linux/host_driver/esp32`. You can manualy load/unload the module as needed.
+
+To add the module:
+
+`$ sudo insmod esp_hosted_fg/host/linux/host_driver/esp32/esp32_spi.ko resetpin=518 clockspeed=10 spi_bus=0 spi_cs=0 spi_mode=3 spi_handshake=517 spi_dataready=524`
+
+##### Module Parameters
+
+| Parameter | Meaning |
+| --- | --- |
+| `resetpin` | GPIO to reset the ESP peripheral |
+| `clockspeed` | SPI CLK frequency (in MHz) |
+| `spi_bus` | SPI bus to use |
+| `spi_cs` | SPI CS/CEx to use |
+| `spi_mode` | SPI mode to use (2 for ESP32, 3 for all other SOCS) |
+| `spi_handshake` | GPIO for Handshake signal |
+| `spi_dataready` | GPIO of Data Ready signal |
+
+To remove the module:
+
+`$ sudo rmmod esp32_spi`
+
### 2.2 ESP Peripheral Firmware
One can load pre-built release binaries on ESP peripheral or compile those from source. Below subsection explains both these methods.
@@ -105,7 +139,7 @@ $ rm -rf sdkconfig build
$ idf.py set-target
```
-For SPI, could be onr of `esp32`, `esp32s2`, `esp32s3`, `esp32c2`, `esp32c3`, `esp32c6`
+For SPI, could be one of `esp32`, `esp32s2`, `esp32s3`, `esp32c2`, `esp32c3`, `esp32c6`, `esp32c5`
* Execute following command to configure the project
```
$ idf.py menuconfig
@@ -123,6 +157,18 @@ $ idf.py -p build flash
$ idf.py -p monitor
```
+> [!NOTE}
+> For `esp32c2`, the standard configuration (which runs Wi-Fi and Bluetooth) disables the [Network Split Feature](Network_Split.md) due to lack of memory. There is a customized configuration for `esp32c2`, for wifi-only operation with Network Split enabled. This configuration disables Bluetooth to save memory.
+>
+> To use this configuration, execute
+>
+> ```sh
+> rm sdkconfig
+> idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.esp32c2.wifionly" menuconfig
+> ```
+>
+> Save the configuration. You can now run `idf.py` with the `build`, `flash` and `monitor` options as per normal.
+
## 3. Checking the Setup
- Firmware log
diff --git a/esp_hosted_fg/docs/Linux_based_host/UART_setup.md b/esp_hosted_fg/docs/Linux_based_host/UART_setup.md
index 7d514c8757..57f3834702 100644
--- a/esp_hosted_fg/docs/Linux_based_host/UART_setup.md
+++ b/esp_hosted_fg/docs/Linux_based_host/UART_setup.md
@@ -1,9 +1,11 @@
# Bluetooth/BLE connectivity Setup over UART
-| Supported Chipsets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S3 | ESP32-C6 |
-| ------------------ | ----- | -------- | -------- | -------- | -------- |
-| 4 line UART supported | yes | no | yes | yes | no |
-| 2 line UART supported | yes | yes | yes | yes | yes |
+| Supported Chipsets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S3 | ESP32-C6 | ESP32-C5 | ESP32-S2 |
+| ------------------ | :---: | :------: | :------: | :------: | :------: | :------: | :------: |
+| 4 line UART | T | NT | T | T | NT | NT | T |
+| 2 line UART | NT | T | NT | NT | T | T | NT |
+
+T - **Tested**, NT - **Not Tested**
In this section, ESP chipset provides a way to run Bluetooth/BLE over UART interface.
Please connect ESP peripheral to Raspberry-Pi with jumper cables (preferably PCB) as mentioned below.
@@ -26,6 +28,12 @@ Raspberry-Pi pinout can be found [here!](https://pinout.xyz/pinout/uart)
#### Four Line UART setup
+> [!NOTE]
+>
+> For UART protocol
+> - Host TX is to be connected to slave RX & vice versa.
+> - Host CTS is to be connected to slave RTS & vice versa.
+
| Raspberry-Pi Pin Function | Raspberry-Pi Pin | ESP32 | ESP32-S3 | ESP32-C3 | ESP32 Pin Function |
|:-------:|:--------:|:---------:|:--------:|:--------:|:--------:|
| RX | 10 | IO5 | IO17 | IO5 | TX |
@@ -39,15 +47,21 @@ Sample SPI+UART setup image looks like:
#### Two Line UART setup
+> [!NOTE]
+>
+> For UART protocol, Host TX is connected to slave RX & vice versa.
-| Raspberry-Pi Pin Function | Raspberry-Pi Pin | ESP32-C2 | ESP32-C6 | ESP Function |
-|:-------:|:--------:|:---------:|:--------:|:--------:|
-| RX | 10 | IO5 | IO5 | TX |
-| TX | 8 | IO18 | IO12 | RX |
+| Raspberry-Pi Pin Function | Raspberry-Pi Pin | ESP32-C2 | ESP32-C5 | ESP32-C6 | ESP Function |
+|:-------:|:--------:|:---------:|:--------:|:--------:|:--------:|
+| RX | 10 | IO5 | IO5 | IO5 | TX |
+| TX | 8 | IO1 | IO23 | IO12 | RX |
-Note:
-- ESP32-C2 only
- - Although, `HCI with UART` is supported on `ESP32-C2`, `Wi-Fi + Bluetooth` (together) when used with `SPI+UART` setup, Bluetooth on UART works fine but Wi-Fi on SPI faces low throughput problem. By the time this is rectified, please use 'SPI only' i.e. `HCI over SPI` and `Wi-Fi over SPI` transport combination. In `SPI only` setup, there is no such limitation.
+> [ !CAUTION ]
+> - ESP32-C2 only
+> - ESP32-C2 has much less IRAM, without PSRAM support.
+> - With `SPI+UART` mode, i.e. Wi-Fi on SPI & BLE over UART mode, Wi-Fi on SPI faces low throughput problem when uart is loaded.
+> - With `SPI only` mode, i.e. Wi-Fi & BLE, both, running over SPI, both, Wi-Fi and Bluetooth work smooth.
+> - Conclusion, For `ESP32-C2`, prefer using `SPI only` mode.
### 1.2 Raspberry-Pi Software Setup
@@ -150,7 +164,7 @@ $ idf.py menuconfig
- Set Bluetooth over UART
- ESP32 / ESP32-C3/S3
- navigate to `Component config -> Bluetooth -> Bluetooth controller -> HCI mode`, select `UART(H4)`
- - ESP32-C2/C6
+ - ESP32-C2/C5/C6
- Navigate to `Component config -> Bluetooth -> Bluetooth -> Controller`, select `Enabled` (Should be enabled by default)
- Navigate to `Component config -> Bluetooth -> Controller Options -> HCI Config -> Select HCI interface`, select `uart`
- Navigate to `Component config > Bluetooth > Controller Options > HCI Config`
@@ -158,6 +172,9 @@ $ idf.py menuconfig
- ESP32-C2
- Change `HCI uart Tx gpio` to `5`
- Change `HCI uart Rx gpio` to `18`
+ - ESP32-C2
+ - Change `HCI uart Tx gpio` to `5`
+ - Change `HCI uart Rx gpio` to `23`
- ESP32-C6
- Change `HCI uart Tx gpio` to `5`
- Change `HCI uart Rx gpio` to `12`
diff --git a/esp_hosted_fg/docs/Linux_based_host/rpi_esp32c6_sdio_setup.png b/esp_hosted_fg/docs/Linux_based_host/rpi_esp32c6_sdio_setup.png
new file mode 100755
index 0000000000..bdbffb0688
Binary files /dev/null and b/esp_hosted_fg/docs/Linux_based_host/rpi_esp32c6_sdio_setup.png differ
diff --git a/esp_hosted_fg/docs/Linux_based_host/rpi_esp_sdio_setup.jpeg b/esp_hosted_fg/docs/Linux_based_host/rpi_esp_sdio_setup.jpeg
deleted file mode 100644
index 8400d9712c..0000000000
Binary files a/esp_hosted_fg/docs/Linux_based_host/rpi_esp_sdio_setup.jpeg and /dev/null differ
diff --git a/esp_hosted_fg/docs/MCU_based_host/MCU_based_readme.md b/esp_hosted_fg/docs/MCU_based_host/MCU_based_readme.md
index 527d5349c2..74472365e3 100644
--- a/esp_hosted_fg/docs/MCU_based_host/MCU_based_readme.md
+++ b/esp_hosted_fg/docs/MCU_based_host/MCU_based_readme.md
@@ -2,6 +2,12 @@
- Directory structure for microprocessor based host is explained [here](directory_structure.md)
- Below diagram shows hardware and software block diagram for a typical MCU based system built with ESP-Hosted.
+
+> [!CAUTION]
+>
+> MCU support in ESP-Hosted-FG is now deprecated. For all MCU-based applications, please use the dedicated [ESP-Hosted-MCU repository](https://github.com/espressif/esp-hosted-mcu) instead. The information below is kept for backward compatibility only.
+
+

# 1. Development Environment Setup
diff --git a/esp_hosted_fg/docs/common/c_demo.md b/esp_hosted_fg/docs/common/c_demo.md
index 8d89c7d3c9..4735656a4c 100644
--- a/esp_hosted_fg/docs/common/c_demo.md
+++ b/esp_hosted_fg/docs/common/c_demo.md
@@ -3,10 +3,31 @@
### Introduction
- This demo application showcases a way to configure control path.
- App is available under directory [c_support/](../../host/linux/host_control/c_support)
-- App interacts with `Hosted Control Library` using [control path APIs](./ctrl_apis.md). APIs header could be found at [ctrl_api.h](../../host/control_lib/include/ctrl_api.h)
+- App interacts with [`Hosted Control Library`](../../host/control_lib) using [control path APIs](./ctrl_apis.md).
+- API header could be found at [ctrl_api.h](../../host/control_lib/include/ctrl_api.h)
+
+## Sample Applications
+
+The c_support directory contains several applications to interface with ESP devices:
+
+- 1. `test.out` \
+Uses **test.c**: Simplistic demo application to test control RPC APIs
+
+- 2. `stress.out` \
+Uses **stress.c**: Internal stress testing for control path APIs
+
+- 3. `hosted_shell.out` \
+**hosted_shell.c**: Interactive shell interface extended over test
+
+- 4. `hosted_daemon.out` \
+**hosted_daemon.c**: Background daemon for network management
+
+These apps work over [Hosted Control Library](../../host/control_lib/) as base.\
+These apps also use **app_custom_rpc.c**, which provides simple Custom RPC implementation for application-specific communication
+
+## 1. Demo App (test.c)
### Source files
-- This demo app works over [Hosted Control Library](../../host/control_lib/)
- Source files are [test.c](../../host/linux/host_control/c_support/test.c) and [test_utils.c](../../host/linux/host_control/c_support/test_utils.c)
- Config file : [ctrl_config.h](../../host/linux/host_control/c_support/ctrl_config.h)
@@ -51,11 +72,20 @@
|||
| get_fw_version | Get Firmware Version |
|||
+| get_dhcp_dns_status | Get DHCP and DNS status (Works if Network Split is enabled) |
+|||
| set_country_code | Set Country Code with IEEE802.11d disabled |
| set_country_code_enabled | Set Country Code with IEEE802.11d enabled |
| get_country_code | Get the current Country Code|
+|||
+| send_packed_data__only_ack | Custom RPC demo 1 - send data with acknowledgement only |
+| send_packed_data__echo_back_as_response | Custom RPC demo 2 - send data with echo back as response |
+| send_packed_data__echo_back_as_event | Custom RPC demo 3 - send data with echo back as event |
+
+
> [!NOTE]
+>
> 1. With IEEE802.11d enabled, the country info of the AP to which the station is connected is used. E.g. if the configured country is US and the country info of the AP to which the station is connected is JP then the country info that will be used is JP. If the station disconnected from the AP the country info is set back to the country info of the station automatically, US in the example.
> 2. With IEEE802.11d disabled, then the configured country info is used always.
> 3. When the country info is changed because of configuration or because the station connects to a different external AP, the country IE in probe response/beacon of the soft-AP is also changed.
@@ -77,7 +107,9 @@ $ sudo ./test.out \
set_wifi_max_tx_power || get_wifi_curr_tx_power || \
ota || \
enable_wifi || disable_wifi || enable_bt || disable_bt || get_fw_version || \
- set_country_code || set_country_code_enabled || get_country_code
+ set_country_code || set_country_code_enabled || get_country_code || \
+ get_dhcp_dns_status || send_packed_data__only_ack || \
+ send_packed_data__echo_back_as_response || send_packed_data__echo_back_as_event
]
```
For example,
@@ -90,16 +122,18 @@ $ sudo ./test.out get_wifi_mode
- After `sta_connect`, User needs to run the DHCP client to obtain an IP address from an external AP. Then network data path will be open for higher applications to use `ethsta0` interface for data communication. For an example as below.
```sh
- $ sudo dhclient ethsta0 -r
-
- $ sudo dhclient ethsta0 -v
+ $ sudo killall dhclient # kill earlier dhclient processes
+ $ sudo dhclient ethsta0 -v # Run DHCP client to get IP from AP/Router
```
- Disconnect AP in station mode
- After disconnect, user can remove DHCP lease. For example,
```sh
- $ sudo dhclient ethsta0 -r
+ $ sudo dhclient ethsta0 -r # clean-up earlier assigned DHCP IP
+ and
+ $ sudo killall dhclient # kill earlier dhclient processes
+
```
- For softAP vendor specific IE
@@ -130,9 +164,9 @@ $ sudo ./test.out get_wifi_mode
- Set Wi-Fi max transmit power
- This is just a request to Wi-Fi driver. The actual power set may slightly differ from exact requested power.
-# C stress Application
+## 2. Stress Testing Application (stress.c)
-[stress.c](../../host/linux/host_control/c_support/stress.c) use for stress testing of control path APIs. It is very similar to demo app, just additionally allows multiple iteration testing.
+[stress.c](../../host/linux/host_control/c_support/stress.c) is used for internal stress testing of control path APIs. It is similar to the demo app but additionally allows multiple iteration testing.
### Source files
- Source files are [stress.c](../../host/linux/host_control/c_support/stress.c) and [test_utils.c](../../host/linux/host_control/c_support/test_utils.c)
@@ -155,5 +189,129 @@ $ sudo ./stress.out [get_sta_mac_addr] [get_softap_m
For example:
$ sudo ./stress.out 10 scan sta_connect sta_disconnect ap_start sta_list ap_stop wifi_tx_power
+```
+
+## 3. Interactive Shell Application (hosted_shell.c)
+
+[hosted_shell.c](../../host/linux/host_control/c_support/hosted_shell.c) provides an interactive shell interface for controlling the ESP device. It offers a more user-friendly way to interact with the device through a command-line shell with features like command auto-completion, and hints.
+
+
+### Features
+- Interactive command-line interface
+- Tab completion for commands and arguments
+- Command hints
+- Help documentation for all commands
+
+### How to build and run
+
+###### replxx
+`replxx` is used as command line processor which is shell handler. You are free to change to your preffered shell handler.
+
+You need to install replxx by following GitHub page, https://github.com/AmokHuginnsson/replxx.
+
+```sh
+# install replxx software from above link first
+$ make hosted_shell
+$ sudo ./hosted_shell.out
+```
+
+In the shell, you can type double tab to see all available commands
+## 4. Network Management Daemon (hosted_daemon.c)
+
+[hosted_daemon.c](../../host/linux/host_control/c_support/hosted_daemon.c) implements a background daemon that manages network interfaces for ESP device. It handles network events and automatically configures interfaces based on events from the ESP device.
+
+### Features
+- Runs as a daemon in the background
+- Automatically manages network interfaces
+- Handles DHCP and DNS configuration
+- Responds to network state changes from ESP device
+
+### How to build and run
+```sh
+$ make hosted_daemon
+$ sudo ./hosted_daemon.out
+```
+
+To run in foreground mode (for debugging):
+```sh
+$ sudo ./hosted_daemon.out -f
```
+
+# Custom RPC Communication (app_custom_rpc.c)
+
+[app_custom_rpc.c](../../host/linux/host_control/c_support/app_custom_rpc.c) demonstrates how to use the Custom Remote Procedure Call (RPC) functionality of ESP Hosted. This allows application-specific communication between the host and ESP device.
+
+### Features
+- Demonstrates custom communication between host and ESP device
+- Allows sending events and requests with custom data
+- Shows how to handle custom responses and events
+
+> [!NOTE]
+>
+> 1. Provides APIs for sending packed data between host and ESP device.
+> 2. User is responsible for serializing data before sending and deserializing after receiving.
+
+### Example Demo Functions
+- `custom_rpc_demo1_request_only_ack`: Sends a request with only acknowledgement (uses `CUSTOM_RPC_REQ_ID__ONLY_ACK`)
+- `custom_rpc_demo2_request_echo_back_as_response`: Sends data and receives an echo back as response (uses `CUSTOM_RPC_REQ_ID__ECHO_BACK_RESPONSE`)
+- `custom_rpc_demo3_request_echo_back_as_event`: Sends data and receives echo back as an event (uses `CUSTOM_RPC_REQ_ID__ECHO_BACK_AS_EVENT` and `CUSTOM_RPC_EVENT_ID__DEMO_ECHO_BACK_REQUEST`)
+
+These demos are integrated in applications like `test.out` and `hosted_shell.out` and demonstrate the complete flow of custom RPC communication between host and ESP device.
+It uses underlying control path API for reliable communication.
+
+> [!NOTE]
+>
+> Current APIs discussed can carry your own 'packed' data from host to slave or vice versa. If you need pure serialised message handling, you can add new message in esp_hosted_config.proto and handle similar to other existing RPC protobuf messages
+
+### Adding New Application-Specific RPC
+
+1. Get ready with your own packed data in bytes. **The data would be assumed to be already serialized**, outside knowledge of ESP-Hosted
+2. User can extend functionalities to add new user request IDs and Event IDs in file [esp_hosted_custom_rpc.h](../../host/linux/host_control/include/esp_hosted_custom_rpc.h)
+3. Implementation of **host handlers** & adding own message types:
+- Header
+ - Use the provided APIs in `esp_hosted_custom_rpc.h` to send and receive custom RPC data
+ - Optionally add new Request or Event IDs to the existing enums:
+ ```c
+ typedef enum {
+ CUSTOM_RPC_REQ_ID__ONLY_ACK = 1,
+ CUSTOM_RPC_REQ_ID__ECHO_BACK_RESPONSE,
+ CUSTOM_RPC_REQ_ID__ECHO_BACK_AS_EVENT,
+ /* Add your custom request IDs here */
+ } custom_rpc_req_id_e;
+
+ typedef enum {
+ CUSTOM_RPC_EVENT_ID__DEMO_ECHO_BACK_REQUEST = 1,
+ /* Add your custom event IDs here */
+ } custom_rpc_event_id_e;
+ ```
+
+- Host
+ - Add your custom `requests` or `events` in [app_custom_rpc.c](../../host/linux/host_control/c_support/app_custom_rpc.c) and [app_custom_rpc.h](../../host/linux/host_control/c_support/app_custom_rpc.h).
+ - Optionally, add your own Request and Message ID handling functions similar to the existing demo functions
+
+ > [!CAUTION] Custom RPC Request - Response
+ >
+ > 1. The handlers in these requests should be as concise as possible.
+ > 2. Although it is not interrupt context, try not to have blocking calls in the response handler, as this function is called as callback.
+
+- Slave
+ - In [slave_control.c](../../esp/esp_driver/network_adapter/main/slave_control.c), the default response handler for underlying RPC request handler is called with:
+ ```c
+ register_custom_rpc_unserialised_req_handler()
+ ```
+ - [esp_hosted_coprocessor.c](../../esp/esp_driver/network_adapter/main/esp_hosted_coprocessor.c): The default response handler for these requests is handled with:
+ ```c
+ register_custom_rpc_unserialised_req_handler(handle_custom_unserialised_rpc_request);
+ ```
+ - For your own message IDs, add cases in `handle_custom_unserialised_rpc_request()`
+
+ > [!CAUTION] Custom RPC events
+ >
+ > 1. The handlers in these requests should be as concise as possible.
+ > 2. Although it is not interrupt context, try not to have blocking calls in the response handler, as this function is called as callback.
+ > 3. Refrain sending any synchronous RPC request as this would make it dead block (RPC Request `without` a response function callback registered - > `Sync RPC Req`)
+ > 4. Sending any 'asynchronous' RPC request is supported (RPC Request `with` a response function callback registered - > `Async RPC Req`)
+
+ - You can also trigger events instead of immediate responses as demonstrated in `CUSTOM_RPC_REQ_ID__ECHO_BACK_AS_EVENT`
+ - To add your own event, you can re-use `create_and_send_custom_rpc_unserialised_event()`
diff --git a/esp_hosted_fg/docs/common/ctrl_apis.md b/esp_hosted_fg/docs/common/ctrl_apis.md
index 33e0d407d8..39bbe40e76 100644
--- a/esp_hosted_fg/docs/common/ctrl_apis.md
+++ b/esp_hosted_fg/docs/common/ctrl_apis.md
@@ -1498,6 +1498,180 @@ Ethernet interface name
---
+### 1.33 [ctrl_cmd_t](#416-struct-ctrl_cmd_t) * get_dhcp_dns_status([ctrl_cmd_t](#416-struct-ctrl_cmd_t) req)
+
+This is used to get the DHCP and DNS status for the specified interface
+
+#### Parameters
+- `ctrl_cmd_t req` :
+Control request as input with following
+ - `req.ctrl_resp_cb` : optional
+ - `NULL` :
+ - Treat as synchronous procedure
+ - Application would be blocked till response is received from hosted control library
+ - `Non-NULL` :
+ - Treat as asynchronous procedure
+ - Callback function of type [ctrl_resp_cb_t](#31-typedef-int-ctrl_resp_cb_t-ctrl_cmd_t-resp) is registered
+ - Application would be will **not** be blocked for response and API is returned immediately
+ - Response from ESP when received by hosted control library, this callback would be called
+ - `req.cmd_timeout_sec` : optional
+ - Timeout duration to wait for response in sync or async procedure
+ - Default value is 30 sec
+ - In case of async procedure, response callback function with error control response would be called to wait for response
+
+#### Return
+
+- `ctrl_cmd_t *app_resp` :
+dynamically allocated response pointer of type struct `ctrl_cmd_t *`
+ - **`resp->resp_event_status`** :
+ - 0 : `SUCCESS`
+ - != 0 : `FAILURE`
+ - **`app_resp->u.dhcp_dns_status.iface`** :
+ - Interface type for which status is returned
+ - **`app_resp->u.dhcp_dns_status.net_link_up`** :
+ - 1: Network link is up
+ - 0: Network link is down
+ - **`app_resp->u.dhcp_dns_status.dhcp_up`** :
+ - 1: DHCP is up
+ - 0: DHCP is down
+ - **`app_resp->u.dhcp_dns_status.dhcp_ip`** :
+ - IP address assigned via DHCP
+ - **`app_resp->u.dhcp_dns_status.dhcp_nm`** :
+ - Network mask
+ - **`app_resp->u.dhcp_dns_status.dhcp_gw`** :
+ - Gateway address
+ - **`app_resp->u.dhcp_dns_status.dns_up`** :
+ - 1: DNS is up
+ - 0: DNS is down
+ - **`app_resp->u.dhcp_dns_status.dns_ip`** :
+ - DNS server IP address
+ - **`app_resp->u.dhcp_dns_status.dns_type`** :
+ - Type of DNS server configuration
+- `NULL` :
+ - Synchronous procedure: Failure
+ - Asynchronous procedure:
+ - Expected as NULL return value as response is processed in callback function
+ - In callback function, parameter `ctrl_cmd_t *app_resp` behaves same as above
+
+#### Note
+- Application is expected to free `ctrl_cmd_t *app_resp`
+
+---
+
+### 1.34 [ctrl_cmd_t](#416-struct-ctrl_cmd_t) * set_dhcp_dns_status([ctrl_cmd_t](#416-struct-ctrl_cmd_t) req)
+
+This is used to set the DHCP and DNS status for the specified interface
+
+#### Parameters
+- `ctrl_cmd_t req` :
+Control request as input with following
+ - **`req.u.dhcp_dns_status.iface`** :
+ - Interface type for which to set status
+ - **`req.u.dhcp_dns_status.net_link_up`** :
+ - 1: Set network link up
+ - 0: Set network link down
+ - **`req.u.dhcp_dns_status.dhcp_up`** :
+ - 1: Enable DHCP
+ - 0: Disable DHCP
+ - **`req.u.dhcp_dns_status.dhcp_ip`** :
+ - IP address to assign
+ - **`req.u.dhcp_dns_status.dhcp_nm`** :
+ - Network mask to set
+ - **`req.u.dhcp_dns_status.dhcp_gw`** :
+ - Gateway address to set
+ - **`req.u.dhcp_dns_status.dns_up`** :
+ - 1: Enable DNS
+ - 0: Disable DNS
+ - **`req.u.dhcp_dns_status.dns_ip`** :
+ - DNS server IP address to use
+ - **`req.u.dhcp_dns_status.dns_type`** :
+ - Type of DNS server configuration to use
+ - `req.ctrl_resp_cb` : optional
+ - `NULL` :
+ - Treat as synchronous procedure
+ - Application would be blocked till response is received from hosted control library
+ - `Non-NULL` :
+ - Treat as asynchronous procedure
+ - Callback function of type [ctrl_resp_cb_t](#31-typedef-int-ctrl_resp_cb_t-ctrl_cmd_t-resp) is registered
+ - Application would be will **not** be blocked for response and API is returned immediately
+ - Response from ESP when received by hosted control library, this callback would be called
+ - `req.cmd_timeout_sec` : optional
+ - Timeout duration to wait for response in sync or async procedure
+ - Default value is 30 sec
+ - In case of async procedure, response callback function with error control response would be called to wait for response
+
+#### Return
+
+- `ctrl_cmd_t *app_resp` :
+dynamically allocated response pointer of type struct `ctrl_cmd_t *`
+ - **`resp->resp_event_status`** :
+ - 0 : `SUCCESS`
+ - != 0 : `FAILURE`
+- `NULL` :
+ - Synchronous procedure: Failure
+ - Asynchronous procedure:
+ - Expected as NULL return value as response is processed in callback function
+ - In callback function, parameter `ctrl_cmd_t *app_resp` behaves same as above
+
+#### Note
+- Application is expected to free `ctrl_cmd_t *app_resp`
+
+---
+
+### 1.35 [ctrl_cmd_t](#416-struct-ctrl_cmd_t) * send_custom_rpc_unserialised_req_to_slave([ctrl_cmd_t](#416-struct-ctrl_cmd_t) req)
+
+This is used to send custom RPC messages directly to the ESP in an unserialised format.
+
+#### Parameters
+- `ctrl_cmd_t req` :
+Control request as input with following
+ - **`req.u.custom_rpc_unserialised_data.custom_msg_id`** :
+ - Custom message ID to identify the RPC request
+ - **`req.u.custom_rpc_unserialised_data.data`** :
+ - Binary data buffer containing the unserialised message
+ - **`req.u.custom_rpc_unserialised_data.data_len`** :
+ - Size of the data buffer in bytes
+ - **`req.u.custom_rpc_unserialised_data.free_func`** :
+ - Function to free the data buffer when no longer needed
+ - `req.ctrl_resp_cb` : optional
+ - `NULL` :
+ - Treat as synchronous procedure
+ - Application would be blocked till response is received from hosted control library
+ - `Non-NULL` :
+ - Treat as asynchronous procedure
+ - Callback function of type [ctrl_resp_cb_t](#31-typedef-int-ctrl_resp_cb_t-ctrl_cmd_t-resp) is registered
+ - Application would be will **not** be blocked for response and API is returned immediately
+ - Response from ESP when received by hosted control library, this callback would be called
+ - `req.cmd_timeout_sec` : optional
+ - Timeout duration to wait for response in sync or async procedure
+ - Default value is 30 sec
+ - In case of async procedure, response callback function with error control response would be called to wait for response
+
+#### Return
+
+- `ctrl_cmd_t *app_resp` :
+dynamically allocated response pointer of type struct `ctrl_cmd_t *`
+ - **`resp->resp_event_status`** :
+ - 0 : `SUCCESS`
+ - != 0 : `FAILURE`
+ - **`app_resp->u.custom_rpc_unserialised_data.custom_msg_id`** :
+ - Custom message ID from the response, which should match the request
+ - **`app_resp->u.custom_rpc_unserialised_data.data`** :
+ - Binary data buffer containing the unserialised response message
+ - **`app_resp->u.custom_rpc_unserialised_data.data_len`** :
+ - Size of the response data buffer in bytes
+- `NULL` :
+ - Synchronous procedure: Failure
+ - Asynchronous procedure:
+ - Expected as NULL return value as response is processed in callback function
+ - In callback function, parameter `ctrl_cmd_t *app_resp` behaves same as above
+
+#### Note
+- Application is expected to properly allocate and free the data buffer for both request and response
+- Application is expected to free `ctrl_cmd_t *app_resp`
+
+---
+
## 2. Control path events
- Event are something that the application would subscribe to and get notification when some condition occurs. This way application doesnot have to poll for that condition
- Event subscribe
@@ -1513,8 +1687,8 @@ Ethernet interface name
### 2.2 Heartbeat
- Application need to subscribe heartbeat event to get liveliness status of ESP
-- Application need to configure heartbeat using API [config_heartbeat()](#122-ctrl_cmd_t-config_heartbeatctrl_cmd_t-req)
-- This event notification will occur every duration seconds as mentioned in [config_heartbeat()](#122-ctrl_cmd_t-config_heartbeatctrl_cmd_t-req)
+- Application need to configure heartbeat using API [config_heartbeat()](#125-ctrl_cmd_t-config_heartbeatctrl_cmd_t-req)
+- This event notification will occur every duration seconds as mentioned in [config_heartbeat()](#125-ctrl_cmd_t-config_heartbeatctrl_cmd_t-req)
- Events are only notified if application subscribes this event **and** have configured heartbeat
### 2.3 Station disconnected from AP
@@ -1525,6 +1699,16 @@ Ethernet interface name
- This event is useful to understand if any station disconnection with ESP softAP
- MAC address of station disconnecting is given to application
+### 2.5 Station connected to AP
+- This event notifies when the ESP station successfully connects to an external AP
+- Provides information about the connected AP including SSID, BSSID, channel, and authentication mode
+- Application can use this to know when the connection is established without polling
+
+### 2.6 Station connected to ESP SoftAP
+- This event notifies when an external station connects to the ESP SoftAP
+- Provides information about the connected station including MAC address and association ID
+- Application can use this to track connected clients and perform any necessary setup
+
## 3. Function callbacks
### 3.1 typedef int (*ctrl_resp_cb_t) (ctrl_cmd_t * resp)
@@ -1768,7 +1952,7 @@ This contains the Wi-Fi power map value to be set or get using API [wifi_set_max
- `int power` :
- The value set by this API will be mapped to the max_tx_power of the structure wifi_country_t variable in Wi-Fi driver
- - Mapping Table {wifi_max_tx_power, max_tx_power} = {{8, 2}, {20, 5}, {28, 7}, {34, 8}, {44, 11}, {52, 13}, {56, 14}, {60, 15}, {66, 16}, {72, 18}, {80, 20}}
+ - Mapping Table {`wifi_max_tx_power`, `max_tx_power`} = {{8, 2}, {20, 5}, {28, 7}, {34, 8}, {44, 11}, {52, 13}, {56, 14}, {60, 15}, {66, 16}, {72, 18}, {80, 20}}
- Input parameter `wifi_max_tx_power` unit is 0.25dBm, range is [8, 84] corresponding to `2dBm to 20dBm`
- Relationship between set value and actual value. As follows: {set value range, actual value} = {{[8, 19],8}, {[20, 27],20}, {[28, 33],28}, {[34, 43],34}, {[44, 51],44}, {[52, 55],52}, {[56, 59],56}, {[60, 65],60}, {[66, 71],66}, {[72, 79],72}, {[80, 84],80}}
@@ -1835,6 +2019,147 @@ Union of some of the control message, which need extra data to be passed/parsed
---
+### 4.17 _struct_ `fw_version_t`:
+
+- Used for firmware version information returned by [get_fw_version()](#122-ctrl_cmd_t-get_fw_versionctrl_cmd_t-req)
+
+- `char project_name[3]` :
+ - Two-letter code identifying the firmware (default is "FG")
+- `uint32_t major_1` :
+ - First major version number component
+- `uint32_t major_2` :
+ - Second major version number component
+- `uint32_t minor` :
+ - Minor version number
+- `uint32_t rev_patch_1` :
+ - First revision patch number
+- `uint32_t rev_patch_2` :
+ - Second revision patch number
+
+---
+
+### 4.18 _struct_ `country_code_t`:
+
+- Used for Wi-Fi country code settings in [wifi_set_country_code()](#123-ctrl_cmd_t-wifi_set_country_codectrl_cmd_t-req) and [wifi_get_country_code()](#124-ctrl_cmd_t-wifi_get_country_codectrl_cmd_t-req)
+
+- `char country[COUNTRY_CODE_LEN]` :
+ - Country code string, typically 2 characters for country code + 1 character for environment indicator
+- `bool ieee80211d_enabled` :
+ - Enable/disable IEEE 802.11d support
+
+---
+
+### 4.19 _struct_ `dhcp_dns_status_t`:
+
+- Used for DHCP and DNS status in [set_dhcp_dns_status()](#134-ctrl_cmd_t-set_dhcp_dns_statusctrl_cmd_t-req) and [get_dhcp_dns_status()](#133-ctrl_cmd_t-get_dhcp_dns_statusctrl_cmd_t-req)
+
+- `int32_t iface` :
+ - Interface identifier
+- `int32_t net_link_up` :
+ - 1: Network link is up, 0: Network link is down
+- `int32_t dhcp_up` :
+ - 1: DHCP is up, 0: DHCP is down
+- `char dhcp_ip[IP_STR_LEN]` :
+ - IP address assigned via DHCP as a string
+- `char dhcp_nm[IP_STR_LEN]` :
+ - Network mask as a string
+- `char dhcp_gw[IP_STR_LEN]` :
+ - Gateway address as a string
+- `int32_t dns_up` :
+ - 1: DNS is up, 0: DNS is down
+- `char dns_ip[IP_STR_LEN]` :
+ - DNS server IP address as a string
+- `int32_t dns_type` :
+ - Type of DNS server configuration
+
+---
+
+### 4.20 _struct_ `custom_rpc_unserialised_data_t`:
+
+- Used for custom RPC communication in [send_custom_rpc_unserialised_req_to_slave()](#135-ctrl_cmd_t-send_custom_rpc_unserialised_req_to_slavectrl_cmd_t-req)
+
+- `uint32_t custom_msg_id` :
+ - Custom message ID to identify the RPC request/response
+- `uint16_t data_len` :
+ - Size of the data buffer in bytes
+- `custom_data_free_func_t free_func` :
+ - Function to free the data buffer
+- `uint8_t *data` :
+ - Binary data buffer for the unserialised message
+
+---
+
+### 4.21 _struct_ `event_sta_conn_t`:
+
+- Used in the station connection event structure when station connects to an AP
+- Member of the union in control command structure
+
+- `int32_t resp` :
+ - Response status of the event
+- `uint8_t ssid[SSID_LENGTH]` :
+ - SSID of the AP that station connected to
+- `uint32_t ssid_len` :
+ - Length of the SSID
+- `uint8_t bssid[BSSID_LENGTH]` :
+ - BSSID (MAC address) of the AP
+- `uint32_t channel` :
+ - Channel on which the connection was established
+- `int32_t authmode` :
+ - Authentication mode used for the connection
+- `int32_t aid` :
+ - Association ID assigned by the AP
+
+---
+
+### 4.22 _struct_ `event_softap_sta_conn_t`:
+
+- Used in the station connection event structure when a station connects to ESP SoftAP
+- Member of the union in control command structure
+
+- `int32_t resp` :
+ - Response status of the event
+- `uint8_t mac[BSSID_LENGTH]` :
+ - MAC address of the station that connected
+- `uint32_t aid` :
+ - Association ID assigned to the station
+- `bool is_mesh_child` :
+ - Indicates if the station is a mesh child node (ESP mesh networking feature)
+
+---
+
+### 4.23 _struct_ `event_softap_sta_disconn_t`:
+
+- Used in the station disconnection event structure when a station disconnects from ESP SoftAP
+- Member of the union in control command structure
+
+- `int32_t resp` :
+ - Response status of the event
+- `uint8_t mac[BSSID_LENGTH]` :
+ - MAC address of the station that disconnected
+- `uint32_t aid` :
+ - Association ID that was assigned to the station
+- `bool is_mesh_child` :
+ - Indicates if the station was a mesh child node
+- `uint32_t reason` :
+ - Reason code for the disconnection
+
+---
+
+### 4.24 _struct_ `feature_enable_disable_t`:
+
+- Used for enabling or disabling specific features in [feature_config()](#132-ctrl_cmd_t-feature_configctrl_cmd_t-req)
+
+- `uint32_t feature` :
+ - Feature identifier from the `hosted_features_t` enum
+ - 1 : `HOSTED_WIFI` - Wi-Fi functionality
+ - 2 : `HOSTED_BT` - Bluetooth functionality
+ - 3 : `HOSTED_IS_NETWORK_SPLIT_ON` - Network split functionality
+- `bool enable` :
+ - 1: Enable the feature
+ - 0: Disable the feature
+
+---
+
## 5. Enumerations
### 5.1 _enum_ `wifi_mode_e` \
@@ -1919,10 +2244,23 @@ _Values_:
#### Note
This structure is map to `CtrlMsgType` from `esp_hosted_config.pb-c.h`
-### 5.8 _enum_ `AppMsgId_e` :
+### 5.8 _enum_ `HostedFeature` :
+Enumeration for available features that can be enabled or disabled with feature_config() API
+_Values_:
+- `HOSTED_FEATURE__Hosted_InvalidFeature` = 0 :
+Invalid feature identifier
+- `HOSTED_FEATURE__Hosted_Wifi` = 1 :
+Wi-Fi functionality
+- `HOSTED_FEATURE__Hosted_Bluetooth` = 2 :
+Bluetooth functionality
+- `HOSTED_FEATURE__Hosted_Is_Network_Split_On` = 3 :
+Network split functionality
+---
+
+### 5.9 _enum_ `AppMsgId_e` :
The message id of control msg. This could be one of request, response or event appmsgid_e \
_Values_:
-#### 5.8.1 Requests
+#### 5.9.1 Requests
- `CTRL_REQ_BASE` = 100
- `CTRL_REQ_GET_MAC_ADDR` = 101
- `CTRL_REQ_SET_MAC_ADDR` = 102
@@ -1957,9 +2295,16 @@ _Values_:
- `CTRL_REQ_CONFIG_HEARTBEAT` = 121
-- `CTRL_REQ_MAX` = 122
-
-#### 5.8.2 Responses
+- `CTRL_REQ_ENABLE_DISABLE` = 122
+- `CTRL_REQ_GET_FW_VERSION` = 123
+- `CTRL_REQ_SET_COUNTRY_CODE` = 124
+- `CTRL_REQ_GET_COUNTRY_CODE` = 125
+- `CTRL_REQ_SET_DHCP_DNS_STATUS` = 126
+- `CTRL_REQ_GET_DHCP_DNS_STATUS` = 127
+- `CTRL_REQ_CUSTOM_RPC_UNSERIALISED_MSG` = 128
+- `CTRL_REQ_MAX` = 129
+
+#### 5.9.2 Responses
- `CTRL_RESP_BASE` = 200
- `CTRL_RESP_GET_MAC_ADDR` = 201
- `CTRL_RESP_SET_MAC_ADDRESS` = 202
@@ -1989,20 +2334,31 @@ _Values_:
- `CTRL_RESP_OTA_END` = 218
-- `CTRL_RESP_SET_WIFI_MAX_TX_POWER` = 219
-- `CTRL_RESP_GET_WIFI_CURR_TX_POWER` = 220
+- `CTRL_RESP_SET_WIFI_MAX_TX_POWER` = 219
+- `CTRL_RESP_GET_WIFI_CURR_TX_POWER` = 220
-- `CTRL_RESP_CONFIG_HEARTBEAT` = 221
-- `CTRL_RESP_MAX` = 222
+- `CTRL_RESP_CONFIG_HEARTBEAT` = 221
+- `CTRL_RESP_ENABLE_DISABLE` = 222
+- `CTRL_RESP_GET_FW_VERSION` = 223
+- `CTRL_RESP_SET_COUNTRY_CODE` = 224
+- `CTRL_RESP_GET_COUNTRY_CODE` = 225
+- `CTRL_RESP_SET_DHCP_DNS_STATUS` = 226
+- `CTRL_RESP_GET_DHCP_DNS_STATUS` = 227
+- `CTRL_RESP_CUSTOM_RPC_UNSERIALISED_MSG` = 228
+- `CTRL_RESP_MAX` = 229
-#### 5.8.3 Events
+#### 5.9.3 Events
- `CTRL_EVENT_BASE` = 300
- `CTRL_EVENT_ESP_INIT` = 301
- `CTRL_EVENT_HEARTBEAT` = 302
- `CTRL_EVENT_STATION_DISCONNECT_FROM_AP` = 303
- `CTRL_EVENT_STATION_DISCONNECT_FROM_ESP_SOFTAP` = 304
-- `CTRL_EVENT_MAX` = 305
+- `CTRL_EVENT_STATION_CONNECTED_TO_AP` = 305
+- `CTRL_EVENT_STATION_CONNECTED_TO_ESP_SOFTAP` = 306
+- `CTRL_EVENT_DHCP_DNS_STATUS` = 307
+- `CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG` = 308
+- `CTRL_EVENT_MAX` = 309
#### Note
This enum is mapping to `CtrlMsgId` from `esp_hosted_config.pb-c.h`
diff --git a/esp_hosted_fg/docs/icons/esp32c5.svg b/esp_hosted_fg/docs/icons/esp32c5.svg
new file mode 100644
index 0000000000..10063702cb
--- /dev/null
+++ b/esp_hosted_fg/docs/icons/esp32c5.svg
@@ -0,0 +1,24 @@
+
diff --git a/esp_hosted_fg/docs/icons/wifi_dual_band.svg b/esp_hosted_fg/docs/icons/wifi_dual_band.svg
new file mode 100644
index 0000000000..c627e3f143
--- /dev/null
+++ b/esp_hosted_fg/docs/icons/wifi_dual_band.svg
@@ -0,0 +1,24 @@
+
diff --git a/esp_hosted_fg/docs/sdio_protocol.md b/esp_hosted_fg/docs/sdio_protocol.md
index b85f058a5b..2bb93e7258 100644
--- a/esp_hosted_fg/docs/sdio_protocol.md
+++ b/esp_hosted_fg/docs/sdio_protocol.md
@@ -5,8 +5,8 @@ This section explains the SDIO communication protocol between a host and ESP per
### 1.1 SDIO transport layer
-| Supported Targets | ESP32 | ESP32-C6 |
-| ----------------- | ----- | -------- |
+| Supported Targets | ESP32 | ESP32-C6 | ESP32-C5 |
+| ----------------- | ----- | -------- | -------- |
ESP peripheral advertises 2 SDIO functions. ESP-Hosted solution is implemented on function 1. Though function 2 is advertised, it is not in use.
@@ -60,4 +60,3 @@ bit 4: BT mode - BR/EDR only mode
#### 1.1.4 Deinit peripheral device
Host sets bit 1 of 0x3FF5508C interrupt register. This tells ESP peripheral to stop the data path.
-
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/CMakeLists.txt b/esp_hosted_fg/esp/esp_driver/network_adapter/CMakeLists.txt
index d125dfbd6a..b05ee3af72 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/CMakeLists.txt
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/CMakeLists.txt
@@ -26,3 +26,19 @@ set(PROJECT_VER "${PROJECT_VER}")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(network_adapter)
idf_build_set_property(COMPILE_OPTIONS "-fdiagnostics-color=always" APPEND)
+
+if(NOT CONFIG_IDF_TARGET_ESP32C2 AND NOT CONFIG_IDF_TARGET_ESP32C3)
+ idf_component_get_property(lwip lwip COMPONENT_LIB)
+ if(TARGET ${lwip})
+ # Use generator expressions to only apply to non-INTERFACE targets
+ get_target_property(lwip_type ${lwip} TYPE)
+ if(NOT lwip_type STREQUAL "INTERFACE_LIBRARY")
+ message(STATUS "********** Configuring LWIP for network split mode with custom hook **********")
+ target_include_directories(${lwip} PRIVATE "${PROJECT_DIR}/main")
+ target_compile_definitions(${lwip} PRIVATE "-DESP_IDF_LWIP_HOOK_FILENAME=\"esp_hosted_lwip_src_port_hook.h\"")
+ endif()
+ endif()
+else()
+ message(STATUS "********** Skipping LWIP for network split mode with custom hook **********")
+ # Do not reference esp_http_client for esp32c2 and esp32c3
+endif()
\ No newline at end of file
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/CMakeLists.txt b/esp_hosted_fg/esp/esp_driver/network_adapter/main/CMakeLists.txt
index 8af1ec0236..e5568ff1e0 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/main/CMakeLists.txt
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/CMakeLists.txt
@@ -1,5 +1,32 @@
-set(COMPONENT_SRCS "slave_control.c" "../../../../common/esp_hosted_config.pb-c.c" "protocomm_pserial.c" "app_main.c" "slave_bt.c" "mempool.c" "stats.c" "mempool_ll.c")
-set(COMPONENT_ADD_INCLUDEDIRS "." "../../../../common/include")
+set(common_dir "../../../../common")
+
+set(COMPONENT_SRCS
+ "slave_control.c"
+ "${common_dir}/esp_hosted_config.pb-c.c"
+ "${common_dir}/utils/esp_hosted_cli.c"
+ "protocomm_pserial.c"
+ "esp_hosted_coprocessor.c"
+ "slave_bt.c"
+ "mempool.c"
+ "stats.c"
+ "mempool_ll.c"
+ "host_power_save.c"
+ "lwip_filter.c"
+)
+
+if(CONFIG_ESP_HOSTED_COPROCESSOR_EXAMPLE_MQTT)
+ list(APPEND COMPONENT_SRCS mqtt_example.c)
+endif()
+
+if(CONFIG_ESP_HOSTED_COPROCESSOR_EXAMPLE_HTTP_CLIENT)
+ list(APPEND COMPONENT_SRCS http_req.c)
+endif()
+
+set(COMPONENT_ADD_INCLUDEDIRS
+ "."
+ "${common_dir}/include"
+ "${common_dir}/utils"
+)
if(CONFIG_ESP_SDIO_HOST_INTERFACE)
list(APPEND COMPONENT_SRCS sdio_slave_api.c)
@@ -7,7 +34,6 @@ else(CONFIG_ESP_SPI_HOST_INTERFACE)
list(APPEND COMPONENT_SRCS spi_slave_api.c)
endif()
-
register_component()
target_compile_definitions(${COMPONENT_LIB} PRIVATE)
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/Kconfig.projbuild b/esp_hosted_fg/esp/esp_driver/network_adapter/main/Kconfig.projbuild
index 2be4bab8b2..7b2ae481b5 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/main/Kconfig.projbuild
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/Kconfig.projbuild
@@ -1,20 +1,27 @@
menu "Example Configuration"
+ config ESP_HOSTED_COPROCESSOR
+ bool
+ default y
+
+ # set this to y to use the ESP32-C5 RaspPi Mating Board in SPI mode
+ config ESP_ESP32C5_SPI_RASPI_MATING_BOARD
+ bool
+ default n
+
+ comment "SPI Configuration set for ESP32-C5 RaspPi Mating Board"
+ depends on ESP_ESP32C5_SPI_RASPI_MATING_BOARD
choice ESP_HOST_INTERFACE
bool "Transport layer"
- default ESP_SDIO_HOST_INTERFACE if IDF_TARGET_ESP32
- default ESP_SPI_HOST_INTERFACE if IDF_TARGET_ESP32S2
- default ESP_SPI_HOST_INTERFACE if IDF_TARGET_ESP32S3
- default ESP_SPI_HOST_INTERFACE if IDF_TARGET_ESP32C2
- default ESP_SPI_HOST_INTERFACE if IDF_TARGET_ESP32C3
- default ESP_SPI_HOST_INTERFACE if IDF_TARGET_ESP32C5
- default ESP_SPI_HOST_INTERFACE if IDF_TARGET_ESP32C6
+ default ESP_SPI_HOST_INTERFACE if ESP_ESP32C5_SPI_RASPI_MATING_BOARD
+ default ESP_SDIO_HOST_INTERFACE if SOC_SDIO_SLAVE_SUPPORTED
+ default ESP_SPI_HOST_INTERFACE
help
Bus interface to be used for communication with the host
config ESP_SDIO_HOST_INTERFACE
bool "SDIO interface"
- depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32C6
+ depends on SOC_SDIO_SLAVE_SUPPORTED
help
Enable/Disable SDIO host interface
@@ -24,90 +31,255 @@ menu "Example Configuration"
Enable/Disable SPI host interface
endchoice
- menu "SPI Configuration"
- depends on ESP_SPI_HOST_INTERFACE
+ menu "Transport Priority Queue Configuration"
+ config ESP_ENABLE_TX_PRIORITY_QUEUES
+ depends on !ESP_SDIO_HOST_INTERFACE
+ bool "Enable TX priority queues"
+ default n
+ help
+ Enable separate priority queues for TX based on interface type (WiFi, BT, Serial)
- config ESP_SPI_CONTROLLER
- int "SPI controller to use"
- depends on IDF_TARGET_ESP32 && ESP_SPI_HOST_INTERFACE
- default 2
- range 2 3
+ config ESP_TX_WIFI_Q_SIZE
+ int "TX WiFi queue size"
+ depends on ESP_ENABLE_TX_PRIORITY_QUEUES
+ default 10 if IDF_TARGET_ESP32C2
+ default 20
+ help
+ Size of TX queue for WiFi packets
+
+ config ESP_TX_BT_Q_SIZE
+ int "TX BT queue size"
+ depends on ESP_ENABLE_TX_PRIORITY_QUEUES
+ default 3
help
- SPI controller to be used. HSPI->2, VSPI->3
+ Size of TX queue for BT packets
- config ESP_SPI_GPIO_HANDSHAKE
- int "GPIO pin for handshake"
- default 3 if IDF_TARGET_ESP32C2
- default 3 if IDF_TARGET_ESP32C3
- default 3 if IDF_TARGET_ESP32C5
- default 3 if IDF_TARGET_ESP32C6
+ config ESP_TX_SERIAL_Q_SIZE
+ int "TX Serial queue size"
+ depends on ESP_ENABLE_TX_PRIORITY_QUEUES
default 2
help
- GPIO pin to use for handshake with other spi controller
+ Size of TX queue for Serial packets
- config ESP_SPI_GPIO_DATA_READY
- int "GPIO pin for data ready interrupt"
- default 4
+ config ESP_TX_Q_SIZE
+ int "ESP to Host transport queue size"
+ depends on !ESP_ENABLE_TX_PRIORITY_QUEUES
+ default 6 if IDF_TARGET_ESP32C2
+ default 10
help
- GPIO pin for indicating host that SPI slave has data to be read by host
+ Size of Tx queue for packets
- config ESP_ENABLE_TX_PRIORITY_QUEUES
- bool "Process Tx packets with priority"
+ config ESP_ENABLE_RX_PRIORITY_QUEUES
+ bool "Enable RX priority queues"
default n
+ help
+ Enable separate priority queues for RX based on interface type (WiFi, BT, Serial)
- config ESP_SPI_TX_Q_SIZE
- depends on !ESP_ENABLE_TX_PRIORITY_QUEUES
- int "ESP to host queue size"
+ config ESP_RX_WIFI_Q_SIZE
+ int "RX WiFi queue size"
+ depends on ESP_ENABLE_RX_PRIORITY_QUEUES
+ default 10 if IDF_TARGET_ESP32C2
+ default 20
+ help
+ Size of RX queue for WiFi packets
+
+ config ESP_RX_BT_Q_SIZE
+ int "RX BT queue size"
+ depends on ESP_ENABLE_RX_PRIORITY_QUEUES
+ default 3
+ help
+ Size of RX queue for BT packets
+
+ config ESP_RX_SERIAL_Q_SIZE
+ int "RX Serial queue size"
+ depends on ESP_ENABLE_RX_PRIORITY_QUEUES
+ default 2
+ help
+ Size of RX queue for Serial packets
+
+ config ESP_RX_Q_SIZE
+ int "Host to ESP transport queue size"
+ depends on !ESP_ENABLE_RX_PRIORITY_QUEUES
+ default 6 if IDF_TARGET_ESP32C2
default 10
+ help
+ Size of Rx queue for packets
+ endmenu
- menu "Tx Priority Queues"
- depends on ESP_ENABLE_TX_PRIORITY_QUEUES
+ menu "SPI Full-duplex Configuration"
+ depends on ESP_SPI_HOST_INTERFACE
+
+ choice ESP_SPI_PRIV_MODE
+ bool "Slave SPI mode"
+ default ESP_SPI_PRIV_MODE_2 if IDF_TARGET_ESP32
+ default ESP_SPI_PRIV_MODE_3
+
+ config ESP_SPI_PRIV_MODE_0
+ bool "Slave SPI mode 0"
+
+ config ESP_SPI_PRIV_MODE_1
+ bool "Slave SPI mode 1"
- config ESP_SPI_TX_WIFI_Q_SIZE
- int "ESP to Host SPI queue size"
- default 10 if IDF_TARGET_ESP32C2
- default 20
+ config ESP_SPI_PRIV_MODE_2
+ bool "Slave SPI mode 2"
+
+ config ESP_SPI_PRIV_MODE_3
+ bool "Slave SPI mode 3"
+ endchoice
+
+ config ESP_SPI_MODE
+ int
+ default 0 if ESP_SPI_PRIV_MODE_0
+ default 1 if ESP_SPI_PRIV_MODE_1
+ default 2 if ESP_SPI_PRIV_MODE_2
+ default 3 if ESP_SPI_PRIV_MODE_3
+ default 3
+
+
+ choice SPI_CONTROLLER
+ bool "SPI controller to use"
+ default SPI_HSPI
+
+ config SPI_HSPI
+ bool "FSPI/HSPI"
help
- Very small tx queue will lower ESP == SPI ==> Host data rate
+ "HSPI/FSPI: SPI_controller_1"
- config ESP_SPI_TX_BT_Q_SIZE
- int "ESP to Host SPI queue size"
- default 3
+ config SPI_VSPI
+ depends on IDF_TARGET_ESP32
+ bool "VSPI"
+ help
+ "VSPI: SPI_controller_2"
- config ESP_SPI_TX_SERIAL_Q_SIZE
- int "ESP to Host serial SPI queue size"
- default 2
- endmenu
+ endchoice
- config ESP_ENABLE_RX_PRIORITY_QUEUES
- bool "Process Rx packets with priority"
- default n
+ config ESP_SPI_CONTROLLER
+ int
+ default 2 if SPI_VSPI
+ default 1
+
+ menu "Hosted SPI GPIOs"
+ config ESP_SPI_HSPI_GPIO_MOSI
+ depends on SPI_HSPI
+ int "Slave GPIO pin for Host MOSI"
+ default 13 if IDF_TARGET_ESP32
+ default 11 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
+ default 1 if IDF_TARGET_ESP32C5 && ESP_ESP32C5_SPI_RASPI_MATING_BOARD
+ default 7
+ help
+ SPI controller Host MOSI
+
+ config ESP_SPI_HSPI_GPIO_MISO
+ depends on SPI_HSPI
+ int "Slave GPIO pin for Host MISO"
+ default 12 if IDF_TARGET_ESP32
+ default 13 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
+ default 6 if IDF_TARGET_ESP32C5 && ESP_ESP32C5_SPI_RASPI_MATING_BOARD
+ default 2
+ help
+ SPI controller Host MISO
+
+ config ESP_SPI_HSPI_GPIO_CLK
+ depends on SPI_HSPI
+ int "Slave GPIO pin for Host CLK"
+ default 14 if IDF_TARGET_ESP32
+ default 12 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
+ default 27 if IDF_TARGET_ESP32C5 && ESP_ESP32C5_SPI_RASPI_MATING_BOARD
+ default 6
+ help
+ SPI controller Host CLK
+
+ config ESP_SPI_HSPI_GPIO_CS
+ depends on SPI_HSPI
+ int "Slave GPIO pin for Host CS"
+ default 15 if IDF_TARGET_ESP32
+ default 10 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
+ default 4 if IDF_TARGET_ESP32C5 && ESP_ESP32C5_SPI_RASPI_MATING_BOARD
+ default 10
+ help
+ SPI controller Host CS
- config ESP_SPI_RX_Q_SIZE
- int "Host to ESP SPI queue size"
- depends on !ESP_ENABLE_RX_PRIORITY_QUEUES
- default 10
- help
- Very small RX queue will lower ESP <== SPI == Host data rate
+ config ESP_SPI_VSPI_GPIO_MOSI
+ depends on SPI_VSPI
+ int "Slave GPIO pin for Host MOSI"
+ default 23
+ help
+ SPI controller Host MOSI
- menu "Rx Priority Queues"
- depends on ESP_ENABLE_RX_PRIORITY_QUEUES
- config ESP_SPI_RX_WIFI_Q_SIZE
- int "Host to ESP SPI queue size"
- default 10 if IDF_TARGET_ESP32C2
- default 20
+ config ESP_SPI_VSPI_GPIO_MISO
+ depends on SPI_VSPI
+ int "Slave GPIO pin for Host MISO"
+ default 19
help
- Very small rx queue will lower ESP <== SPI == Host data rate
+ SPI controller Host MISO
- config ESP_SPI_RX_BT_Q_SIZE
- int "Host to ESP SPI queue size"
- default 3
+ config ESP_SPI_VSPI_GPIO_CLK
+ depends on SPI_VSPI
+ int "Slave GPIO pin for Host CLK"
+ default 18
+ help
+ SPI controller Host CLK
- config ESP_SPI_RX_SERIAL_Q_SIZE
- int "Host to ESP serial SPI queue size"
+ config ESP_SPI_VSPI_GPIO_CS
+ depends on SPI_VSPI
+ int "Slave GPIO pin for Host CS"
+ default 5
+ help
+ SPI controller Host CS
+
+ config ESP_SPI_GPIO_MOSI
+ int
+ default ESP_SPI_VSPI_GPIO_MOSI if SPI_VSPI
+ default ESP_SPI_HSPI_GPIO_MOSI
+
+ config ESP_SPI_GPIO_MISO
+ int
+ default ESP_SPI_VSPI_GPIO_MISO if SPI_VSPI
+ default ESP_SPI_HSPI_GPIO_MISO
+
+ config ESP_SPI_GPIO_CLK
+ int
+ default ESP_SPI_VSPI_GPIO_CLK if SPI_VSPI
+ default ESP_SPI_HSPI_GPIO_CLK
+
+ config ESP_SPI_GPIO_CS
+ int
+ default ESP_SPI_VSPI_GPIO_CS if SPI_VSPI
+ default ESP_SPI_HSPI_GPIO_CS
+
+ config ESP_SPI_GPIO_HANDSHAKE
+ int "Slave GPIO pin for handshake"
+ default 25 if IDF_TARGET_ESP32C5 && ESP_ESP32C5_SPI_RASPI_MATING_BOARD
+ default 3 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C5 || IDF_TARGET_ESP32C6
default 2
+ help
+ Slave GPIO pin to use for handshake with other spi controller
+
+ config ESP_SPI_GPIO_DATA_READY
+ int "Slave GPIO pin for data ready interrupt"
+ default 2 if IDF_TARGET_ESP32C5 && ESP_ESP32C5_SPI_RASPI_MATING_BOARD
+ default 4
+ help
+ Slave GPIO pin for indicating host that SPI slave has data to be read by host
+
+ config ESP_SPI_GPIO_RESET
+ int "Slave GPIO pin to reset itself"
+ default -1
+ help
+ Host uses this pin to reset the slave ESP. To re-use ESP 'RST' or 'EN' GPIO, set value to -1
endmenu
+ config ESP_SPI_DEASSERT_HS_ON_CS
+ bool "Deassert Handshake when SPI CS is deasserted"
+ default n if IDF_TARGET_ESP32
+ default y
+ help
+ Deassert Handshake and prepare a new SPI transaction only after
+ CS has been deasserted. This helps prevent data loss with MCUs
+ that delay deasserting CS after the end of a SPI transaction
+ by prematurely starting a new slave SPI transaction
+ since CS is detected by the slave as still asserted.
+
config ESP_SPI_CHECKSUM
bool "SPI checksum ENABLE/DISABLE"
default y
@@ -118,6 +290,21 @@ menu "Example Configuration"
menu "SDIO Configuration"
depends on ESP_SDIO_HOST_INTERFACE
+ config ESP_SDIO_STREAMING_MODE
+ bool "Enable SDIO Streaming Mode"
+ default n
+ help
+ Enable Streaming Mode. Host to receive queued data from slave
+ as one stream instead of individual packets. This can improve
+ host SDIO read performance by doing one large read transaction
+ instead of many smaller read transactions.
+
+ config ESP_SDIO_GPIO_RESET
+ int "Slave GPIO pin to reset itself"
+ default -1
+ help
+ Host uses this pin to reset the slave ESP. To re-use ESP 'RST' or 'EN' GPIO, set value to -1
+
choice
prompt "SDIO Bus Speed"
default ESP_SDIO_HIGH_SPEED
@@ -125,11 +312,85 @@ menu "Example Configuration"
Select the SDIO Slave Bus Speed. Actual speed in use depends on SDIO bus speed the SDIO Master can support
config ESP_SDIO_DEFAULT_SPEED
- bool "Default Speed (20 MHz)"
+ bool "Default Speed (upto 20 MHz)"
config ESP_SDIO_HIGH_SPEED
- bool "High Speed (40 MHz)"
+ bool "High Speed (upto 50 MHz)"
+ endchoice
+
+
+ menu "Hosted SDIO GPIOs"
+ config ESP_SDIO_PIN_CMD
+ int "CMD GPIO number"
+ range 15 15 if IDF_TARGET_ESP32
+ range 18 18 if IDF_TARGET_ESP32C6
+ range 10 10 if IDF_TARGET_ESP32C5
+ help
+ "Value cannot be configured. Displayed for reference."
+
+ config ESP_SDIO_PIN_CLK
+ int "CLK GPIO number"
+ range 14 14 if IDF_TARGET_ESP32
+ range 19 19 if IDF_TARGET_ESP32C6
+ range 9 9 if IDF_TARGET_ESP32C5
+ help
+ "Value cannot be configured. Displayed for reference."
+
+ config ESP_SDIO_PIN_D0
+ int "D0 GPIO number"
+ range 2 2 if IDF_TARGET_ESP32
+ range 20 20 if IDF_TARGET_ESP32C6
+ range 8 8 if IDF_TARGET_ESP32C5
+ help
+ "Value cannot be configured. Displayed for reference."
+
+ config ESP_SDIO_PIN_D1
+ int "D1 GPIO number"
+ range 4 4 if IDF_TARGET_ESP32
+ range 21 21 if IDF_TARGET_ESP32C6
+ range 7 7 if IDF_TARGET_ESP32C5
+ help
+ "Value cannot be configured. Displayed for reference."
+
+ config ESP_SDIO_PIN_D2
+ int "D2 GPIO number"
+ range 12 12 if IDF_TARGET_ESP32
+ range 22 22 if IDF_TARGET_ESP32C6
+ range 14 14 if IDF_TARGET_ESP32C5
+ help
+ "Value cannot be configured. Displayed for reference."
+ config ESP_SDIO_PIN_D3
+ int "D3 GPIO number"
+ range 13 13 if IDF_TARGET_ESP32
+ range 23 23 if IDF_TARGET_ESP32C6
+ range 13 13 if IDF_TARGET_ESP32C5
+ help
+ "Value cannot be configured. Displayed for reference."
+ endmenu
+
+ choice
+ prompt "SDIO Slave Timing"
+ default ESP_SDIO_NSEND_PSAMPLE if IDF_TARGET_ESP32C6
+ default ESP_SDIO_PSEND_PSAMPLE
+ help
+ Select the SDIO timing used by slave. Default value works with most
+ SDMMC controllers but if transfer errors are encountered, selecting a
+ different timing may help resolve the errors.
+ See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/sdio_slave.html#_CPPv419sdio_slave_timing_t
+ for more information
+
+ config ESP_SDIO_PSEND_PSAMPLE
+ bool "Send at positive edge, sample at positive edge"
+
+ config ESP_SDIO_NSEND_PSAMPLE
+ bool "Send at negative edge, sample at positive edge"
+
+ config ESP_SDIO_PSEND_NSAMPLE
+ bool "Send at positive edge, sample at negative edge"
+
+ config ESP_SDIO_NSEND_NSAMPLE
+ bool "Send at negative edge, sample at negative edge"
endchoice
config ESP_SDIO_CHECKSUM
@@ -139,6 +400,10 @@ menu "Example Configuration"
ENABLE/DISABLE software SDIO checksum
endmenu
+ config ESP_GPIO_SLAVE_RESET
+ int
+ default ESP_SPI_GPIO_RESET if ESP_SPI_HOST_INTERFACE
+ default ESP_SDIO_GPIO_RESET if ESP_SDIO_HOST_INTERFACE
config EXAMPLE_HCI_UART_BAUDRATE
int "UART Baudrate for HCI: Only applicable for ESP32-C3/ESP32-S3"
@@ -147,53 +412,393 @@ menu "Example Configuration"
depends on BT_CTRL_HCI_MODE_UART_H4
default 921600
help
- UART Baudrate for HCI over ESP32C2/C3/C6/S3. Please use standard baudrate.
+ UART Baudrate for HCI over ESP32-C2/C3/C6/S3. Please use standard baudrate.
- config ESP_DEFAULT_TASK_STACK_SIZE
- int "ESP-Hosted task stack size"
- default 4096
- help
- Default task size of ESP-Hosted tasks
+ menu "ESP-Hosted Task config"
+ config ESP_DEFAULT_TASK_STACK_SIZE
+ int "ESP-Hosted task stack size"
+ default 4096
+ help
+ Default task size of ESP-Hosted tasks
- config ESP_DEFAULT_TASK_PRIO
- int "ESP-Hosted task priority"
- default 22
- help
- Default task priority of ESP-Hosted tasks
+ config ESP_HOSTED_TASK_PRIORITY_LOW
+ int "ESP-Hosted task priority low"
+ default 5
+ help
+ Low priority of ESP-Hosted tasks
+
+ config ESP_HOSTED_TASK_PRIORITY_DEFAULT
+ int "ESP-Hosted task priority default"
+ default 21
+ help
+ Default task priority of ESP-Hosted tasks
+
+ config ESP_HOSTED_TASK_PRIORITY_HIGH
+ int "ESP-Hosted task priority high"
+ default 22
+ help
+ High priority of ESP-Hosted tasks
+ endmenu
config ESP_CACHE_MALLOC
- bool "Cache allocated memory like mempool - helps to reduce malloc calls"
+ bool "Enable Mempool"
default n if IDF_TARGET_ESP32C2
default y
help
- Cache allocated memory - reduces number of malloc calls
+ Mempool will help to alloc buffer without going to heap for every memory allocation or free
- config ESP_OTA_WORKAROUND
- bool "OTA workaround - Add sleeps while OTA write"
+ menu "Hosted Debugging"
+ config ESP_RAW_THROUGHPUT_TRANSPORT
+ bool "RawTP: Transport level throughput debug test"
+ default n
+ help
+ Find max transport performance which helps to assess stability of porting done
+
+ config ESP_RAW_TP_ESP_TO_HOST_PKT_LEN
+ depends on ESP_RAW_THROUGHPUT_TRANSPORT
+ int "RawTP: ESP to Host packet size"
+ range 1 1500
+ default 1460
+
+ config ESP_RAW_TP_REPORT_INTERVAL
+ depends on ESP_RAW_THROUGHPUT_TRANSPORT
+ int "RawTP: periodic duration to report stats accumulated"
+ default 1
+
+ config ESP_PKT_STATS
+ bool "Transport level packet stats"
+ default n if HOSTED_ON_LOW_MEM
+ default y
+ help
+ On comparing with slave packet stats helps to understand any packet loss at hosted
+
+ config ESP_PKT_STATS_INTERVAL_SEC
+ depends on ESP_PKT_STATS
+ int "Packet stats reporting interval (sec)"
+ default 30
+
+ config ESP_HOSTED_FUNCTION_PROFILING
+ bool "Enable function execution time profiling"
+ default n
+ help
+ Enable this option to measure and report function execution times.
+ This is useful for performance profiling and optimization.
+
+ config ESP_HOSTED_FUNCTION_PROFILING_MAX_ENTRIES
+ int "Maximum number of functions to profile"
+ depends on ESP_HOSTED_FUNCTION_PROFILING
+ default 10
+ range 1 50
+ help
+ Maximum number of unique functions that can be profiled simultaneously.
+ Each entry consumes memory, so keep this value reasonable based on
+ available memory.
+ endmenu
+
+ config NETWORK_SPLIT_ENABLED
+ depends on !IDF_TARGET_ESP32C2 && !IDF_TARGET_ESP32C3
+ bool "Allow Network Split using packet port number"
default y
help
- Enable/disable sleeps while OTA operations
+ Enable the LWIP at slave, additionally to host network stack
+
+ menu "Network split mode configuration"
+ depends on NETWORK_SPLIT_ENABLED
+
+ menu "Slave side (local) LWIP port range (static)"
+ config LWIP_TCP_LOCAL_PORT_RANGE_START
+ int "Slave TCP start port"
+ default 61440
+ help
+ Slave side TCP start port. Host defaults to 49152
+ Slave range: 61440-65535
+ Host range: 49152-61439
+
+ config LWIP_TCP_LOCAL_PORT_RANGE_END
+ int "Slave TCP end port"
+ default 65535
+ help
+ Slave side TCP end port. Host defaults to 61439
+ Slave range: 61440-65535
+ Host range: 49152-61439
+
+ config LWIP_UDP_LOCAL_PORT_RANGE_START
+ int "Slave UDP start port"
+ default 61440
+ help
+ Slave side UDP start port. Host defaults to 49152
+ Slave range: 61440-65535
+ Host range: 49152-61439
+
+ config LWIP_UDP_LOCAL_PORT_RANGE_END
+ int "Slave UDP end port"
+ default 65535
+ help
+ Slave side UDP end port. Host defaults to 61439
+ Slave range: 61440-65535
+ Host range: 49152-61439
+ endmenu
- menu "Enable Debug logs"
+ menu "Host side (remote) LWIP port range (static)"
+ config LWIP_TCP_REMOTE_PORT_RANGE_START
+ int "Host TCP start port"
+ default 49152
+ help
+ Host side TCP start port. Slave defaults to 61440
+ Slave range: 61440-65535
+ Host range: 49152-61439
+
+ config LWIP_TCP_REMOTE_PORT_RANGE_END
+ int "Host TCP end port"
+ default 61439
+ help
+ Host side TCP end port. Slave defaults to 65535
+ Slave range: 61440-65535
+ Host range: 49152-61439
- config ESP_SERIAL_DEBUG
- bool "Debug Serial driver data path"
- default 0
+ config LWIP_UDP_REMOTE_PORT_RANGE_START
+ int "Host UDP start port"
+ default 49152
+ help
+ Host side UDP start port. Slave defaults to 61440
+ Slave range: 61440-65535
+ Host range: 49152-61439
+
+ config LWIP_UDP_REMOTE_PORT_RANGE_END
+ int "Host UDP end port"
+ default 61439
+ help
+ Host side UDP end port. Slave defaults to 65535
+ Slave range: 61440-65535
+ Host range: 49152-61439
+ endmenu
+
+ config ESP_HOSTED_HOST_RESERVED_PORTS_CONFIGURED
+ bool "Extra port forwarding to host (static)"
+ default y
help
- Enable/disable debug prints in serial driver data path
+ Enable static port forwarding to host for specific ports
- config ESP_WLAN_DEBUG
- bool "Debug Wlan driver data path"
- default 0
+ menu "Host Static Port Forwarding"
+ depends on ESP_HOSTED_HOST_RESERVED_PORTS_CONFIGURED
+
+ config ESP_HOSTED_HOST_RESERVED_TCP_SRC_PORTS
+ string "TCP source ports to forward to host (comma separated)"
+ default "22,8554"
+ help
+ Comma separated list of TCP source ports that will be allowed from host (Max 10)
+
+ config ESP_HOSTED_HOST_RESERVED_TCP_DEST_PORTS
+ string "TCP destination ports to forward to host (comma separated)"
+ default "22,80,443,8080,8554"
+ help
+ Comma separated list of TCP destination ports that will be forwarded to host (Max 10)
+
+ config ESP_HOSTED_HOST_RESERVED_UDP_SRC_PORTS
+ string "UDP source ports to allowed from host (comma separated)"
+ default ""
+ help
+ Comma separated list of UDP source ports that will be forwarded to host (Max 10)
+
+ config ESP_HOSTED_HOST_RESERVED_UDP_DEST_PORTS
+ string "UDP destination ports to forward to host (comma separated)"
+ default "53,123"
+ help
+ Comma separated list of UDP destination ports that will be forwarded to host (Max 10)
+ endmenu
+
+ choice
+ prompt "Destination LWIP for unfiltered packet"
+ default ESP_DEFAULT_LWIP_SLAVE
help
- Enable/disable debug prints in wlan driver data path
+ Packets having destination port within 'remote' port range are forwarded to host. Rest unfiltered packets, are to be sent to this LWIP. Please note:
+ (1) These settings are only for IP packets, yet.
+ (2) Extra filtering may be in effect to respond some packets locally by slave LWIP.
+
+ config ESP_DEFAULT_LWIP_SLAVE
+ bool "Send packet to slave LWIP"
- config ESP_BT_DEBUG
- bool "Debug Bluetooth driver data path"
- default 0
+ config ESP_DEFAULT_LWIP_HOST
+ bool "Send packet to host LWIP"
+
+ config ESP_DEFAULT_LWIP_BOTH
+ bool "Send packet to both LWIPs"
+ endchoice
+
+ endmenu
+
+ config HOST_DEEP_SLEEP_ALLOWED
+ bool "Allow host to enter deep sleep. Slave will wakeup host using GPIO"
+ default n
+ help
+ Allow host to power save.
+ Please note: This is not yet supported, would be added in upcoming releases
+
+ menu "Host deep sleep config"
+ depends on HOST_DEEP_SLEEP_ALLOWED
+
+ config HOST_WAKEUP_GPIO
+ int "Host wakeup GPIO"
+ default 23 if IDF_TARGET_ESP32 && !SPI_VSPI
+ default 2 if IDF_TARGET_ESP32C6
+ default 1 if IDF_TARGET_ESP32C3
+ default 25 if IDF_TARGET_ESP32C5
+ default 6 if IDF_TARGET_ESP32C2 && C2_C5_MODULE_SUB_BOARD
+ default -1
+ endmenu
+
+ config ESP_HOSTED_CLI_ENABLED
+ depends on !IDF_TARGET_ESP32C2 && !IDF_TARGET_ESP32C3
+ bool "Start CLI at slave"
+ default y
+
+ choice "Wi-Fi control"
+ prompt "Wi-Fi control"
+ default SLAVE_MANAGES_WIFI
+
+ config SLAVE_MANAGES_WIFI
+ bool "Slave manages Wi-Fi"
+ help
+ If true, slave will manage Wi-Fi.
+
+ config HOST_MANAGES_WIFI
+ bool "Host manages Wi-Fi"
help
- Enable/disable debug prints in Bluetooth driver data path
+ If true, host will manage Wi-Fi.
+ config BOTH_MANAGES_WIFI
+ bool "Both host and slave manage Wi-Fi"
+ help
+ If true, both host and slave will manage Wi-Fi.
+ endchoice
+
+ menu "Wi-Fi Default Example config"
+
+ config ESP_WIFI_SSID
+ string "WiFi SSID"
+ default "myssid"
+ help
+ SSID (network name) for the example to connect to.
+
+ config ESP_WIFI_PASSWORD
+ string "WiFi Password"
+ default "mypassword"
+ help
+ WiFi password (WPA or WPA2) for the example to use.
+
+ choice ESP_WIFI_SAE_MODE
+ prompt "WPA3 SAE mode selection"
+ default ESP_WPA3_SAE_PWE_BOTH
+ help
+ Select mode for SAE as Hunt and Peck, H2E or both.
+ config ESP_WPA3_SAE_PWE_HUNT_AND_PECK
+ bool "HUNT AND PECK"
+ config ESP_WPA3_SAE_PWE_HASH_TO_ELEMENT
+ bool "H2E"
+ config ESP_WPA3_SAE_PWE_BOTH
+ bool "BOTH"
+ endchoice
+
+ config ESP_WIFI_PW_ID
+ string "PASSWORD IDENTIFIER"
+ depends on ESP_WPA3_SAE_PWE_HASH_TO_ELEMENT|| ESP_WPA3_SAE_PWE_BOTH
+ default ""
+ help
+ password identifier for SAE H2E
+
+ config ESP_MAXIMUM_RETRY
+ int "Maximum retry"
+ default 5
+ help
+ Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent.
+
+ choice ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD
+ prompt "WiFi Scan auth mode threshold"
+ default ESP_WIFI_AUTH_WPA2_PSK
+ help
+ The weakest authmode to accept in the scan mode.
+ This value defaults to ESP_WIFI_AUTH_WPA2_PSK incase password is present and ESP_WIFI_AUTH_OPEN is used.
+ Please select ESP_WIFI_AUTH_WEP/ESP_WIFI_AUTH_WPA_PSK incase AP is operating in WEP/WPA mode.
+
+ config ESP_WIFI_AUTH_OPEN
+ bool "OPEN"
+ config ESP_WIFI_AUTH_WEP
+ bool "WEP"
+ config ESP_WIFI_AUTH_WPA_PSK
+ bool "WPA PSK"
+ config ESP_WIFI_AUTH_WPA2_PSK
+ bool "WPA2 PSK"
+ config ESP_WIFI_AUTH_WPA_WPA2_PSK
+ bool "WPA/WPA2 PSK"
+ config ESP_WIFI_AUTH_WPA3_PSK
+ bool "WPA3 PSK"
+ config ESP_WIFI_AUTH_WPA2_WPA3_PSK
+ bool "WPA2/WPA3 PSK"
+ config ESP_WIFI_AUTH_WAPI_PSK
+ bool "WAPI PSK"
+ endchoice
+
+# choice WIFI_CMD_DEFAULT_COUNTRY
+# prompt "Set default country during initialize wifi"
+# default WIFI_CMD_DEFAULT_COUNTRY_CN
+# help
+# Set default wifi country during initialize wifi
+#
+# config WIFI_CMD_DEFAULT_COUNTRY_NONE
+# bool
+# prompt "Do not set country code"
+#
+# config WIFI_CMD_DEFAULT_COUNTRY_CN
+# bool
+# prompt "Set country code to CN (1-13)"
+# endchoice
endmenu
+
+ menu "Example to run"
+ depends on NETWORK_SPLIT_ENABLED
+
+ config ESP_HOSTED_COPROCESSOR_EXAMPLE_MQTT
+ bool "MQTT client example"
+ default y
+
+ menu "MQTT client config"
+ depends on ESP_HOSTED_COPROCESSOR_EXAMPLE_MQTT
+ config BROKER_URL
+ string "Broker URL"
+ default "mqtt://mqtt.eclipseprojects.io"
+ help
+ URL of the broker to connect to
+
+ config BROKER_URL_FROM_STDIN
+ bool
+ default y if BROKER_URL = "FROM_STDIN"
+
+ endmenu
+
+ config ESP_HOSTED_COPROCESSOR_EXAMPLE_HTTP_CLIENT
+ bool "HTTP client example"
+ default y
+
+ menu "HTTP client config"
+ depends on ESP_HOSTED_COPROCESSOR_EXAMPLE_HTTP_CLIENT
+
+ config HTTP_WEBSERVER
+ string "HTTP webserver to send req"
+ default "example.com"
+
+ config HTTP_WEBSERVER_PORT
+ string "HTTP webserver port"
+ default "80"
+
+ config HTTP_WEBSERVER_PATH
+ string "HTTP webserver path"
+ default "/"
+
+ config HTTP_REQ_DELAY
+ int "Delay after every http request (seconds)"
+ default 10
+
+ endmenu
+ endmenu
endmenu
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/app_main.c b/esp_hosted_fg/esp/esp_driver/network_adapter/main/app_main.c
deleted file mode 100644
index 2e316ce30f..0000000000
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/main/app_main.c
+++ /dev/null
@@ -1,807 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-#include
-#include
-#include
-#include "esp_log.h"
-#include "sys/queue.h"
-#include "soc/soc.h"
-#include "nvs_flash.h"
-#include "sdkconfig.h"
-#include
-#ifndef CONFIG_IDF_TARGET_ARCH_RISCV
-#include "xtensa/core-macros.h"
-#endif
-#include "esp_private/wifi.h"
-#include "interface.h"
-#include "esp_wpa.h"
-#include "app_main.h"
-
-#include "freertos/task.h"
-#include "freertos/queue.h"
-#ifdef CONFIG_BT_ENABLED
-#include "esp_bt.h"
-#ifdef CONFIG_BT_HCI_UART_NO
-#include "driver/uart.h"
-#endif
-#endif
-#include "endian.h"
-
-#include
-#include "protocomm_pserial.h"
-#include "slave_control.h"
-#include "slave_bt.c"
-#include "stats.h"
-#include "esp_fw_version.h"
-
-static const char TAG[] = "NETWORK_ADAPTER";
-
-#if CONFIG_ESP_WLAN_DEBUG
-static const char TAG_RX[] = "H -> S";
-static const char TAG_TX[] = "S -> H";
-#endif
-
-#if CONFIG_ESP_SERIAL_DEBUG
-static const char TAG_RX_S[] = "CONTROL H -> S";
-static const char TAG_TX_S[] = "CONTROL S -> H";
-#endif
-
-#ifdef CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
-#define STATS_TICKS pdMS_TO_TICKS(1000*2)
-#define ARRAY_SIZE_OFFSET 5
-#endif
-
-#define UNKNOWN_CTRL_MSG_ID 0
-
-#if CONFIG_ESP_SPI_HOST_INTERFACE
- #ifdef CONFIG_IDF_TARGET_ESP32S2
- #define TO_HOST_QUEUE_SIZE 5
- #else
- #define TO_HOST_QUEUE_SIZE 40
- #endif
-#else
- #define TO_HOST_QUEUE_SIZE 100
-#endif
-
-#define ETH_DATA_LEN 1500
-
-volatile uint8_t datapath = 0;
-volatile uint8_t station_connected = 0;
-volatile uint8_t softap_started = 0;
-volatile uint8_t ota_ongoing = 0;
-
-interface_context_t *if_context = NULL;
-interface_handle_t *if_handle = NULL;
-
-static QueueHandle_t meta_to_host_queue = NULL;
-static QueueHandle_t to_host_queue[MAX_PRIORITY_QUEUES] = {NULL};
-
-
-static protocomm_t *pc_pserial;
-
-static struct rx_data {
- uint8_t valid;
- uint16_t cur_seq_no;
- int len;
- uint8_t data[4096];
-} r;
-
-uint8_t ap_mac[MAC_LEN] = {0};
-
-static void print_firmware_version()
-{
- ESP_LOGI(TAG, "*********************************************************************");
- ESP_LOGI(TAG, " ESP-Hosted Firmware version :: %s-%d.%d.%d.%d.%d",
- PROJECT_NAME, PROJECT_VERSION_MAJOR_1, PROJECT_VERSION_MAJOR_2, PROJECT_VERSION_MINOR, PROJECT_REVISION_PATCH_1, PROJECT_REVISION_PATCH_2);
-#if CONFIG_ESP_SPI_HOST_INTERFACE
- #if BLUETOOTH_UART
- ESP_LOGI(TAG, " Transport used :: SPI + UART ");
- #else
- ESP_LOGI(TAG, " Transport used :: SPI only ");
- #endif
-#else
- #if BLUETOOTH_UART
- ESP_LOGI(TAG, " Transport used :: SDIO + UART ");
- #else
- ESP_LOGI(TAG, " Transport used :: SDIO only ");
- #endif
-#endif
- ESP_LOGI(TAG, "*********************************************************************");
-}
-
-static uint8_t get_capabilities()
-{
- uint8_t cap = 0;
-
- ESP_LOGI(TAG, "Supported features are:");
-#if CONFIG_ESP_SPI_HOST_INTERFACE
- ESP_LOGI(TAG, "- WLAN over SPI");
- cap |= ESP_WLAN_SPI_SUPPORT;
-#else
- ESP_LOGI(TAG, "- WLAN over SDIO");
- cap |= ESP_WLAN_SDIO_SUPPORT;
-#endif
-
-#if CONFIG_ESP_SPI_CHECKSUM || CONFIG_ESP_SDIO_CHECKSUM
- cap |= ESP_CHECKSUM_ENABLED;
-#endif
-
-#ifdef CONFIG_BT_ENABLED
- cap |= get_bluetooth_capabilities();
-#endif
- ESP_LOGI(TAG, "capabilities: 0x%x", cap);
-
- return cap;
-}
-
-static void esp_wifi_set_debug_log()
-{
- /* set WiFi log level and module */
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_ENABLE
- uint32_t g_wifi_log_level = WIFI_LOG_INFO;
- uint32_t g_wifi_log_module = 0;
- uint32_t g_wifi_log_submodule = 0;
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_DEBUG
- g_wifi_log_level = WIFI_LOG_DEBUG;
-#endif
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_VERBOSE
- g_wifi_log_level = WIFI_LOG_VERBOSE;
-#endif
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_MODULE_ALL
- g_wifi_log_module = WIFI_LOG_MODULE_ALL;
-#endif
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_MODULE_WIFI
- g_wifi_log_module = WIFI_LOG_MODULE_WIFI;
-#endif
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_MODULE_COEX
- g_wifi_log_module = WIFI_LOG_MODULE_COEX;
-#endif
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_MODULE_MESH
- g_wifi_log_module = WIFI_LOG_MODULE_MESH;
-#endif
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_SUBMODULE_ALL
- g_wifi_log_submodule |= WIFI_LOG_SUBMODULE_ALL;
-#endif
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_SUBMODULE_INIT
- g_wifi_log_submodule |= WIFI_LOG_SUBMODULE_INIT;
-#endif
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_SUBMODULE_IOCTL
- g_wifi_log_submodule |= WIFI_LOG_SUBMODULE_IOCTL;
-#endif
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_SUBMODULE_CONN
- g_wifi_log_submodule |= WIFI_LOG_SUBMODULE_CONN;
-#endif
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_SUBMODULE_SCAN
- g_wifi_log_submodule |= WIFI_LOG_SUBMODULE_SCAN;
-#endif
- esp_wifi_internal_set_log_level(g_wifi_log_level);
- esp_wifi_internal_set_log_mod(g_wifi_log_module, g_wifi_log_submodule, true);
-
-#endif /* CONFIG_ESP32_WIFI_DEBUG_LOG_ENABLE*/
-
-}
-
-void esp_update_ap_mac(void)
-{
- esp_err_t ret = ESP_OK;
- char mac_str[BSSID_LENGTH] = "";
-
- ret = esp_wifi_get_mac(ESP_IF_WIFI_AP, ap_mac);
- ESP_LOGI(TAG,"Get softap mac address");
- if (ret) {
- ESP_LOGE(TAG,"Error in getting MAC of ESP softap %d", ret);
- } else {
- snprintf(mac_str,BSSID_LENGTH,MACSTR,MAC2STR(ap_mac));
- ESP_LOGI(TAG,"AP mac [%s] ", mac_str);
- }
-}
-
-esp_err_t wlan_ap_rx_callback(void *buffer, uint16_t len, void *eb)
-{
- interface_buffer_handle_t buf_handle = {0};
-
- if (!buffer || !eb || !datapath || ota_ongoing) {
- if (eb) {
- esp_wifi_internal_free_rx_buffer(eb);
- }
- return ESP_OK;
- }
-
- buf_handle.if_type = ESP_AP_IF;
- buf_handle.if_num = 0;
- buf_handle.payload_len = len;
- buf_handle.payload = buffer;
- buf_handle.wlan_buf_handle = eb;
- buf_handle.free_buf_handle = esp_wifi_internal_free_rx_buffer;
-
- if (send_to_host_queue(&buf_handle, PRIO_Q_OTHERS))
- goto DONE;
-
- return ESP_OK;
-
-DONE:
- esp_wifi_internal_free_rx_buffer(eb);
- return ESP_OK;
-}
-
-esp_err_t wlan_sta_rx_callback(void *buffer, uint16_t len, void *eb)
-{
- interface_buffer_handle_t buf_handle = {0};
-
- if (!buffer || !eb || !datapath || ota_ongoing) {
- if (eb) {
- esp_wifi_internal_free_rx_buffer(eb);
- }
- return ESP_OK;
- }
-
- buf_handle.if_type = ESP_STA_IF;
- buf_handle.if_num = 0;
- buf_handle.payload_len = len;
- buf_handle.payload = buffer;
- buf_handle.wlan_buf_handle = eb;
- buf_handle.free_buf_handle = esp_wifi_internal_free_rx_buffer;
-
- if (send_to_host_queue(&buf_handle, PRIO_Q_OTHERS))
- goto DONE;
-
- return ESP_OK;
-
-DONE:
- esp_wifi_internal_free_rx_buffer(eb);
- return ESP_OK;
-}
-
-void process_tx_pkt(interface_buffer_handle_t *buf_handle)
-{
- /* Check if data path is not yet open */
- if (!datapath) {
- /* Post processing */
- if (buf_handle->free_buf_handle && buf_handle->priv_buffer_handle) {
- buf_handle->free_buf_handle(buf_handle->priv_buffer_handle);
- buf_handle->priv_buffer_handle = NULL;
- }
- ESP_LOGD(TAG, "Data path stopped");
- usleep(100*1000);
- return;
- }
- if (if_context && if_context->if_ops && if_context->if_ops->write) {
- if_context->if_ops->write(if_handle, buf_handle);
- }
- /* Post processing */
- if (buf_handle->free_buf_handle && buf_handle->priv_buffer_handle) {
- buf_handle->free_buf_handle(buf_handle->priv_buffer_handle);
- buf_handle->priv_buffer_handle = NULL;
- }
-}
-
-/* Send data to host */
-void send_task(void* pvParameters)
-{
- uint8_t queue_type = 0;
- interface_buffer_handle_t buf_handle = {0};
-
- while (1) {
-
- if (!datapath) {
- usleep(100*1000);
- continue;
- }
-
- if (xQueueReceive(meta_to_host_queue, &queue_type, portMAX_DELAY))
- if (xQueueReceive(to_host_queue[queue_type], &buf_handle, portMAX_DELAY))
- process_tx_pkt(&buf_handle);
- }
-}
-
-void parse_protobuf_req(void)
-{
- protocomm_pserial_data_ready(pc_pserial, r.data,
- r.len, UNKNOWN_CTRL_MSG_ID);
-}
-
-void send_event_to_host(int event_id)
-{
- protocomm_pserial_data_ready(pc_pserial, NULL, 0, event_id);
-}
-
-void send_event_data_to_host(int event_id, void *data, int size)
-{
- protocomm_pserial_data_ready(pc_pserial, data, size, event_id);
-}
-
-void process_serial_rx_pkt(uint8_t *buf)
-{
- struct esp_payload_header *header = NULL;
- uint16_t payload_len = 0;
- uint8_t *payload = NULL;
- int rem_buff_size;
-
- header = (struct esp_payload_header *) buf;
- payload_len = le16toh(header->len);
- payload = buf + le16toh(header->offset);
- rem_buff_size = sizeof(r.data) - r.len;
-
-#if CONFIG_ESP_SERIAL_DEBUG
- ESP_LOG_BUFFER_HEXDUMP(TAG_RX_S, payload, payload_len, ESP_LOG_INFO);
-#endif
-
- while (r.valid)
- {
- ESP_LOGI(TAG,"More segment: %u curr seq: %u header seq: %u\n",
- header->flags & MORE_FRAGMENT, r.cur_seq_no, header->seq_num);
- vTaskDelay(10);
- }
-
- if (!r.len) {
- /* New Buffer */
- r.cur_seq_no = le16toh(header->seq_num);
- }
-
- if (header->seq_num != r.cur_seq_no) {
- /* Sequence number mismatch */
- r.valid = 1;
- parse_protobuf_req();
- return;
- }
-
- memcpy((r.data + r.len), payload, min(payload_len, rem_buff_size));
- r.len += min(payload_len, rem_buff_size);
-
- if (!(header->flags & MORE_FRAGMENT)) {
- /* Received complete buffer */
- r.valid = 1;
- parse_protobuf_req();
- }
-}
-
-void process_rx_pkt(interface_buffer_handle_t *buf_handle)
-{
- struct esp_payload_header *header = NULL;
- uint8_t *payload = NULL;
- uint16_t payload_len = 0;
- int ret = 0;
-
- header = (struct esp_payload_header *) buf_handle->payload;
- payload = buf_handle->payload + le16toh(header->offset);
- payload_len = le16toh(header->len);
-
- ESP_LOGV(TAG, "Rx pkt: type:%u\n",buf_handle->if_type);
- ESP_LOG_BUFFER_HEXDUMP(TAG, payload, payload_len, ESP_LOG_VERBOSE);
-
- if ((buf_handle->if_type == ESP_STA_IF) && station_connected) {
- /* Forward data to wlan driver */
- int retry = 6;
-
- do {
- ret = esp_wifi_internal_tx(ESP_IF_WIFI_STA, payload, payload_len);
- retry--;
-
- if (ret) {
- if (retry % 3)
- usleep(600);
- else
- vTaskDelay(1);
- }
-
- } while (ret && retry);
- /*ESP_LOG_BUFFER_HEXDUMP("spi_sta_rx", payload, payload_len, ESP_LOG_INFO);*/
- } else if (buf_handle->if_type == ESP_AP_IF && softap_started) {
- int retry = 6;
- /* Forward data to wlan driver */
- do {
- ret = esp_wifi_internal_tx(ESP_IF_WIFI_AP, payload, payload_len);
- retry--;
-
- if (ret) {
- if (retry % 3)
- usleep(600);
- else
- vTaskDelay(1);
- }
-
- } while (ret && retry);
- } else if (buf_handle->if_type == ESP_SERIAL_IF) {
- process_serial_rx_pkt(buf_handle->payload);
- }
-#if defined(CONFIG_BT_ENABLED) && BLUETOOTH_HCI
- else if (buf_handle->if_type == ESP_HCI_IF) {
- process_hci_rx_pkt(payload, payload_len);
- }
-#endif
-#if TEST_RAW_TP && TEST_RAW_TP__HOST_TO_ESP
- else if (buf_handle->if_type == ESP_TEST_IF) {
- debug_update_raw_tp_rx_count(payload_len);
- }
-#endif
-
- /* Free buffer handle */
- if (buf_handle->free_buf_handle && buf_handle->priv_buffer_handle) {
- buf_handle->free_buf_handle(buf_handle->priv_buffer_handle);
- buf_handle->priv_buffer_handle = NULL;
- }
-}
-
-/* Get data from host */
-void recv_task(void* pvParameters)
-{
- interface_buffer_handle_t buf_handle = {0};
-
- for (;;) {
-
- if (!datapath) {
- /* Datapath is not enabled by host yet*/
- usleep(100*1000);
- continue;
- }
-
- /* receive data from transport layer */
- if (if_context && if_context->if_ops && if_context->if_ops->read) {
- int len = if_context->if_ops->read(if_handle, &buf_handle);
- if (len <= 0) {
- usleep(10*1000);
- continue;
- }
- }
-
- process_rx_pkt(&buf_handle);
- }
-}
-
-static ssize_t serial_read_data(uint8_t *data, ssize_t len)
-{
- len = min(len, r.len);
- if (r.valid) {
- memcpy(data, r.data, len);
- r.valid = 0;
- r.len = 0;
- r.cur_seq_no = 0;
- } else {
- ESP_LOGI(TAG,"No data to be read, len %d", len);
- }
- return len;
-}
-
-int send_to_host_queue(interface_buffer_handle_t *buf_handle, uint8_t queue_type)
-{
-
-#if 0
- process_tx_pkt(buf_handle);
-#else
- int ret = xQueueSend(to_host_queue[queue_type], buf_handle, portMAX_DELAY);
- if (ret != pdTRUE) {
- ESP_LOGE(TAG, "Failed to send buffer into queue[%u]\n",queue_type);
- return ESP_FAIL;
- }
-
- if (queue_type == PRIO_Q_SERIAL)
- ret = xQueueSendToFront(meta_to_host_queue, &queue_type, portMAX_DELAY);
- else
- ret = xQueueSend(meta_to_host_queue, &queue_type, portMAX_DELAY);
-
- if (ret != pdTRUE) {
- ESP_LOGE(TAG, "Failed to send buffer into meta queue[%u]\n",queue_type);
- return ESP_FAIL;
- }
-#endif
-
- return ESP_OK;
-}
-
-static esp_err_t serial_write_data(uint8_t* data, ssize_t len)
-{
- uint8_t *pos = data;
- int32_t left_len = len;
- int32_t frag_len = 0;
- static uint16_t seq_num = 0;
-
- do {
- interface_buffer_handle_t buf_handle = {0};
-
- seq_num++;
-
- buf_handle.if_type = ESP_SERIAL_IF;
- buf_handle.if_num = 0;
- buf_handle.seq_num = seq_num;
-
- if (left_len > ETH_DATA_LEN) {
- frag_len = ETH_DATA_LEN;
- buf_handle.flag = MORE_FRAGMENT;
- } else {
- frag_len = left_len;
- buf_handle.flag = 0;
- buf_handle.priv_buffer_handle = data;
- buf_handle.free_buf_handle = free;
- }
-
- buf_handle.payload = pos;
- buf_handle.payload_len = frag_len;
-
- if (send_to_host_queue(&buf_handle, PRIO_Q_SERIAL)) {
- if (data) {
- free(data);
- data = NULL;
- }
- return ESP_FAIL;
- }
-
-#if CONFIG_ESP_SERIAL_DEBUG
- ESP_LOG_BUFFER_HEXDUMP(TAG_TX_S, data, frag_len, ESP_LOG_INFO);
-#endif
-
- left_len -= frag_len;
- pos += frag_len;
- } while(left_len);
-
- return ESP_OK;
-}
-
-static esp_err_t initialise_wifi(void)
-{
- wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
-
- ESP_ERROR_CHECK(esp_event_loop_create_default());
-
- ESP_ERROR_CHECK(esp_wifi_init(&cfg));
-
- esp_wifi_set_debug_log();
-
- ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM) );
-
- ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL) );
-
- ESP_ERROR_CHECK(esp_wifi_start());
-
- return 0;
-}
-
-int event_handler(uint8_t val)
-{
- switch(val) {
- case ESP_OPEN_DATA_PATH:
- if (if_handle) {
- if_handle->state = ACTIVE;
- datapath = 1;
- ESP_EARLY_LOGI(TAG, "Start Data Path");
- } else {
- ESP_EARLY_LOGI(TAG, "Failed to Start Data Path");
- }
- break;
-
- case ESP_CLOSE_DATA_PATH:
- datapath = 0;
- if (if_handle) {
- ESP_EARLY_LOGI(TAG, "Stop Data Path");
- if_handle->state = DEACTIVE;
- } else {
- ESP_EARLY_LOGI(TAG, "Failed to Stop Data Path");
- }
- break;
- }
- return 0;
-}
-
-#ifdef CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
-/* These functions are only for debugging purpose
- * Please do not enable in production environments
- */
-static esp_err_t print_real_time_stats(TickType_t xTicksToWait)
-{
- TaskStatus_t *start_array = NULL, *end_array = NULL;
- UBaseType_t start_array_size, end_array_size;
- uint32_t start_run_time, end_run_time;
- esp_err_t ret;
-
- /* Allocate array to store current task states */
- start_array_size = uxTaskGetNumberOfTasks() + ARRAY_SIZE_OFFSET;
- start_array = malloc(sizeof(TaskStatus_t) * start_array_size);
- if (start_array == NULL) {
- ret = ESP_ERR_NO_MEM;
- goto exit;
- }
- /* Get current task states */
- start_array_size = uxTaskGetSystemState(start_array,
- start_array_size, &start_run_time);
- if (start_array_size == 0) {
- ret = ESP_ERR_INVALID_SIZE;
- goto exit;
- }
-
- vTaskDelay(xTicksToWait);
-
- /* Allocate array to store tasks states post delay */
- end_array_size = uxTaskGetNumberOfTasks() + ARRAY_SIZE_OFFSET;
- end_array = malloc(sizeof(TaskStatus_t) * end_array_size);
- if (end_array == NULL) {
- ret = ESP_ERR_NO_MEM;
- goto exit;
- }
- /* Get post delay task states */
- end_array_size = uxTaskGetSystemState(end_array, end_array_size, &end_run_time);
- if (end_array_size == 0) {
- ret = ESP_ERR_INVALID_SIZE;
- goto exit;
- }
-
- /* Calculate total_elapsed_time in units of run time stats clock period */
- uint32_t total_elapsed_time = (end_run_time - start_run_time);
- if (total_elapsed_time == 0) {
- ret = ESP_ERR_INVALID_STATE;
- goto exit;
- }
-
- ESP_LOGI(TAG,"| Task | Run Time | Percentage");
- /* Match each task in start_array to those in the end_array */
- for (int i = 0; i < start_array_size; i++) {
- int k = -1;
- for (int j = 0; j < end_array_size; j++) {
- if (start_array[i].xHandle == end_array[j].xHandle) {
- k = j;
- /* Mark that task have been matched by overwriting their handles */
- start_array[i].xHandle = NULL;
- end_array[j].xHandle = NULL;
- break;
- }
- }
- /* Check if matching task found */
- if (k >= 0) {
- uint32_t task_elapsed_time = end_array[k].ulRunTimeCounter -
- start_array[i].ulRunTimeCounter;
- uint32_t percentage_time = (task_elapsed_time * 100UL) /
- (total_elapsed_time * portNUM_PROCESSORS);
- ESP_LOGI(TAG,"| %s | %d | %d%%", start_array[i].pcTaskName,
- task_elapsed_time, percentage_time);
- }
- }
-
- /* Print unmatched tasks */
- for (int i = 0; i < start_array_size; i++) {
- if (start_array[i].xHandle != NULL) {
- ESP_LOGI(TAG,"| %s | Deleted", start_array[i].pcTaskName);
- }
- }
- for (int i = 0; i < end_array_size; i++) {
- if (end_array[i].xHandle != NULL) {
- ESP_LOGI(TAG,"| %s | Created", end_array[i].pcTaskName);
- }
- }
- ret = ESP_OK;
-
-exit: /* Common return path */
- if (start_array)
- free(start_array);
- if (end_array)
- free(end_array);
- return ret;
-}
-
-void task_runtime_stats_task(void* pvParameters)
-{
- while (1) {
- ESP_LOGI(TAG,"\n\nGetting real time stats over %d ticks", STATS_TICKS);
- if (print_real_time_stats(STATS_TICKS) == ESP_OK) {
- ESP_LOGI(TAG,"Real time stats obtained");
- } else {
- ESP_LOGI(TAG,"Error getting real time stats");
- }
- vTaskDelay(pdMS_TO_TICKS(1000*2));
- }
-}
-#endif
-
-void app_main()
-{
- esp_err_t ret;
- uint8_t capa = 0;
- uint8_t prio_q_idx = 0;
-#ifdef CONFIG_BT_ENABLED
- uint8_t mac[MAC_LEN] = {0};
-#endif
- print_firmware_version();
-
- capa = get_capabilities();
-
- /* Initialize NVS */
- ret = nvs_flash_init();
-
- if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
- ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
- ESP_ERROR_CHECK(nvs_flash_erase());
- ret = nvs_flash_init();
- }
- ESP_ERROR_CHECK( ret );
-
-#ifdef CONFIG_BT_ENABLED
- initialise_bluetooth();
-
- ret = esp_read_mac(mac, ESP_MAC_BT);
- if (ret) {
- ESP_LOGE(TAG,"Failed to read BT Mac addr\n");
- } else {
- ESP_LOGI(TAG, "ESP Bluetooth MAC addr: %2x:%2x:%2x:%2x:%2x:%2x",
- mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
- }
-#endif
-
- pc_pserial = protocomm_new();
- if (pc_pserial == NULL) {
- ESP_LOGE(TAG,"Failed to allocate memory for new instance of protocomm ");
- return;
- }
-
- /* Endpoint for control command responses */
- if (protocomm_add_endpoint(pc_pserial, CTRL_EP_NAME_RESP,
- data_transfer_handler, NULL) != ESP_OK) {
- ESP_LOGE(TAG, "Failed to add enpoint");
- return;
- }
-
- /* Endpoint for control notifications for events subscribed by user */
- if (protocomm_add_endpoint(pc_pserial, CTRL_EP_NAME_EVENT,
- ctrl_notify_handler, NULL) != ESP_OK) {
- ESP_LOGE(TAG, "Failed to add enpoint");
- return;
- }
-
- protocomm_pserial_start(pc_pserial, serial_write_data, serial_read_data);
-
- if_context = interface_insert_driver(event_handler);
-
-#if CONFIG_ESP_SPI_HOST_INTERFACE
- datapath = 1;
-#endif
-
- if (!if_context || !if_context->if_ops) {
- ESP_LOGE(TAG, "Failed to insert driver\n");
- return;
- }
-
- if_handle = if_context->if_ops->init();
-
- if (!if_handle) {
- ESP_LOGE(TAG, "Failed to initialize driver\n");
- return;
- }
-
- meta_to_host_queue = xQueueCreate(TO_HOST_QUEUE_SIZE*3, sizeof(uint8_t));
- assert(meta_to_host_queue);
- for (prio_q_idx=0; prio_q_idx
+#include
+#include
+#include "esp_log.h"
+#include "sys/queue.h"
+#include "soc/soc.h"
+#include "nvs_flash.h"
+#include "sdkconfig.h"
+#include
+#include
+#ifndef CONFIG_IDF_TARGET_ARCH_RISCV
+#include "xtensa/core-macros.h"
+#endif
+#include "esp_private/wifi.h"
+#include "interface.h"
+#include "esp_wpa.h"
+#include "esp_hosted_coprocessor.h"
+#include "driver/gpio.h"
+
+#include "freertos/task.h"
+#include "freertos/queue.h"
+
+// enable only if BT component enabled and soc supports BT
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_SOC_BT_SUPPORTED)
+#include "esp_bt.h"
+#ifdef CONFIG_BT_HCI_UART_NO
+#include "driver/uart.h"
+#endif
+#endif
+
+#include "endian.h"
+
+#include
+#include "protocomm_pserial.h"
+#include "slave_control.h"
+#include "slave_bt.h"
+#include "stats.h"
+#include "esp_fw_version.h"
+#include "esp_hosted_cli.h"
+
+#if CONFIG_NETWORK_SPLIT_ENABLED
+ #include "host_power_save.h"
+ #include "esp_hosted_config.pb-c.h"
+
+
+ volatile uint8_t station_got_ip = 0;
+
+ //#ifdef CONFIG_SLAVE_MANAGES_WIFI
+ #include "wifi_cmd.h"
+
+ /* Perform DHCP at slave & send IP info at host */
+ #define H_SLAVE_LWIP_DHCP_AT_SLAVE 1
+
+ //#else
+ //#define H_SLAVE_LWIP_DHCP_AT_SLAVE 0
+ //#endif
+#endif
+
+#include "lwip_filter.h"
+#include "esp_hosted_custom_rpc.h"
+
+static const char TAG[] = "fg_slave";
+
+
+#define UNKNOWN_CTRL_MSG_ID 0
+
+#define TO_HOST_QUEUE_SIZE 10
+
+#define ETH_DATA_LEN 1500
+#define MAX_WIFI_STA_TX_RETRY 2
+
+
+
+volatile uint8_t datapath = 0;
+volatile uint8_t station_connected = 0;
+volatile uint8_t softap_started = 0;
+
+interface_context_t *if_context = NULL;
+interface_handle_t *if_handle = NULL;
+
+esp_netif_t *slave_sta_netif = NULL;
+
+static protocomm_t *pc_pserial;
+SemaphoreHandle_t host_reset_sem;
+
+static struct rx_data {
+ uint8_t valid;
+ uint16_t cur_seq_no;
+ int len;
+ uint8_t data[4096];
+} r;
+
+/* Add at the top with other static variables */
+#if H_HOST_PS_ALLOWED
+#define MAX_DHCP_DNS_RETRIES 10
+static int dhcp_dns_retry_count = 0;
+static TimerHandle_t delayed_dhcp_dns_timer = NULL;
+#endif
+
+static esp_err_t handle_custom_unserialised_rpc_request(const custom_rpc_unserialised_data_t *req, custom_rpc_unserialised_data_t *resp_out);
+esp_err_t create_and_send_custom_rpc_unserialised_event(uint32_t custom_event_id, const void *data, size_t data_len);
+
+static void print_firmware_version()
+{
+ ESP_LOGI(TAG, "*********************************************************************");
+ ESP_LOGI(TAG, " ESP-Hosted Firmware version :: %s-%d.%d.%d.%d.%d",
+ PROJECT_NAME, PROJECT_VERSION_MAJOR_1, PROJECT_VERSION_MAJOR_2, PROJECT_VERSION_MINOR, PROJECT_REVISION_PATCH_1, PROJECT_REVISION_PATCH_2);
+#if CONFIG_ESP_SPI_HOST_INTERFACE
+ #if BLUETOOTH_UART
+ ESP_LOGI(TAG, " Transport used :: SPI + UART ");
+ #else
+ ESP_LOGI(TAG, " Transport used :: SPI only ");
+ #endif
+#else
+ #if BLUETOOTH_UART
+ ESP_LOGI(TAG, " Transport used :: SDIO + UART ");
+ #else
+ ESP_LOGI(TAG, " Transport used :: SDIO only ");
+ #endif
+#endif
+ ESP_LOGI(TAG, "*********************************************************************");
+}
+
+static uint8_t get_capabilities(void)
+{
+ uint8_t cap = 0;
+
+ ESP_LOGI(TAG, "Supported features are:");
+#if CONFIG_ESP_SPI_HOST_INTERFACE
+ ESP_LOGI(TAG, "- WLAN over SPI");
+ cap |= ESP_WLAN_SPI_SUPPORT;
+#else
+ ESP_LOGI(TAG, "- WLAN over SDIO");
+ cap |= ESP_WLAN_SDIO_SUPPORT;
+#endif
+
+#if CONFIG_ESP_SPI_CHECKSUM || CONFIG_ESP_SDIO_CHECKSUM
+ cap |= ESP_CHECKSUM_ENABLED;
+#endif
+
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_SOC_BT_SUPPORTED)
+ cap |= get_bluetooth_capabilities();
+#endif
+ ESP_LOGI(TAG, "capabilities: 0x%x", cap);
+
+ return cap;
+}
+
+static inline esp_err_t populate_buff_handle(interface_buffer_handle_t *buf_handle,
+ uint8_t if_type,
+ uint8_t *buf,
+ uint16_t len,
+ void (*free_buf_func)(void *data),
+ void *free_buf_handle,
+ uint8_t flag,
+ uint8_t if_num,
+ uint16_t seq_num)
+{
+ buf_handle->if_type = if_type;
+ buf_handle->payload = buf;
+ buf_handle->payload_len = len;
+ buf_handle->priv_buffer_handle = free_buf_handle;
+ buf_handle->free_buf_handle = free_buf_func;
+ buf_handle->flag = flag;
+ buf_handle->if_num = if_num;
+ buf_handle->seq_num = seq_num;
+
+ return ESP_OK;
+}
+
+#define populate_wifi_buffer_handle(Buf_hdL, TypE, BuF, LeN) \
+ populate_buff_handle(Buf_hdL, TypE, BuF, LeN, esp_wifi_internal_free_rx_buffer, eb, 0, 0, 0);
+
+
+esp_err_t wlan_ap_rx_callback(void *buffer, uint16_t len, void *eb)
+{
+ interface_buffer_handle_t buf_handle = {0};
+
+ if (!buffer || !eb || !datapath) {
+ if (eb) {
+ esp_wifi_internal_free_rx_buffer(eb);
+ }
+ return ESP_OK;
+ }
+ ESP_HEXLOGV("AP_Get", buffer, len, 32);
+
+ populate_wifi_buffer_handle(&buf_handle, ESP_AP_IF, buffer, len);
+
+ if (send_to_host_queue(&buf_handle, PRIO_Q_OTHERS))
+ goto DONE;
+
+ return ESP_OK;
+
+DONE:
+ esp_wifi_internal_free_rx_buffer(eb);
+ return ESP_OK;
+}
+
+/* This function would check the incoming packet from AP
+ * to send it to local lwip or host lwip depending upon the
+ * destination port used in the packet
+ */
+esp_err_t wlan_sta_rx_callback(void *buffer, uint16_t len, void *eb)
+{
+ interface_buffer_handle_t buf_handle = {0};
+ hosted_l2_bridge bridge_to_use = HOST_LWIP_BRIDGE;
+
+ if (!buffer || !eb) {
+ if (eb) {
+ ESP_LOGD(TAG, "drop wifi packet. datapath: %u", datapath);
+ esp_wifi_internal_free_rx_buffer(eb);
+ }
+ return ESP_OK;
+ }
+
+ ESP_HEXLOGV("STA_Get", buffer, len, 64);
+
+#if ESP_PKT_STATS
+ pkt_stats.sta_lwip_in++;
+#endif
+
+#ifdef CONFIG_NETWORK_SPLIT_ENABLED
+ /* Filter and route the packet based on destination port */
+ bridge_to_use = filter_and_route_packet(buffer, len);
+#else
+ /* default as co-processor mode */
+ bridge_to_use = HOST_LWIP_BRIDGE;
+#endif
+
+ switch (bridge_to_use) {
+ case HOST_LWIP_BRIDGE:
+ if (!datapath) {
+ ESP_LOGV(TAG, "datapath closed, drop packet");
+ goto DONE;
+ }
+ /* Send to Host */
+ ESP_LOGV(TAG, "host packet");
+ populate_wifi_buffer_handle(&buf_handle, ESP_STA_IF, buffer, len);
+
+ if (unlikely(send_to_host_queue(&buf_handle, PRIO_Q_OTHERS)))
+ goto DONE;
+
+#if ESP_PKT_STATS
+ pkt_stats.sta_sh_in++;
+ pkt_stats.sta_host_lwip_out++;
+#endif
+ break;
+
+ case SLAVE_LWIP_BRIDGE:
+ /* Send to local LWIP */
+ ESP_LOGV(TAG, "slave packet");
+ esp_netif_receive(slave_sta_netif, buffer, len, eb);
+#if ESP_PKT_STATS
+ pkt_stats.sta_slave_lwip_out++;
+#endif
+ break;
+
+ case BOTH_LWIP_BRIDGE:
+ ESP_LOGV(TAG, "slave & host packet");
+
+ void * copy_buff = malloc(len);
+ assert(copy_buff);
+ memcpy(copy_buff, buffer, len);
+
+ /* slave LWIP */
+ esp_netif_receive(slave_sta_netif, buffer, len, eb);
+
+ ESP_LOGV(TAG, "slave & host packet");
+ if (datapath) {
+ /* Host LWIP, free up wifi buffers */
+ populate_buff_handle(&buf_handle, ESP_STA_IF, copy_buff, len, free, copy_buff, 0, 0, 0);
+ if (unlikely(send_to_host_queue(&buf_handle, PRIO_Q_OTHERS)))
+ goto DONE;
+
+ #if ESP_PKT_STATS
+ pkt_stats.sta_sh_in++;
+ pkt_stats.sta_both_lwip_out++;
+ #endif
+ } else {
+ #if ESP_PKT_STATS
+ pkt_stats.sta_slave_lwip_out++;
+ #endif
+ }
+
+ break;
+
+ default:
+ ESP_LOGV(TAG, "Packet filtering failed, drop packet");
+ goto DONE;
+ }
+
+ return ESP_OK;
+
+DONE:
+ esp_wifi_internal_free_rx_buffer(eb);
+ return ESP_OK;
+}
+
+static void process_tx_pkt(interface_buffer_handle_t *buf_handle)
+{
+ int host_awake = 1;
+
+ /* Check if data path is not yet open */
+ if (!datapath) {
+ /* Post processing */
+ if (buf_handle->free_buf_handle && buf_handle->priv_buffer_handle) {
+ buf_handle->free_buf_handle(buf_handle->priv_buffer_handle);
+ buf_handle->priv_buffer_handle = NULL;
+ }
+ ESP_LOGD(TAG, "Data path stopped");
+ usleep(100*1000);
+ return;
+ }
+ if (if_context && if_context->if_ops && if_context->if_ops->write) {
+
+ if (is_host_power_saving() && is_host_wakeup_needed(buf_handle)) {
+ ESP_LOGI(TAG, "Host sleeping, trigger wake-up");
+ ESP_HEXLOGW("Wakeup_pkt", buf_handle->payload+H_ESP_PAYLOAD_HEADER_OFFSET,
+ buf_handle->payload_len, buf_handle->payload_len);
+ host_awake = wakeup_host(portMAX_DELAY);
+ buf_handle->flag |= FLAG_WAKEUP_PKT;
+ }
+
+ if (host_awake)
+ if_context->if_ops->write(if_handle, buf_handle);
+ else
+ ESP_LOGI(TAG, "Host wakeup failed, drop packet");
+ }
+
+ /* Post processing */
+ if (buf_handle->free_buf_handle && buf_handle->priv_buffer_handle) {
+ buf_handle->free_buf_handle(buf_handle->priv_buffer_handle);
+ buf_handle->priv_buffer_handle = NULL;
+ }
+}
+
+static void parse_protobuf_req(void)
+{
+ protocomm_pserial_data_ready(pc_pserial, r.data,
+ r.len, UNKNOWN_CTRL_MSG_ID);
+}
+
+esp_err_t send_event_to_host(int event_id)
+{
+ return protocomm_pserial_data_ready(pc_pserial, NULL, 0, event_id);
+}
+
+esp_err_t send_event_data_to_host(int event_id, void *data, int size)
+{
+ return protocomm_pserial_data_ready(pc_pserial, data, size, event_id);
+}
+
+static void process_serial_rx_pkt(uint8_t *buf)
+{
+ struct esp_payload_header *header = NULL;
+ uint16_t payload_len = 0;
+ uint8_t *payload = NULL;
+ int rem_buff_size;
+
+ header = (struct esp_payload_header *) buf;
+ payload_len = le16toh(header->len);
+ payload = buf + le16toh(header->offset);
+ rem_buff_size = sizeof(r.data) - r.len;
+
+ ESP_HEXLOGV("serial_rx", payload, payload_len, 32);
+
+ while (r.valid)
+ {
+ ESP_LOGI(TAG,"More segment: %u curr seq: %u header seq: %u\n",
+ header->flags & MORE_FRAGMENT, r.cur_seq_no, header->seq_num);
+ vTaskDelay(10);
+ }
+
+ if (!r.len) {
+ /* New Buffer */
+ r.cur_seq_no = le16toh(header->seq_num);
+ }
+
+ if (header->seq_num != r.cur_seq_no) {
+ /* Sequence number mismatch */
+ r.valid = 1;
+ ESP_LOGV(TAG, "Final Frag: r.valid=1");
+ parse_protobuf_req();
+ return;
+ }
+
+ memcpy((r.data + r.len), payload, min(payload_len, rem_buff_size));
+ r.len += min(payload_len, rem_buff_size);
+
+ if (!(header->flags & MORE_FRAGMENT)) {
+ /* Received complete buffer */
+ r.valid = 1;
+ ESP_LOGV(TAG, "no frag case: r.valid=1");
+ parse_protobuf_req();
+ }
+}
+
+
+
+static void process_priv_pkt(uint8_t *payload, uint16_t payload_len)
+{
+ struct esp_priv_event *event;
+
+ if (!payload || !payload_len)
+ return;
+
+ event = (struct esp_priv_event *) payload;
+
+ if (event->event_type == ESP_PRIV_EVENT_INIT) {
+ ESP_HEXLOGD("init_config", event->event_data, event->event_len, 32);
+ } else {
+ ESP_LOGW(TAG, "Drop unknown event\n\r");
+ }
+}
+
+static void process_rx_pkt(interface_buffer_handle_t *buf_handle)
+{
+
+ struct esp_payload_header *header = NULL;
+ uint8_t *payload = NULL;
+ uint16_t payload_len = 0;
+ int ret = 0;
+ int retry_wifi_tx = MAX_WIFI_STA_TX_RETRY;
+
+ header = (struct esp_payload_header *) buf_handle->payload;
+ payload = buf_handle->payload + le16toh(header->offset);
+ payload_len = le16toh(header->len);
+
+ ESP_HEXLOGV("bus_RX", payload, payload_len, 16);
+
+
+ if (buf_handle->if_type == ESP_STA_IF && station_connected) {
+ /* Forward data to wlan driver */
+ do {
+ ret = esp_wifi_internal_tx(ESP_IF_WIFI_STA, payload, payload_len);
+ if (ret) {
+ vTaskDelay(pdMS_TO_TICKS(1));
+ }
+
+ retry_wifi_tx--;
+ } while (ret && retry_wifi_tx);
+
+#if ESP_PKT_STATS
+ if (ret)
+ pkt_stats.hs_bus_sta_fail++;
+ else
+ pkt_stats.hs_bus_sta_out++;
+#endif
+ } else if (buf_handle->if_type == ESP_AP_IF && softap_started) {
+ /* Forward data to wlan driver */
+ esp_wifi_internal_tx(ESP_IF_WIFI_AP, payload, payload_len);
+ ESP_HEXLOGV("AP_Put", payload, payload_len, 32);
+ } else if (buf_handle->if_type == ESP_SERIAL_IF) {
+#if ESP_PKT_STATS
+ pkt_stats.serial_rx++;
+#endif
+ process_serial_rx_pkt(buf_handle->payload);
+ } else if (buf_handle->if_type == ESP_PRIV_IF) {
+ process_priv_pkt(payload, payload_len);
+ }
+#if defined(CONFIG_BT_ENABLED) && BLUETOOTH_HCI
+ else if (buf_handle->if_type == ESP_HCI_IF) {
+ process_hci_rx_pkt(payload, payload_len);
+ }
+#endif
+#if TEST_RAW_TP
+ else if (buf_handle->if_type == ESP_TEST_IF) {
+ debug_update_raw_tp_rx_count(payload_len);
+ }
+#endif
+
+ /* Free buffer handle */
+ if (buf_handle->free_buf_handle && buf_handle->priv_buffer_handle) {
+ buf_handle->free_buf_handle(buf_handle->priv_buffer_handle);
+ buf_handle->priv_buffer_handle = NULL;
+ }
+
+}
+
+/* Get data from host */
+static void recv_task(void* pvParameters)
+{
+ interface_buffer_handle_t buf_handle = {0};
+
+ for (;;) {
+
+ if (!datapath) {
+ /* Datapath is not enabled by host yet*/
+ vTaskDelay(pdMS_TO_TICKS(1));
+ continue;
+ }
+
+ /* receive data from transport layer */
+ if (if_context && if_context->if_ops && if_context->if_ops->read) {
+ int len = if_context->if_ops->read(if_handle, &buf_handle);
+ if (len <= 0) {
+ vTaskDelay(2);
+ continue;
+ }
+ }
+
+ process_rx_pkt(&buf_handle);
+ }
+}
+
+static ssize_t serial_read_data(uint8_t *data, ssize_t len)
+{
+ len = min(len, r.len);
+ if (r.valid) {
+ memcpy(data, r.data, len);
+ r.valid = 0;
+ r.len = 0;
+ r.cur_seq_no = 0;
+ } else {
+ ESP_LOGI(TAG,"No data to be read, len %d", len);
+ }
+ return len;
+}
+
+int send_to_host_queue(interface_buffer_handle_t *buf_handle, uint8_t queue_type)
+{
+ process_tx_pkt(buf_handle);
+ return ESP_OK;
+}
+
+static esp_err_t serial_write_data(uint8_t* data, ssize_t len)
+{
+ uint8_t *pos = data;
+ int32_t left_len = len;
+ int32_t frag_len = 0;
+ static uint16_t seq_num = 0;
+
+ do {
+ interface_buffer_handle_t buf_handle = {0};
+
+ seq_num++;
+
+ buf_handle.if_type = ESP_SERIAL_IF;
+ buf_handle.if_num = 0;
+ buf_handle.seq_num = seq_num;
+
+ if (left_len > ETH_DATA_LEN) {
+ frag_len = ETH_DATA_LEN;
+ buf_handle.flag = MORE_FRAGMENT;
+ } else {
+ frag_len = left_len;
+ buf_handle.flag = 0;
+ buf_handle.priv_buffer_handle = data;
+ buf_handle.free_buf_handle = free;
+ }
+
+ buf_handle.payload = pos;
+ buf_handle.payload_len = frag_len;
+
+ if (send_to_host_queue(&buf_handle, PRIO_Q_SERIAL)) {
+ if (data) {
+ free(data);
+ data = NULL;
+ }
+ return ESP_FAIL;
+ }
+
+ ESP_HEXLOGV("serial_tx_create", data, frag_len, 32);
+
+ left_len -= frag_len;
+ pos += frag_len;
+ } while(left_len);
+
+ return ESP_OK;
+}
+
+int event_handler(uint8_t val)
+{
+ switch(val) {
+ case ESP_OPEN_DATA_PATH:
+ if (if_handle) {
+ if_handle->state = ACTIVE;
+ datapath = 1;
+ ESP_EARLY_LOGI(TAG, "Start Data Path");
+ if (host_reset_sem) {
+ xSemaphoreGive(host_reset_sem);
+ }
+ } else {
+ ESP_EARLY_LOGI(TAG, "Failed to Start Data Path");
+ }
+ break;
+
+ case ESP_CLOSE_DATA_PATH:
+ datapath = 0;
+ if (if_handle) {
+ ESP_EARLY_LOGI(TAG, "Stop Data Path");
+ if_handle->state = DEACTIVE;
+ } else {
+ ESP_EARLY_LOGI(TAG, "Failed to Stop Data Path");
+ }
+ break;
+
+ case ESP_POWER_SAVE_ON:
+ host_power_save_alert(ESP_POWER_SAVE_ON);
+ if_handle->state = ACTIVE;
+ break;
+
+ case ESP_POWER_SAVE_OFF:
+ if_handle->state = ACTIVE;
+ if (host_reset_sem) {
+ xSemaphoreGive(host_reset_sem);
+ }
+ host_power_save_alert(ESP_POWER_SAVE_OFF);
+ break;
+ }
+ return 0;
+}
+
+#if defined(CONFIG_ESP_GPIO_SLAVE_RESET) && (CONFIG_ESP_GPIO_SLAVE_RESET != -1)
+static void IRAM_ATTR gpio_resetpin_isr_handler(void* arg)
+{
+
+ ESP_EARLY_LOGI(TAG, "*********");
+ if (CONFIG_ESP_GPIO_SLAVE_RESET == -1) {
+ ESP_EARLY_LOGI(TAG, "%s: using EN pin for slave reset", __func__);
+ return;
+ }
+
+ static uint32_t lasthandshaketime_us;
+ uint32_t currtime_us = esp_timer_get_time();
+
+ if (gpio_get_level(CONFIG_ESP_GPIO_SLAVE_RESET) == 0) {
+ lasthandshaketime_us = currtime_us;
+ } else {
+ uint32_t diff = currtime_us - lasthandshaketime_us;
+ ESP_EARLY_LOGI(TAG, "%s Diff: %u", __func__, diff);
+ if (diff < 500) {
+ return; //ignore everything < half ms after an earlier irq
+ } else {
+ ESP_EARLY_LOGI(TAG, "Host triggered slave reset");
+ esp_restart();
+ }
+ }
+}
+
+static void register_reset_pin(uint32_t gpio_num)
+{
+ if (gpio_num != -1) {
+ ESP_LOGI(TAG, "Using GPIO [%lu] as slave reset pin", gpio_num);
+ gpio_reset_pin(gpio_num);
+
+ gpio_config_t slave_reset_pin_conf={
+ .intr_type=GPIO_INTR_DISABLE,
+ .mode=GPIO_MODE_INPUT,
+ .pull_up_en=1,
+ .pin_bit_mask=(1< 8).
+ * If you want to connect the device to deprecated WEP/WPA networks, Please set the threshold value
+ * to WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK and set the password with length and format matching to
+ * WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK standards.
+ */
+ .threshold.authmode = ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD,
+ .sae_pwe_h2e = ESP_WIFI_SAE_MODE,
+ .sae_h2e_identifier = EXAMPLE_H2E_IDENTIFIER,
+ .scan_method = WIFI_ALL_CHANNEL_SCAN,
+ .sort_method = WIFI_CONNECT_AP_BY_SIGNAL,
+
+ },
+ };
+
+ ESP_ERROR_CHECK(esp_hosted_set_sta_config(WIFI_IF_STA, &wifi_config) );
+
+ return ESP_OK;
+}
+
+static bool wifi_is_provisioned(void)
+{
+ wifi_config_t wifi_cfg = {0};
+
+ if (esp_wifi_get_config(WIFI_IF_STA, &wifi_cfg) != ESP_OK) {
+ ESP_LOGI(TAG, "Wifi get config failed");
+ return false;
+ }
+
+ ESP_LOGI(TAG, "SSID: %s", wifi_cfg.sta.ssid);
+
+ if (strlen((const char *) wifi_cfg.sta.ssid)) {
+ ESP_LOGI(TAG, "Wifi provisioned");
+ return true;
+ }
+ ESP_LOGI(TAG, "Wifi not provisioned, Fallback to example config");
+
+ return false;
+}
+
+static int connect_sta(void)
+{
+ wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+
+ ESP_ERROR_CHECK(esp_hosted_wifi_init(&cfg));
+
+ ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
+
+#if CONFIG_WIFI_CMD_DEFAULT_COUNTRY_CN
+ /* Only set country once during first initialize wifi */
+ static bool country_code_has_set = false;
+ if (country_code_has_set == false) {
+ wifi_country_t country = {
+ .cc = "CN",
+ .schan = 1,
+ .nchan = 13,
+ .policy = 0
+ };
+ esp_wifi_set_country(&country);
+ country_code_has_set = true;
+ }
+#endif
+
+ if (! wifi_is_provisioned()) {
+ fallback_to_sdkconfig_wifi_config();
+ }
+
+ ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
+
+ ESP_ERROR_CHECK(esp_wifi_start() );
+
+#if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS
+#if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_MU_STATS
+ esp_wifi_enable_rx_statistics(true, true);
+#else
+ esp_wifi_enable_rx_statistics(true, false);
+#endif
+#endif
+
+#if CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS
+ esp_wifi_enable_tx_statistics(ESP_WIFI_ACI_BE, true);
+#endif
+
+ return ESP_OK;
+}
+#endif
+
+#if 1
+#if H_HOST_PS_ALLOWED
+
+/* Update timer callback function */
+static void delayed_dhcp_dns_timer_cb(TimerHandle_t xTimer)
+{
+ /* Check if host has fetched IP or max retries reached */
+ if (has_host_fetched_auto_ip() || dhcp_dns_retry_count >= MAX_DHCP_DNS_RETRIES) {
+ /* Stop retrying */
+ if (delayed_dhcp_dns_timer) {
+ xTimerDelete(delayed_dhcp_dns_timer, 0);
+ delayed_dhcp_dns_timer = NULL;
+ }
+ dhcp_dns_retry_count = 0;
+ return;
+ }
+
+ send_dhcp_dns_info_to_host(0, 0);
+ dhcp_dns_retry_count++;
+
+#if 0
+ vTaskDelay(pdMS_TO_TICKS(50));
+ s2h_dhcp_dns.dhcp_up = 1;
+ send_dhcp_dns_info_to_host(1, 0);
+#endif
+}
+
+/* Function to schedule delayed DHCP/DNS info send */
+static void schedule_delayed_dhcp_dns_info(void)
+{
+ const TickType_t delay_ticks = pdMS_TO_TICKS(500); /* 500ms delay */
+
+ /* Delete existing timer if any */
+ if (delayed_dhcp_dns_timer) {
+ xTimerDelete(delayed_dhcp_dns_timer, 0);
+ delayed_dhcp_dns_timer = NULL;
+ }
+
+ /* Create and start one-shot timer */
+ delayed_dhcp_dns_timer = xTimerCreate("DhcpDns",
+ delay_ticks,
+ pdFALSE, /* One-shot timer */
+ 0,
+ delayed_dhcp_dns_timer_cb);
+
+ if (delayed_dhcp_dns_timer) {
+ if (xTimerStart(delayed_dhcp_dns_timer, 0) != pdPASS) {
+ ESP_LOGE(TAG, "Failed to start delayed DHCP/DNS timer");
+ xTimerDelete(delayed_dhcp_dns_timer, 0);
+ delayed_dhcp_dns_timer = NULL;
+ }
+ } else {
+ ESP_LOGE(TAG, "Failed to create delayed DHCP/DNS timer");
+ }
+}
+#endif
+/* Update host wakeup callback */
+void host_wakeup_callback(void)
+{
+ /* Handle immediate wakeup tasks */
+#if H_HOST_PS_ALLOWED
+ /* Reset retry count on new wakeup */
+ dhcp_dns_retry_count = 0;
+
+ /* Schedule delayed DHCP/DNS info send */
+ if (station_connected) {
+ schedule_delayed_dhcp_dns_info();
+ }
+#endif
+}
+#else
+static void host_wakeup_callback(void)
+{
+#if H_HOST_PS_ALLOWED
+ send_dhcp_dns_info_to_host(1, 0);
+#endif
+}
+#endif
+
+static void host_reset_task(void* pvParameters)
+{
+ uint8_t capa = 0;
+
+ ESP_LOGI(TAG, "host reset handler task started");
+
+ while (1) {
+
+ if (host_reset_sem) {
+ xSemaphoreTake(host_reset_sem, portMAX_DELAY);
+ } else {
+ vTaskDelay(pdMS_TO_TICKS(100));
+ continue;
+ }
+
+ capa = get_capabilities();
+ /* send capabilities to host */
+ ESP_LOGI(TAG,"Send slave up event");
+ generate_startup_event(capa);
+ send_event_to_host(CTRL_MSG_ID__Event_ESPInit);
+
+#ifdef CONFIG_NETWORK_SPLIT_ENABLED
+ ESP_LOGI(TAG,"--- Wait for IP ---");
+ while (!station_got_ip) {
+ vTaskDelay(pdMS_TO_TICKS(50));
+ }
+ send_dhcp_dns_info_to_host(1, 1);
+#endif
+ }
+}
+
+
+esp_err_t esp_hosted_coprocessor_init(void)
+{
+ assert(host_reset_sem = xSemaphoreCreateBinary());
+
+ print_firmware_version();
+
+#if CONFIG_NETWORK_SPLIT_ENABLED
+ ESP_ERROR_CHECK(esp_netif_init());
+#endif
+ ESP_ERROR_CHECK(esp_event_loop_create_default());
+
+#if defined(CONFIG_ESP_GPIO_SLAVE_RESET) && (CONFIG_ESP_GPIO_SLAVE_RESET != -1)
+ register_reset_pin(CONFIG_ESP_GPIO_SLAVE_RESET);
+#endif
+
+
+#ifdef CONFIG_ESP_HOSTED_HOST_RESERVED_PORTS_CONFIGURED
+ ESP_LOGI(TAG, "Configuring host static port forwarding rules from slave kconfig");
+ configure_host_static_port_forwarding_rules(CONFIG_ESP_HOSTED_HOST_RESERVED_TCP_SRC_PORTS,
+ CONFIG_ESP_HOSTED_HOST_RESERVED_TCP_DEST_PORTS,
+ CONFIG_ESP_HOSTED_HOST_RESERVED_UDP_SRC_PORTS,
+ CONFIG_ESP_HOSTED_HOST_RESERVED_UDP_DEST_PORTS);
+#endif
+
+
+ host_power_save_init(host_wakeup_callback);
+
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_SOC_BT_SUPPORTED)
+ initialise_bluetooth();
+#endif
+
+ pc_pserial = protocomm_new();
+ if (pc_pserial == NULL) {
+ ESP_LOGE(TAG,"Failed to allocate memory for new instance of protocomm ");
+ return ESP_FAIL;
+ }
+
+ /* Endpoint for control command responses */
+ if (protocomm_add_endpoint(pc_pserial, CTRL_EP_NAME_RESP,
+ data_transfer_handler, NULL) != ESP_OK) {
+ ESP_LOGE(TAG, "Failed to add enpoint");
+ return ESP_FAIL;
+ }
+
+ /* Endpoint for control notifications for events subscribed by user */
+ if (protocomm_add_endpoint(pc_pserial, CTRL_EP_NAME_EVENT,
+ ctrl_notify_handler, NULL) != ESP_OK) {
+ ESP_LOGE(TAG, "Failed to add enpoint");
+ return ESP_FAIL;
+ }
+
+ protocomm_pserial_start(pc_pserial, serial_write_data, serial_read_data);
+
+ if_context = interface_insert_driver(event_handler);
+
+#if CONFIG_ESP_SPI_HOST_INTERFACE
+ datapath = 1;
+ if (host_reset_sem)
+ xSemaphoreGive(host_reset_sem);
+#endif
+
+ if (!if_context || !if_context->if_ops) {
+ ESP_LOGE(TAG, "Failed to insert driver\n");
+ return ESP_FAIL;
+ }
+
+ if_handle = if_context->if_ops->init();
+
+ if (!if_handle) {
+ ESP_LOGE(TAG, "Failed to initialize driver\n");
+ return ESP_FAIL;
+ }
+
+
+ assert(xTaskCreate(recv_task , "recv_task" ,
+ CONFIG_ESP_DEFAULT_TASK_STACK_SIZE, NULL ,
+ CONFIG_ESP_HOSTED_TASK_PRIORITY_DEFAULT, NULL) == pdTRUE);
+ create_debugging_tasks();
+
+#ifdef H_ESP_HOSTED_CLI_ENABLED
+ esp_hosted_cli_start();
+#endif
+
+#ifdef CONFIG_NETWORK_SPLIT_ENABLED
+
+ create_slave_sta_netif(H_SLAVE_LWIP_DHCP_AT_SLAVE);
+
+ ESP_LOGI(TAG, "Default LWIP post filtering packets to send: %s",
+#if defined(CONFIG_ESP_DEFAULT_LWIP_SLAVE)
+ "slave. Host need to use **static netif** only"
+#elif defined(CONFIG_ESP_DEFAULT_LWIP_HOST)
+ "host"
+#elif defined(CONFIG_ESP_DEFAULT_LWIP_BOTH)
+ "host+slave"
+#endif
+ );
+#endif
+
+#if 1
+ connect_sta();
+#endif
+
+ ESP_LOGI(TAG, "bus tx locked on slave bootup");
+
+ while(!datapath) {
+ vTaskDelay(10);
+ }
+ ESP_LOGI(TAG, "bus tx unlocked");
+
+ assert(xTaskCreate(host_reset_task, "host_reset_task" ,
+ CONFIG_ESP_DEFAULT_TASK_STACK_SIZE, NULL ,
+ CONFIG_ESP_HOSTED_TASK_PRIORITY_DEFAULT, NULL) == pdTRUE);
+
+
+ #ifdef CONFIG_NETWORK_SPLIT_ENABLED
+ while (!station_got_ip)
+ sleep(1);
+ #endif
+
+ /* Register how you are going to handle the user defined RPC requests */
+
+ register_custom_rpc_unserialised_req_handler(handle_custom_unserialised_rpc_request);
+
+ return ESP_OK;
+}
+
+void app_main(void)
+{
+ /* Initialize NVS */
+ esp_err_t ret = nvs_flash_init();
+
+ if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
+ ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
+ ESP_ERROR_CHECK(nvs_flash_erase());
+ ret = nvs_flash_init();
+ }
+ ESP_ERROR_CHECK( ret );
+
+ esp_hosted_coprocessor_init();
+#ifdef CONFIG_NETWORK_SPLIT_ENABLED
+
+
+#ifdef ESP_HOSTED_COPROCESSOR_EXAMPLE_HTTP_CLIENT
+ extern void slave_http_req_example(void);
+ slave_http_req_example();
+#endif
+
+#endif
+
+}
+
+/* Example callback functions */
+static esp_err_t handle_custom_unserialised_rpc_request(const custom_rpc_unserialised_data_t *req, custom_rpc_unserialised_data_t *resp_out) {
+ /* --------- Caution ----------
+ * Keep this function as simple, small and fast as possible
+ * This function is as callback in the Rx thread.
+ * Do not use any blocking calls here
+ * ----------------------------
+ */
+ esp_err_t ret = ESP_FAIL;
+
+ /* Process custom data from req */
+ ESP_LOGI(TAG, "Received custom RPC request [%" PRIu32 "] with len: %u", req->custom_msg_id, req->data_len);
+ ESP_HEXLOGD("RPC_DATA_IN", req->data, req->data_len, 32);
+
+ /* Clear response data structure before use */
+ memset(resp_out, 0, sizeof(custom_rpc_unserialised_data_t));
+
+ resp_out->custom_msg_id = req->custom_msg_id; /* Right now Response ID is same as Request ID, you can customise it as needed */
+
+ switch (req->custom_msg_id) {
+
+ case CUSTOM_RPC_REQ_ID__ECHO_BACK_RESPONSE:
+ /* Example: Echo back the data */
+ if (req->data_len > 0) {
+ resp_out->data = malloc(req->data_len);
+ if (resp_out->data) {
+ memcpy(resp_out->data, req->data, req->data_len);
+ resp_out->data_len = req->data_len;
+ resp_out->free_func = free; /* Always set free function when allocating memory */
+ ESP_LOGI(TAG, "Echoing back %u bytes of data", req->data_len);
+ ret = ESP_OK;
+ } else {
+ ESP_LOGE(TAG, "Failed to allocate memory for response data");
+ ret = ESP_FAIL;
+ }
+ } else {
+ /* No data to echo back, still consider it a success */
+ ESP_LOGI(TAG, "No data to echo back");
+ ret = ESP_OK;
+ }
+ break;
+
+ case CUSTOM_RPC_REQ_ID__ECHO_BACK_AS_EVENT:
+ /* Process the request and trigger an event */
+ if (req->data_len > 0 && req->data) {
+ /* Map the request 'CUSTOM_RPC_REQ_ID__ECHO_BACK_AS_EVENT' to event 'CUSTOM_RPC_EVENT_ID__DEMO_ECHO_BACK_REQUEST' */
+ ret = create_and_send_custom_rpc_unserialised_event(CUSTOM_RPC_EVENT_ID__DEMO_ECHO_BACK_REQUEST, req->data, req->data_len);
+ } else {
+ ESP_LOGI(TAG, "No data to echo back as event");
+ ret = ESP_OK;
+ }
+ break;
+
+ case CUSTOM_RPC_REQ_ID__ONLY_ACK:
+ /* Just process the request, don't return any data */
+ ESP_LOGI(TAG, "Processing request with ID [%" PRIu32 "] - acknowledgement only", req->custom_msg_id);
+ ret = ESP_OK;
+ break;
+
+ default:
+ /* Handle unknown message IDs */
+ ESP_LOGW(TAG, "Unhandled custom RPC request ID [%" PRIu32 "], just acknowledging receipt", req->custom_msg_id);
+ ret = ESP_OK; /* Still return OK to acknowledge receipt */
+ break;
+ }
+
+ /* Debug output for response */
+ if (resp_out->data && resp_out->data_len > 0) {
+ ESP_HEXLOGD("RPC_DATA_OUT", resp_out->data, resp_out->data_len, 32);
+ }
+
+ return ret;
+}
+
+/* Create a helper function to allocate and fill event data structure */
+esp_err_t create_and_send_custom_rpc_unserialised_event(uint32_t custom_event_id, const void *data, size_t data_len) {
+ /* Calculate total size needed for the structure plus data */
+
+ custom_rpc_unserialised_data_t event_data = {0};
+ event_data.data_len = data && data_len > 0 ? data_len : 0;
+
+ ESP_LOGI(TAG, "Creating custom RPC event with ID [%" PRIu32 "], data: %p, data length: %u", custom_event_id, data, event_data.data_len);
+
+ if (event_data.data_len) {
+ /* Allocate memory for the entire structure */
+ event_data.data = (uint8_t *)malloc(event_data.data_len);
+ if (!event_data.data) {
+ ESP_LOGE(TAG, "Failed to allocate memory for custom RPC event");
+ return ESP_FAIL;
+ }
+ memcpy(event_data.data, data, event_data.data_len);
+ }
+
+ /* Fill in the data */
+ event_data.custom_msg_id = custom_event_id;
+ event_data.free_func = (event_data.data_len) ? free : NULL;
+
+
+ /* Send the event */
+ esp_err_t ret = send_custom_rpc_unserialised_event(&event_data);
+
+ return ret;
+}
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/app_main.h b/esp_hosted_fg/esp/esp_driver/network_adapter/main/esp_hosted_coprocessor.h
similarity index 95%
rename from esp_hosted_fg/esp/esp_driver/network_adapter/main/app_main.h
rename to esp_hosted_fg/esp/esp_driver/network_adapter/main/esp_hosted_coprocessor.h
index 653873769f..9b5e102739 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/main/app_main.h
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/esp_hosted_coprocessor.h
@@ -29,4 +29,6 @@
typedef struct {
interface_context_t *context;
} adapter;
+
+esp_err_t esp_hosted_coprocessor_init(void);
#endif
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/esp_hosted_lwip_src_port_hook.h b/esp_hosted_fg/esp/esp_driver/network_adapter/main/esp_hosted_lwip_src_port_hook.h
new file mode 100644
index 0000000000..6ad4d5d76a
--- /dev/null
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/esp_hosted_lwip_src_port_hook.h
@@ -0,0 +1,70 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Unlicense OR CC0-1.0
+ */
+
+
+#ifndef __ESP_HOSTED_LWIP_SRC_PORT_HOOK_H__
+#define __ESP_HOSTED_LWIP_SRC_PORT_HOOK_H__
+
+#include "lwip/opt.h"
+
+/* ----------------------------------Slave (local) Port Config---------------------------------------- */
+/* If configured, Any new UDP socket would automatically bind as local port within this specified UDP port range.
+ * Please note, Reserved ports (generally <1024) like DHCP, etc would still work as they generally are hardcoded
+ */
+
+#define ENSURE_PORT_RANGE(port, START, END) \
+ (((port) >= (START) && (port) <= (END)) ? \
+ (port) : \
+ (((port) % ((END) - (START) + 1)) + (START)))
+
+#ifdef CONFIG_LWIP_TCP_LOCAL_PORT_RANGE_START
+#define TCP_LOCAL_PORT_RANGE_START CONFIG_LWIP_TCP_LOCAL_PORT_RANGE_START
+#define TCP_LOCAL_PORT_RANGE_END CONFIG_LWIP_TCP_LOCAL_PORT_RANGE_END
+#define TCP_ENSURE_LOCAL_PORT_RANGE(port) ENSURE_PORT_RANGE(port, TCP_LOCAL_PORT_RANGE_START, TCP_LOCAL_PORT_RANGE_END)
+#if CONFIG_LWIP_TCP_LOCAL_PORT_RANGE_END == 0xffff
+ #define IS_LOCAL_TCP_PORT(port) (port>=TCP_LOCAL_PORT_RANGE_START)
+#else
+ #define IS_LOCAL_TCP_PORT(port) (port>=TCP_LOCAL_PORT_RANGE_START && (port<=CONFIG_LWIP_TCP_LOCAL_PORT_RANGE_END))
+#endif
+#endif
+
+#ifdef CONFIG_LWIP_TCP_REMOTE_PORT_RANGE_START
+#define TCP_REMOTE_PORT_RANGE_START CONFIG_LWIP_TCP_REMOTE_PORT_RANGE_START
+#define TCP_REMOTE_PORT_RANGE_END CONFIG_LWIP_TCP_REMOTE_PORT_RANGE_END
+#define TCP_ENSURE_REMOTE_PORT_RANGE(port) ENSURE_PORT_RANGE(port, TCP_REMOTE_PORT_RANGE_START, TCP_REMOTE_PORT_RANGE_END)
+#if CONFIG_LWIP_TCP_REMOTE_PORT_RANGE_END == 0xffff
+ #define IS_REMOTE_TCP_PORT(port) (port>=TCP_REMOTE_PORT_RANGE_START)
+#else
+ #define IS_REMOTE_TCP_PORT(port) (port>=TCP_REMOTE_PORT_RANGE_START && (port<=CONFIG_LWIP_TCP_REMOTE_PORT_RANGE_END))
+#endif
+#endif
+
+#ifdef CONFIG_LWIP_UDP_LOCAL_PORT_RANGE_START
+#define UDP_LOCAL_PORT_RANGE_START CONFIG_LWIP_UDP_LOCAL_PORT_RANGE_START
+#define UDP_LOCAL_PORT_RANGE_END CONFIG_LWIP_UDP_LOCAL_PORT_RANGE_END
+#define UDP_ENSURE_LOCAL_PORT_RANGE(port) ENSURE_PORT_RANGE(port, UDP_LOCAL_PORT_RANGE_START, UDP_LOCAL_PORT_RANGE_END)
+
+#if CONFIG_LWIP_UDP_LOCAL_PORT_RANGE_END == 0xffff
+ #define IS_LOCAL_UDP_PORT(port) (port>=UDP_LOCAL_PORT_RANGE_START)
+#else
+ #define IS_LOCAL_UDP_PORT(port) (port>=UDP_LOCAL_PORT_RANGE_START && (port<=CONFIG_LWIP_UDP_LOCAL_PORT_RANGE_END))
+#endif
+#define DNS_PORT_ALLOWED(port) IS_LOCAL_UDP_PORT(port)
+#endif
+
+#ifdef CONFIG_LWIP_UDP_REMOTE_PORT_RANGE_START
+#define UDP_REMOTE_PORT_RANGE_START CONFIG_LWIP_UDP_REMOTE_PORT_RANGE_START
+#define UDP_REMOTE_PORT_RANGE_END CONFIG_LWIP_UDP_REMOTE_PORT_RANGE_END
+#define UDP_ENSURE_REMOTE_PORT_RANGE(port) ENSURE_PORT_RANGE(port, UDP_REMOTE_PORT_RANGE_START, UDP_REMOTE_PORT_RANGE_END)
+
+#if CONFIG_LWIP_UDP_REMOTE_PORT_RANGE_END == 0xffff
+ #define IS_REMOTE_UDP_PORT(port) (port>=UDP_REMOTE_PORT_RANGE_START)
+#else
+ #define IS_REMOTE_UDP_PORT(port) (port>=UDP_REMOTE_PORT_RANGE_START && (port<=CONFIG_LWIP_UDP_REMOTE_PORT_RANGE_END))
+#endif
+#endif
+
+#endif /* __ESP_HOSTED_LWIP_SOURCE_PORT_BINDING_HOOK_H__ */
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/host_power_save.c b/esp_hosted_fg/esp/esp_driver/network_adapter/main/host_power_save.c
new file mode 100644
index 0000000000..811f9712c8
--- /dev/null
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/host_power_save.c
@@ -0,0 +1,250 @@
+/*
+ * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "host_power_save.h"
+#include "adapter.h"
+#include "driver/gpio.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/semphr.h"
+#include "freertos/timers.h"
+#include "esp_log.h"
+#include
+#include "esp_timer.h"
+#include "adapter.h"
+
+static char *TAG = "host_ps";
+
+#if H_HOST_PS_ALLOWED
+ SemaphoreHandle_t wakeup_sem;
+
+ uint8_t power_save_on;
+ #define GPIO_HOST_WAKEUP (CONFIG_HOST_WAKEUP_GPIO)
+
+ /* Assuming wakup gpio neg 'level' interrupt */
+ #define set_host_wakeup_gpio() gpio_set_level(GPIO_HOST_WAKEUP, 1)
+ #define reset_host_wakeup_gpio() gpio_set_level(GPIO_HOST_WAKEUP, 0)
+
+ static void oobTimerCallback( TimerHandle_t xTimer );
+ static void (*host_wakeup_cb)(void);
+ int64_t host_wakeup_time = 0;
+#endif
+
+
+int is_host_wakeup_needed(interface_buffer_handle_t *buf_handle)
+{
+ int wakup_needed = 0;
+ char reason[100] = "";
+#if H_HOST_PS_ALLOWED
+ uint8_t *buf_start;
+
+ buf_start = buf_handle->payload;
+
+#if 0
+ /* Flow conttrol packet cannot miss */
+ if (buf_handle->flow_ctl_en) {
+ strlcpy(reason, "flow_ctl_pkt", sizeof(reason));
+ wakup_needed = 1;
+ goto end;
+ }
+#endif
+ if (!buf_start) {
+ /* Do not wake up */
+ strlcpy(reason, "NULL_TxBuff", sizeof(reason));
+ wakup_needed = 0;
+ goto end;
+ }
+
+ /* Wake up for serial msg */
+ switch (buf_handle->if_type) {
+
+ case ESP_SERIAL_IF:
+ strlcpy(reason, "serial tx msg", sizeof(reason));
+ wakup_needed = 1;
+ goto end;
+ break;
+
+ case ESP_HCI_IF:
+ strlcpy(reason, "bt tx msg", sizeof(reason));
+ wakup_needed = 1;
+ goto end;
+ break;
+
+ case ESP_PRIV_IF:
+ strlcpy(reason, "priv tx msg", sizeof(reason));
+ wakup_needed = 1;
+ goto end;
+ break;
+
+ case ESP_TEST_IF:
+ strlcpy(reason, "test tx msg", sizeof(reason));
+ wakup_needed = 1;
+ goto end;
+ break;
+
+ case ESP_STA_IF:
+
+ /* TODO: parse packet if lwip split not configured.
+ * Decide if packets need to reach to host or not
+ **/
+ strlcpy(reason, "sta tx msg", sizeof(reason));
+ wakup_needed = 1;
+ goto end;
+ break;
+
+ case ESP_AP_IF:
+ strlcpy(reason, "ap tx msg", sizeof(reason));
+ wakup_needed = 1;
+ goto end;
+ break;
+ }
+
+end:
+#else
+ strlcpy(reason, "host_ps_disabled", sizeof(reason));
+ wakup_needed = 0;
+#endif
+
+ if (wakup_needed) {
+ ESP_LOGI(TAG, "Wakeup needed, reason %s", reason);
+ } else {
+ ESP_LOGI(TAG, "Wakeup not needed");
+ }
+ return wakup_needed;
+}
+
+
+void host_power_save_init(void (*fn_host_wakeup_cb)(void))
+{
+#if H_HOST_PS_ALLOWED
+ /* Configuration for the OOB line */
+ gpio_config_t io_conf={
+ .intr_type=GPIO_INTR_DISABLE,
+ .mode=GPIO_MODE_OUTPUT,
+ .pin_bit_mask=(1ULL< timeout_ms) {
+ /* timeout */
+ ESP_LOGI(TAG, "%s:%u timeout Curr:%llu start:%llu timeout:%lu",
+ __func__,__LINE__, GET_CURR_TIME_IN_MS(), start_time, timeout_ms);
+ break;
+ }
+
+ } while (1);
+
+ return wakeup_success;
+
+#else
+ return 1;
+#endif
+}
+
+void host_power_save_alert(uint32_t ps_evt)
+{
+#if H_HOST_PS_ALLOWED
+ BaseType_t do_yeild = pdFALSE;
+
+ if (ESP_POWER_SAVE_ON == ps_evt) {
+ ESP_EARLY_LOGI(TAG, "Host Sleep");
+ if (wakeup_sem) {
+ /* Host sleeping */
+ xSemaphoreTakeFromISR(wakeup_sem, &do_yeild);
+ }
+ power_save_on = 1;
+
+ } else if (ESP_POWER_SAVE_OFF == ps_evt) {
+ ESP_EARLY_LOGI(TAG, "Host Awake");
+ power_save_on = 0;
+
+ /* Update wakeup timestamp */
+ host_wakeup_time = esp_timer_get_time() / 1000; /* Convert to ms */
+
+ if (host_wakeup_cb) {
+ host_wakeup_cb();
+ }
+ if (wakeup_sem) {
+ xSemaphoreGiveFromISR(wakeup_sem, &do_yeild);
+ }
+ } else {
+ ESP_EARLY_LOGI(TAG, "Ignore event[%u]", ps_evt);
+ }
+
+ if (do_yeild == pdTRUE) {
+ portYIELD_FROM_ISR();
+ }
+#endif
+}
+
+#if H_HOST_PS_ALLOWED
+static void oobTimerCallback( TimerHandle_t xTimer )
+{
+ xTimerDelete(xTimer, 0);
+ reset_host_wakeup_gpio();
+}
+#endif
+
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/host_power_save.h b/esp_hosted_fg/esp/esp_driver/network_adapter/main/host_power_save.h
new file mode 100644
index 0000000000..c3ec478044
--- /dev/null
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/host_power_save.h
@@ -0,0 +1,50 @@
+/*
+ * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef __HOST_POWER_SAVE_H__
+#define __HOST_POWER_SAVE_H__
+
+#include "sdkconfig.h"
+#include "interface.h"
+
+#if defined(CONFIG_HOST_DEEP_SLEEP_ALLOWED)
+#error "Host power save is not supported, yet. will be supported in future releases"
+#if CONFIG_HOST_WAKEUP_GPIO == -1
+#error "CONFIG_HOST_WAKEUP_GPIO is not configured. Either disable host power save or configure the host wakeup GPIO pin using 'idf.py menuconfig'"
+#endif
+ #define H_HOST_PS_ALLOWED 1
+ extern uint8_t power_save_on;
+ extern int64_t host_wakeup_time;
+#endif
+
+
+void host_power_save_init(void (*host_wakeup_callback)(void));
+void host_power_save_deinit(void);
+int is_host_wakeup_needed(interface_buffer_handle_t *buf_handle);
+int wakeup_host(uint32_t timeout_ms);
+void host_power_save_alert(uint32_t ps_evt);
+
+/* Add new API to get last wakeup time */
+static inline int64_t get_last_wakeup_time(void)
+{
+#if H_HOST_PS_ALLOWED
+ return host_wakeup_time;
+#else
+ return 0;
+#endif
+}
+
+static inline int is_host_power_saving(void)
+{
+#if H_HOST_PS_ALLOWED
+ return power_save_on;
+#else
+ return 0;
+#endif
+}
+
+
+#endif
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/http_req.c b/esp_hosted_fg/esp/esp_driver/network_adapter/main/http_req.c
new file mode 100644
index 0000000000..a0c57714e7
--- /dev/null
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/http_req.c
@@ -0,0 +1,131 @@
+/* HTTP GET Example using plain POSIX sockets
+
+ This example code 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.
+*/
+#include
+#include "sdkconfig.h"
+
+#ifdef CONFIG_ESP_HOSTED_COPROCESSOR_EXAMPLE_HTTP_CLIENT
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_system.h"
+#include "esp_log.h"
+
+#include "lwip/err.h"
+#include "lwip/sockets.h"
+#include "lwip/sys.h"
+#include "lwip/netdb.h"
+#include "lwip/dns.h"
+
+
+
+extern volatile uint8_t station_connected;
+/* Constants that aren't configurable in menuconfig */
+#define WEB_SERVER CONFIG_HTTP_WEBSERVER
+#define WEB_PORT CONFIG_HTTP_WEBSERVER_PORT
+#define WEB_PATH CONFIG_HTTP_WEBSERVER_PATH
+
+static const char *TAG = "http_req";
+
+static const char *REQUEST = "GET " WEB_PATH " HTTP/1.0\r\n"
+ "Host: "WEB_SERVER":"WEB_PORT"\r\n"
+ "User-Agent: esp-idf/1.0 esp32\r\n"
+ "\r\n";
+
+static void http_get_task(void *pvParameters)
+{
+ const struct addrinfo hints = {
+ .ai_family = AF_INET,
+ .ai_socktype = SOCK_STREAM,
+ };
+ struct addrinfo *res;
+ struct in_addr *addr;
+ int s, r;
+ char recv_buf[64];
+
+ while(1) {
+ int err = getaddrinfo(WEB_SERVER, WEB_PORT, &hints, &res);
+
+ if(err != 0 || res == NULL) {
+ ESP_LOGE(TAG, "DNS lookup failed err=%d res=%p", err, res);
+ vTaskDelay(1000 / portTICK_PERIOD_MS);
+ continue;
+ }
+
+ /* Code to print the resolved IP.
+
+Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */
+ addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
+ ESP_LOGV(TAG, "DNS lookup succeeded. IP=%s", inet_ntoa(*addr));
+
+ s = socket(res->ai_family, res->ai_socktype, 0);
+ if(s < 0) {
+ ESP_LOGE(TAG, "... Failed to allocate socket.");
+ freeaddrinfo(res);
+ vTaskDelay(1000 / portTICK_PERIOD_MS);
+ continue;
+ }
+ ESP_LOGV(TAG, "... allocated socket");
+
+ if(connect(s, res->ai_addr, res->ai_addrlen) != 0) {
+ ESP_LOGE(TAG, "... socket connect failed errno=%d", errno);
+ close(s);
+ freeaddrinfo(res);
+ vTaskDelay(4000 / portTICK_PERIOD_MS);
+ continue;
+ }
+
+ ESP_LOGV(TAG, "... connected");
+ freeaddrinfo(res);
+
+ if (write(s, REQUEST, strlen(REQUEST)) < 0) {
+ ESP_LOGE(TAG, "... socket send failed");
+ close(s);
+ vTaskDelay(4000 / portTICK_PERIOD_MS);
+ continue;
+ }
+ ESP_LOGV(TAG, "... socket send success");
+
+ struct timeval receiving_timeout;
+ receiving_timeout.tv_sec = 5;
+ receiving_timeout.tv_usec = 0;
+ if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &receiving_timeout,
+ sizeof(receiving_timeout)) < 0) {
+ ESP_LOGE(TAG, "... failed to set socket receiving timeout");
+ close(s);
+ vTaskDelay(4000 / portTICK_PERIOD_MS);
+ continue;
+ }
+ ESP_LOGV(TAG, "... set socket receiving timeout success");
+
+ /* Read HTTP response */
+ do {
+ bzero(recv_buf, sizeof(recv_buf));
+ r = read(s, recv_buf, sizeof(recv_buf)-1);
+#if 0
+ for(int i = 0; i < r; i++) {
+ putchar(recv_buf[i]);
+ }
+#endif
+ } while(r > 0);
+
+ if (r)
+ ESP_LOGE(TAG, "HTTP req: return=%d errno=%d.", r, errno);
+ else
+ ESP_LOGI(TAG, "HTTP req fetched successful");
+
+ close(s);
+
+ vTaskDelay(CONFIG_HTTP_REQ_DELAY * 1000 / portTICK_PERIOD_MS);
+ }
+}
+
+void slave_http_req_example(void)
+{
+ xTaskCreate(&http_get_task, "http_get_task", 4096, NULL, CONFIG_ESP_HOSTED_TASK_PRIORITY_LOW, NULL);
+}
+#endif
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/idf_component.yml b/esp_hosted_fg/esp/esp_driver/network_adapter/main/idf_component.yml
new file mode 100644
index 0000000000..cb4d2b2053
--- /dev/null
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/idf_component.yml
@@ -0,0 +1,21 @@
+dependencies:
+ cmd_system:
+ path: ${IDF_PATH}/examples/system/console/advanced/components/cmd_system
+ rules:
+ - if: target not in ["esp32c2", "esp32c3"]
+ espressif/iperf:
+ version: "*"
+ rules:
+ - if: target not in ["esp32c2", "esp32c3"]
+ espressif/iperf-cmd:
+ version: "~0.1.1"
+ rules:
+ - if: target not in ["esp32c2", "esp32c3"]
+ esp-qa/wifi-cmd:
+ version: "~0.1.0"
+ rules:
+ - if: target not in ["esp32c2", "esp32c3"]
+ esp-qa/ping-cmd:
+ version: "~0.0.1"
+ rules:
+ - if: target not in ["esp32c2", "esp32c3"]
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/interface.h b/esp_hosted_fg/esp/esp_driver/network_adapter/main/interface.h
index 712f80581c..976fa22ace 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/main/interface.h
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/interface.h
@@ -17,10 +17,11 @@
#ifndef __TRANSPORT_LAYER_INTERFACE_H
#define __TRANSPORT_LAYER_INTERFACE_H
#include "esp_err.h"
+#include "esp_hosted_log.h"
#ifdef CONFIG_ESP_SDIO_HOST_INTERFACE
-#if defined(CONFIG_IDF_TARGET_ESP32)||defined(CONFIG_IDF_TARGET_ESP32C6)
+#if CONFIG_SOC_SDIO_SLAVE_SUPPORTED
#include "driver/sdio_slave.h"
#else
#error "SDIO is not supported for this chipset"
@@ -75,6 +76,14 @@ typedef struct {
INTERFACE_STATE state;
}interface_handle_t;
+#if CONFIG_ESP_SPI_HOST_INTERFACE
+#define MAX_TRANSPORT_BUF_SIZE 1600
+#elif CONFIG_ESP_SDIO_HOST_INTERFACE
+#define MAX_TRANSPORT_BUF_SIZE 1536
+#endif
+
+#define BSSID_BYTES_SIZE 6
+
typedef struct {
interface_handle_t * (*init)(void);
int32_t (*write)(interface_handle_t *handle, interface_buffer_handle_t *buf_handle);
@@ -94,4 +103,11 @@ interface_context_t * interface_insert_driver(int (*callback)(uint8_t val));
int interface_remove_driver();
void generate_startup_event(uint8_t cap);
int send_to_host_queue(interface_buffer_handle_t *buf_handle, uint8_t queue_type);
+
+void send_dhcp_dns_info_to_host(uint8_t network_up, uint8_t send_wifi_connected);
+
+#ifndef min
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
#endif
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/lwip_filter.c b/esp_hosted_fg/esp/esp_driver/network_adapter/main/lwip_filter.c
new file mode 100644
index 0000000000..11c699d925
--- /dev/null
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/lwip_filter.c
@@ -0,0 +1,525 @@
+/* LWIP packet filtering implementation */
+
+#include
+#include
+#include
+
+#include "esp_log.h"
+#include "esp_timer.h"
+#include "host_power_save.h"
+#include "lwip_filter.h"
+
+#if defined(CONFIG_NETWORK_SPLIT_ENABLED) && defined(CONFIG_LWIP_ENABLE)
+#include "lwip/opt.h"
+#include "lwip/err.h"
+#include "lwip/sys.h"
+#include "lwip/etharp.h"
+#include "lwip/prot/iana.h"
+#include "lwip/prot/ip.h"
+#include "lwip/prot/tcp.h"
+#include "lwip/prot/udp.h"
+#include "lwip/prot/icmp.h"
+#include "lwip/tcp.h"
+#include "lwip/udp.h"
+#include "lwip/priv/tcp_priv.h"
+
+
+
+static const char *TAG = "lwip_filter";
+
+#define MQTT_PORT 1883
+#define WAKEUP_HOST_STRING "wakeup-host"
+#define DEFAULT_IPERF_PORT 5001
+
+/* Use LWIP's port range macros instead of redefining */
+/* #define IS_REMOTE_TCP_PORT(port) ((port) != MQTT_PORT) */
+/* #define IS_REMOTE_UDP_PORT(port) (1) */
+
+#ifdef CONFIG_SLAVE_MANAGES_WIFI
+ #define DHCP_LWIP_BRIDGE SLAVE_LWIP_BRIDGE
+#else
+ #define DHCP_LWIP_BRIDGE HOST_LWIP_BRIDGE
+#endif
+
+#if defined(CONFIG_ESP_DEFAULT_LWIP_SLAVE)
+ #define DEFAULT_LWIP_TO_SEND SLAVE_LWIP_BRIDGE
+#elif defined(CONFIG_ESP_DEFAULT_LWIP_HOST)
+ #define DEFAULT_LWIP_TO_SEND HOST_LWIP_BRIDGE
+#elif defined(CONFIG_ESP_DEFAULT_LWIP_BOTH)
+ #define DEFAULT_LWIP_TO_SEND BOTH_LWIP_BRIDGE
+#else
+ #error "Select one of the LWIP to forward"
+#endif
+
+/* Cache for TCP port checks */
+static struct {
+ uint64_t last_check_time;
+ int last_result;
+ uint16_t last_port;
+} tcp_cache = {0};
+
+/* Cache for UDP port checks */
+static struct {
+ uint64_t last_check_time;
+ int last_result;
+ uint16_t last_port;
+} udp_cache = {0};
+
+#define MAX_ALLOWED_TCP_SRC_PORTS 10
+#define MAX_ALLOWED_UDP_SRC_PORTS 10
+#define MAX_ALLOWED_TCP_DST_PORTS 10
+#define MAX_ALLOWED_UDP_DST_PORTS 10
+
+/* In the file-scope variables section */
+static uint16_t allowed_tcp_src_ports[MAX_ALLOWED_TCP_SRC_PORTS] = {0};
+static uint16_t allowed_udp_src_ports[MAX_ALLOWED_UDP_SRC_PORTS] = {0};
+static uint16_t allowed_tcp_dst_ports[MAX_ALLOWED_TCP_DST_PORTS] = {0};
+static uint16_t allowed_udp_dst_ports[MAX_ALLOWED_UDP_DST_PORTS] = {0};
+static int allowed_tcp_src_ports_count = 0;
+static int allowed_udp_src_ports_count = 0;
+static int allowed_tcp_dst_ports_count = 0;
+static int allowed_udp_dst_ports_count = 0;
+
+/* Parse a comma-separated list of ports into an array */
+static int init_allowed_ports(const char *ports_str, int *ports_count, uint16_t *ports_array, int max_ports, const char *port_type) {
+ /* Only initialize once */
+ static bool tcp_src_initialized = false;
+ static bool tcp_dst_initialized = false;
+ static bool udp_src_initialized = false;
+ static bool udp_dst_initialized = false;
+
+ /* Check if already initialized for this port type */
+ if ((strcmp(port_type, "tcp_src") == 0 && tcp_src_initialized) ||
+ (strcmp(port_type, "tcp_dst") == 0 && tcp_dst_initialized) ||
+ (strcmp(port_type, "udp_src") == 0 && udp_src_initialized) ||
+ (strcmp(port_type, "udp_dst") == 0 && udp_dst_initialized)) {
+ return 0;
+ }
+
+ /* Reset counter */
+ *ports_count = 0;
+
+ /* If no ports string provided, return */
+ if (!ports_str || !ports_str[0]) {
+ ESP_LOGI(TAG, "No %s ports configured", port_type);
+ return 0;
+ }
+
+ char port_buf[6]; /* Max 5 digits for a port + null terminator */
+ int port_buf_idx = 0;
+
+ for (int i = 0; ports_str[i] != '\0' && *ports_count < max_ports; i++) {
+ if (isdigit((unsigned char)ports_str[i])) { /* Fix: cast to unsigned char */
+ port_buf[port_buf_idx++] = ports_str[i];
+ if (port_buf_idx >= sizeof(port_buf) - 1) {
+ port_buf_idx = sizeof(port_buf) - 2; /* Prevent overflow */
+ }
+ } else if (ports_str[i] == ',') {
+ if (port_buf_idx > 0) {
+ port_buf[port_buf_idx] = '\0';
+ ports_array[(*ports_count)++] = atoi(port_buf);
+ port_buf_idx = 0;
+ }
+ }
+ }
+
+ /* Process the last port if there's no trailing comma */
+ if (port_buf_idx > 0) {
+ port_buf[port_buf_idx] = '\0';
+ ports_array[(*ports_count)++] = atoi(port_buf);
+ }
+
+ /* Log the results */
+ ESP_LOGI(TAG, "Initialized %d allowed %s ports:", *ports_count, port_type);
+ for (int i = 0; i < *ports_count; i++) {
+ ESP_LOGI(TAG, " - Port %d", ports_array[i]);
+ }
+
+ /* Mark as initialized */
+ if (strcmp(port_type, "tcp_src") == 0) {
+ tcp_src_initialized = true;
+ } else if (strcmp(port_type, "tcp_dst") == 0) {
+ tcp_dst_initialized = true;
+ } else if (strcmp(port_type, "udp_src") == 0) {
+ udp_src_initialized = true;
+ } else if (strcmp(port_type, "udp_dst") == 0) {
+ udp_dst_initialized = true;
+ }
+
+ return 0;
+}
+
+
+static int init_allowed_tcp_ports(const char *ports_str_src, const char *ports_str_dst) {
+ int ret1 = 0, ret2 = 0;
+
+ if (ports_str_src && strlen(ports_str_src) > 0) {
+ ESP_LOGI(TAG, "Host reserved TCP src ports: %s", ports_str_src);
+ ret1 = init_allowed_ports(ports_str_src, &allowed_tcp_src_ports_count,
+ allowed_tcp_src_ports, MAX_ALLOWED_TCP_SRC_PORTS, "tcp_src");
+ }
+
+ if (ports_str_dst && strlen(ports_str_dst) > 0) {
+ ESP_LOGI(TAG, "Host reserved TCP dst ports: %s", ports_str_dst);
+ ret2 = init_allowed_ports(ports_str_dst, &allowed_tcp_dst_ports_count,
+ allowed_tcp_dst_ports, MAX_ALLOWED_TCP_DST_PORTS, "tcp_dst");
+ }
+
+ if (ret1) {
+ ESP_LOGE(TAG, "Failed to initialize allowed TCP src ports");
+ return ret1;
+ }
+ if (ret2) {
+ ESP_LOGE(TAG, "Failed to initialize allowed TCP dst ports");
+ return ret2;
+ }
+ return 0;
+}
+
+static int init_allowed_udp_ports(const char *ports_str_src, const char *ports_str_dst) {
+ int ret1=0, ret2=0;
+ if (ports_str_src && strlen(ports_str_src) > 0) {
+ ESP_LOGI(TAG, "host reserved udp src ports: %s", ports_str_src);
+ ret1 = init_allowed_ports(ports_str_src, &allowed_udp_src_ports_count, allowed_udp_src_ports, MAX_ALLOWED_UDP_SRC_PORTS, "udp_src");
+ }
+ if (ports_str_dst && strlen(ports_str_dst) > 0) {
+ ESP_LOGI(TAG, "host reserved udp dst ports: %s", ports_str_dst);
+ ret2 = init_allowed_ports(ports_str_dst, &allowed_udp_dst_ports_count, allowed_udp_dst_ports, MAX_ALLOWED_UDP_DST_PORTS, "udp_dst");
+ }
+
+ if (ret1) {
+ ESP_LOGE(TAG, "Failed to initialize allowed udp src ports");
+ return ret1;
+ }
+ if (ret2) {
+ ESP_LOGE(TAG, "Failed to initialize allowed udp dst ports");
+ return ret2;
+ }
+ return 0;
+}
+
+static int punch_hole_for_host_ports_from_config(const char *ports_str_tcp_src,
+ const char *ports_str_tcp_dst,
+ const char *ports_str_udp_src,
+ const char *ports_str_udp_dst) {
+ int ret1 = 0, ret2 = 0;
+
+ ESP_LOGI(TAG, "Host reserved TCP src ports: %s",
+ ports_str_tcp_src && strlen(ports_str_tcp_src) > 0 ? ports_str_tcp_src : "none");
+ ESP_LOGI(TAG, "Host reserved TCP dst ports: %s",
+ ports_str_tcp_dst && strlen(ports_str_tcp_dst) > 0 ? ports_str_tcp_dst : "none");
+ ret1 = init_allowed_tcp_ports(ports_str_tcp_src, ports_str_tcp_dst);
+
+ ESP_LOGI(TAG, "Host reserved UDP src ports: %s",
+ ports_str_udp_src && strlen(ports_str_udp_src) > 0 ? ports_str_udp_src : "none");
+ ESP_LOGI(TAG, "Host reserved UDP dst ports: %s",
+ ports_str_udp_dst && strlen(ports_str_udp_dst) > 0 ? ports_str_udp_dst : "none");
+ ret2 = init_allowed_udp_ports(ports_str_udp_src, ports_str_udp_dst);
+
+ if (ret1) {
+ ESP_LOGE(TAG, "Failed to initialize allowed TCP ports");
+ return ret1;
+ }
+ if (ret2) {
+ ESP_LOGE(TAG, "Failed to initialize allowed UDP ports");
+ return ret2;
+ }
+ return 0;
+}
+
+/* Add this function to check if a port is allowed */
+static inline bool is_tcp_src_port_allowed(uint16_t port) {
+ for (int i = 0; i < allowed_tcp_src_ports_count; i++) {
+ if (port == allowed_tcp_src_ports[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static inline bool is_tcp_dst_port_allowed(uint16_t port) {
+ for (int i = 0; i < allowed_tcp_dst_ports_count; i++) {
+ if (port == allowed_tcp_dst_ports[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static inline bool is_udp_src_port_allowed(uint16_t port) {
+ for (int i = 0; i < allowed_udp_src_ports_count; i++) {
+ if (port == allowed_udp_src_ports[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static inline bool is_udp_dst_port_allowed(uint16_t port) {
+ for (int i = 0; i < allowed_udp_dst_ports_count; i++) {
+ if (port == allowed_udp_dst_ports[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool host_mqtt_wakeup_triggered(const void *payload, uint16_t payload_length)
+{
+ /* Check if payload contains "wakeup-host" string */
+ if (payload_length >= strlen(WAKEUP_HOST_STRING) &&
+ memcmp(payload, WAKEUP_HOST_STRING, strlen(WAKEUP_HOST_STRING)) == 0) {
+ return true;
+ }
+ return false;
+}
+
+static int is_local_tcp_port_open(uint16_t port)
+{
+ uint64_t current_time = esp_timer_get_time() >> 10; /* Approx ms */
+
+ /* Return cached result if within 1 sec window */
+ if (tcp_cache.last_port == port &&
+ (current_time - tcp_cache.last_check_time) < 1000) {
+ tcp_cache.last_check_time = current_time;
+ return tcp_cache.last_result;
+ }
+
+ /* Use LWIP protection for thread safety */
+ SYS_ARCH_DECL_PROTECT(old_level);
+ SYS_ARCH_PROTECT(old_level);
+
+ int found = 0;
+ struct tcp_pcb *pcb;
+ for(pcb = tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {
+ if (pcb->local_port == port) {
+ found = 1;
+ break;
+ }
+ }
+
+ SYS_ARCH_UNPROTECT(old_level);
+
+ /* Cache the result */
+ tcp_cache.last_check_time = current_time;
+ tcp_cache.last_result = found;
+ tcp_cache.last_port = port;
+
+ ESP_LOGI(TAG, "is_local_tcp_port (%u) open: %d", port, found);
+ return found;
+}
+
+static int is_local_udp_port_open(uint16_t port)
+{
+ uint64_t current_time = esp_timer_get_time() >> 10; /* Approx ms */
+
+ /* Return cached result if within 1 sec window */
+ if (udp_cache.last_port == port &&
+ (current_time - udp_cache.last_check_time) < 1000) {
+ udp_cache.last_check_time = current_time;
+ return udp_cache.last_result;
+ }
+
+ /* Use LWIP protection for thread safety */
+ SYS_ARCH_DECL_PROTECT(old_level);
+ SYS_ARCH_PROTECT(old_level);
+
+ int found = 0;
+ struct udp_pcb *pcb;
+ for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
+ if (pcb->local_port == port) {
+ found = 1;
+ break;
+ }
+ }
+
+ SYS_ARCH_UNPROTECT(old_level);
+
+ /* Cache the result */
+ udp_cache.last_check_time = current_time;
+ udp_cache.last_result = found;
+ udp_cache.last_port = port;
+
+ ESP_LOGI(TAG, "is_local_udp_port (%u) open: %d", port, found);
+ return found;
+}
+
+hosted_l2_bridge filter_and_route_packet(void *frame_data, uint16_t frame_length)
+{
+ hosted_l2_bridge result = DEFAULT_LWIP_TO_SEND;
+
+ struct eth_hdr *ethhdr = (struct eth_hdr *)frame_data;
+ struct ip_hdr *iphdr;
+ u8_t proto;
+ u16_t dst_port = 0;
+ u16_t src_port = 0;
+
+ /* Check if the frame is a MAC broadcast */
+ if (ethhdr->dest.addr[0] & 0x01) {
+ result = SLAVE_LWIP_BRIDGE;
+ return result;
+ }
+
+ /* Check if the frame contains an IP packet */
+ if (lwip_ntohs(ethhdr->type) == ETHTYPE_IP) {
+ ESP_LOGV(TAG, "new ip packet");
+
+ /* Get the IP header */
+ iphdr = (struct ip_hdr *)((u8_t *)frame_data + SIZEOF_ETH_HDR);
+ /* Get the protocol from the IP header */
+ proto = IPH_PROTO(iphdr);
+
+ if (proto == IP_PROTO_TCP) {
+ struct tcp_hdr *tcphdr = (struct tcp_hdr *)((u8_t *)iphdr + IPH_HL(iphdr) * 4);
+ dst_port = lwip_ntohs(tcphdr->dest);
+ src_port = lwip_ntohs(tcphdr->src);
+
+ ESP_LOGV(TAG, "dst_port: %u, src_port: %u", dst_port, src_port);
+
+ /* Check for allowed ports (SSH, RTSP, etc.) */
+ if (is_tcp_src_port_allowed(src_port) || is_tcp_dst_port_allowed(dst_port)) {
+ ESP_LOGV(TAG, "Priority tcp port traffic detected, forwarding to host");
+ result = HOST_LWIP_BRIDGE;
+ return result;
+ }
+
+ /* Check for iperf port */
+ if (dst_port == DEFAULT_IPERF_PORT) {
+ ESP_LOGV(TAG, "iperf pkt %u", DEFAULT_IPERF_PORT);
+ if (is_local_tcp_port_open(dst_port)) {
+ result = SLAVE_LWIP_BRIDGE;
+ return result;
+ } else if (!is_host_power_saving()) {
+ result = HOST_LWIP_BRIDGE;
+ return result;
+ }
+ }
+
+ if (IS_REMOTE_TCP_PORT(dst_port)) {
+ if (is_host_power_saving()) {
+ /* filter host destined mqtt packet says 'wake-up-host' */
+ if (src_port == MQTT_PORT) {
+ #define TCP_HDR_LEN(tcphdr) ((TCPH_FLAGS(tcphdr) >> 12) * 4)
+
+ u16_t tcp_hdr_len = TCP_HDR_LEN(tcphdr);
+ u16_t mqtt_payload_length = lwip_ntohs(tcphdr->wnd);
+ u8_t *mqtt_payload = (u8_t *)tcphdr + tcp_hdr_len;
+
+ if (host_mqtt_wakeup_triggered(mqtt_payload, mqtt_payload_length)) {
+ ESP_LOGV(TAG, "Wakeup host: MQTT wakeup pkt");
+ result = HOST_LWIP_BRIDGE;
+ return result;
+ } else {
+ /* drop any other host destined mqtt packet */
+ result = INVALID_BRIDGE;
+ ESP_LOGW(TAG, "mqtt pkt DROPPED dst %u src %u => lwip %u", dst_port, src_port, result);
+ return result;
+ }
+ } else {
+ ESP_LOGV(TAG, "Wakeup host: TCP pkt");
+ result = INVALID_BRIDGE;
+ ESP_LOGW(TAG, "host pkt dropped in power save (dst %u src %u)", dst_port, src_port);
+ return result;
+ }
+ } else {
+ /* As host is not sleeping, send packets freely */
+ result = HOST_LWIP_BRIDGE;
+ return result;
+ }
+ } else if (IS_LOCAL_TCP_PORT(dst_port)) {
+ result = SLAVE_LWIP_BRIDGE;
+ return result;
+ }
+
+ } else if (proto == IP_PROTO_UDP) {
+ ESP_LOGV(TAG, "new udp packet");
+ struct udp_hdr *udphdr = (struct udp_hdr *)((u8_t *)iphdr + IPH_HL(iphdr) * 4);
+ dst_port = lwip_ntohs(udphdr->dest);
+ src_port = lwip_ntohs(udphdr->src);
+
+ ESP_LOGV(TAG, "UDP dst_port: %u, src_port: %u", dst_port, src_port);
+
+ /* Check for allowed ports */
+ if (is_udp_src_port_allowed(src_port) || is_udp_dst_port_allowed(dst_port)) {
+ ESP_LOGV(TAG, "Priority udp port traffic detected, forwarding to host");
+ result = HOST_LWIP_BRIDGE;
+ return result;
+ }
+
+ /* Check for iperf UDP port */
+ if (dst_port == DEFAULT_IPERF_PORT) {
+ ESP_LOGV(TAG, "Detected iperf UDP packet on port %u", DEFAULT_IPERF_PORT);
+ if (is_local_udp_port_open(dst_port)) {
+ result = SLAVE_LWIP_BRIDGE;
+ return result;
+ } else if (!is_host_power_saving()) {
+ result = HOST_LWIP_BRIDGE;
+ return result;
+ }
+ }
+
+ if (dst_port == LWIP_IANA_PORT_DHCP_CLIENT) {
+ result = DHCP_LWIP_BRIDGE;
+ return result;
+ }
+
+ if (IS_REMOTE_UDP_PORT(dst_port)) {
+ if (is_host_power_saving()) {
+ ESP_LOGW(TAG, "host pkt dropped in power save (dst %u src %u)", dst_port, src_port);
+ result = INVALID_BRIDGE;
+ return result;
+ } else {
+ result = HOST_LWIP_BRIDGE;
+ return result;
+ }
+ } else if (IS_LOCAL_UDP_PORT(dst_port)) {
+ result = SLAVE_LWIP_BRIDGE;
+ return result;
+ }
+
+ } else if (proto == IP_PROTO_ICMP) {
+ ESP_LOGV(TAG, "new icmp packet");
+ struct icmp_echo_hdr *icmphdr = (struct icmp_echo_hdr *)((u8_t *)iphdr + IPH_HL(iphdr) * 4);
+ if (icmphdr->type == ICMP_ECHO) {
+ /* ping request */
+ result = SLAVE_LWIP_BRIDGE;
+ return result;
+ } else if (icmphdr->type == ICMP_ER) {
+ if (is_host_power_saving()) {
+ result = SLAVE_LWIP_BRIDGE;
+ return result;
+ } else {
+ /* ping response */
+ ESP_HEXLOGV("icmp_er", frame_data, frame_length, 64);
+ result = BOTH_LWIP_BRIDGE;
+ return result;
+ }
+ }
+ }
+
+ } else if (lwip_ntohs(ethhdr->type) == ETHTYPE_ARP) {
+ ESP_LOGV(TAG, "new arp packet");
+ struct etharp_hdr *arphdr = (struct etharp_hdr *)((u8_t *)frame_data + SIZEOF_ETH_HDR);
+
+ if (arphdr->opcode == lwip_htons(ARP_REQUEST)) {
+ result = SLAVE_LWIP_BRIDGE;
+ return result;
+ } else {
+ if (is_host_power_saving()) {
+ result = SLAVE_LWIP_BRIDGE;
+ return result;
+ } else {
+ ESP_HEXLOGV("arp_reply", frame_data, frame_length, 64);
+ result = BOTH_LWIP_BRIDGE;
+ return result;
+ }
+ }
+ }
+
+ return result;
+}
+
+int configure_host_static_port_forwarding_rules(const char *ports_str_tcp_src, const char *ports_str_tcp_dst, const char *ports_str_udp_src, const char *ports_str_udp_dst) {
+ return punch_hole_for_host_ports_from_config(ports_str_tcp_src, ports_str_tcp_dst, ports_str_udp_src, ports_str_udp_dst);
+}
+#endif
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/lwip_filter.h b/esp_hosted_fg/esp/esp_driver/network_adapter/main/lwip_filter.h
new file mode 100644
index 0000000000..df3aac88fb
--- /dev/null
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/lwip_filter.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include
+#include
+#include
+
+typedef enum {
+ SLAVE_LWIP_BRIDGE,
+ HOST_LWIP_BRIDGE,
+ BOTH_LWIP_BRIDGE,
+ INVALID_BRIDGE,
+} hosted_l2_bridge;
+
+#if defined(CONFIG_NETWORK_SPLIT_ENABLED) && defined(CONFIG_LWIP_ENABLE)
+#include "esp_hosted_lwip_src_port_hook.h"
+
+hosted_l2_bridge filter_and_route_packet(void *frame_data, uint16_t frame_length);
+
+int configure_host_static_port_forwarding_rules(const char *ports_str_tcp_src, const char *ports_str_tcp_dst,
+ const char *ports_str_udp_src, const char *ports_str_udp_dst);
+#endif
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/mempool.c b/esp_hosted_fg/esp/esp_driver/network_adapter/main/mempool.c
index 650a2fc45b..6d8c1c336b 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/main/mempool.c
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/mempool.c
@@ -76,7 +76,7 @@ struct hosted_mempool * hosted_mempool_create(void *pre_allocated_mem,
new->block_size = block_size;
#if MEMPOOL_DEBUG
- ESP_LOGI(MEM_TAG, "Create mempool %p with num_blk[%lu] blk_size:[%lu]", new->pool, new->num_blocks, new->block_size);
+ ESP_LOGI(TAG, "Create mempool %p with num_blk[%u] blk_size:[%u]", new->pool, (unsigned int)new->num_blocks, (unsigned int)new->block_size);
#endif
return new;
@@ -97,9 +97,8 @@ void hosted_mempool_destroy(struct hosted_mempool *mempool)
#ifdef CONFIG_ESP_CACHE_MALLOC
if (!mempool)
return;
-#if MEMPOOL_DEBUG
- ESP_LOGI(MEM_TAG, "Destroy mempool %p num_blk[%lu] blk_size:[%lu]", mempool->pool, mempool->num_blocks, mempool->block_size);
-#endif
+
+ ESP_LOGI(TAG, "Destroy mempool %p num_blk[%u] blk_size:[%u]", mempool->pool, (unsigned int)mempool->num_blocks, (unsigned int)mempool->block_size);
FREE(mempool->pool);
@@ -125,7 +124,7 @@ void * hosted_mempool_alloc(struct hosted_mempool *mempool,
if(nbytes > mempool->block_size) {
ESP_LOGE(TAG, "Exp alloc bytes[%u] > mempool block size[%u]\n",
- nbytes, mempool->block_size);
+ (unsigned int)nbytes, (unsigned int)mempool->block_size);
return NULL;
}
#endif
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/mempool.h b/esp_hosted_fg/esp/esp_driver/network_adapter/main/mempool.h
index 40bff4e297..a772a675b0 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/main/mempool.h
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/mempool.h
@@ -35,8 +35,9 @@ struct hosted_mempool {
#endif
#define MEM_DUMP(s) \
- printf("%s free:%lu min-free:%lu lfb-def:%u lfb-8bit:%u\n\n", s, \
+ printf("%s free:%lu min-free:%lu lfb-dma:%u lfb-def:%u lfb-8bit:%u\n", s, \
esp_get_free_heap_size(), esp_get_minimum_free_heap_size(), \
+ heap_caps_get_largest_free_block(MALLOC_CAP_DMA),\
heap_caps_get_largest_free_block(MALLOC_CAP_DEFAULT),\
heap_caps_get_largest_free_block(MALLOC_CAP_8BIT))
@@ -44,6 +45,7 @@ struct hosted_mempool {
#define MEMPOOL_FAIL -1
#define CALLOC(x,y) calloc(x,y)
+#define MALLOC(x) malloc(x)
#define MEM_ALLOC(x) heap_caps_malloc(x, MALLOC_CAP_DMA)
#define FREE(x) do { \
if (x) { \
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/mqtt_example.c b/esp_hosted_fg/esp/esp_driver/network_adapter/main/mqtt_example.c
new file mode 100644
index 0000000000..8aae33e10d
--- /dev/null
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/mqtt_example.c
@@ -0,0 +1,274 @@
+/* MQTT (over TCP) Example
+
+ This example code 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.
+*/
+
+#include
+#include
+#include
+#include
+#include "sdkconfig.h"
+
+#ifdef CONFIG_ESP_HOSTED_COPROCESSOR_EXAMPLE_MQTT
+
+#include "esp_wifi.h"
+#include "esp_system.h"
+#include "nvs_flash.h"
+#include "esp_event.h"
+#include "esp_netif.h"
+//#include "protocol_examples_common.h"
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "freertos/queue.h"
+
+
+#include "esp_log.h"
+#include "mqtt_client.h"
+#include "host_power_save.h"
+
+#include "lwip/sockets.h"
+#include "lwip/dns.h"
+#include "lwip/netdb.h"
+
+static const char *TAG = "mqtt_example";
+static esp_mqtt_client_handle_t client;
+static uint8_t client_started;
+
+#define WAKEUP_HOST_STRING "wakeup-host"
+
+static void log_error_if_nonzero(const char *message, int error_code)
+{
+ if (error_code != 0) {
+ ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code);
+ }
+}
+
+static bool host_mqtt_wakeup_triggered(const void *payload, uint16_t payload_length)
+{
+ /* Check if payload contains "wakeup-host" string */
+ if (payload_length >= strlen(WAKEUP_HOST_STRING) &&
+ memcmp(payload, WAKEUP_HOST_STRING, strlen(WAKEUP_HOST_STRING)) == 0) {
+ return true;
+ }
+ return false;
+}
+
+/*
+ * @brief Event handler registered to receive MQTT events
+ *
+ * This function is called by the MQTT client event loop.
+ *
+ * @param handler_args user data registered to the event.
+ * @param base Event base for the handler(always MQTT Base in this example).
+ * @param event_id The id for the received event.
+ * @param event_data The data for the event, esp_mqtt_event_handle_t.
+ */
+static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
+{
+ ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32 "", base, event_id);
+ esp_mqtt_event_handle_t event = event_data;
+ esp_mqtt_client_handle_t client = event->client;
+ int msg_id;
+ switch ((esp_mqtt_event_id_t)event_id) {
+ case MQTT_EVENT_CONNECTED:
+ ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
+ msg_id = esp_mqtt_client_publish(client, "/topic/qos1", "data_3", 0, 1, 0);
+ ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
+
+ msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
+ ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
+
+ msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
+ ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
+
+ msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");
+ ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);
+ break;
+ case MQTT_EVENT_DISCONNECTED:
+ ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
+ break;
+
+ case MQTT_EVENT_SUBSCRIBED:
+ ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
+ msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
+ ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
+ break;
+ case MQTT_EVENT_UNSUBSCRIBED:
+ ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
+ break;
+ case MQTT_EVENT_PUBLISHED:
+ ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
+ break;
+ case MQTT_EVENT_DATA:
+ ESP_LOGI(TAG, "MQTT_EVENT_DATA");
+ printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
+ printf("DATA=%.*s\r\n", event->data_len, event->data);
+
+ if (host_mqtt_wakeup_triggered(event->data, event->data_len)) {
+ wakeup_host(portMAX_DELAY);
+ }
+ break;
+ case MQTT_EVENT_ERROR:
+ ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
+ if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
+ log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err);
+ log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err);
+ log_error_if_nonzero("captured as transport's socket errno", event->error_handle->esp_transport_sock_errno);
+ ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));
+
+ }
+ break;
+ default:
+ ESP_LOGI(TAG, "Other event id:%d", event->event_id);
+ break;
+ }
+}
+
+#if 0
+static int check_ip_reachability(const char *ip, int port)
+{
+ int sock;
+ struct sockaddr_in server;
+
+ // Create socket
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock == -1) {
+ printf("Could not create socket\n");
+ return ESP_FAIL;
+ }
+
+ // Configure the server address
+ server.sin_addr.s_addr = inet_addr(ip);
+ server.sin_family = AF_INET;
+ server.sin_port = htons(port);
+
+ // Set a timeout for the connection attempt
+ struct timeval timeout;
+ timeout.tv_sec = 5; // 5 seconds timeout
+ timeout.tv_usec = 0;
+ setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
+
+ // Try to connect to the server
+ if (connect(sock, (struct sockaddr *)&server, sizeof(server)) < 0) {
+ printf("Connection to %s on port %d failed\n", ip, port);
+ close(sock);
+ return ESP_FAIL;
+ }
+
+ printf("Successfully connected to %s on port %d\n", ip, port);
+ close(sock);
+ return ESP_OK;
+}
+#endif
+
+static esp_mqtt_client_handle_t example_mqtt_init_internal(void)
+{
+ esp_mqtt_client_config_t mqtt_cfg = {
+ .broker.address.uri = CONFIG_BROKER_URL,
+ };
+#if CONFIG_BROKER_URL_FROM_STDIN
+ char line[128];
+
+ if (strcmp(mqtt_cfg.broker.address.uri, "FROM_STDIN") == 0) {
+ int count = 0;
+ printf("Please enter url of mqtt broker\n");
+ while (count < 128) {
+ int c = fgetc(stdin);
+ if (c == '\n') {
+ line[count] = '\0';
+ break;
+ } else if (c > 0 && c < 127) {
+ line[count] = c;
+ ++count;
+ }
+ vTaskDelay(10 / portTICK_PERIOD_MS);
+ }
+ mqtt_cfg.broker.address.uri = line;
+ printf("Broker url: %s\n", line);
+ } else {
+ ESP_LOGE(TAG, "Configuration mismatch: wrong broker url");
+ abort();
+ }
+#endif /* CONFIG_BROKER_URL_FROM_STDIN */
+
+ client = esp_mqtt_client_init(&mqtt_cfg);
+ /* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */
+ esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
+
+ return client;
+}
+
+esp_err_t example_mqtt_init(void)
+{
+#if 0
+ esp_err_t err;
+ err = check_ip_reachability("8.8.8.8", 53);
+ if (err) {
+ ESP_LOGI(TAG, "Failed to start the mqtt");
+ return NULL;
+ }
+#endif
+
+ ESP_LOGI(TAG, "[APP] Startup..");
+ ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
+ ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
+
+ esp_log_level_set("*", ESP_LOG_INFO);
+ esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE);
+ esp_log_level_set("mqtt_example", ESP_LOG_VERBOSE);
+ esp_log_level_set("transport_base", ESP_LOG_VERBOSE);
+ esp_log_level_set("esp-tls", ESP_LOG_VERBOSE);
+ esp_log_level_set("transport", ESP_LOG_VERBOSE);
+ esp_log_level_set("outbox", ESP_LOG_VERBOSE);
+
+ example_mqtt_init_internal();
+
+ if (client)
+ return ESP_OK;
+ else
+ return ESP_FAIL;
+}
+
+esp_err_t example_mqtt_resume(void)
+{
+ if (!client) {
+ example_mqtt_init();
+ }
+
+ if (client && !client_started) {
+ client_started = 1;
+ ESP_LOGV(TAG, "mqtt client started");
+ return esp_mqtt_client_start(client);
+ }
+ ESP_LOGV(TAG, "%s : client[%p] client_started[%u]",
+ __func__, client, client_started);
+
+ return ESP_OK;
+}
+
+esp_err_t example_mqtt_pause(void)
+{
+ if (client && client_started) {
+ client_started = 0;
+ ESP_LOGV(TAG, "mqtt client stopped");
+ return esp_mqtt_client_stop(client);
+#if 0
+ if (ESP_OK == esp_mqtt_client_destroy(client)) {
+ client = NULL;
+ }
+#endif
+ }
+ ESP_LOGV(TAG, "%s : client[%p] client_started[%u]",
+ __func__, client, client_started);
+
+ return ESP_OK;
+}
+
+
+#endif
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/mqtt_example.h b/esp_hosted_fg/esp/esp_driver/network_adapter/main/mqtt_example.h
new file mode 100644
index 0000000000..c0ca6bfbca
--- /dev/null
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/mqtt_example.h
@@ -0,0 +1,18 @@
+/* MQTT (over TCP) Example
+
+ This example code 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.
+*/
+#ifndef __MQTT_EXAMPLE_H__
+#define __MQTT_EXAMPLE_H__
+
+#ifdef CONFIG_ESP_HOSTED_COPROCESSOR_EXAMPLE_MQTT
+esp_err_t example_mqtt_init(void);
+esp_err_t example_mqtt_resume(void);
+esp_err_t example_mqtt_pause(void);
+#endif
+#endif
+
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/protocomm_pserial.c b/esp_hosted_fg/esp/esp_driver/network_adapter/main/protocomm_pserial.c
index 3bdb5ab41d..5b71d6ed70 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/main/protocomm_pserial.c
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/protocomm_pserial.c
@@ -25,11 +25,16 @@
#include
#include "protocomm_pserial.h"
#include "adapter.h"
+#include "esp_hosted_log.h"
static const char TAG[] = "protocomm_pserial";
#define EPNAME_MAX 16
-#define REQ_Q_MAX 10
+#if defined(CONFIG_IDF_TARGET_ESP32C2)
+ #define REQ_Q_MAX 3
+#else
+ #define REQ_Q_MAX 10
+#endif
#define SIZE_OF_TYPE 1
#define SIZE_OF_LENGTH 2
@@ -88,7 +93,7 @@ static esp_err_t compose_tlv(char *epname, uint8_t **out, size_t *outlen)
ep_len + SIZE_OF_TYPE + SIZE_OF_LENGTH + *outlen;
uint8_t *buf = (uint8_t *)calloc(1, buf_len);
if (buf == NULL) {
- ESP_LOGE(TAG,"%s Failed to allocate memory", __func__);
+ ESP_LOGE(TAG,"%s Mem Alloc Failed [%d]bytes", __func__, (int)buf_len);
return ESP_FAIL;
}
buf[len] = PROTO_PSER_TLV_T_EPNAME;
@@ -170,7 +175,7 @@ static esp_err_t protocomm_pserial_ctrl_req_handler(protocomm_t *pc,
return ESP_FAIL;
}
- /*ESP_LOG_BUFFER_HEXDUMP("serial_tx", out, outlen<16?outlen:16, ESP_LOG_INFO); */
+ ESP_HEXLOGV("serial_tx", out, outlen, 32);
ret = (pserial_cfg->xmit)(out, (ssize_t) outlen);
if (ret != ESP_OK) {
@@ -228,12 +233,12 @@ esp_err_t protocomm_pserial_data_ready(protocomm_t *pc,
}
if (len) {
- buf = (uint8_t *)malloc(len);
- if (buf == NULL) {
- ESP_LOGE(TAG,"%s Failed to allocate memory", __func__);
- return ESP_FAIL;
- }
- memcpy(buf, in, len);
+ buf = (uint8_t *)malloc(len);
+ if (buf == NULL) {
+ ESP_LOGE(TAG,"%s Failed to allocate memory", __func__);
+ return ESP_FAIL;
+ }
+ memcpy(buf, in, len);
}
arg.msg_id = msg_id;
@@ -279,6 +284,7 @@ static void pserial_task(void *params)
if ((arg.msg_id > CTRL_MSG_ID__Event_Base) &&
(arg.msg_id < CTRL_MSG_ID__Event_Max)) {
/* Events */
+ ESP_HEXLOGV("pserial_evt_rx", arg.data, arg.len, 32);
ret = protocomm_pserial_ctrl_evnt_handler(pc, arg.data, arg.len, arg.msg_id);
} else {
/* Request */
@@ -326,7 +332,7 @@ esp_err_t protocomm_pserial_start(protocomm_t *pc,
pc->priv = pserial_cfg;
xTaskCreate(pserial_task, "pserial_task", CONFIG_ESP_DEFAULT_TASK_STACK_SIZE,
- (void *) pc, CONFIG_ESP_DEFAULT_TASK_PRIO, NULL);
+ (void *) pc, CONFIG_ESP_HOSTED_TASK_PRIORITY_DEFAULT, NULL);
return ESP_OK;
}
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/sdio_slave_api.c b/esp_hosted_fg/esp/esp_driver/network_adapter/main/sdio_slave_api.c
index 1447a89d04..00248db0a9 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/main/sdio_slave_api.c
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/sdio_slave_api.c
@@ -18,6 +18,7 @@
#include
#include
#include "esp_log.h"
+#include "esp_hosted_log.h"
#include "interface.h"
#include "adapter.h"
#include "sdio_slave_api.h"
@@ -27,25 +28,77 @@
#include "mempool.h"
#include "stats.h"
#include "esp_fw_version.h"
+#include "host_power_save.h"
-#define SDIO_SLAVE_QUEUE_SIZE 20
-#define BUFFER_SIZE 1536 /* 512*3 */
-#define BUFFER_NUM 10
-static uint8_t sdio_slave_rx_buffer[BUFFER_NUM][BUFFER_SIZE];
+#define SIMPLIFIED_SDIO_SLAVE 1
+#define SDIO_DRIVER_TX_QUEUE_SIZE 10
+#define SDIO_RX_BUFFER_SIZE MAX_TRANSPORT_BUF_SIZE
+#define SDIO_RX_BUFFER_NUM 20
+static uint8_t sdio_slave_rx_buffer[SDIO_RX_BUFFER_NUM][SDIO_RX_BUFFER_SIZE];
-#define SDIO_MEMPOOL_NUM_BLOCKS 40
static struct hosted_mempool * buf_mp_tx_g;
interface_context_t context;
interface_handle_t if_handle_g;
-static const char TAG[] = "SDIO_SLAVE";
+static const char *TAG = "SDIO_SLAVE";
+
+#if !SIMPLIFIED_SDIO_SLAVE
+#ifdef CONFIG_ESP_ENABLE_RX_PRIORITY_QUEUES
+ #define SDIO_RX_WIFI_QUEUE_SIZE CONFIG_ESP_RX_WIFI_Q_SIZE
+ #define SDIO_RX_BT_QUEUE_SIZE CONFIG_ESP_RX_BT_Q_SIZE
+ #define SDIO_RX_SERIAL_QUEUE_SIZE CONFIG_ESP_RX_SERIAL_Q_SIZE
+ #define SDIO_RX_TOTAL_QUEUE_SIZE (SDIO_RX_WIFI_QUEUE_SIZE+SDIO_RX_BT_QUEUE_SIZE+SDIO_RX_SERIAL_QUEUE_SIZE)
+#else
+ #define SDIO_RX_QUEUE_SIZE CONFIG_ESP_RX_Q_SIZE
+ #define SDIO_RX_TOTAL_QUEUE_SIZE SDIO_RX_QUEUE_SIZE
+#endif
+
+
+/* Semaphore to count number of Tx bufs in IDF SDIO driver */
+static SemaphoreHandle_t sdio_send_queue_sem = NULL;
+
+#ifdef CONFIG_ESP_ENABLE_RX_PRIORITY_QUEUES
+ static QueueHandle_t sdio_rx_queue[MAX_PRIORITY_QUEUES];
+ static SemaphoreHandle_t sdio_rx_sem;
+#else
+ static QueueHandle_t sdio_rx_queue;
+#endif
+#else
+ #define SDIO_RX_QUEUE_SIZE CONFIG_ESP_RX_Q_SIZE
+ #define SDIO_RX_TOTAL_QUEUE_SIZE SDIO_RX_QUEUE_SIZE
+#endif
+
+#if !SIMPLIFIED_SDIO_SLAVE
+ #define SDIO_MEMPOOL_NUM_BLOCKS ((SDIO_RX_TOTAL_QUEUE_SIZE + SDIO_DRIVER_TX_QUEUE_SIZE + SDIO_RX_BUFFER_NUM + 10))
+#else
+ #define SDIO_MEMPOOL_NUM_BLOCKS (SDIO_DRIVER_TX_QUEUE_SIZE + SDIO_RX_BUFFER_NUM)
+#endif
+/* Note: Sometimes the SDIO card is detected but gets problem in
+ * Read/Write or handling ISR because of SDIO timing issues.
+ * In these cases, Please tune timing below via Menuconfig
+ * */
+#if CONFIG_ESP_SDIO_PSEND_PSAMPLE
+ #define SDIO_SLAVE_TIMING SDIO_SLAVE_TIMING_PSEND_PSAMPLE
+#elif CONFIG_ESP_SDIO_NSEND_PSAMPLE
+ #define SDIO_SLAVE_TIMING SDIO_SLAVE_TIMING_NSEND_PSAMPLE
+#elif CONFIG_ESP_SDIO_PSEND_NSAMPLE
+ #define SDIO_SLAVE_TIMING SDIO_SLAVE_TIMING_PSEND_NSAMPLE
+#elif CONFIG_ESP_SDIO_NSEND_NSAMPLE
+ #define SDIO_SLAVE_TIMING SDIO_SLAVE_TIMING_NSEND_NSAMPLE
+#else
+ #error No SDIO Slave Timing configured
+#endif
static interface_handle_t * sdio_init(void);
static int32_t sdio_write(interface_handle_t *handle, interface_buffer_handle_t *buf_handle);
static int sdio_read(interface_handle_t *if_handle, interface_buffer_handle_t *buf_handle);
static esp_err_t sdio_reset(interface_handle_t *handle);
static void sdio_deinit(interface_handle_t *handle);
+#if !SIMPLIFIED_SDIO_SLAVE
+static void sdio_rx_task(void* pvParameters);
+static void sdio_tx_done_task(void* pvParameters);
+#endif
if_ops_t if_ops = {
.init = sdio_init,
@@ -57,19 +110,25 @@ if_ops_t if_ops = {
static inline void sdio_mempool_create(void)
{
- buf_mp_tx_g = hosted_mempool_create(NULL, 0, SDIO_MEMPOOL_NUM_BLOCKS, BUFFER_SIZE);
+ buf_mp_tx_g = hosted_mempool_create(NULL, 0, SDIO_MEMPOOL_NUM_BLOCKS, SDIO_RX_BUFFER_SIZE);
#ifdef CONFIG_ESP_CACHE_MALLOC
assert(buf_mp_tx_g);
#endif
}
+
static inline void sdio_mempool_destroy(void)
{
hosted_mempool_destroy(buf_mp_tx_g);
}
-static inline void *sdio_buffer_tx_alloc(uint need_memset)
+
+static inline void *sdio_buffer_tx_alloc(size_t nbytes, uint need_memset)
{
- return hosted_mempool_alloc(buf_mp_tx_g, BUFFER_SIZE, need_memset);
+ /* TODO: When Mempool is not needed, SDIO should use
+ * exact bytes for allocation instead of SDIO_RX_BUFFER_SIZE
+ * To reduce strain on system memory */
+ return hosted_mempool_alloc(buf_mp_tx_g, nbytes, need_memset);
}
+
static inline void sdio_buffer_tx_free(void *buf)
{
hosted_mempool_free(buf_mp_tx_g, buf);
@@ -100,9 +159,17 @@ IRAM_ATTR static void event_cb(uint8_t val)
return;
}
+ if (val == ESP_POWER_SAVE_OFF) {
+ //sdio_reset(&if_handle_g);
+ }
+
if (context.event_handler) {
context.event_handler(val);
}
+
+ if (val == ESP_POWER_SAVE_ON) {
+ sdio_reset(&if_handle_g);
+ }
}
void generate_startup_event(uint8_t cap)
@@ -120,7 +187,7 @@ void generate_startup_event(uint8_t cap)
memset(&buf_handle, 0, sizeof(buf_handle));
- buf_handle.payload = sdio_buffer_tx_alloc(MEMSET_REQUIRED);
+ buf_handle.payload = sdio_buffer_tx_alloc(512, MEMSET_REQUIRED);
assert(buf_handle.payload);
header = (struct esp_payload_header *) buf_handle.payload;
@@ -129,6 +196,7 @@ void generate_startup_event(uint8_t cap)
header->if_num = 0;
header->offset = htole16(sizeof(struct esp_payload_header));
header->priv_pkt_type = ESP_PACKET_TYPE_EVENT;
+ UPDATE_HEADER_TX_PKT_NO(header);
/* Populate event data */
event = (struct esp_priv_event *) (buf_handle.payload + sizeof(struct esp_payload_header));
@@ -182,16 +250,24 @@ void generate_startup_event(uint8_t cap)
header->checksum = htole16(compute_checksum(buf_handle.payload, buf_handle.payload_len));
#endif
- ESP_LOG_BUFFER_HEXDUMP("sdio_tx", buf_handle.payload, buf_handle.payload_len, ESP_LOG_VERBOSE);
+ ESP_HEXLOGV("bus_tx_init", buf_handle.payload, buf_handle.payload_len, 32);
+#if !SIMPLIFIED_SDIO_SLAVE
+ xSemaphoreTake(sdio_send_queue_sem, portMAX_DELAY);
+ ret = sdio_slave_send_queue(buf_handle.payload, buf_handle.payload_len,
+ buf_handle.payload, portMAX_DELAY);
+#else
ret = sdio_slave_transmit(buf_handle.payload, buf_handle.payload_len);
+#endif
if (ret != ESP_OK) {
ESP_LOGE(TAG , "sdio slave tx error, ret : 0x%x\r\n", ret);
sdio_buffer_tx_free(buf_handle.payload);
return;
}
-
+#if SIMPLIFIED_SDIO_SLAVE
sdio_buffer_tx_free(buf_handle.payload);
+#endif
+
}
static void sdio_read_done(void *handle)
@@ -204,9 +280,13 @@ static interface_handle_t * sdio_init(void)
esp_err_t ret = ESP_OK;
sdio_slave_buf_handle_t handle = {0};
sdio_slave_config_t config = {
+#if CONFIG_ESP_SDIO_STREAMING_MODE
.sending_mode = SDIO_SLAVE_SEND_STREAM,
- .send_queue_size = SDIO_SLAVE_QUEUE_SIZE,
- .recv_buffer_size = BUFFER_SIZE,
+#else
+ .sending_mode = SDIO_SLAVE_SEND_PACKET,
+#endif
+ .send_queue_size = SDIO_DRIVER_TX_QUEUE_SIZE,
+ .recv_buffer_size = SDIO_RX_BUFFER_SIZE,
.event_cb = event_cb,
/* Note: For small devkits there may be no pullups on the board.
@@ -216,34 +296,56 @@ static interface_handle_t * sdio_init(void)
bus in your real design.
*/
//.flags = SDIO_SLAVE_FLAG_INTERNAL_PULLUP,
- /* Note: Sometimes the SDIO card is detected but gets problem in
- * Read/Write or handling ISR because of SDIO timing issues.
- * In these cases, Please tune timing below using value from
- * https://github.com/espressif/esp-idf/blob/release/v5.0/components/hal/include/hal/sdio_slave_types.h#L26-L38
- * */
-#if defined(CONFIG_IDF_TARGET_ESP32C6)
- .timing = SDIO_SLAVE_TIMING_NSEND_PSAMPLE,
-#endif
- };
#if CONFIG_ESP_SDIO_DEFAULT_SPEED
- config.flags |= SDIO_SLAVE_FLAG_DEFAULT_SPEED;
+ .flags = SDIO_SLAVE_FLAG_DEFAULT_SPEED,
#elif CONFIG_ESP_SDIO_HIGH_SPEED
- config.flags |= SDIO_SLAVE_FLAG_HIGH_SPEED;
+ .flags = SDIO_SLAVE_FLAG_HIGH_SPEED,
#else
#error Invalid SDIO bus speed selection
#endif
+ .timing = SDIO_SLAVE_TIMING,
+ };
-#if defined(CONFIG_IDF_TARGET_ESP32C6)
- ESP_LOGI(TAG, "%s: ESP32-C6 SDIO timing: %u\n", __func__, config.timing);
+#if !SIMPLIFIED_SDIO_SLAVE
+#if CONFIG_ESP_SDIO_STREAMING_MODE
+ ESP_LOGI(TAG, "%s: sending mode: SDIO_SLAVE_SEND_STREAM", __func__);
+#else
+ ESP_LOGI(TAG, "%s: sending mode: SDIO_SLAVE_SEND_PACKET", __func__);
+#endif
#else
- ESP_LOGI(TAG, "%s: ESP32 SDIO timing: %u\n", __func__, config.timing);
+ ESP_LOGI(TAG, "%s: simplified SDIO slave, timing[%u]", __func__, config.timing);
#endif
+ ESP_LOGI(TAG, "%s: SDIO RxQ[%d] timing[%u]\n", __func__, SDIO_RX_TOTAL_QUEUE_SIZE, config.timing);
+
+#if !SIMPLIFIED_SDIO_SLAVE
+
+ sdio_send_queue_sem = xSemaphoreCreateCounting(SDIO_DRIVER_TX_QUEUE_SIZE, SDIO_DRIVER_TX_QUEUE_SIZE);
+ assert(sdio_send_queue_sem);
+
+ #ifdef CONFIG_ESP_ENABLE_RX_PRIORITY_QUEUES
+
+ sdio_rx_sem = xSemaphoreCreateCounting(SDIO_RX_TOTAL_QUEUE_SIZE, 0);
+ assert(sdio_rx_sem);
+
+ sdio_rx_queue[PRIO_Q_OTHERS] = xQueueCreate(SDIO_RX_WIFI_QUEUE_SIZE, sizeof(interface_buffer_handle_t));
+ assert(sdio_rx_queue[PRIO_Q_OTHERS]);
+ sdio_rx_queue[PRIO_Q_BT] = xQueueCreate(SDIO_RX_BT_QUEUE_SIZE, sizeof(interface_buffer_handle_t));
+ assert(sdio_rx_queue[PRIO_Q_BT]);
+ sdio_rx_queue[PRIO_Q_SERIAL] = xQueueCreate(SDIO_RX_SERIAL_QUEUE_SIZE, sizeof(interface_buffer_handle_t));
+ assert(sdio_rx_queue[PRIO_Q_SERIAL]);
+ #else
+ sdio_rx_queue = xQueueCreate(SDIO_RX_QUEUE_SIZE, sizeof(interface_buffer_handle_t));
+ assert(sdio_rx_queue);
+ #endif
+#endif
+
ret = sdio_slave_initialize(&config);
if (ret != ESP_OK) {
return NULL;
}
- for (int i = 0; i < BUFFER_NUM; i++) {
+
+ for (int i = 0; i < SDIO_RX_BUFFER_NUM; i++) {
handle = sdio_slave_recv_register_buf(sdio_slave_rx_buffer[i]);
assert(handle != NULL);
@@ -275,16 +377,79 @@ static interface_handle_t * sdio_init(void)
sdio_mempool_create();
if_handle_g.state = INIT;
+#if !SIMPLIFIED_SDIO_SLAVE
+ assert(xTaskCreate(sdio_rx_task, "sdio_rx_task" ,
+ CONFIG_ESP_DEFAULT_TASK_STACK_SIZE, NULL,
+ CONFIG_ESP_HOSTED_TASK_PRIORITY_HIGH, NULL) == pdTRUE);
+
+ // task to clean up after doing sdio tx
+ assert(xTaskCreate(sdio_tx_done_task, "sdio_tx_done_task" ,
+ CONFIG_ESP_DEFAULT_TASK_STACK_SIZE, NULL,
+ CONFIG_ESP_HOSTED_TASK_PRIORITY_HIGH, NULL) == pdTRUE);
+#endif
return &if_handle_g;
}
+/* wait for sdio to finish tx, then free the buffer */
+#if !SIMPLIFIED_SDIO_SLAVE
+static void sdio_tx_done_task(void* pvParameters)
+{
+ esp_err_t res;
+ uint8_t sendbuf = 0;
+ uint8_t *sendbuf_p = &sendbuf;
+
+ while (true) {
+ res = sdio_slave_send_get_finished((void**)&sendbuf_p, portMAX_DELAY);
+ if (res) {
+ ESP_LOGE(TAG, "sdio_slave_send_get_finished() error");
+ continue;
+ }
+ xSemaphoreGive(sdio_send_queue_sem);
+ sdio_buffer_tx_free(sendbuf_p);
+ }
+}
+#endif
+
+static inline struct esp_payload_header * update_tx_header(uint8_t* sendbuf,
+ interface_buffer_handle_t *buf_handle)
+{
+ struct esp_payload_header *header = (struct esp_payload_header *)sendbuf;
+ uint16_t offset = sizeof(struct esp_payload_header);
+
+ if (unlikely(!header))
+ return NULL;
+
+ memset (header, 0, sizeof(struct esp_payload_header));
+
+ /* Initialize header */
+ header->if_type = buf_handle->if_type;
+ header->if_num = buf_handle->if_num;
+ header->len = htole16(buf_handle->payload_len);
+ header->offset = htole16(offset);
+ header->seq_num = htole16(buf_handle->seq_num);
+ header->flags = buf_handle->flag;
+ UPDATE_HEADER_TX_PKT_NO(header);
+
+#if CONFIG_ESP_SDIO_CHECKSUM
+ header->checksum = htole16(compute_checksum(sendbuf,
+ offset+buf_handle->payload_len));
+#endif
+
+ return header;
+}
+
+static inline esp_err_t copy_tx_payload(uint8_t *sendbuf, uint8_t* payload, uint16_t len)
+{
+ memcpy(sendbuf + sizeof(struct esp_payload_header), payload, len);
+ return ESP_OK;
+}
+
static int32_t sdio_write(interface_handle_t *handle, interface_buffer_handle_t *buf_handle)
{
- esp_err_t ret = ESP_OK;
int32_t total_len = 0;
uint8_t* sendbuf = NULL;
- uint16_t offset = 0;
- struct esp_payload_header *header = NULL;
+ uint16_t offset = sizeof(struct esp_payload_header);
+ int ret = 0;
if (!handle || !buf_handle) {
ESP_LOGE(TAG , "Invalid arguments");
@@ -292,59 +457,183 @@ static int32_t sdio_write(interface_handle_t *handle, interface_buffer_handle_t
}
if (handle->state != ACTIVE) {
+ ESP_LOGD(TAG, "%s: Driver state not active, drop", __func__);
return ESP_FAIL;
}
- if (!buf_handle->payload_len || !buf_handle->payload) {
- ESP_LOGE(TAG , "Invalid arguments, len:%d", buf_handle->payload_len);
+ if (is_host_power_saving()) {
+ ESP_LOGD(TAG, "%s: Host sleeping, drop", __func__);
return ESP_FAIL;
}
- total_len = buf_handle->payload_len + sizeof (struct esp_payload_header);
+ total_len = buf_handle->payload_len + offset;
- sendbuf = sdio_buffer_tx_alloc(MEMSET_REQUIRED);
+ sendbuf = sdio_buffer_tx_alloc(total_len, MEMSET_REQUIRED);
if (sendbuf == NULL) {
- ESP_LOGE(TAG , "Malloc send buffer fail!");
+ ESP_LOGE(TAG, "send buffer[%"PRIu32"] malloc fail", total_len);
return ESP_FAIL;
}
- header = (struct esp_payload_header *) sendbuf;
-
- memset (header, 0, sizeof(struct esp_payload_header));
-
- /* Initialize header */
- header->if_type = buf_handle->if_type;
- header->if_num = buf_handle->if_num;
- header->len = htole16(buf_handle->payload_len);
- offset = sizeof(struct esp_payload_header);
- header->offset = htole16(offset);
-
- memcpy(sendbuf + offset, buf_handle->payload, buf_handle->payload_len);
+ copy_tx_payload(sendbuf, buf_handle->payload, buf_handle->payload_len);
+ update_tx_header(sendbuf, buf_handle);
-#if CONFIG_ESP_SDIO_CHECKSUM
- header->checksum = htole16(compute_checksum(sendbuf,
- offset+buf_handle->payload_len));
-#endif
+ ESP_HEXLOGV("bus_tx", sendbuf, total_len, 32);
+#if !SIMPLIFIED_SDIO_SLAVE
+ if (xSemaphoreTake(sdio_send_queue_sem, portMAX_DELAY) != pdTRUE) {
+ sdio_buffer_tx_free(sendbuf);
+ return ESP_FAIL;
+ }
+ ret = sdio_slave_send_queue(sendbuf, total_len, sendbuf, portMAX_DELAY);
+#else
ret = sdio_slave_transmit(sendbuf, total_len);
+#endif
if (ret != ESP_OK) {
ESP_LOGE(TAG , "sdio slave transmit error, ret : 0x%x\r\n", ret);
+#if !SIMPLIFIED_SDIO_SLAVE
+ xSemaphoreGive(sdio_send_queue_sem);
+#endif
sdio_buffer_tx_free(sendbuf);
return ESP_FAIL;
}
+#if SIMPLIFIED_SDIO_SLAVE
sdio_buffer_tx_free(sendbuf);
+#endif
+
+#if ESP_PKT_STATS
+ if (buf_handle->if_type == ESP_STA_IF)
+ pkt_stats.sta_sh_out++;
+ else if (buf_handle->if_type == ESP_SERIAL_IF)
+ pkt_stats.serial_tx_total++;
+#endif
return buf_handle->payload_len;
}
+#if !SIMPLIFIED_SDIO_SLAVE
static int sdio_read(interface_handle_t *if_handle, interface_buffer_handle_t *buf_handle)
+{
+ if (!if_handle || (if_handle->state != ACTIVE) || !buf_handle) {
+ ESP_LOGE(TAG, "%s: Invalid state/args", __func__);
+ return ESP_FAIL;
+ }
+
+
+ #ifdef CONFIG_ESP_ENABLE_RX_PRIORITY_QUEUES
+ xSemaphoreTake(sdio_rx_sem, portMAX_DELAY);
+
+ if (pdFALSE == xQueueReceive(sdio_rx_queue[PRIO_Q_SERIAL], buf_handle, 0))
+ if (pdFALSE == xQueueReceive(sdio_rx_queue[PRIO_Q_BT], buf_handle, 0))
+ if (pdFALSE == xQueueReceive(sdio_rx_queue[PRIO_Q_OTHERS], buf_handle, 0)) {
+ ESP_LOGE(TAG, "%s No element in rx queue", __func__);
+ return ESP_FAIL;
+ }
+ #else
+ xQueueReceive(sdio_rx_queue, buf_handle, portMAX_DELAY);
+ #endif
+
+ return buf_handle->payload_len;
+}
+
+static void sdio_rx_task(void* pvParameters)
{
esp_err_t ret = ESP_OK;
struct esp_payload_header *header = NULL;
-#if CONFIG_ESP_SDIO_CHECKSUM
+ #if CONFIG_ESP_SDIO_CHECKSUM
uint16_t rx_checksum = 0, checksum = 0;
-#endif
+ #endif
+ uint16_t len = 0, offset = 0;
+ size_t sdio_read_len = 0;
+ interface_buffer_handle_t buf_handle = {0};
+ uint8_t flags = 0;
+
+ for(;;) {
+
+ ret = sdio_slave_recv(&(buf_handle.sdio_buf_handle), &(buf_handle.payload),
+ &(sdio_read_len), portMAX_DELAY);
+ if (ret) {
+ ESP_LOGE(TAG, "sdio_slave_recv returned failure");
+ continue;
+ }
+
+ buf_handle.payload_len = sdio_read_len & 0xFFFF;
+
+ header = (struct esp_payload_header *) buf_handle.payload;
+ UPDATE_HEADER_RX_PKT_NO(header);
+
+ flags = header->flags;
+ if (flags & FLAG_POWER_SAVE_STARTED) {
+ if (context.event_handler) {
+ context.event_handler(ESP_POWER_SAVE_ON);
+ }
+ } else if (flags & FLAG_POWER_SAVE_STOPPED) {
+ if (context.event_handler) {
+ context.event_handler(ESP_POWER_SAVE_OFF);
+ }
+ }
+
+ len = le16toh(header->len);
+ if (!len) {
+ ESP_LOGE(TAG, "sdio_slave_recv returned 0 len");
+ sdio_read_done(buf_handle.sdio_buf_handle);
+ continue;
+ }
+
+ offset = le16toh(header->offset);
+
+ if (buf_handle.payload_len < len+offset) {
+ ESP_LOGE(TAG, "%s: err: read_len[%u] < len[%u]+offset[%u]", __func__,
+ buf_handle.payload_len, len, offset);
+ sdio_read_done(buf_handle.sdio_buf_handle);
+ continue;
+ }
+
+ #if CONFIG_ESP_SDIO_CHECKSUM
+ rx_checksum = le16toh(header->checksum);
+ header->checksum = 0;
+
+ checksum = compute_checksum(buf_handle.payload, len+offset);
+
+ if (checksum != rx_checksum) {
+ ESP_LOGE(TAG, "sdio rx calc_chksum[%u] != exp_chksum[%u], drop pkt", checksum, rx_checksum);
+ sdio_read_done(buf_handle.sdio_buf_handle);
+ continue;
+ }
+ #endif
+
+ buf_handle.if_type = header->if_type;
+ buf_handle.if_num = header->if_num;
+ buf_handle.free_buf_handle = sdio_read_done;
+
+ #if ESP_PKT_STATS
+ if (header->if_type == ESP_STA_IF)
+ pkt_stats.hs_bus_sta_in++;
+ #endif
+
+
+ #ifdef CONFIG_ESP_ENABLE_RX_PRIORITY_QUEUES
+ if (header->if_type == ESP_SERIAL_IF) {
+ xQueueSend(sdio_rx_queue[PRIO_Q_SERIAL], &buf_handle, portMAX_DELAY);
+ } else if (header->if_type == ESP_HCI_IF) {
+ xQueueSend(sdio_rx_queue[PRIO_Q_BT], &buf_handle, portMAX_DELAY);
+ } else {
+ xQueueSend(sdio_rx_queue[PRIO_Q_OTHERS], &buf_handle, portMAX_DELAY);
+ }
+ xSemaphoreGive(sdio_rx_sem);
+ #else
+ xQueueSend(sdio_rx_queue, &buf_handle, portMAX_DELAY);
+ #endif
+ }
+}
+#else /* SIMPLIFIED_SDIO_SLAVE */
+static int sdio_read(interface_handle_t *if_handle, interface_buffer_handle_t *buf_handle)
+{
+ esp_err_t ret = ESP_OK;
+ struct esp_payload_header *header = NULL;
+ #if CONFIG_ESP_SDIO_CHECKSUM
+ uint16_t rx_checksum = 0, checksum = 0;
+ #endif
uint16_t len = 0;
size_t sdio_read_len = 0;
@@ -367,26 +656,34 @@ static int sdio_read(interface_handle_t *if_handle, interface_buffer_handle_t *b
buf_handle->payload_len = sdio_read_len & 0xFFFF;
header = (struct esp_payload_header *) buf_handle->payload;
+ UPDATE_HEADER_RX_PKT_NO(header);
len = le16toh(header->len) + le16toh(header->offset);
-#if CONFIG_ESP_SDIO_CHECKSUM
+ #if CONFIG_ESP_SDIO_CHECKSUM
rx_checksum = le16toh(header->checksum);
header->checksum = 0;
checksum = compute_checksum(buf_handle->payload, len);
if (checksum != rx_checksum) {
+ ESP_LOGE(TAG, "sdio rx calc_chksum[%u] != exp_chksum[%u], drop pkt", checksum, rx_checksum);
sdio_read_done(buf_handle->sdio_buf_handle);
return ESP_FAIL;
}
-#endif
+ #endif
+
+ #if ESP_PKT_STATS
+ if (header->if_type == ESP_STA_IF)
+ pkt_stats.hs_bus_sta_in++;
+ #endif
buf_handle->if_type = header->if_type;
buf_handle->if_num = header->if_num;
buf_handle->free_buf_handle = sdio_read_done;
return len;
}
+#endif /* !SIMPLIFIED_SDIO_SLAVE */
static esp_err_t sdio_reset(interface_handle_t *handle)
{
@@ -398,6 +695,16 @@ static esp_err_t sdio_reset(interface_handle_t *handle)
if (ret != ESP_OK)
return ret;
+ sdio_slave_set_host_intena(SDIO_SLAVE_HOSTINT_SEND_NEW_PACKET |
+ SDIO_SLAVE_HOSTINT_BIT0 |
+ SDIO_SLAVE_HOSTINT_BIT1 |
+ SDIO_SLAVE_HOSTINT_BIT2 |
+ SDIO_SLAVE_HOSTINT_BIT3 |
+ SDIO_SLAVE_HOSTINT_BIT4 |
+ SDIO_SLAVE_HOSTINT_BIT5 |
+ SDIO_SLAVE_HOSTINT_BIT6 |
+ SDIO_SLAVE_HOSTINT_BIT7);
+
ret = sdio_slave_start();
if (ret != ESP_OK)
return ret;
@@ -409,6 +716,9 @@ static esp_err_t sdio_reset(interface_handle_t *handle)
ret = sdio_slave_send_get_finished(&handle, 0);
if (ret != ESP_OK)
break;
+#if !SIMPLIFIED_SDIO_SLAVE
+ xSemaphoreGive(sdio_send_queue_sem);
+#endif
if (handle) {
ret = sdio_slave_recv_load_buf(handle);
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/sdio_slave_api.h b/esp_hosted_fg/esp/esp_driver/network_adapter/main/sdio_slave_api.h
index 4a251bca4a..0e09408b62 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/main/sdio_slave_api.h
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/sdio_slave_api.h
@@ -17,9 +17,9 @@
#ifndef __SDIO_SLAVE_API_H
#define __SDIO_SLAVE_API_H
-#ifdef CONFIG_IDF_TARGET_ESP32
-#elif defined CONFIG_IDF_TARGET_ESP32S2
- #error "SDIO is not supported for ESP32S2. Please use SPI"
+#if CONFIG_SOC_SDIO_SLAVE_SUPPORTED
+#else
+ #error "SDIO is not supported for this target. Please use SPI"
#endif
#endif
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/slave_bt.c b/esp_hosted_fg/esp/esp_driver/network_adapter/main/slave_bt.c
index 501c62a7e7..d4e626ac3e 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/main/slave_bt.c
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/slave_bt.c
@@ -13,16 +13,32 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
+#include
+#include
+#include
+#include "adapter.h"
+
+// check: abort if BT Host is enabled
+#if defined(CONFIG_BT_ENABLED) && !defined(CONFIG_BT_CONTROLLER_ONLY)
+#error "BT Host is enabled. This takes up extra memory and is not used by ESP-Hosted."
+#error "Disable it by selecting idf.py menuconfig -> Component config -> Bluetooth -> Host -> Disabled"
+#error "If you want to enable BT Host, disable the errors in esp_hosted_fg/esp/esp_driver/network_adapter/main/slave_bt.c"
+#endif
+
+// enable only if BT component enabled and soc supports BT
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_SOC_BT_SUPPORTED)
-#ifdef CONFIG_BT_ENABLED
#include
+
#include "driver/gpio.h"
#include "driver/uart.h"
-#include "esp_bt.h"
#include "esp_log.h"
#include "slave_bt.h"
+#include "esp_hosted_log.h"
#include "soc/lldesc.h"
+#include "esp_mac.h"
+#include "esp_idf_version.h"
#if BT_OVER_C3_S3
@@ -34,7 +50,7 @@
#endif
-static const char BT_TAG[] = "ESP_BT";
+static const char *TAG = "h_bt";
static bool bt_available(void)
{
@@ -66,7 +82,7 @@ static int host_rcv_pkt(uint8_t *data, uint16_t len)
buf = (uint8_t *) malloc(len);
if (!buf) {
- ESP_LOGE(BT_TAG, "HCI Send packet: memory allocation failed");
+ ESP_LOGE(TAG, "HCI Send packet: memory allocation failed");
return ESP_FAIL;
}
@@ -81,9 +97,7 @@ static int host_rcv_pkt(uint8_t *data, uint16_t len)
buf_handle.wlan_buf_handle = buf;
buf_handle.free_buf_handle = free;
-#if CONFIG_ESP_BT_DEBUG
- ESP_LOG_BUFFER_HEXDUMP("bt_tx", data, len, ESP_LOG_INFO);
-#endif
+ ESP_HEXLOGV("bt_tx new", data, len, 32);
if (send_to_host_queue(&buf_handle, PRIO_Q_BT)) {
free(buf);
@@ -105,14 +119,13 @@ void process_hci_rx_pkt(uint8_t *payload, uint16_t payload_len) {
/* VHCI needs one extra byte at the start of payload */
/* that is accomodated in esp_payload_header */
-#if CONFIG_ESP_BT_DEBUG
- ESP_LOG_BUFFER_HEXDUMP("bt_rx", payload, payload_len, ESP_LOG_INFO);
-#endif
+ ESP_HEXLOGV("bt_rx", payload, payload_len, 32);
+
payload--;
payload_len++;
if (!esp_vhci_host_check_send_available()) {
- ESP_LOGD(BT_TAG, "VHCI not available");
+ ESP_LOGD(TAG, "VHCI not available");
}
#if SOC_ESP_NIMBLE_CONTROLLER
@@ -122,7 +135,7 @@ void process_hci_rx_pkt(uint8_t *payload, uint16_t payload_len) {
if (xSemaphoreTake(vhci_send_sem, VHCI_MAX_TIMEOUT_MS) == pdTRUE) {
esp_vhci_host_send_packet(payload, payload_len);
} else {
- ESP_LOGI(BT_TAG, "VHCI sem timeout");
+ ESP_LOGI(TAG, "VHCI sem timeout");
}
}
#endif
@@ -142,14 +155,14 @@ static bool hci_uart_tl_flow_off(void);
static void hci_uart_tl_finish_transfers(void);
struct uart_txrxchannel {
- esp_bt_hci_tl_callback_t callback;
- void *arg;
- lldesc_t link;
+ esp_bt_hci_tl_callback_t callback;
+ void *arg;
+ lldesc_t link;
};
struct uart_env_tag {
- struct uart_txrxchannel tx;
- struct uart_txrxchannel rx;
+ struct uart_txrxchannel tx;
+ struct uart_txrxchannel rx;
};
struct uart_env_tag uart_env;
@@ -159,21 +172,21 @@ static gdma_channel_handle_t s_rx_channel;
static gdma_channel_handle_t s_tx_channel;
static esp_bt_hci_tl_t s_hci_uart_tl_funcs = {
- ._magic = ESP_BT_HCI_TL_MAGIC_VALUE,
- ._version = ESP_BT_HCI_TL_VERSION,
- ._reserved = 0,
- ._open = (void *)hci_uart_tl_init,
- ._close = (void *)hci_uart_tl_deinit,
- ._finish_transfers = (void *)hci_uart_tl_finish_transfers,
- ._recv = (void *)hci_uart_tl_recv_async,
- ._send = (void *)hci_uart_tl_send_async,
- ._flow_on = (void *)hci_uart_tl_flow_on,
- ._flow_off = (void *)hci_uart_tl_flow_off,
+ ._magic = ESP_BT_HCI_TL_MAGIC_VALUE,
+ ._version = ESP_BT_HCI_TL_VERSION,
+ ._reserved = 0,
+ ._open = (void *)hci_uart_tl_init,
+ ._close = (void *)hci_uart_tl_deinit,
+ ._finish_transfers = (void *)hci_uart_tl_finish_transfers,
+ ._recv = (void *)hci_uart_tl_recv_async,
+ ._send = (void *)hci_uart_tl_send_async,
+ ._flow_on = (void *)hci_uart_tl_flow_on,
+ ._flow_off = (void *)hci_uart_tl_flow_off,
};
static bool hci_uart_tl_init(void)
{
- return true;
+ return true;
}
static void hci_uart_tl_deinit(void)
@@ -181,39 +194,39 @@ static void hci_uart_tl_deinit(void)
}
static IRAM_ATTR void hci_uart_tl_recv_async(uint8_t *buf, uint32_t size,
- esp_bt_hci_tl_callback_t callback, void *arg)
+ esp_bt_hci_tl_callback_t callback, void *arg)
{
- assert(buf != NULL);
- assert(size != 0);
- assert(callback != NULL);
- uart_env.rx.callback = callback;
- uart_env.rx.arg = arg;
+ assert(buf != NULL);
+ assert(size != 0);
+ assert(callback != NULL);
+ uart_env.rx.callback = callback;
+ uart_env.rx.arg = arg;
- memset(&uart_env.rx.link, 0, sizeof(lldesc_t));
- uart_env.rx.link.buf = buf;
- uart_env.rx.link.size = size;
+ memset(&uart_env.rx.link, 0, sizeof(lldesc_t));
+ uart_env.rx.link.buf = buf;
+ uart_env.rx.link.size = size;
- s_uhci_hw->pkt_thres.thrs = size;
+ s_uhci_hw->pkt_thres.thrs = size;
- gdma_start(s_rx_channel, (intptr_t)(&uart_env.rx.link));
+ gdma_start(s_rx_channel, (intptr_t)(&uart_env.rx.link));
}
static IRAM_ATTR void hci_uart_tl_send_async(uint8_t *buf, uint32_t size,
- esp_bt_hci_tl_callback_t callback, void *arg)
+ esp_bt_hci_tl_callback_t callback, void *arg)
{
- assert(buf != NULL);
- assert(size != 0);
- assert(callback != NULL);
+ assert(buf != NULL);
+ assert(size != 0);
+ assert(callback != NULL);
- uart_env.tx.callback = callback;
- uart_env.tx.arg = arg;
+ uart_env.tx.callback = callback;
+ uart_env.tx.arg = arg;
- memset(&uart_env.tx.link, 0, sizeof(lldesc_t));
- uart_env.tx.link.length = size;
- uart_env.tx.link.buf = buf;
- uart_env.tx.link.eof = 1;
+ memset(&uart_env.tx.link, 0, sizeof(lldesc_t));
+ uart_env.tx.link.length = size;
+ uart_env.tx.link.buf = buf;
+ uart_env.tx.link.eof = 1;
- gdma_start(s_tx_channel, (intptr_t)(&uart_env.tx.link));
+ gdma_start(s_tx_channel, (intptr_t)(&uart_env.tx.link));
}
static void hci_uart_tl_flow_on(void)
@@ -222,7 +235,7 @@ static void hci_uart_tl_flow_on(void)
static bool hci_uart_tl_flow_off(void)
{
- return true;
+ return true;
}
static void hci_uart_tl_finish_transfers(void)
@@ -230,147 +243,151 @@ static void hci_uart_tl_finish_transfers(void)
}
static IRAM_ATTR bool hci_uart_tl_rx_eof_callback(gdma_channel_handle_t dma_chan,
- gdma_event_data_t *event_data, void *user_data)
+ gdma_event_data_t *event_data, void *user_data)
{
- assert(dma_chan == s_rx_channel);
- assert(uart_env.rx.callback != NULL);
- esp_bt_hci_tl_callback_t callback = uart_env.rx.callback;
- void *arg = uart_env.rx.arg;
+ assert(dma_chan == s_rx_channel);
+ assert(uart_env.rx.callback != NULL);
+ esp_bt_hci_tl_callback_t callback = uart_env.rx.callback;
+ void *arg = uart_env.rx.arg;
- // clear callback pointer
- uart_env.rx.callback = NULL;
- uart_env.rx.arg = NULL;
+ // clear callback pointer
+ uart_env.rx.callback = NULL;
+ uart_env.rx.arg = NULL;
- // call handler
- callback(arg, ESP_BT_HCI_TL_STATUS_OK);
+ // call handler
+ callback(arg, ESP_BT_HCI_TL_STATUS_OK);
- // send notification to Bluetooth Controller task
- esp_bt_h4tl_eif_io_event_notify(1);
+ // send notification to Bluetooth Controller task
+ esp_bt_h4tl_eif_io_event_notify(1);
- return true;
+ return true;
}
static IRAM_ATTR bool hci_uart_tl_tx_eof_callback(gdma_channel_handle_t dma_chan,
- gdma_event_data_t *event_data, void *user_data)
+ gdma_event_data_t *event_data, void *user_data)
{
- assert(dma_chan == s_tx_channel);
- assert(uart_env.tx.callback != NULL);
- esp_bt_hci_tl_callback_t callback = uart_env.tx.callback;
- void *arg = uart_env.tx.arg;
+ assert(dma_chan == s_tx_channel);
+ assert(uart_env.tx.callback != NULL);
+ esp_bt_hci_tl_callback_t callback = uart_env.tx.callback;
+ void *arg = uart_env.tx.arg;
- // clear callback pointer
- uart_env.tx.callback = NULL;
- uart_env.tx.arg = NULL;
+ // clear callback pointer
+ uart_env.tx.callback = NULL;
+ uart_env.tx.arg = NULL;
- // call handler
- callback(arg, ESP_BT_HCI_TL_STATUS_OK);
+ // call handler
+ callback(arg, ESP_BT_HCI_TL_STATUS_OK);
- // send notification to Bluetooth Controller task
- esp_bt_h4tl_eif_io_event_notify(1);
+ // send notification to Bluetooth Controller task
+ esp_bt_h4tl_eif_io_event_notify(1);
- return true;
+ return true;
}
#endif
#if BT_OVER_C3_S3
static void init_uart_c3_s3(void)
{
- ESP_LOGD(BT_TAG, "Set-up BLE for ESP32-C3/ESP32-S3");
+ ESP_LOGD(TAG, "Set-up BLE for ESP32-C3/ESP32-S3");
#if BLUETOOTH_UART == 1
periph_module_enable(PERIPH_UART1_MODULE);
- periph_module_reset(PERIPH_UART1_MODULE);
+ periph_module_reset(PERIPH_UART1_MODULE);
#elif BLUETOOTH_UART == 2
periph_module_enable(PERIPH_UART2_MODULE);
- periph_module_reset(PERIPH_UART2_MODULE);
+ periph_module_reset(PERIPH_UART2_MODULE);
#endif
periph_module_enable(PERIPH_UHCI0_MODULE);
- periph_module_reset(PERIPH_UHCI0_MODULE);
-
- gpio_config_t io_output_conf = {
- .intr_type = DISABLE_INTR_ON_GPIO, /* Disable interrupt */
- .mode = GPIO_MODE_OUTPUT, /* Output mode */
- .pin_bit_mask = GPIO_OUTPUT_PIN_SEL, /* Bit mask of the output pins */
- .pull_down_en = 0, /* Disable pull-down mode */
- .pull_up_en = 0, /* Disable pull-up mode */
- };
- gpio_config(&io_output_conf);
-
- gpio_config_t io_input_conf = {
- .intr_type = DISABLE_INTR_ON_GPIO, /* Disable interrupt */
- .mode = GPIO_MODE_INPUT, /* Input mode */
- .pin_bit_mask = GPIO_INPUT_PIN_SEL, /* Bit mask of the input pins */
- .pull_down_en = 0, /* Disable pull-down mode */
- .pull_up_en = 0, /* Disable pull-down mode */
- };
- gpio_config(&io_input_conf);
+ periph_module_reset(PERIPH_UHCI0_MODULE);
+
+ gpio_config_t io_output_conf = {
+ .intr_type = DISABLE_INTR_ON_GPIO, /* Disable interrupt */
+ .mode = GPIO_MODE_OUTPUT, /* Output mode */
+ .pin_bit_mask = GPIO_OUTPUT_PIN_SEL, /* Bit mask of the output pins */
+ .pull_down_en = 0, /* Disable pull-down mode */
+ .pull_up_en = 0, /* Disable pull-up mode */
+ };
+ gpio_config(&io_output_conf);
+
+ gpio_config_t io_input_conf = {
+ .intr_type = DISABLE_INTR_ON_GPIO, /* Disable interrupt */
+ .mode = GPIO_MODE_INPUT, /* Input mode */
+ .pin_bit_mask = GPIO_INPUT_PIN_SEL, /* Bit mask of the input pins */
+ .pull_down_en = 0, /* Disable pull-down mode */
+ .pull_up_en = 0, /* Disable pull-down mode */
+ };
+ gpio_config(&io_input_conf);
ESP_ERROR_CHECK( uart_set_pin(BLUETOOTH_UART, BT_TX_PIN,
BT_RX_PIN, BT_RTS_PIN, BT_CTS_PIN) );
- ESP_LOGI(BT_TAG, "UART Pins: Tx:%u Rx:%u RTS:%u CTS:%u",
+ ESP_LOGI(TAG, "UART Pins: Tx:%u Rx:%u RTS:%u CTS:%u",
BT_TX_PIN, BT_RX_PIN, BT_RTS_PIN, BT_CTS_PIN);
- // configure UART1
- ESP_LOGI(BT_TAG, "baud rate for HCI uart :: %d \n",
+ // configure UART1
+ ESP_LOGI(TAG, "baud rate for HCI uart :: %d \n",
CONFIG_EXAMPLE_HCI_UART_BAUDRATE);
- uart_config_t uart_config = {
- .baud_rate = CONFIG_EXAMPLE_HCI_UART_BAUDRATE,
-
- .data_bits = UART_DATA_8_BITS,
- .parity = UART_PARITY_DISABLE,
- .stop_bits = UART_STOP_BITS_1,
- .flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS,
- .rx_flow_ctrl_thresh = UART_RX_THRS,
- .source_clk = UART_SCLK_APB,
- };
- ESP_ERROR_CHECK(uart_param_config(BLUETOOTH_UART, &uart_config));
-
- // install DMA driver
- gdma_channel_alloc_config_t tx_channel_config = {
- .flags.reserve_sibling = 1,
- .direction = GDMA_CHANNEL_DIRECTION_TX,
- };
- ESP_ERROR_CHECK(gdma_new_channel(&tx_channel_config, &s_tx_channel));
- gdma_channel_alloc_config_t rx_channel_config = {
- .direction = GDMA_CHANNEL_DIRECTION_RX,
- .sibling_chan = s_tx_channel,
- };
- ESP_ERROR_CHECK(gdma_new_channel(&rx_channel_config, &s_rx_channel));
-
- gdma_connect(s_tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0));
- gdma_connect(s_rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0));
-
- gdma_strategy_config_t strategy_config = {
- .auto_update_desc = false,
- .owner_check = false
- };
- gdma_apply_strategy(s_tx_channel, &strategy_config);
- gdma_apply_strategy(s_rx_channel, &strategy_config);
-
- gdma_rx_event_callbacks_t rx_cbs = {
- .on_recv_eof = hci_uart_tl_rx_eof_callback
- };
- gdma_register_rx_event_callbacks(s_rx_channel, &rx_cbs, NULL);
-
- gdma_tx_event_callbacks_t tx_cbs = {
- .on_trans_eof = hci_uart_tl_tx_eof_callback
- };
- gdma_register_tx_event_callbacks(s_tx_channel, &tx_cbs, NULL);
-
- // configure UHCI
- uhci_ll_init(s_uhci_hw);
- uhci_ll_set_eof_mode(s_uhci_hw, UHCI_RX_LEN_EOF);
- // disable software flow control
- s_uhci_hw->escape_conf.val = 0;
- uhci_ll_attach_uart_port(s_uhci_hw, 1);
+ uart_config_t uart_config = {
+ .baud_rate = CONFIG_EXAMPLE_HCI_UART_BAUDRATE,
+
+ .data_bits = UART_DATA_8_BITS,
+ .parity = UART_PARITY_DISABLE,
+ .stop_bits = UART_STOP_BITS_1,
+ .flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS,
+ .rx_flow_ctrl_thresh = UART_RX_THRS,
+ .source_clk = UART_SCLK_APB,
+ };
+ ESP_ERROR_CHECK(uart_param_config(BLUETOOTH_UART, &uart_config));
+
+ // install DMA driver
+ gdma_channel_alloc_config_t tx_channel_config = {
+ .flags.reserve_sibling = 1,
+ .direction = GDMA_CHANNEL_DIRECTION_TX,
+ };
+ ESP_ERROR_CHECK(gdma_new_channel(&tx_channel_config, &s_tx_channel));
+ gdma_channel_alloc_config_t rx_channel_config = {
+ .direction = GDMA_CHANNEL_DIRECTION_RX,
+ .sibling_chan = s_tx_channel,
+ };
+ ESP_ERROR_CHECK(gdma_new_channel(&rx_channel_config, &s_rx_channel));
+
+ gdma_connect(s_tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0));
+ gdma_connect(s_rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0));
+
+ gdma_strategy_config_t strategy_config = {
+ .auto_update_desc = false,
+ .owner_check = false
+ };
+ gdma_apply_strategy(s_tx_channel, &strategy_config);
+ gdma_apply_strategy(s_rx_channel, &strategy_config);
+
+ gdma_rx_event_callbacks_t rx_cbs = {
+ .on_recv_eof = hci_uart_tl_rx_eof_callback
+ };
+ gdma_register_rx_event_callbacks(s_rx_channel, &rx_cbs, NULL);
+
+ gdma_tx_event_callbacks_t tx_cbs = {
+ .on_trans_eof = hci_uart_tl_tx_eof_callback
+ };
+ gdma_register_tx_event_callbacks(s_tx_channel, &tx_cbs, NULL);
+
+ // configure UHCI
+ uhci_ll_init(s_uhci_hw);
+#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 5, 0)
+ uhci_ll_set_eof_mode(s_uhci_hw, UHCI_RX_LEN_EOF);
+#else
+ uhci_ll_rx_set_eof_mode(s_uhci_hw, UHCI_RX_LEN_EOF);
+#endif
+ // disable software flow control
+ s_uhci_hw->escape_conf.val = 0;
+ uhci_ll_attach_uart_port(s_uhci_hw, 1);
}
#endif
#if CONFIG_IDF_TARGET_ESP32
static void init_uart_esp32(void)
{
- ESP_LOGD(BT_TAG, "Set-up BLE for ESP32");
+ ESP_LOGD(TAG, "Set-up BLE for ESP32");
#if BLUETOOTH_UART == 1
periph_module_enable(PERIPH_UART1_MODULE);
periph_module_reset(PERIPH_UART1_MODULE);
@@ -385,51 +402,50 @@ static void init_uart_esp32(void)
ESP_ERROR_CHECK( uart_set_pin(BLUETOOTH_UART, BT_TX_PIN,
BT_RX_PIN, BT_RTS_PIN, BT_CTS_PIN) );
- ESP_LOGI(BT_TAG, "UART Pins: Tx:%u Rx:%u RTS:%u CTS:%u",
+ ESP_LOGI(TAG, "UART Pins: Tx:%u Rx:%u RTS:%u CTS:%u",
BT_TX_PIN, BT_RX_PIN, BT_RTS_PIN, BT_CTS_PIN);
}
-#endif
+#endif /* CONFIG_IDF_TARGET_ESP32 */
-#if (defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C6))
-static void init_uart_c2_c6(void)
+#if (defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C6)) || defined(CONFIG_IDF_TARGET_ESP32C5)
+static void init_uart_c2_c6_c5(void)
{
- ESP_LOGD(BT_TAG, "Set-up BLE for ESP32-C2/C6");
-
-#if defined(CONFIG_IDF_TARGET_ESP32C2)
- ESP_LOGI(BT_TAG, "UART Pins: Tx:%u Rx:%u", BT_TX_PIN, BT_RX_PIN);
-#elif defined(CONFIG_IDF_TARGET_ESP32C6)
- //ESP_ERROR_CHECK( uart_set_pin(BLUETOOTH_UART, BT_TX_PIN,
- // BT_RX_PIN, BT_RTS_PIN, BT_CTS_PIN) );
- ESP_LOGI(BT_TAG, "UART Pins: Tx:%u Rx:%u", BT_TX_PIN, BT_RX_PIN);
- //ESP_LOGI(BT_TAG, "UART Pins: Tx:%u Rx:%u RTS:%u CTS:%u",
- //BT_TX_PIN, BT_RX_PIN, BT_RTS_PIN, BT_CTS_PIN);
-#endif
+ ESP_LOGD(TAG, "Set-up BLE for ESP32-C2/C6/C5");
+
+#if defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C5)
+ //ESP_ERROR_CHECK( uart_set_pin(BLUETOOTH_UART, BT_TX_PIN,
+ // BT_RX_PIN, BT_RTS_PIN, BT_CTS_PIN) );
+ ESP_LOGI(TAG, "UART Pins: Tx:%u Rx:%u", BT_TX_PIN, BT_RX_PIN);
+ //ESP_LOGI(TAG, "UART Pins: Tx:%u Rx:%u RTS:%u CTS:%u",
+ //BT_TX_PIN, BT_RX_PIN, BT_RTS_PIN, BT_CTS_PIN);
+#endif /* CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32C6 */
}
-#endif
+#endif /* CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32C6 */
void init_uart(void)
{
#if CONFIG_IDF_TARGET_ESP32
init_uart_esp32();
-#elif (defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C6))
- init_uart_c2_c6();
+#elif (defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C6)) || defined(CONFIG_IDF_TARGET_ESP32C5)
+ init_uart_c2_c6_c5();
#elif BT_OVER_C3_S3
init_uart_c3_s3();
-#endif
+#endif /* BT_OVER_C3_S3 */
}
#endif
#if BLUETOOTH_HCI
#if SOC_ESP_NIMBLE_CONTROLLER
+
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0)
#include "nimble/ble_hci_trans.h"
typedef enum {
- DATA_TYPE_COMMAND = 1,
- DATA_TYPE_ACL = 2,
- DATA_TYPE_SCO = 3,
- DATA_TYPE_EVENT = 4
+ DATA_TYPE_COMMAND = 1,
+ DATA_TYPE_ACL = 2,
+ DATA_TYPE_SCO = 3,
+ DATA_TYPE_EVENT = 4
} serial_data_type_t;
/* Host-to-controller command. */
@@ -450,7 +466,7 @@ void esp_vhci_host_send_packet(uint8_t *data, uint16_t len)
struct ble_hci_cmd *cmd = NULL;
cmd = (struct ble_hci_cmd *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD);
if (!cmd) {
- ESP_LOGE(BT_TAG, "Failed to allocate memory for HCI transport buffer");
+ ESP_LOGE(TAG, "Failed to allocate memory for HCI transport buffer");
return;
}
@@ -468,57 +484,61 @@ void esp_vhci_host_send_packet(uint8_t *data, uint16_t len)
}
bool esp_vhci_host_check_send_available() {
- // not need to check in esp new controller
- return true;
+ // not need to check in esp new controller
+ return true;
}
int
ble_hs_hci_rx_evt(uint8_t *hci_ev, void *arg)
{
- uint16_t len = hci_ev[1] + 3;
- uint8_t *data = (uint8_t *)malloc(len);
- data[0] = 0x04;
- memcpy(&data[1], hci_ev, len - 1);
- ble_hci_trans_buf_free(hci_ev);
- vhci_host_cb.notify_host_recv(data, len);
- free(data);
- return 0;
+ uint16_t len = hci_ev[1] + 3;
+ uint8_t *data = (uint8_t *)malloc(len);
+ data[0] = 0x04;
+ memcpy(&data[1], hci_ev, len - 1);
+ ble_hci_trans_buf_free(hci_ev);
+ vhci_host_cb.notify_host_recv(data, len);
+ free(data);
+ return 0;
}
int
ble_hs_rx_data(struct os_mbuf *om, void *arg)
{
- uint16_t len = om->om_len + 1;
- uint8_t *data = (uint8_t *)malloc(len);
- data[0] = 0x02;
- os_mbuf_copydata(om, 0, len - 1, &data[1]);
- vhci_host_cb.notify_host_recv(data, len);
- free(data);
- os_mbuf_free_chain(om);
- return 0;
+ uint16_t len = om->om_len + 1;
+ uint8_t *data = (uint8_t *)malloc(len);
+ data[0] = 0x02;
+ os_mbuf_copydata(om, 0, len - 1, &data[1]);
+ vhci_host_cb.notify_host_recv(data, len);
+ free(data);
+ os_mbuf_free_chain(om);
+ return 0;
}
+#endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0) */
-#endif
-#endif
-#endif
+#endif /* SOC_ESP_NIMBLE_CONTROLLER */
+#endif /* BLUETOOTH_HCI */
esp_err_t initialise_bluetooth(void)
{
+ uint8_t mac[BSSID_BYTES_SIZE] = {0};
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
if (bt_available()) {
- ESP_LOGI(BT_TAG, "BT is already configured earlier, ignoring");
+ ESP_LOGI(TAG, "BT is already configured earlier, ignoring");
return 0;
}
+ ESP_ERROR_CHECK(esp_read_mac(mac, ESP_MAC_BT));
+ ESP_LOGI(TAG, "ESP Bluetooth MAC addr: %02x:%02x:%02x:%02x:%02x:%02x",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
#ifdef BLUETOOTH_UART
#if BT_OVER_C3_S3
bt_cfg.hci_tl_funcs = &s_hci_uart_tl_funcs;
- #endif
+ #endif /* BT_OVER_C3_S3 */
init_uart();
-#endif
+#endif /* BLUETOOTH_UART */
ESP_ERROR_CHECK( esp_bt_controller_init(&bt_cfg) );
#if BLUETOOTH_BLE
ESP_ERROR_CHECK( esp_bt_controller_enable(ESP_BT_MODE_BLE) );
@@ -526,31 +546,31 @@ esp_err_t initialise_bluetooth(void)
ESP_ERROR_CHECK( esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT) );
#elif BLUETOOTH_BT_BLE
ESP_ERROR_CHECK( esp_bt_controller_enable(ESP_BT_MODE_BTDM) );
-#endif
+#endif /* BLUETOOTH_BT_BLE */
#if BLUETOOTH_HCI
esp_err_t ret = ESP_OK;
#if SOC_ESP_NIMBLE_CONTROLLER && (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0))
- ble_hci_trans_cfg_hs((ble_hci_trans_rx_cmd_fn *)ble_hs_hci_rx_evt,NULL,
- (ble_hci_trans_rx_acl_fn *)ble_hs_rx_data,NULL);
+ ble_hci_trans_cfg_hs((ble_hci_trans_rx_cmd_fn *)ble_hs_hci_rx_evt,NULL,
+ (ble_hci_trans_rx_acl_fn *)ble_hs_rx_data,NULL);
#else
ret = esp_vhci_host_register_callback(&vhci_host_cb);
-#endif
+#endif /* SOC_ESP_NIMBLE_CONTROLLER */
if (ret != ESP_OK) {
- ESP_LOGE(BT_TAG, "Failed to register VHCI callback");
+ ESP_LOGE(TAG, "Failed to register VHCI callback");
return ret;
}
vhci_send_sem = xSemaphoreCreateBinary();
if (vhci_send_sem == NULL) {
- ESP_LOGE(BT_TAG, "Failed to create VHCI send sem");
+ ESP_LOGE(TAG, "Failed to create VHCI send sem");
return ESP_ERR_NO_MEM;
}
xSemaphoreGive(vhci_send_sem);
-#endif
+#endif /* BLUETOOTH_HCI */
return ESP_OK;
}
@@ -568,7 +588,7 @@ void deinitialize_bluetooth(void)
vSemaphoreDelete(vhci_send_sem);
vhci_send_sem = NULL;
}
-#endif
+#endif /* BLUETOOTH_HCI */
esp_bt_controller_disable();
esp_bt_controller_deinit();
}
@@ -576,32 +596,34 @@ void deinitialize_bluetooth(void)
uint8_t get_bluetooth_capabilities(void)
{
uint8_t cap = 0;
- ESP_LOGI(BT_TAG, "- BT/BLE");
+ ESP_LOGI(TAG, "- BT/BLE");
#if BLUETOOTH_HCI
+
#if CONFIG_ESP_SPI_HOST_INTERFACE
- ESP_LOGI(BT_TAG, " - HCI Over SPI");
+ ESP_LOGI(TAG, " - HCI Over SPI");
cap |= ESP_BT_SPI_SUPPORT;
-#else
- ESP_LOGI(BT_TAG, " - HCI Over SDIO");
+#elif CONFIG_ESP_SDIO_HOST_INTERFACE
+ ESP_LOGI(TAG, " - HCI Over SDIO");
cap |= ESP_BT_SDIO_SUPPORT;
-#endif
+#endif /* CONFIG_ESP_SDIO_HOST_INTERFACE */
+
#elif BLUETOOTH_UART
- ESP_LOGI(BT_TAG, " - HCI Over UART");
+ ESP_LOGI(TAG, " - HCI Over UART");
cap |= ESP_BT_UART_SUPPORT;
-#endif
+#endif /* BLUETOOTH_UART */
#if BLUETOOTH_BLE
- ESP_LOGI(BT_TAG, " - BLE only");
+ ESP_LOGI(TAG, " - BLE only");
cap |= ESP_BLE_ONLY_SUPPORT;
#elif BLUETOOTH_BT
- ESP_LOGI(BT_TAG, " - BR_EDR only");
+ ESP_LOGI(TAG, " - BR_EDR only");
cap |= ESP_BR_EDR_ONLY_SUPPORT;
#elif BLUETOOTH_BT_BLE
- ESP_LOGI(BT_TAG, " - BT/BLE dual mode");
- cap |= ESP_BLE_ONLY_SUPPORT | ESP_BR_EDR_ONLY_SUPPORT;
-#endif
+ ESP_LOGI(TAG, " - BT/BLE dual mode");
+ cap |= ESP_BLE_ONLY_SUPPORT | ESP_BR_EDR_ONLY_SUPPORT;
+#endif /* BLUETOOTH_BT_BLE */
+
return cap;
}
-
-#endif
+#endif /* CONFIG_BT_ENABLED && CONFIG_SOC_BT_SUPPORTED */
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/slave_bt.h b/esp_hosted_fg/esp/esp_driver/network_adapter/main/slave_bt.h
index 0b63203e7d..1d2718e3a2 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/main/slave_bt.h
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/slave_bt.h
@@ -17,7 +17,11 @@
#ifndef __SLAVE_BT_H__
#define __SLAVE_BT_H__
-#ifdef CONFIG_BT_ENABLED
+#include "esp_err.h"
+
+// include only if BT component enabled and soc supports BT
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_SOC_BT_SUPPORTED)
+#include "esp_bt.h"
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
#include "driver/periph_ctrl.h"
@@ -50,7 +54,7 @@
#define BLUETOOTH_UART CONFIG_BTDM_CTRL_HCI_UART_NO
#endif
-#elif (defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C6))
+#elif (defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C5))
#define BLUETOOTH_BLE 1
@@ -85,14 +89,7 @@
#define BT_RTS_PIN 19
#define BT_CTS_PIN 23
- #elif defined(CONFIG_IDF_TARGET_ESP32C2)
-
- #define BT_TX_PIN 5
- #define BT_RX_PIN 18
- //#define BT_RTS_PIN 9
- //#define BT_CTS_PIN 8
-
- #elif defined(CONFIG_IDF_TARGET_ESP32C6)
+ #elif defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C5)
#define BT_TX_PIN CONFIG_BT_LE_HCI_UART_TX_PIN
#define BT_RX_PIN CONFIG_BT_LE_HCI_UART_RX_PIN
@@ -133,6 +130,6 @@ void deinitialize_bluetooth(void);
esp_err_t initialise_bluetooth(void);
uint8_t get_bluetooth_capabilities(void);
-#endif /* CONFIG_BT_ENABLED */
+#endif /* CONFIG_BT_ENABLED && CONFIG_SOC_BT_SUPPORTED */
#endif /* __SLAVE_BT_H__ */
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/slave_control.c b/esp_hosted_fg/esp/esp_driver/network_adapter/main/slave_control.c
index 318bbb2985..bd122fc6e3 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/main/slave_control.c
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/slave_control.c
@@ -23,6 +23,14 @@
#include "esp_ota_ops.h"
#include "slave_bt.h"
#include "esp_fw_version.h"
+#ifdef CONFIG_NETWORK_SPLIT_ENABLED
+#include "esp_check.h"
+#include "lwip/inet.h"
+#include "host_power_save.h"
+#include "mqtt_example.h"
+#endif
+#include "esp_timer.h"
+
#define MAC_STR_LEN 17
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
@@ -32,14 +40,7 @@
#define MIN_TX_POWER 8
#define MAX_TX_POWER 84
-/* Bits for wifi connect event */
-#define WIFI_CONNECTED_BIT BIT0
-#define WIFI_FAIL_BIT BIT1
-#define WIFI_NO_AP_FOUND_BIT BIT2
-#define WIFI_WRONG_PASSWORD_BIT BIT3
-#define WIFI_HOST_REQUEST_BIT BIT4
-
-#define MAX_STA_CONNECT_ATTEMPTS 2
+#define MAX_STA_CONNECT_ATTEMPTS 3
#define TIMEOUT_IN_MIN (60*TIMEOUT_IN_SEC)
#define TIMEOUT_IN_HOUR (60*TIMEOUT_IN_MIN)
@@ -50,10 +51,6 @@
#endif
#define RESTART_TIMEOUT (5*TIMEOUT_IN_SEC)
-#if CONFIG_ESP_OTA_WORKAROUND
-#define OTA_SLEEP_TIME_MS (40)
-#endif
-
#define MIN_HEARTBEAT_INTERVAL (10)
#define MAX_HEARTBEAT_INTERVAL (60*60)
@@ -69,6 +66,28 @@
} \
}
+#ifdef CONFIG_NETWORK_SPLIT_ENABLED
+
+typedef struct {
+ int iface;
+ int net_link_up;
+ int dhcp_up;
+ uint8_t dhcp_ip[64];
+ uint8_t dhcp_nm[64];
+ uint8_t dhcp_gw[64];
+ int dns_up;
+ uint8_t dns_ip[64];
+ int dns_type;
+} ctrl_msg_set_dhcp_dns_status_t;
+
+static ctrl_msg_set_dhcp_dns_status_t s2h_dhcp_dns;
+
+#endif
+
+static wifi_config_t new_wifi_config;
+static bool new_config_recvd;
+static bool prev_wifi_config_valid;
+
typedef struct esp_ctrl_msg_cmd {
int req_num;
esp_err_t (*command_handler)(CtrlMsg *req,
@@ -76,13 +95,17 @@ typedef struct esp_ctrl_msg_cmd {
} esp_ctrl_msg_req_t;
static const char* TAG = "slave_ctrl";
-extern volatile uint8_t ota_ongoing;
static TimerHandle_t handle_heartbeat_task;
static uint32_t hb_num;
-static bool event_registered = false;
-/* FreeRTOS event group to signal when we are connected*/
-static EventGroupHandle_t wifi_event_group;
+#ifdef CONFIG_NETWORK_SPLIT_ENABLED
+static esp_event_handler_instance_t instance_ip;
+extern volatile uint8_t station_got_ip;
+//static ip_event_got_ip_t lkg_sta_got_ip_event = {0};
+#endif
+static wifi_event_sta_connected_t lkg_sta_connected_event = {0};
+
+uint16_t sta_connect_retry;
static bool scan_done = false;
static esp_ota_handle_t handle;
@@ -101,14 +124,18 @@ static void softap_event_unregister(void);
static void ap_scan_list_event_register(void);
static void ap_scan_list_event_unregister(void);
static esp_err_t convert_mac_to_bytes(uint8_t *out, char *s);
+static bool is_wifi_config_equal(const wifi_config_t *cfg1, const wifi_config_t *cfg2);
extern esp_err_t wlan_sta_rx_callback(void *buffer, uint16_t len, void *eb);
extern esp_err_t wlan_ap_rx_callback(void *buffer, uint16_t len, void *eb);
-void esp_update_ap_mac(void);
extern volatile uint8_t station_connected;
extern volatile uint8_t softap_started;
+
+/* Callback storage */
+static custom_rpc_unserialised_req_handler_t custom_rpc_unserialised_req_handler = NULL;
+
/* OTA end timer callback */
void vTimerCallback( TimerHandle_t xTimer )
{
@@ -116,53 +143,345 @@ void vTimerCallback( TimerHandle_t xTimer )
esp_restart();
}
+static void send_wifi_event_data_to_host(int event, void *event_data, int event_size)
+{
+ send_event_data_to_host(event, event_data, event_size);
+}
+
+static bool wifi_is_provisioned(wifi_config_t *wifi_cfg)
+{
+ if (!wifi_cfg) {
+ ESP_LOGI(TAG, "NULL wifi cfg passed, ignore");
+ return false;
+ }
+
+ if (esp_wifi_get_config(WIFI_IF_STA, wifi_cfg) != ESP_OK) {
+ ESP_LOGI(TAG, "Wifi get config failed");
+ return false;
+ }
+
+ ESP_LOGI(TAG, "SSID: %s", wifi_cfg->sta.ssid);
+
+ if (strlen((const char *) wifi_cfg->sta.ssid)) {
+ ESP_LOGI(TAG, "Wifi provisioned");
+ return true;
+ }
+ ESP_LOGI(TAG, "Wifi not provisioned, Fallback to example config");
+
+ return false;
+}
+
+esp_err_t esp_hosted_set_sta_config(wifi_interface_t iface, wifi_config_t *cfg)
+{
+
+ wifi_config_t current_config = {0};
+ if (!wifi_is_provisioned(¤t_config)) {
+ if (esp_wifi_set_config(WIFI_IF_STA, cfg) != ESP_OK) {
+ ESP_LOGW(TAG, "not provisioned and failed to set wifi config");
+ } else {
+ ESP_LOGI(TAG, "Provisioned new Wi-Fi config");
+ prev_wifi_config_valid = false;
+ }
+ }
+
+ if (!is_wifi_config_equal(cfg, ¤t_config)) {
+ new_config_recvd = 1;
+ ESP_LOGI(TAG, "Setting new WiFi config SSID: %s", cfg->sta.ssid);
+
+ prev_wifi_config_valid = false;
+ memcpy(&new_wifi_config, cfg, sizeof(wifi_config_t));
+
+ } else {
+ ESP_LOGI(TAG, "WiFi config unchanged, keeping current connection");
+ }
+
+ return ESP_OK;
+}
+
+#ifdef CONFIG_NETWORK_SPLIT_ENABLED
+
+void send_dhcp_dns_info_to_host(uint8_t network_up, uint8_t send_wifi_connected)
+{
+ ctrl_msg_set_dhcp_dns_status_t s2h_dhcp_dns_DOWN = {0};
+ ctrl_msg_set_dhcp_dns_status_t *evnt_to_send = &s2h_dhcp_dns_DOWN;
+
+ if (is_host_power_saving()) {
+ ESP_LOGI(TAG, "Host in power save, suppress network update");
+ return;
+ }
+ ESP_EARLY_LOGI(TAG, "Send DHCP-DNS status to Host");
+ if (network_up && s2h_dhcp_dns.dhcp_up && s2h_dhcp_dns.net_link_up && s2h_dhcp_dns.dns_up) {
+ evnt_to_send = &s2h_dhcp_dns;
+ }
+ send_event_data_to_host(CTRL_MSG_ID__Event_SetDhcpDnsStatus,
+ evnt_to_send, sizeof(ctrl_msg_set_dhcp_dns_status_t));
+
+ if (send_wifi_connected && station_connected) {
+ send_wifi_event_data_to_host(CTRL_MSG_ID__Event_StationConnectedToAP,
+ &lkg_sta_connected_event, sizeof(wifi_event_sta_connected_t));
+ }
+}
+
+static void event_handler_ip(void* arg, esp_event_base_t event_base,
+ int32_t event_id, void* event_data)
+{
+ char ip_s[16] = {0};
+ char nm_s[16] = {0};
+ char gw_s[16] = {0};
+ char dns_ip_s[16] = {0};
+
+ if (event_base == IP_EVENT) {
+ switch (event_id) {
+
+ case IP_EVENT_STA_GOT_IP: {
+ ESP_LOGI(TAG, "Got IP");
+ ip_event_got_ip_t* event = event_data;
+ esp_netif_t *netif = event->esp_netif;
+ esp_netif_dns_info_t dns = {0};
+
+ //memcpy(&lkg_sta_got_ip_event, event_data, sizeof(ip_event_got_ip_t));
+ ESP_ERROR_CHECK(esp_wifi_internal_set_sta_ip());
+ ESP_ERROR_CHECK(esp_netif_get_dns_info(netif, ESP_NETIF_DNS_MAIN, &dns));
+
+ esp_ip4addr_ntoa(&event->ip_info.ip, ip_s, sizeof(ip_s));
+ esp_ip4addr_ntoa(&event->ip_info.netmask, nm_s, sizeof(nm_s));
+ esp_ip4addr_ntoa(&event->ip_info.gw, gw_s, sizeof(gw_s));
+ esp_ip4addr_ntoa(&dns.ip.u_addr.ip4, dns_ip_s, sizeof(dns_ip_s));
+
+ ESP_LOGI(TAG, "Slave sta dhcp {IP[%s] NM[%s] GW[%s]} dns{type[%u] ip[%s]}",
+ ip_s, nm_s, gw_s, dns.ip.type, dns_ip_s);
+
+ s2h_dhcp_dns.net_link_up = 1;
+ s2h_dhcp_dns.dhcp_up = 1;
+ s2h_dhcp_dns.dns_up = 1;
+ strlcpy((char*)s2h_dhcp_dns.dhcp_ip, ip_s, sizeof(s2h_dhcp_dns.dhcp_ip));
+ strlcpy((char*)s2h_dhcp_dns.dhcp_nm, nm_s, sizeof(s2h_dhcp_dns.dhcp_nm));
+ strlcpy((char*)s2h_dhcp_dns.dhcp_gw, gw_s, sizeof(s2h_dhcp_dns.dhcp_gw));
+ strlcpy((char*)s2h_dhcp_dns.dns_ip, dns_ip_s, sizeof(s2h_dhcp_dns.dns_ip));
+ s2h_dhcp_dns.dns_type = ESP_NETIF_DNS_MAIN;
+
+#ifdef CONFIG_SLAVE_MANAGES_WIFI
+ send_dhcp_dns_info_to_host(1, 0);
+#endif
+ station_got_ip = 1;
+#ifdef CONFIG_ESP_HOSTED_COPROCESSOR_EXAMPLE_MQTT
+ example_mqtt_resume();
+#endif
+ break;
+ } case IP_EVENT_STA_LOST_IP: {
+#ifdef CONFIG_ESP_HOSTED_COPROCESSOR_EXAMPLE_MQTT
+ example_mqtt_pause();
+#endif
+ ESP_LOGI(TAG, "Lost IP address");
+ station_got_ip = 0;
+ memset(&s2h_dhcp_dns, 0, sizeof(s2h_dhcp_dns));
+#ifdef CONFIG_SLAVE_MANAGES_WIFI
+ send_dhcp_dns_info_to_host(0, 0);
+#endif
+ break;
+ }
+
+ }
+ }
+}
+#endif
+
+
+
+
+#if defined(CONFIG_NETWORK_SPLIT_ENABLED) && defined(CONFIG_SLAVE_MANAGES_WIFI)
+static esp_err_t get_slave_static_ip(wifi_interface_t iface, esp_netif_ip_info_t *ip_info, uint8_t *netlink_up)
+{
+
+ if (!ip_info || !netlink_up) {
+ ESP_LOGE(TAG, "Invalid parameters");
+ return ESP_FAIL;
+ }
+
+ esp_netif_t * slave_sta_netif = NULL;
+ if (iface==WIFI_IF_STA) {
+ slave_sta_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
+ ESP_LOGI(TAG, "Sta netif: %p", slave_sta_netif);
+ } else if (iface==WIFI_IF_AP) {
+ slave_sta_netif = esp_netif_get_handle_from_ifkey("WIFI_AP_DEF");
+ } else {
+ ESP_LOGE(TAG, "unsupported wifi interface yet");
+ return ESP_FAIL;
+ }
+
+ if (!slave_sta_netif) {
+ ESP_LOGE(TAG, "station netif not available");
+ return ESP_FAIL;
+ }
+
+ ESP_ERROR_CHECK(esp_netif_get_ip_info(slave_sta_netif, ip_info));
+ *netlink_up = esp_netif_is_netif_up(slave_sta_netif);
+
+
+ return ESP_OK;
+}
+
+esp_err_t get_slave_dns(wifi_interface_t iface, esp_netif_dns_info_t *dns)
+{
+
+ if (!dns) {
+ ESP_LOGE(TAG, "Invalid parameters");
+ return ESP_FAIL;
+ }
+
+ esp_netif_t * slave_sta_netif = NULL;
+ if (iface==WIFI_IF_STA) {
+ slave_sta_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
+ } else if (iface==WIFI_IF_AP) {
+ slave_sta_netif = esp_netif_get_handle_from_ifkey("WIFI_AP_DEF");
+ } else {
+ ESP_LOGE(TAG, "unsupported wifi interface yet");
+ return ESP_FAIL;
+ }
+
+ if (!slave_sta_netif) {
+ ESP_LOGE(TAG, "station netif not available");
+ return ESP_FAIL;
+ }
+
+ ESP_ERROR_CHECK(esp_netif_get_dns_info(slave_sta_netif, ESP_NETIF_DNS_MAIN, dns));
+
+ return ESP_OK;
+}
+#endif
+
+#if defined(CONFIG_NETWORK_SPLIT_ENABLED) && !defined(CONFIG_SLAVE_MANAGES_WIFI)
+extern esp_netif_t *slave_sta_netif;
+
+static esp_err_t set_slave_static_ip(wifi_interface_t iface, char *ip, char *nm, char *gw)
+{
+
+ esp_netif_ip_info_t ip_info = {0};
+
+ ESP_RETURN_ON_FALSE(iface == WIFI_IF_STA, ESP_FAIL, TAG, "only sta iface supported yet");
+
+ ip_info.ip.addr = ipaddr_addr(ip);
+ ip_info.netmask.addr = ipaddr_addr(nm);
+ ip_info.gw.addr = ipaddr_addr(gw);
+
+ ESP_LOGI(TAG, "Set static IP addr ip:%s nm:%s gw:%s", ip, nm, gw);
+ ESP_ERROR_CHECK(esp_netif_set_ip_info(slave_sta_netif, &ip_info));
+ esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, (wifi_rxcb_t) wlan_sta_rx_callback);
+
+
+ return ESP_OK;
+}
+
+esp_err_t set_slave_dns(wifi_interface_t iface, char *ip, uint8_t type)
+{
+ esp_netif_dns_info_t dns = {0};
+
+ ESP_RETURN_ON_FALSE(iface == WIFI_IF_STA, ESP_FAIL, TAG, "only sta iface supported yet");
+
+ dns.ip.u_addr.ip4.addr = ipaddr_addr(ip);
+ dns.ip.type = type;
+
+ ESP_LOGI(TAG, "Set DNS ip:%s type:%u", ip, type);
+ ESP_ERROR_CHECK(esp_netif_set_dns_info(slave_sta_netif, ESP_NETIF_DNS_MAIN, &dns));
+
+ return ESP_OK;
+}
+#endif
+
/* event handler for station connect/disconnect to/from AP */
static void station_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
+ int ret = 0;
/* Event handlers are called from event loop callbacks.
* Please make sure that this callback function is as small as possible to avoid stack overflow */
if (event_id == WIFI_EVENT_STA_DISCONNECTED) {
- wifi_event_sta_disconnected_t * disconnected_event =
- (wifi_event_sta_disconnected_t *) event_data;
/* Mark as station disconnected */
station_connected = false;
+ #ifdef CONFIG_NETWORK_SPLIT_ENABLED
+ s2h_dhcp_dns.dhcp_up = s2h_dhcp_dns.dns_up = s2h_dhcp_dns.net_link_up = 0;
+ station_got_ip = 0;
+ #endif
- if ((WIFI_HOST_REQUEST_BIT & xEventGroupGetBits(wifi_event_group)) != WIFI_HOST_REQUEST_BIT) {
- /* Event should not be triggered if event handler is
- * called as part of host triggered procedure like sta_disconnect etc
- **/
+ wifi_event_sta_disconnected_t * disconnected_event =
+ (wifi_event_sta_disconnected_t *) event_data;
- send_event_data_to_host(CTRL_MSG_ID__Event_StationDisconnectFromAP,
- disconnected_event, sizeof(wifi_event_sta_disconnected_t));
- ESP_LOGI(TAG, "Station disconnected, reason[%u]",
- disconnected_event->reason);
- } else {
- ESP_LOGI(TAG, "Manual Wi-Fi disconnected, no event raised");
+ send_wifi_event_data_to_host(CTRL_MSG_ID__Event_StationDisconnectFromAP,
+ disconnected_event, sizeof(wifi_event_sta_disconnected_t));
+ ESP_LOGI(TAG, "Station disconnected, reason[%u]",
+ disconnected_event->reason);
+
+#ifdef CONFIG_NETWORK_SPLIT_ENABLED
+ send_dhcp_dns_info_to_host(0, 0);
+#endif
+
+ ESP_LOGI(TAG, "Sta mode disconnect, retry[%u]", sta_connect_retry);
+ sta_connect_retry++;
+
+ /* Refresh from saved config, if not done already */
+ if (!prev_wifi_config_valid || new_config_recvd) {
+ if (new_config_recvd) {
+ ret = esp_wifi_set_config(WIFI_IF_STA, &new_wifi_config);
+ if (ret) {
+ ESP_LOGE(TAG, "Error[0x%x] while setting the wifi config", ret);
+ if (!softap_started) {
+ esp_wifi_stop();
+ esp_wifi_set_mode(WIFI_MODE_STA);
+ esp_wifi_start();
+ }
+ } else {
+ ESP_LOGW(TAG, "Successfully set new wifi config");
+ new_config_recvd = 0;
+ }
+ } else {
+ ESP_LOGI(TAG, "use wifi params from flash");
+ }
}
- /* find out reason for failure and
- * set corresponding event bit */
- if (disconnected_event->reason == WIFI_REASON_NO_AP_FOUND)
- xEventGroupSetBits(wifi_event_group, WIFI_NO_AP_FOUND_BIT);
- else if ((disconnected_event->reason == WIFI_REASON_CONNECTION_FAIL) ||
- (disconnected_event->reason == WIFI_REASON_NOT_AUTHED))
- xEventGroupSetBits(wifi_event_group, WIFI_WRONG_PASSWORD_BIT);
- else
- xEventGroupSetBits(wifi_event_group, WIFI_FAIL_BIT);
+#if 1
+ esp_wifi_connect();
+#endif
} else if (event_id == WIFI_EVENT_STA_CONNECTED) {
- if ((WIFI_HOST_REQUEST_BIT & xEventGroupGetBits(wifi_event_group)) != WIFI_HOST_REQUEST_BIT) {
- /* Event should not be triggered if event handler is
- * called as part of host triggered procedure like sta_disconnect etc
- **/
- ESP_LOGI(TAG, "Wifi Connected");
- send_event_data_to_host(CTRL_MSG_ID__Event_StationConnectedToAP,
- event_data, sizeof(wifi_event_sta_connected_t));
+ wifi_event_sta_connected_t * connected_event =
+ (wifi_event_sta_connected_t *) event_data;
+
+ if (new_config_recvd) {
+ ESP_LOGI(TAG, "New wifi config still unapplied, applying it");
+ /* Still not applied new config, so apply it */
+ ret = esp_wifi_set_config(WIFI_IF_STA, &new_wifi_config);
+ if (ret) {
+ ESP_LOGE(TAG, "Error[0x%x] while setting the wifi config", ret);
+ } else {
+ new_config_recvd = 0;
+ }
+ esp_wifi_disconnect();
+ return;
+ }
+ sta_connect_retry = 0;
+ prev_wifi_config_valid = true;
+
+ /* Event should not be triggered if event handler is
+ * called as part of host triggered procedure like sta_disconnect etc
+ **/
+ send_wifi_event_data_to_host(CTRL_MSG_ID__Event_StationConnectedToAP,
+ connected_event, sizeof(wifi_event_sta_connected_t));
+
+ memcpy(&lkg_sta_connected_event, connected_event, sizeof(wifi_event_sta_connected_t));
+
+ esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, (wifi_rxcb_t) wlan_sta_rx_callback);
+ station_connected = true;
+ ESP_LOGI(TAG, "--- Station connected %s ---", connected_event->ssid);
+
+#if 1
+ } else if (event_id == WIFI_EVENT_STA_START) {
+ if (station_connected) {
+ ESP_LOGI(TAG, "Wifi already connected");
+ return;
} else {
- ESP_LOGI(TAG, "Manual Wi-Fi connected, no event raised");
+ esp_wifi_connect();
}
- xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_BIT);
+#endif
}
}
@@ -175,18 +494,17 @@ static void softap_event_handler(void *arg, esp_event_base_t event_base,
wifi_event_ap_staconnected_t *event = (wifi_event_ap_staconnected_t *) event_data;
ESP_LOGI(TAG, "station "MACSTR" join, AID=%d",
MAC2STR(event->mac), event->aid);
- send_event_data_to_host(CTRL_MSG_ID__Event_StationConnectedToESPSoftAP,
+ send_wifi_event_data_to_host(CTRL_MSG_ID__Event_StationConnectedToESPSoftAP,
event, sizeof(wifi_event_ap_staconnected_t));
} else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {
wifi_event_ap_stadisconnected_t *event =
(wifi_event_ap_stadisconnected_t *) event_data;
ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d",
MAC2STR(event->mac), event->aid);
- send_event_data_to_host(CTRL_MSG_ID__Event_StationDisconnectFromESPSoftAP,
+ send_wifi_event_data_to_host(CTRL_MSG_ID__Event_StationDisconnectFromESPSoftAP,
event, sizeof(wifi_event_ap_stadisconnected_t));
} else if (event_id == WIFI_EVENT_AP_START) {
esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_AP, (wifi_rxcb_t) wlan_ap_rx_callback);
- esp_update_ap_mac();
} else if (event_id == WIFI_EVENT_AP_STOP) {
ESP_LOGI(TAG,"softap stop handler stop");
esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_AP,NULL);
@@ -210,6 +528,22 @@ static void station_event_register(void)
WIFI_EVENT_STA_CONNECTED, &station_event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT,
WIFI_EVENT_STA_DISCONNECTED, &station_event_handler, NULL));
+ ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT,
+ WIFI_EVENT_STA_START, &station_event_handler, NULL));
+
+#ifdef CONFIG_NETWORK_SPLIT_ENABLED
+ ESP_LOGI(TAG, "Registering IP event handler");
+ ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
+ IP_EVENT_STA_GOT_IP,
+ &event_handler_ip,
+ NULL,
+ &instance_ip));
+ ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
+ IP_EVENT_STA_LOST_IP,
+ &event_handler_ip,
+ NULL,
+ &instance_ip));
+#endif
}
/* register softap start/stop, station connect/disconnect events */
@@ -385,20 +719,21 @@ static esp_err_t req_set_wifi_mode_handler (CtrlMsg *req,
CtrlMsg *resp, void *priv_data)
{
esp_err_t ret = ESP_OK;
- wifi_mode_t num = 0;
+ wifi_mode_t mode = 0, curr_mode = 0;
CtrlMsgRespSetMode *resp_payload = NULL;
- if (!req || !resp || !req->req_set_wifi_mode) {
+ if (!req || !resp) {
ESP_LOGE(TAG, "Invalid parameters");
return ESP_FAIL;
}
- if (req->req_set_wifi_mode->mode >= WIFI_MODE_MAX) {
- ESP_LOGE(TAG, "Invalid wifi mode");
+ if(!req->req_set_wifi_mode) {
+ ESP_LOGE(TAG, "Invalid wifi mode payload");
return ESP_FAIL;
}
- resp_payload = (CtrlMsgRespSetMode *)calloc(1,sizeof(CtrlMsgRespSetMode));
+ resp_payload = (CtrlMsgRespSetMode *)
+ calloc(1, sizeof(CtrlMsgRespSetMode));
if (!resp_payload) {
ESP_LOGE(TAG,"Failed to allocate memory");
return ESP_ERR_NO_MEM;
@@ -407,16 +742,49 @@ static esp_err_t req_set_wifi_mode_handler (CtrlMsg *req,
resp->payload_case = CTRL_MSG__PAYLOAD_RESP_SET_WIFI_MODE;
resp->resp_set_wifi_mode = resp_payload;
- num = req->req_set_wifi_mode->mode;
- ret = esp_wifi_set_mode(num);
+ ret = esp_wifi_get_mode(&curr_mode);
if (ret) {
- ESP_LOGE(TAG,"Failed to set mode");
+ ESP_LOGE(TAG, "Failed to get current WiFi mode %d", ret);
goto err;
}
- ESP_LOGI(TAG,"Set wifi mode %d ", num);
+ if (req->req_set_wifi_mode->mode < WIFI_MODE_NULL ||
+ req->req_set_wifi_mode->mode >= WIFI_MODE_MAX) {
+ ESP_LOGE(TAG,"Invalid WiFi mode");
+ goto err;
+ }
+
+ mode = req->req_set_wifi_mode->mode;
+ if (curr_mode == mode) {
+ ESP_LOGI(TAG,"WiFi mode unchanged");
+ resp_payload->resp = SUCCESS;
+ return ESP_OK;
+ }
+
+ if (mode != WIFI_MODE_STA && station_connected) {
+ /* Station is connected to AP, and the user is trying to change
+ * mode to either AP or APSTA, we must disconnect the station from AP, to initiate new mode
+ */
+ ESP_LOGI(TAG,"Station connected, disconnecting it before reconfiguring WiFi");
+ esp_wifi_disconnect();
+ }
+
+ ret = esp_wifi_set_mode(mode);
+ if (ret) {
+ ESP_LOGE(TAG, "Failed to set WiFi mode %d", ret);
+ goto err;
+ }
+
+ if (curr_mode == WIFI_MODE_STA || curr_mode == WIFI_MODE_APSTA) {
+ ESP_LOGI(TAG, "WiFi mode changed from %d to %d, invalidating cached config", curr_mode, mode);
+ prev_wifi_config_valid = false;
+ memset(&new_wifi_config, 0, sizeof(wifi_config_t));
+ }
+
+ ESP_LOGI(TAG, "Set WiFi mode to %d", mode);
resp_payload->resp = SUCCESS;
return ESP_OK;
+
err:
resp_payload->resp = FAILURE;
return ESP_OK;
@@ -431,12 +799,12 @@ static esp_err_t req_connect_ap_handler (CtrlMsg *req,
esp_err_t ret = ESP_OK;
wifi_config_t *wifi_cfg = NULL;
CtrlMsgRespConnectAP *resp_payload = NULL;
- EventBits_t bits = {0};
- int retry = 0;
+ bool wifi_changed = false;
#if WIFI_DUALBAND_SUPPORT
- wifi_band_mode_t band_mode = 0; // 0 is currently an invalid value
- wifi_band_mode_t requested_band_mode = 0; // 0 is currently an invalid value
+ wifi_band_mode_t band_mode = 0;
+ wifi_band_mode_t requested_band_mode = 0;
#endif
+ wifi_mode_t mode = 0;
if (!req || !resp || !req->req_connect_ap) {
ESP_LOGE(TAG, "Invalid parameters");
@@ -454,46 +822,29 @@ static esp_err_t req_connect_ap_handler (CtrlMsg *req,
resp->resp_connect_ap = resp_payload;
resp_payload->resp = SUCCESS;
- if (!event_registered) {
- wifi_event_group = xEventGroupCreate();
- event_registered = true;
- station_event_register();
+ ret = esp_wifi_get_mode(&mode);
+ if (ret) {
+ ESP_LOGE(TAG,"Failed to get wifi mode[0x%x]", ret);
+ resp_payload->resp = ret;
+ goto err;
}
- xEventGroupSetBits(wifi_event_group, WIFI_HOST_REQUEST_BIT);
- if (station_connected) {
- /* As station is already connected, disconnect from the AP
- * before connecting to requested AP */
- ret = esp_wifi_disconnect();
+ if ( (mode != WIFI_MODE_STA) && (mode != WIFI_MODE_APSTA) ) {
+ ESP_LOGI(TAG, "Existing mode: %u", mode);
+ if (softap_started) {
+ ret = esp_wifi_set_mode(WIFI_MODE_APSTA);
+ ESP_LOGI(TAG,"softap+station mode set");
+ } else {
+ ret = esp_wifi_set_mode(WIFI_MODE_STA);
+ ESP_LOGI(TAG,"station mode set");
+ }
+
if (ret) {
- ESP_LOGE(TAG, "Failed to disconnect");
+ ESP_LOGE(TAG,"Failed to set mode[0x%x]", ret);
resp_payload->resp = ret;
goto err;
}
- xEventGroupWaitBits(wifi_event_group,
- (WIFI_FAIL_BIT),
- pdFALSE,
- pdFALSE,
- STA_MODE_TIMEOUT);
- ESP_LOGI(TAG, "Disconnected from previously connected AP");
- esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, NULL);
- xEventGroupClearBits(wifi_event_group,
- (WIFI_CONNECTED_BIT | WIFI_FAIL_BIT |
- WIFI_NO_AP_FOUND_BIT | WIFI_WRONG_PASSWORD_BIT));
- station_connected = false;
- }
-
- if (softap_started) {
- ret = esp_wifi_set_mode(WIFI_MODE_APSTA);
- ESP_LOGI(TAG,"softap+station mode set");
- } else {
- ret = esp_wifi_set_mode(WIFI_MODE_STA);
- ESP_LOGI(TAG,"station mode set");
- }
- if (ret) {
- ESP_LOGE(TAG,"Failed to set mode");
- resp_payload->resp = ret;
- goto err;
+ wifi_changed = true;
}
wifi_cfg = (wifi_config_t *)calloc(1,sizeof(wifi_config_t));
@@ -503,6 +854,13 @@ static esp_err_t req_connect_ap_handler (CtrlMsg *req,
goto err;
}
+ /* Make sure that we connect to strongest signal, when multiple SSID with
+ * the same name. This should take a small extra time to search for all SSIDs,
+ * but with this, there will be high performance gain on data throughput
+ */
+ wifi_cfg->sta.scan_method = WIFI_ALL_CHANNEL_SCAN;
+ wifi_cfg->sta.sort_method = WIFI_CONNECT_AP_BY_SIGNAL;
+ /* Fill wifi_cfg with new request parameters */
if (req->req_connect_ap->ssid) {
strlcpy((char *)wifi_cfg->sta.ssid, req->req_connect_ap->ssid,
sizeof(wifi_cfg->sta.ssid));
@@ -512,7 +870,7 @@ static esp_err_t req_connect_ap_handler (CtrlMsg *req,
sizeof(wifi_cfg->sta.password));
}
if ((req->req_connect_ap->bssid) &&
- (strlen((char *)req->req_connect_ap->bssid))) {
+ (strlen((char *)req->req_connect_ap->bssid))) {
ret = convert_mac_to_bytes(wifi_cfg->sta.bssid, req->req_connect_ap->bssid);
if (ret) {
ESP_LOGE(TAG, "Failed to convert BSSID into bytes");
@@ -528,15 +886,8 @@ static esp_err_t req_connect_ap_handler (CtrlMsg *req,
if (req->req_connect_ap->listen_interval >= 0) {
wifi_cfg->sta.listen_interval = req->req_connect_ap->listen_interval;
}
-#if WIFI_DUALBAND_SUPPORT
- // get current band_mode
- ret = esp_wifi_get_band_mode(&band_mode);
- if (ret != ESP_OK) {
- ESP_LOGW(TAG, "failed to get band mode, defaulting to AUTO");
- band_mode = WIFI_BAND_MODE_AUTO;
- }
- // get requested band mode
+#if WIFI_DUALBAND_SUPPORT
if (req->req_connect_ap->band_mode) {
requested_band_mode = req->req_connect_ap->band_mode;
} else {
@@ -544,32 +895,32 @@ static esp_err_t req_connect_ap_handler (CtrlMsg *req,
requested_band_mode = WIFI_BAND_MODE_AUTO;
}
- // compare and update current band mode, if needed
+ ret = esp_wifi_get_band_mode(&band_mode);
+ if (ret != ESP_OK) {
+ ESP_LOGW(TAG, "failed to get band mode [0x%x], defaulting to AUTO", ret);
+ band_mode = WIFI_BAND_MODE_AUTO;
+ }
if (band_mode != requested_band_mode) {
ret = esp_wifi_set_band_mode(requested_band_mode);
if (ret) {
- ESP_LOGE(TAG, "failed to set band mode");
+ ESP_LOGE(TAG, "failed to set band mode 0x%x", ret);
+ resp_payload->resp = ret;
goto err;
}
band_mode = requested_band_mode;
+ ESP_LOGI(TAG, "Set band mode to new value 0x%x", band_mode);
+ resp_payload->band_mode = band_mode;
+ wifi_changed = true;
}
#endif
- /* Make sure that we connect to strongest signal, when multiple SSID with
- * the same name. This should take a small extra time to search for all SSIDs,
- * but with this, there will be hige performace gain on data throughput
- */
- wifi_cfg->sta.scan_method = WIFI_ALL_CHANNEL_SCAN;
- wifi_cfg->sta.sort_method = WIFI_CONNECT_AP_BY_SIGNAL;
-
- ret = esp_wifi_get_mac(ESP_IF_WIFI_STA , mac);
- ESP_LOGI(TAG,"Get station mac address");
+ ret = esp_wifi_get_mac(ESP_IF_WIFI_STA, mac);
if (ret) {
- ESP_LOGE(TAG,"Error in getting MAC of ESP Station %d", ret);
+ ESP_LOGE(TAG,"Error in getting MAC of ESP Station 0x%x", ret);
resp_payload->resp = ret;
goto err;
}
- snprintf(mac_str,BSSID_LENGTH,MACSTR,MAC2STR(mac));
+ snprintf(mac_str, BSSID_LENGTH, MACSTR, MAC2STR(mac));
ESP_LOGI(TAG,"mac [%s] ", mac_str);
resp_payload->mac.len = strnlen(mac_str, BSSID_LENGTH);
@@ -585,86 +936,78 @@ static esp_err_t req_connect_ap_handler (CtrlMsg *req,
goto err;
}
- do {
- ret = esp_wifi_set_config(ESP_IF_WIFI_STA, wifi_cfg);
- if (ret == ESP_ERR_WIFI_PASSWORD) {
- ESP_LOGE(TAG,"Invalid password");
- resp_payload->resp = ret;
- goto err;
- } else if (ret) {
- resp_payload->resp = ret;
- ESP_LOGE(TAG, "Failed to set AP config");
- goto err;
- }
+ ret = esp_hosted_set_sta_config(WIFI_IF_STA, wifi_cfg);
+ if (ret) {
+ resp_payload->resp = ret;
+ ESP_LOGE(TAG, "esp_hosted_set_sta_config failed with ret[0x%x]", ret);
+ goto err;
+ }
- ret = esp_wifi_connect();
- if (ret) {
- ESP_LOGI(TAG, "Failed to connect to SSID:'%s', password:'%s'",
- req->req_connect_ap->ssid ? req->req_connect_ap->ssid : "(null)",
- req->req_connect_ap->pwd ? req->req_connect_ap->pwd : "(null)");
- }
+ if (!wifi_changed && station_connected && prev_wifi_config_valid) {
+#if WIFI_DUALBAND_SUPPORT
+ resp_payload->band_mode = band_mode;
+#endif
+ resp_payload->resp = SUCCESS;
+ mem_free(wifi_cfg);
- if (event_registered)
- bits = xEventGroupWaitBits(wifi_event_group,
- (WIFI_CONNECTED_BIT | WIFI_FAIL_BIT |
- WIFI_NO_AP_FOUND_BIT | WIFI_WRONG_PASSWORD_BIT),
- pdFALSE,
- pdFALSE,
- STA_MODE_TIMEOUT);
- if (bits & WIFI_CONNECTED_BIT) {
- ESP_LOGI(TAG, "connected to ap SSID:'%s', password:'%s'",
- req->req_connect_ap->ssid ? req->req_connect_ap->ssid :"(null)",
- req->req_connect_ap->pwd ? req->req_connect_ap->pwd :"(null)");
- station_connected = true;
- esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, (wifi_rxcb_t) wlan_sta_rx_callback);
- ret = SUCCESS;
- break;
+#ifdef CONFIG_NETWORK_SPLIT_ENABLED
+ send_dhcp_dns_info_to_host(1, 1);
+#else
+ ESP_LOGI(TAG, "No change in Wi-Fi config. Send connected event to host");
+ send_wifi_event_data_to_host(CTRL_MSG_ID__Event_StationConnectedToAP,
+ &lkg_sta_connected_event, sizeof(wifi_event_sta_connected_t));
+#endif
+ return ESP_OK;
+ }
+
+ if (wifi_changed || !prev_wifi_config_valid) {
+
+ if (station_connected) {
+ /* Disconnect if band or any wifi config changed
+ * This would auto trigger connect with new config */
+ ESP_LOGI(TAG, "---Triggering station mode stop ---");
+
+ if (!softap_started) {
+ /* Take leverage of softap not started, to make faster transitions */
+ esp_wifi_stop();
+ esp_wifi_set_mode(WIFI_MODE_STA);
+ esp_wifi_start();
+ } else {
+ ret = esp_wifi_disconnect();
+ }
} else {
- if (bits & WIFI_NO_AP_FOUND_BIT) {
- ESP_LOGI(TAG, "No AP available as SSID:'%s'",
- req->req_connect_ap->ssid ? req->req_connect_ap->ssid : "(null)");
- resp_payload->resp = CTRL__STATUS__No_AP_Found;
- } else if (bits & WIFI_WRONG_PASSWORD_BIT) {
- ESP_LOGI(TAG, "Password incorrect for SSID:'%s', password:'%s'",
- req->req_connect_ap->ssid ? req->req_connect_ap->ssid : "(null)",
- req->req_connect_ap->pwd ? req->req_connect_ap->pwd :"(null)");
- resp_payload->resp = CTRL__STATUS__Connection_Fail;
- } else if (bits & WIFI_FAIL_BIT) {
- ESP_LOGI(TAG, "Failed to connect to SSID:'%s', password:'%s'",
- req->req_connect_ap->ssid ? req->req_connect_ap->ssid : "(null)",
- req->req_connect_ap->pwd ? req->req_connect_ap->pwd : "(null)");
+ /* No Prior connection, trigger new */
+ ESP_LOGI(TAG, "---Triggering connect---");
+ if (!softap_started) {
+ /* Take leverage of softap not started, to make faster transitions */
+ esp_wifi_stop();
+ esp_wifi_set_mode(WIFI_MODE_STA);
+ esp_wifi_start();
+ ret = esp_wifi_connect();
} else {
- ESP_LOGE(TAG, "STA_MODE_TIMEOUT occured");
+ ret = esp_wifi_connect();
}
- esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, NULL);
- }
- if (event_registered)
- xEventGroupClearBits(wifi_event_group,
- (WIFI_CONNECTED_BIT | WIFI_FAIL_BIT |
- WIFI_NO_AP_FOUND_BIT | WIFI_WRONG_PASSWORD_BIT));
- retry++;
+ }
+ if (ret) {
+ resp_payload->resp = ret;
+ ESP_LOGE(TAG, "failed with ret[0x%x]", ret);
+ goto err;
+ }
+ }
- } while(retry < MAX_STA_CONNECT_ATTEMPTS);
err:
- if (station_connected) {
#if WIFI_DUALBAND_SUPPORT
- resp_payload->band_mode = band_mode;
+ resp_payload->band_mode = band_mode;
#endif
- ESP_LOGI(TAG, "%s:%u Set resp to Success",__func__,__LINE__);
- resp_payload->resp = SUCCESS;
- } else {
- ESP_LOGI(TAG, "%s:%u Set resp[%"PRId32"]",__func__,__LINE__, resp_payload->resp);
- mem_free(resp_payload->mac.data);
- resp_payload->mac.len = 0;
+ ESP_LOGI(TAG, "%s:%u Set resp to Success",__func__,__LINE__);
+ resp_payload->resp = SUCCESS;
+
+ if (wifi_cfg) {
+ mem_free(wifi_cfg);
}
- mem_free(wifi_cfg);
- if (event_registered)
- xEventGroupClearBits(wifi_event_group,
- (WIFI_CONNECTED_BIT | WIFI_FAIL_BIT | WIFI_HOST_REQUEST_BIT |
- WIFI_NO_AP_FOUND_BIT | WIFI_WRONG_PASSWORD_BIT));
return ESP_OK;
}
@@ -797,38 +1140,19 @@ static esp_err_t req_disconnect_ap_handler (CtrlMsg *req,
goto err;
}
- if (event_registered) {
- xEventGroupSetBits(wifi_event_group, WIFI_HOST_REQUEST_BIT);
- }
ret = esp_wifi_disconnect();
if (ret) {
ESP_LOGE(TAG,"Failed to disconnect");
goto err;
}
- if (event_registered)
- xEventGroupWaitBits(wifi_event_group,
- (WIFI_FAIL_BIT),
- pdFALSE,
- pdFALSE,
- STA_MODE_TIMEOUT);
-
ESP_LOGI(TAG,"Disconnected from AP");
resp_payload->resp = SUCCESS;
station_connected = false;
+ prev_wifi_config_valid = false; /* Mark config as invalid after disconnection */
- if (event_registered) {
- xEventGroupClearBits(wifi_event_group,
- (WIFI_CONNECTED_BIT | WIFI_FAIL_BIT | WIFI_HOST_REQUEST_BIT |
- WIFI_NO_AP_FOUND_BIT | WIFI_WRONG_PASSWORD_BIT));
- }
return ESP_OK;
err:
- if (event_registered) {
- xEventGroupClearBits(wifi_event_group,
- (WIFI_CONNECTED_BIT | WIFI_FAIL_BIT | WIFI_HOST_REQUEST_BIT |
- WIFI_NO_AP_FOUND_BIT | WIFI_WRONG_PASSWORD_BIT));
- }
resp_payload->resp = FAILURE;
return ESP_OK;
}
@@ -1075,14 +1399,14 @@ static esp_err_t req_start_softap_handler (CtrlMsg *req,
// set bandwidth, based on band mode
switch (band_mode) {
- case WIFI_BAND_MODE_2G_ONLY:
+ case WIFI_BAND_MODE_2G_ONLY:
bandwidths.ghz_2g = req->req_start_softap->bw;
break;
- case WIFI_BAND_MODE_5G_ONLY:
+ case WIFI_BAND_MODE_5G_ONLY:
bandwidths.ghz_5g = req->req_start_softap->bw;
break;
// auto and default have the same settings
- case WIFI_BAND_MODE_AUTO:
+ case WIFI_BAND_MODE_AUTO:
default:
bandwidths.ghz_2g = req->req_start_softap->bw;
bandwidths.ghz_5g = req->req_start_softap->bw;
@@ -1535,7 +1859,7 @@ static esp_err_t req_set_mac_address_handler (CtrlMsg *req,
ESP_LOGE(TAG, "Failed to set MAC address, error %d ", ret);
goto err;
}
-
+ ESP_LOGI(TAG, "interface: %d, mac: " MACSTR, interface, MAC2STR(mac));
resp_payload->resp = SUCCESS;
return ESP_OK;
@@ -1565,11 +1889,8 @@ static esp_err_t req_set_power_save_mode_handler (CtrlMsg *req,
resp->payload_case = CTRL_MSG__PAYLOAD_RESP_SET_POWER_SAVE_MODE;
resp->resp_set_power_save_mode = resp_payload;
- /*
- * WIFI_PS_NONE mode can not use in case of coex i.e. Wi-Fi+BT/BLE.
- * By default ESP has WIFI_PS_MIN_MODEM power save mode
- */
- if ((req->req_set_power_save_mode->mode == WIFI_PS_MIN_MODEM) ||
+ if ((req->req_set_power_save_mode->mode == WIFI_PS_NONE) ||
+ (req->req_set_power_save_mode->mode == WIFI_PS_MIN_MODEM) ||
(req->req_set_power_save_mode->mode == WIFI_PS_MAX_MODEM)) {
ret = esp_wifi_set_ps(req->req_set_power_save_mode->mode);
if (ret) {
@@ -1656,12 +1977,8 @@ static esp_err_t req_ota_begin_handler (CtrlMsg *req,
}
ESP_LOGI(TAG, "Prepare partition for OTA\n");
- ota_ongoing=1;
-#if CONFIG_ESP_OTA_WORKAROUND
- vTaskDelay(OTA_SLEEP_TIME_MS/portTICK_PERIOD_MS);
-#endif
+
ret = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &handle);
- ota_ongoing=0;
if (ret) {
ESP_LOGE(TAG, "OTA update failed in OTA begin");
goto err;
@@ -1703,19 +2020,10 @@ static esp_err_t req_ota_write_handler (CtrlMsg *req,
resp->payload_case = CTRL_MSG__PAYLOAD_RESP_OTA_WRITE;
resp->resp_ota_write = resp_payload;
- ota_ongoing=1;
-#if CONFIG_ESP_OTA_WORKAROUND
- /* Delay added is to give chance to transfer pending data at transport
- * Care to be taken, when OTA ongoing, no other processing should happen
- * So big sleep is added before any flash operations start
- * */
- vTaskDelay(OTA_SLEEP_TIME_MS/portTICK_PERIOD_MS);
-#endif
printf(".");
fflush(stdout);
ret = esp_ota_write( handle, (const void *)req->req_ota_write->ota_data.data,
req->req_ota_write->ota_data.len);
- ota_ongoing=0;
if (ret != ESP_OK) {
ESP_LOGE(TAG, "OTA write failed with return code 0x%x",ret);
resp_payload->resp = FAILURE;
@@ -1747,12 +2055,7 @@ static esp_err_t req_ota_end_handler (CtrlMsg *req,
resp->payload_case = CTRL_MSG__PAYLOAD_RESP_OTA_END;
resp->resp_ota_end = resp_payload;
- ota_ongoing=1;
-#if CONFIG_ESP_OTA_WORKAROUND
- vTaskDelay(OTA_SLEEP_TIME_MS/portTICK_PERIOD_MS);
-#endif
ret = esp_ota_end(handle);
- ota_ongoing=0;
if (ret != ESP_OK) {
if (ret == ESP_ERR_OTA_VALIDATE_FAILED) {
ESP_LOGE(TAG, "Image validation failed, image is corrupted");
@@ -1993,11 +2296,6 @@ static esp_err_t req_set_country_code_handler (CtrlMsg *req,
esp_err_t ret = ESP_OK;
- if (!req || !resp) {
- ESP_LOGE(TAG, "Invalid parameters");
- return ESP_FAIL;
- }
-
resp_payload = (CtrlMsgRespSetCountryCode *)
calloc(1,sizeof(CtrlMsgRespSetCountryCode));
if (!resp_payload) {
@@ -2071,7 +2369,9 @@ static esp_err_t req_get_country_code_handler (CtrlMsg *req,
ret = esp_wifi_get_country_code(country_code);
if (ret == ESP_OK) {
+ country_code[COUNTRY_CODE_LEN-1] = '\0';
resp_payload->country.data = (uint8_t *)country_code;
+ ESP_LOGI(TAG,"Returning %s", country_code);
resp_payload->country.len = COUNTRY_CODE_LEN;
resp_payload->resp = SUCCESS;
} else {
@@ -2079,6 +2379,184 @@ static esp_err_t req_get_country_code_handler (CtrlMsg *req,
resp_payload->resp = ret;
}
+ if (!req || !resp) {
+ ESP_LOGE(TAG, "Invalid parameters");
+ return ESP_FAIL;
+ }
+
+ return ESP_OK;
+}
+
+
+#define COPY_AS_RESP_IP(dest, src, max_len) \
+{ \
+ dest.data = (uint8_t*)strndup((char*)src, max_len); \
+ if (!dest.data) { \
+ ESP_LOGE(TAG, "%s:%u Failed to duplicate bytes\n",__func__,__LINE__); \
+ resp_payload->resp = FAILURE; \
+ return ESP_OK; \
+ } \
+ dest.len = min(max_len,strlen((char*)src)+1); \
+}
+
+#if H_HOST_PS_ALLOWED
+static int64_t host_last_fetched_auto_ip_time = 0;
+
+
+/* Update the has_host_fetched_auto_ip function */
+bool has_host_fetched_auto_ip(void)
+{
+ int64_t current_time = esp_timer_get_time() / 1000; /* Convert to ms */
+
+ /* If host just woke up and last fetch was before sleep, return false */
+ if (host_last_fetched_auto_ip_time < get_last_wakeup_time()) {
+ host_last_fetched_auto_ip_time = current_time;
+ return false;
+ }
+
+ host_last_fetched_auto_ip_time = current_time;
+ return true;
+}
+#endif
+
+static esp_err_t req_get_dhcp_dns_status(CtrlMsg *req, CtrlMsg *resp, void *priv_data)
+{
+
+ CtrlMsgRespGetDhcpDnsStatus *resp_payload = NULL;
+
+ if (!req || !resp) {
+ ESP_LOGE(TAG, "Invalid parameters");
+ return ESP_FAIL;
+ }
+
+ resp_payload = (CtrlMsgRespGetDhcpDnsStatus *)calloc(1,sizeof(CtrlMsgRespGetDhcpDnsStatus));
+ if (!resp_payload) {
+ ESP_LOGE(TAG, "Failed to allocate memory");
+ return ESP_ERR_NO_MEM;
+ }
+
+ ctrl_msg__resp__get_dhcp_dns_status__init(resp_payload);
+ resp->payload_case = CTRL_MSG__PAYLOAD_RESP_GET_DHCP_DNS_STATUS;
+ resp->resp_get_dhcp_dns_status = resp_payload;
+
+
+#if defined(CONFIG_NETWORK_SPLIT_ENABLED) && defined(CONFIG_SLAVE_MANAGES_WIFI)
+ int ret1, ret2;
+ esp_netif_ip_info_t ip_info = {0};
+ esp_netif_dns_info_t dns = {0};
+ uint8_t netlink_up = 0;
+
+ ret1 = get_slave_static_ip(resp_payload->iface, &ip_info, &netlink_up);
+ ret2 = get_slave_dns(resp_payload->iface, &dns);
+
+ if (ret1 || ret2) {
+ ESP_LOGE(TAG, "Failed to get DHCP/DNS status");
+ resp_payload->dhcp_up = 0;
+ resp_payload->dns_up = 0;
+ resp_payload->net_link_up = 0;
+ resp_payload->resp = ESP_FAIL;
+ return ESP_OK;
+ }
+ ESP_LOGI(TAG, "static_ip_ret: %d dns_ret: %d", ret1, ret2);
+
+ resp_payload->net_link_up = netlink_up;
+ resp_payload->dhcp_up = netlink_up;
+ resp_payload->dns_up = netlink_up;
+
+ resp_payload->dns_type = dns.ip.type;
+
+ char sta_ip[64] = {0};
+ char sta_nm[64] = {0};
+ char sta_gw[64] = {0};
+ char sta_dns_ip[64] = {0};
+
+
+ if (esp_ip4addr_ntoa(&ip_info.ip, sta_ip, sizeof(sta_ip)))
+ COPY_AS_RESP_IP(resp_payload->dhcp_ip, sta_ip, strlen((char *)sta_ip) + 1);
+ if (esp_ip4addr_ntoa(&ip_info.netmask, sta_nm, sizeof(sta_nm)))
+ COPY_AS_RESP_IP(resp_payload->dhcp_nm, sta_nm, strlen((char *)sta_nm) + 1);
+ if (esp_ip4addr_ntoa(&ip_info.gw, sta_gw, sizeof(sta_gw)))
+ COPY_AS_RESP_IP(resp_payload->dhcp_gw, sta_gw, strlen((char *)sta_gw) + 1);
+ if (esp_ip4addr_ntoa(&dns.ip.u_addr.ip4, sta_dns_ip, sizeof(sta_dns_ip)))
+ COPY_AS_RESP_IP(resp_payload->dns_ip, sta_dns_ip, strlen((char *)sta_dns_ip) + 1);
+
+ ESP_LOGI(TAG, "Fetched IP: %s, NM: %s, GW: %s, DNS IP: %s, Type: %"PRId32,
+ (char *)resp_payload->dhcp_ip.data,
+ (char *)resp_payload->dhcp_nm.data,
+ (char *)resp_payload->dhcp_gw.data,
+ (char *)resp_payload->dns_ip.data,
+ resp_payload->dns_type);
+
+ resp_payload->resp = SUCCESS;
+#else
+ resp_payload->resp = FAILURE;
+#endif
+ return ESP_OK;
+}
+
+static esp_err_t req_set_dhcp_dns_status(CtrlMsg *req, CtrlMsg *resp, void *priv_data)
+{
+ CtrlMsgRespSetDhcpDnsStatus *resp_set_dhcp_dns = NULL;
+
+ if (!req || !resp) {
+ ESP_LOGE(TAG, "Invalid parameters");
+ return ESP_FAIL;
+ }
+
+ resp_set_dhcp_dns = (CtrlMsgRespSetDhcpDnsStatus *)calloc(1,sizeof(CtrlMsgRespSetDhcpDnsStatus));
+ if (!resp_set_dhcp_dns) {
+ ESP_LOGE(TAG, "Failed to allocate memory");
+ return ESP_ERR_NO_MEM;
+ }
+
+ ctrl_msg__resp__set_dhcp_dns_status__init(resp_set_dhcp_dns);
+ resp->payload_case = CTRL_MSG__PAYLOAD_RESP_SET_DHCP_DNS_STATUS;
+ resp->resp_set_dhcp_dns_status = resp_set_dhcp_dns;
+
+#if defined(CONFIG_NETWORK_SPLIT_ENABLED) && !defined(CONFIG_SLAVE_MANAGES_WIFI)
+
+ CtrlMsgReqSetDhcpDnsStatus *req_payload = NULL;
+
+ req_payload = req->req_set_dhcp_dns_status;
+
+ uint8_t iface = req_payload->iface;
+ uint8_t net_link_up = req_payload->net_link_up;
+ uint8_t dhcp_up = req_payload->dhcp_up;
+ uint8_t dns_up = req_payload->dns_up;
+ uint8_t dns_type = req_payload->dns_type;
+
+ char dhcp_ip[64] = {0};
+ char dhcp_nm[64] = {0};
+ char dhcp_gw[64] = {0};
+ char dns_ip[64] = {0};
+
+ ESP_LOGI(TAG, "iface: %u link_up:%u dhcp_up:%u dns_up:%u dns_type:%u",
+ iface, net_link_up, dhcp_up, dns_up, dns_type);
+
+ if (req_payload->dhcp_ip.len)
+ ESP_LOGI(TAG, "dhcp ip: %s" , (char *)req_payload->dhcp_ip.data);
+ if (req_payload->dhcp_nm.len)
+ ESP_LOGI(TAG, "dhcp nm: %s" , (char *)req_payload->dhcp_nm.data);
+ if (req_payload->dhcp_gw.len)
+ ESP_LOGI(TAG, "dhcp gw: %s" , (char *)req_payload->dhcp_gw.data);
+ if (req_payload->dns_ip.len)
+ ESP_LOGI(TAG, "dns ip: %s" , (char *)req_payload->dns_ip.data);
+
+ RPC_REQ_COPY_BYTES(dhcp_ip, req_payload->dhcp_ip, sizeof(dhcp_ip));
+ RPC_REQ_COPY_BYTES(dhcp_nm, req_payload->dhcp_nm, sizeof(dhcp_nm));
+ RPC_REQ_COPY_BYTES(dhcp_gw, req_payload->dhcp_gw, sizeof(dhcp_gw));
+ RPC_REQ_COPY_BYTES(dns_ip, req_payload->dns_ip, sizeof(dns_ip));
+
+ if (dhcp_up)
+ set_slave_static_ip(iface, dhcp_ip, dhcp_nm, dhcp_gw);
+
+ if (dns_up)
+ set_slave_dns(iface, dns_ip, dns_type);
+
+ resp_set_dhcp_dns->resp = SUCCESS;
+#else
+ resp_set_dhcp_dns->resp = FAILURE;
+#endif
return ESP_OK;
}
@@ -2120,6 +2598,21 @@ static esp_err_t start_heartbeat(int duration)
return ESP_OK;
}
+esp_err_t esp_hosted_wifi_init(wifi_init_config_t *cfg)
+{
+ if (station_connected) {
+ ESP_LOGW(TAG, "Wifi already init");
+ return ESP_OK;
+ }
+
+ ESP_ERROR_CHECK(esp_wifi_init(cfg));
+
+ ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_FLASH));
+
+ station_event_register();
+
+ return ESP_OK;
+}
static esp_err_t enable_disable_feature(HostedFeature feature, bool enable)
{
@@ -2132,10 +2625,11 @@ static esp_err_t enable_disable_feature(HostedFeature feature, bool enable)
switch(feature) {
case HOSTED_FEATURE__Hosted_Wifi:
+ val = esp_wifi_get_mode(&mode);
if (enable) {
- val = esp_wifi_get_mode(&mode);
if (val == ESP_ERR_WIFI_NOT_INIT) {
esp_wifi_init(&cfg);
+ esp_wifi_set_storage(WIFI_STORAGE_FLASH);
esp_wifi_set_mode(WIFI_MODE_NULL);
esp_wifi_start();
ESP_LOGI(TAG, "Wifi configured, user need to trigger sta/softap APIs to further proceed");
@@ -2143,14 +2637,19 @@ static esp_err_t enable_disable_feature(HostedFeature feature, bool enable)
ESP_LOGI(TAG, "Wifi already configured earlier, ignore");
}
} else {
- esp_wifi_stop();
- esp_wifi_deinit();
- ESP_LOGI(TAG, "Destroy Wifi instance");
+ if (val != ESP_ERR_WIFI_NOT_INIT) {
+ esp_wifi_stop();
+ esp_wifi_deinit();
+ ESP_LOGI(TAG, "Destroy Wifi instance");
+ } else {
+ ESP_LOGI(TAG, "Wifi already destroyed, ignore");
+ }
}
break;
case HOSTED_FEATURE__Hosted_Bluetooth:
-#ifdef CONFIG_BT_ENABLED
+// enable only if BT component enabled and soc supports BT
+#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_SOC_BT_SUPPORTED)
if (enable) {
initialise_bluetooth();
} else {
@@ -2163,6 +2662,16 @@ static esp_err_t enable_disable_feature(HostedFeature feature, bool enable)
#endif
break;
+ case HOSTED_FEATURE__Hosted_Is_Network_Split_On:
+ #if CONFIG_NETWORK_SPLIT_ENABLED
+ ESP_LOGI(TAG, "Network split enabled: true");
+ return ESP_OK;
+ #else
+ ESP_LOGI(TAG, "Network split enabled: false");
+ return ESP_FAIL;
+ #endif
+ break;
+
default:
ESP_LOGI(TAG, "Unsupported feature[%u]", feature);
ret = ESP_FAIL;
@@ -2257,7 +2766,72 @@ static esp_err_t req_enable_disable(CtrlMsg *req,
ESP_LOGI(TAG, "Request successful");
} else {
resp_payload->resp = FAILURE;
- ESP_LOGI(TAG, "Request Failed");
+ if (req->req_enable_disable_feat->feature != HOSTED_FEATURE__Hosted_Is_Network_Split_On) {
+ ESP_LOGI(TAG, "Request Failed");
+ }
+ }
+
+ return ESP_OK;
+}
+
+static esp_err_t req_custom_unserialised_rpc_msg_handler(CtrlMsg *req, CtrlMsg *resp, void *priv_data)
+{
+ if (!req || !resp) {
+ ESP_LOGE(TAG, "Invalid parameters");
+ return ESP_FAIL;
+ }
+
+ /* Prepare response */
+ resp->resp_custom_rpc_unserialised_msg = (CtrlMsgRespCustomRpcUnserialisedMsg *)calloc(1, sizeof(CtrlMsgRespCustomRpcUnserialisedMsg));
+ if (!resp->resp_custom_rpc_unserialised_msg) {
+ ESP_LOGE(TAG, "Failed to allocate memory for response");
+ return ESP_FAIL;
+ }
+ ctrl_msg__resp__custom_rpc_unserialised_msg__init(resp->resp_custom_rpc_unserialised_msg);
+
+ /* Default values */
+ resp->resp_custom_rpc_unserialised_msg->resp = FAILURE;
+ resp->payload_case = CTRL_MSG__PAYLOAD_RESP_CUSTOM_RPC_UNSERIALISED_MSG;
+ resp->msg_id = CTRL_MSG_ID__Resp_Custom_RPC_Unserialised_Msg;
+
+ /* Check if handler is registered */
+ if (custom_rpc_unserialised_req_handler) {
+ custom_rpc_unserialised_data_t req_data = {0};
+ custom_rpc_unserialised_data_t resp_data = {0};
+
+ /* Set up request data if available */
+ if (req->req_custom_rpc_unserialised_msg && req->req_custom_rpc_unserialised_msg->data.data && req->req_custom_rpc_unserialised_msg->data.len > 0) {
+ req_data.data = req->req_custom_rpc_unserialised_msg->data.data;
+ req_data.data_len = req->req_custom_rpc_unserialised_msg->data.len;
+ }
+ req_data.custom_msg_id = req->req_custom_rpc_unserialised_msg->custom_msg_id;
+
+ /* Call the callback function */
+ esp_err_t ret = custom_rpc_unserialised_req_handler(&req_data, &resp_data);
+
+ if (ret == ESP_OK) {
+ resp->resp_custom_rpc_unserialised_msg->resp = SUCCESS;
+ resp->resp_custom_rpc_unserialised_msg->data.len = resp_data.data_len;
+ resp->resp_custom_rpc_unserialised_msg->custom_msg_id = resp_data.custom_msg_id;
+ if (resp_data.data && resp_data.data_len > 0) {
+ /* Allocate and copy response data */
+ resp->resp_custom_rpc_unserialised_msg->data.data = malloc(resp_data.data_len);
+ if (resp->resp_custom_rpc_unserialised_msg->data.data) {
+ memcpy(resp->resp_custom_rpc_unserialised_msg->data.data, resp_data.data, resp_data.data_len);
+ resp->resp_custom_rpc_unserialised_msg->data.len = resp_data.data_len;
+ } else {
+ ESP_LOGE(TAG, "Failed to allocate memory in %s", __func__);
+ }
+ }
+ }
+
+ /* Free memory if a free function was provided */
+ if (resp_data.free_func && resp_data.data && resp_data.data_len > 0) {
+ resp_data.free_func(resp_data.data);
+ }
+ } else {
+ ESP_LOGE(TAG, "No handler registered for USR1");
+ resp->resp_custom_rpc_unserialised_msg->resp = FAILURE;
}
return ESP_OK;
@@ -2364,6 +2938,18 @@ static esp_ctrl_msg_req_t req_table[] = {
.req_num = CTRL_MSG_ID__Req_GetCountryCode,
.command_handler = req_get_country_code_handler
},
+ {
+ .req_num = CTRL_MSG_ID__Req_SetDhcpDnsStatus,
+ .command_handler = req_set_dhcp_dns_status
+ },
+ {
+ .req_num = CTRL_MSG_ID__Req_GetDhcpDnsStatus,
+ .command_handler = req_get_dhcp_dns_status
+ },
+ {
+ .req_num = CTRL_MSG_ID__Req_Custom_RPC_Unserialised_Msg,
+ .command_handler = req_custom_unserialised_rpc_msg_handler
+ },
};
@@ -2540,6 +3126,20 @@ static void esp_ctrl_msg_cleanup(CtrlMsg *resp)
}
mem_free(resp->resp_get_country_code);
break;
+ } case (CTRL_MSG_ID__Resp_SetDhcpDnsStatus) : {
+ mem_free(resp->resp_set_dhcp_dns_status);
+ break;
+ } case (CTRL_MSG_ID__Resp_GetDhcpDnsStatus): {
+ mem_free(resp->resp_get_dhcp_dns_status->dhcp_ip.data);
+ mem_free(resp->resp_get_dhcp_dns_status->dhcp_nm.data);
+ mem_free(resp->resp_get_dhcp_dns_status->dhcp_gw.data);
+ mem_free(resp->resp_get_dhcp_dns_status->dns_ip.data);
+ mem_free(resp->resp_get_dhcp_dns_status);
+ break;
+ } case (CTRL_MSG_ID__Resp_Custom_RPC_Unserialised_Msg): {
+ mem_free(resp->resp_custom_rpc_unserialised_msg->data.data);
+ mem_free(resp->resp_custom_rpc_unserialised_msg);
+ break;
} case (CTRL_MSG_ID__Event_ESPInit) : {
mem_free(resp->event_esp_init);
break;
@@ -2564,6 +3164,17 @@ static void esp_ctrl_msg_cleanup(CtrlMsg *resp)
mem_free(resp->event_station_connected_to_esp_softap->mac.data);
mem_free(resp->event_station_connected_to_esp_softap);
break;
+ } case (CTRL_MSG_ID__Event_SetDhcpDnsStatus) : {
+ mem_free(resp->event_set_dhcp_dns_status);
+ break;
+ } case (CTRL_MSG_ID__Event_Custom_RPC_Unserialised_Msg): {
+ if (resp->event_custom_rpc_unserialised_msg) {
+ if (resp->event_custom_rpc_unserialised_msg->data.data) {
+ mem_free(resp->event_custom_rpc_unserialised_msg->data.data);
+ }
+ mem_free(resp->event_custom_rpc_unserialised_msg);
+ }
+ break;
} default: {
ESP_LOGE(TAG, "Unsupported CtrlMsg type[%u]",resp->msg_id);
break;
@@ -2692,8 +3303,10 @@ static esp_err_t ctrl_ntfy_StationConnectedToAP(CtrlMsg *ntfy,
ntfy_payload->channel = evt->channel;
ntfy_payload->resp = FAILURE;
+ ESP_LOGD(TAG, "--- Station connected %s len[%d]---", evt->ssid, evt->ssid_len);
/* ssid */
ntfy_payload->ssid_len = evt->ssid_len;
+ ntfy_payload->ssid.len = evt->ssid_len;
ntfy_payload->ssid.data = (uint8_t *)strndup((const char*)evt->ssid, ntfy_payload->ssid.len);
if (!ntfy_payload->ssid.data) {
ESP_LOGE(TAG, "%s: mem allocate failed for[%" PRIu32 "] bytes",
@@ -2760,7 +3373,7 @@ static esp_err_t ctrl_ntfy_StationDisconnectFromAP(CtrlMsg *ntfy,
ntfy_payload->ssid.data = (uint8_t *)strndup((const char*)evt->ssid, ntfy_payload->ssid.len);
if (!ntfy_payload->ssid.data) {
ESP_LOGE(TAG, "%s: mem allocate failed for[%"PRIu32"] bytes",
- __func__, ntfy_payload->ssid_len);
+ __func__, (uint32_t)ntfy_payload->ssid.len);
ntfy_payload->ssid.len = 0;
ntfy_payload->resp = ESP_ERR_NO_MEM;
goto err;
@@ -2774,8 +3387,8 @@ static esp_err_t ctrl_ntfy_StationDisconnectFromAP(CtrlMsg *ntfy,
} else {
ntfy_payload->bssid.data = (uint8_t *)strndup(bssid_l, BSSID_LENGTH);
if (!ntfy_payload->bssid.data) {
- ESP_LOGE(TAG, "%s: allocate failed for [%d] bytes",
- __func__, ntfy_payload->bssid.len);
+ ESP_LOGE(TAG, "%s: allocate failed for [%"PRIu32"] bytes",
+ __func__, (uint32_t)ntfy_payload->bssid.len);
ntfy_payload->bssid.len = 0;
ntfy_payload->resp = ESP_ERR_NO_MEM;
goto err;
@@ -2882,6 +3495,112 @@ static esp_err_t ctrl_ntfy_StationDisconnectFromESPSoftAP(CtrlMsg *ntfy,
return ESP_OK;
}
+static esp_err_t ctrl_ntfy_SetDhcpDnsStatus(CtrlMsg *ntfy,
+ const uint8_t *data, ssize_t len)
+{
+ CtrlMsgEventSetDhcpDnsStatus *p_c = NULL;
+
+ p_c = (CtrlMsgEventSetDhcpDnsStatus*)
+ calloc(1,sizeof(CtrlMsgEventSetDhcpDnsStatus));
+ if (!p_c) {
+ ESP_LOGE(TAG,"Failed to allocate memory");
+ return ESP_ERR_NO_MEM;
+ }
+ ctrl_msg__event__set_dhcp_dns_status__init(p_c);
+
+ ntfy->payload_case = CTRL_MSG__PAYLOAD_EVENT_SET_DHCP_DNS_STATUS;
+ ntfy->event_set_dhcp_dns_status = p_c;
+
+#ifdef CONFIG_NETWORK_SPLIT_ENABLED
+ ctrl_msg_set_dhcp_dns_status_t * p_a = (ctrl_msg_set_dhcp_dns_status_t*)data;
+
+
+
+ p_c->iface = p_a->iface;
+ p_c->net_link_up = p_a->net_link_up;
+ p_c->dhcp_up = p_a->dhcp_up;
+ p_c->dns_up = p_a->dns_up;
+ p_c->dns_type = p_a->dns_type;
+
+ p_c->dhcp_ip.data = p_a->dhcp_ip;
+ p_c->dhcp_ip.len = sizeof(p_a->dhcp_ip);
+ p_c->dhcp_nm.data = p_a->dhcp_nm;
+ p_c->dhcp_nm.len = sizeof(p_a->dhcp_nm);
+ p_c->dhcp_gw.data = p_a->dhcp_gw;
+ p_c->dhcp_gw.len = sizeof(p_a->dhcp_gw);
+ p_c->dns_ip.data = p_a->dns_ip;
+ p_c->dns_ip.len = sizeof(p_a->dns_ip);
+
+ ESP_LOGI(TAG, "DHCP IP: %s, NM: %s, GW: %s, DNS IP: %s, Type: %"PRId32,
+ p_c->dhcp_ip.data,
+ p_c->dhcp_nm.data,
+ p_c->dhcp_gw.data,
+ p_c->dns_ip.data,
+ p_c->dns_type);
+ p_c->resp = SUCCESS;
+#else
+ p_c->resp = FAILURE;
+#endif
+ return ESP_OK;
+}
+
+static esp_err_t ctrl_ntfy_Custom_RPC_Unserialised_Msg(CtrlMsg *ntfy, const uint8_t *data, ssize_t struct_size)
+{
+ if (!data || struct_size <= 0) {
+ /* len is only struct size, not data length */
+ ESP_LOGE(TAG, "Invalid data or length");
+ return ESP_FAIL;
+ }
+ custom_rpc_unserialised_data_t *event_data = (custom_rpc_unserialised_data_t *)data;
+ uint16_t data_len = event_data->data_len;
+ uint32_t custom_event_id = event_data->custom_msg_id;
+ custom_data_free_func_t free_func = event_data->free_func;
+
+
+ ntfy->msg_id = CTRL_MSG_ID__Event_Custom_RPC_Unserialised_Msg;
+ ntfy->payload_case = CTRL_MSG__PAYLOAD_EVENT_CUSTOM_RPC_UNSERIALISED_MSG;
+ ntfy->event_custom_rpc_unserialised_msg = (CtrlMsgEventCustomRpcUnserialisedMsg *)calloc(1, sizeof(CtrlMsgEventCustomRpcUnserialisedMsg));
+ if (!ntfy->event_custom_rpc_unserialised_msg) {
+ ESP_LOGE(TAG, "Failed to allocate memory for Custom RPC Unserialised Msg");
+ if (free_func && event_data->data) {
+ free_func(event_data->data);
+ }
+ return ESP_FAIL;
+ }
+ ctrl_msg__event__custom_rpc_unserialised_msg__init(ntfy->event_custom_rpc_unserialised_msg);
+
+ ntfy->event_custom_rpc_unserialised_msg->custom_evt_id = custom_event_id;
+
+ if (data_len > 0) {
+ ntfy->event_custom_rpc_unserialised_msg->data.data = (uint8_t *)malloc(data_len);
+ if (!ntfy->event_custom_rpc_unserialised_msg->data.data) {
+ ESP_LOGE(TAG, "Failed to allocate memory for Custom RPC Unserialised Msg data");
+ free(ntfy->event_custom_rpc_unserialised_msg);
+ ntfy->event_custom_rpc_unserialised_msg = NULL;
+ ntfy->payload_case = CTRL_MSG__PAYLOAD__NOT_SET;
+ if (free_func && event_data->data) {
+ free_func(event_data->data);
+ }
+ return ESP_FAIL;
+ }
+ memcpy(ntfy->event_custom_rpc_unserialised_msg->data.data, event_data->data, data_len);
+ ntfy->event_custom_rpc_unserialised_msg->data.len = data_len;
+ } else {
+ ntfy->event_custom_rpc_unserialised_msg->data.data = NULL;
+ ntfy->event_custom_rpc_unserialised_msg->data.len = 0;
+ }
+
+ /* Set event data here */
+ ntfy->event_custom_rpc_unserialised_msg->resp = SUCCESS;
+
+ if (free_func && event_data->data) {
+ /* clear the data from user */
+ free_func(event_data->data);
+ }
+ return ESP_OK;
+}
+
+
esp_err_t ctrl_notify_handler(uint32_t session_id,const uint8_t *inbuf,
ssize_t inlen, uint8_t **outbuf, ssize_t *outlen, void *priv_data)
{
@@ -2916,6 +3635,12 @@ esp_err_t ctrl_notify_handler(uint32_t session_id,const uint8_t *inbuf,
} case (CTRL_MSG_ID__Event_StationConnectedToESPSoftAP) : {
ret = ctrl_ntfy_StationConnectedToESPSoftAP(&ntfy, inbuf, inlen);
break;
+ } case (CTRL_MSG_ID__Event_SetDhcpDnsStatus) : {
+ ret = ctrl_ntfy_SetDhcpDnsStatus(&ntfy, inbuf, inlen);
+ break;
+ } case (CTRL_MSG_ID__Event_Custom_RPC_Unserialised_Msg): {
+ ret = ctrl_ntfy_Custom_RPC_Unserialised_Msg(&ntfy, inbuf, inlen);
+ break;
} default: {
ESP_LOGE(TAG, "Incorrect/unsupported Ctrl Notification[%u]\n",ntfy.msg_id);
goto err;
@@ -2953,3 +3678,75 @@ esp_err_t ctrl_notify_handler(uint32_t session_id,const uint8_t *inbuf,
esp_ctrl_msg_cleanup(&ntfy);
return ESP_FAIL;
}
+
+/* Helper function to compare WiFi configurations */
+static bool is_wifi_config_equal(const wifi_config_t *cfg1, const wifi_config_t *cfg2)
+{
+ /* Compare SSID */
+ if (strcmp((char *)cfg1->sta.ssid, (char *)cfg2->sta.ssid) != 0) {
+ ESP_LOGD(TAG, "SSID different: '%s' vs '%s'", cfg1->sta.ssid, cfg2->sta.ssid);
+ return false;
+ }
+
+ /* Compare password */
+ if (strcmp((char *)cfg1->sta.password, (char *)cfg2->sta.password) != 0) {
+ ESP_LOGD(TAG, "Password different");
+ return false;
+ }
+
+ /* Compare BSSID if set */
+ if (cfg1->sta.bssid_set && cfg2->sta.bssid_set) {
+ if (memcmp(cfg1->sta.bssid, cfg2->sta.bssid, MAC_LEN) != 0) {
+ ESP_LOGD(TAG, "BSSID different");
+ return false;
+ }
+ } else if (cfg1->sta.bssid_set != cfg2->sta.bssid_set) {
+ ESP_LOGD(TAG, "BSSID set status different: %d vs %d",
+ cfg1->sta.bssid_set, cfg2->sta.bssid_set);
+ return false;
+ }
+
+ /* Compare channel if set */
+ if (cfg1->sta.channel != 0 && cfg2->sta.channel != 0) {
+ if (cfg1->sta.channel != cfg2->sta.channel) {
+ ESP_LOGD(TAG, "Channel different: %d vs %d",
+ cfg1->sta.channel, cfg2->sta.channel);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* Registration functions */
+esp_err_t register_custom_rpc_unserialised_req_handler(custom_rpc_unserialised_req_handler_t handler) {
+ if (handler) {
+ ESP_LOGI(TAG, "Registering handler %p for custom packed RPC request", handler);
+ custom_rpc_unserialised_req_handler = handler;
+ return ESP_OK;
+ }
+ return ESP_FAIL;
+}
+
+esp_err_t unregister_custom_rpc_unserialised_req_handler(void) {
+ if (custom_rpc_unserialised_req_handler) {
+ custom_rpc_unserialised_req_handler = NULL;
+ return ESP_OK;
+ }
+ return ESP_FAIL;
+}
+
+/* Event sending functions */
+esp_err_t send_custom_rpc_unserialised_event(custom_rpc_unserialised_data_t *event_data) {
+ if (!event_data) {
+ ESP_LOGE(TAG, "Invalid event data");
+ return ESP_FAIL;
+ }
+
+ ESP_LOGI(TAG, "Sending custom RPC unserialised Event[%" PRIu32 "], len: %" PRIu32,
+ event_data->custom_msg_id, (uint32_t) event_data->data_len);
+
+ /* Send event to host */
+ return send_event_data_to_host(CTRL_MSG_ID__Event_Custom_RPC_Unserialised_Msg, event_data, sizeof(custom_rpc_unserialised_data_t));
+}
+
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/slave_control.h b/esp_hosted_fg/esp/esp_driver/network_adapter/main/slave_control.h
index 1435aa26ea..4fdc59c47a 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/main/slave_control.h
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/slave_control.h
@@ -16,8 +16,9 @@
#ifndef __SLAVE_CONTROL__H__
#define __SLAVE_CONTROL__H__
#include
-#define min(X, Y) (((X) < (Y)) ? (X) : (Y))
-
+#include
+#include "host_power_save.h"
+#include "esp_wifi.h"
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
#define TIMEOUT_IN_SEC (1000 / portTICK_PERIOD_MS)
#else
@@ -27,11 +28,11 @@
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)
// 5G band support only available in ESP-IDF 5.4 or later
-#if CONFIG_SOC_WIFI_HE_SUPPORT_5G
+#if CONFIG_SOC_WIFI_SUPPORT_5G || CONFIG_SOC_WIFI_HE_SUPPORT_5G
#define WIFI_DUALBAND_SUPPORT 1
#else
#define WIFI_DUALBAND_SUPPORT 0
-#endif // CONFIG_SOC_WIFI_HE_SUPPORT_5G
+#endif
#else
#define WIFI_DUALBAND_SUPPORT 0
@@ -56,11 +57,74 @@ typedef struct {
uint16_t count;
} credentials_t;
+#define RPC_RET_FAIL_IF(ConDiTiOn) do { \
+ int rEt = (ConDiTiOn); \
+ if (rEt) { \
+ resp_payload->resp = rEt; \
+ ESP_LOGE(TAG, "%s:%u failed [%s] = [%d]", __func__,__LINE__,#ConDiTiOn, rEt); \
+ return ESP_OK; \
+ } \
+} while(0);
+
+#define RPC_REQ_COPY_BYTES(dest, src, num_bytes) \
+ if (src.len && src.data) \
+ memcpy((char*)dest, src.data, min(min(sizeof(dest), num_bytes), src.len));
+
+#define RPC_RESP_COPY_STR(dest, src, max_len) \
+ if (src) { \
+ dest.data = (uint8_t*)strndup((char*)src, max_len); \
+ if (!dest.data) { \
+ ESP_LOGE(TAG, "%s:%u Failed to duplicate bytes\n",__func__,__LINE__); \
+ resp_payload->resp = FAILURE; \
+ return ESP_OK; \
+ } \
+ dest.len = min(max_len,strlen((char*)src)+1); \
+ }
+
+
esp_err_t data_transfer_handler(uint32_t session_id,const uint8_t *inbuf,
ssize_t inlen,uint8_t **outbuf, ssize_t *outlen, void *priv_data);
esp_err_t ctrl_notify_handler(uint32_t session_id,const uint8_t *inbuf,
ssize_t inlen, uint8_t **outbuf, ssize_t *outlen, void *priv_data);
-void send_event_to_host(int event_id);
-void send_event_data_to_host(int event_id, void *data, int size);
+esp_err_t send_event_to_host(int event_id);
+esp_err_t send_event_data_to_host(int event_id, void *data, int size);
+
+#if 1
+
+esp_err_t esp_hosted_wifi_init(wifi_init_config_t *cfg);
+esp_err_t esp_hosted_set_sta_config(wifi_interface_t iface, wifi_config_t *cfg);
+#endif
+
+#if H_HOST_PS_ALLOWED
+bool has_host_fetched_auto_ip(void);
+#endif
+
+typedef void (*custom_data_free_func_t)(void *data);
+
+typedef struct {
+ /* Custom message ID can be populated by user to differentiate
+ between different types of request/response/event messages */
+ uint32_t custom_msg_id;
+ //uint32_t custom_data_type;
+ size_t data_len;
+ custom_data_free_func_t free_func;
+
+ /* Please note, this byte to byte would be trasferred, without any serialization/deserialization
+ *
+ * To perform serialised operation:
+ * Alternative 1. To have serialised data, ensure you handle endienness manually at user space level
+ * Alternative 2. Add up new message in the esp_hosted_config.proto file with all IEs
+ */
+ uint8_t *data;
+} custom_rpc_unserialised_data_t;
+
+typedef esp_err_t (*custom_rpc_unserialised_req_handler_t)(const custom_rpc_unserialised_data_t *req_data, custom_rpc_unserialised_data_t *resp_data);
+typedef void (*custom_rpc_unserialised_event_callback_t)(custom_rpc_unserialised_data_t *event_data);
+
+/* Function to register custom handlers */
+esp_err_t register_custom_rpc_unserialised_req_handler(custom_rpc_unserialised_req_handler_t handler);
+
+/* Function to send custom events */
+esp_err_t send_custom_rpc_unserialised_event(custom_rpc_unserialised_data_t *event_data);
#endif /*__SLAVE_CONTROL__H__*/
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/spi_slave_api.c b/esp_hosted_fg/esp/esp_driver/network_adapter/main/spi_slave_api.c
index a9bfbfd153..12b04f27e6 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/main/spi_slave_api.c
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/spi_slave_api.c
@@ -18,26 +18,38 @@
#include
#include
#include
+#include
#include "soc/gpio_reg.h"
#include "esp_log.h"
#include "interface.h"
#include "adapter.h"
#include "driver/spi_slave.h"
#include "driver/gpio.h"
-#include "endian.h"
#include "freertos/task.h"
#include "mempool.h"
#include "stats.h"
#include "esp_timer.h"
#include "esp_fw_version.h"
+// de-assert HS signal on CS, instead of at end of transaction
+#if defined(CONFIG_ESP_SPI_DEASSERT_HS_ON_CS)
+#define HS_DEASSERT_ON_CS (1)
+#else
+#define HS_DEASSERT_ON_CS (0)
+#endif
+
static const char TAG[] = "SPI_DRIVER";
/* SPI settings */
#define SPI_BITS_PER_WORD 8
-#define SPI_MODE_0 0
-#define SPI_MODE_1 1
-#define SPI_MODE_2 2
-#define SPI_MODE_3 3
+#define ESP_SPI_MODE CONFIG_ESP_SPI_MODE
+#define GPIO_MOSI CONFIG_ESP_SPI_GPIO_MOSI
+#define GPIO_MISO CONFIG_ESP_SPI_GPIO_MISO
+#define GPIO_SCLK CONFIG_ESP_SPI_GPIO_CLK
+#define GPIO_CS CONFIG_ESP_SPI_GPIO_CS
+#define GPIO_DATA_READY CONFIG_ESP_SPI_GPIO_DATA_READY
+#define GPIO_HANDSHAKE CONFIG_ESP_SPI_GPIO_HANDSHAKE
+
+#define ESP_SPI_CONTROLLER CONFIG_ESP_SPI_CONTROLLER
/* SPI-DMA settings */
#define SPI_DMA_ALIGNMENT_BYTES 4
@@ -46,121 +58,58 @@ static const char TAG[] = "SPI_DRIVER";
#define MAKE_SPI_DMA_ALIGNED(VAL) (VAL += SPI_DMA_ALIGNMENT_BYTES - \
((VAL)& SPI_DMA_ALIGNMENT_MASK))
-/* Chipset specific configurations */
-#ifdef CONFIG_IDF_TARGET_ESP32
-
- #if (CONFIG_ESP_SPI_CONTROLLER == 3)
- #define ESP_SPI_CONTROLLER 2
- #define GPIO_MOSI 23
- #define GPIO_MISO 19
- #define GPIO_SCLK 18
- #define GPIO_CS 5
- #elif (CONFIG_ESP_SPI_CONTROLLER == 2)
- #define ESP_SPI_CONTROLLER 1
- #define GPIO_MISO 12
- #define GPIO_MOSI 13
- #define GPIO_SCLK 14
- #define GPIO_CS 15
- #else
- #error "Please choose correct SPI controller"
- #endif
-
+#if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2)
#define DMA_CHAN ESP_SPI_CONTROLLER
-
-#elif defined CONFIG_IDF_TARGET_ESP32S2
-
- #define ESP_SPI_CONTROLLER 1
- #define GPIO_MOSI 11
- #define GPIO_MISO 13
- #define GPIO_SCLK 12
- #define GPIO_CS 10
- #define DMA_CHAN ESP_SPI_CONTROLLER
-
-#elif defined CONFIG_IDF_TARGET_ESP32C2
-
- #define ESP_SPI_CONTROLLER 1
- #define GPIO_MOSI 7
- #define GPIO_MISO 2
- #define GPIO_SCLK 6
- #define GPIO_CS 10
- #define DMA_CHAN SPI_DMA_CH_AUTO
-
-#elif defined CONFIG_IDF_TARGET_ESP32C3
-
- #define ESP_SPI_CONTROLLER 1
- #define GPIO_MOSI 7
- #define GPIO_MISO 2
- #define GPIO_SCLK 6
- #define GPIO_CS 10
- #define DMA_CHAN SPI_DMA_CH_AUTO
-
-#elif defined CONFIG_IDF_TARGET_ESP32S3
-
- #define ESP_SPI_CONTROLLER 1
- #define GPIO_MOSI 11
- #define GPIO_MISO 13
- #define GPIO_SCLK 12
- #define GPIO_CS 10
- #define DMA_CHAN SPI_DMA_CH_AUTO
-
-#elif defined CONFIG_IDF_TARGET_ESP32C5
-
- #define ESP_SPI_CONTROLLER 1
- #define GPIO_MOSI 7
- #define GPIO_MISO 2
- #define GPIO_SCLK 6
- #define GPIO_CS 10
+#else
#define DMA_CHAN SPI_DMA_CH_AUTO
+#endif
-#elif defined CONFIG_IDF_TARGET_ESP32C6
+#if ESP_SPI_MODE==0
+# error "SPI mode 0 at SLAVE is NOT supported"
+#endif
+/* SPI internal configs */
+#define SPI_BUFFER_SIZE MAX_TRANSPORT_BUF_SIZE
- #define ESP_SPI_CONTROLLER 1
- #define GPIO_MOSI 7
- #define GPIO_MISO 2
- #define GPIO_SCLK 6
- #define GPIO_CS 10
- #define DMA_CHAN SPI_DMA_CH_AUTO
+#define GPIO_MASK_DATA_READY (1ULL << GPIO_DATA_READY)
+#define GPIO_MASK_HANDSHAKE (1ULL << GPIO_HANDSHAKE)
+#if HS_DEASSERT_ON_CS
+#define H_CS_INTR_TO_CLEAR_HS GPIO_INTR_ANYEDGE
+#else
+#define H_CS_INTR_TO_CLEAR_HS GPIO_INTR_NEGEDGE
#endif
+
/* Max SPI slave CLK in IO_MUX tested in IDF:
* ESP32: 10MHz
* ESP32-C2/C3/S2/S3: 40MHz
* ESP32-C6: 26MHz
*/
-#define GPIO_HS CONFIG_ESP_SPI_GPIO_HANDSHAKE
-#define GPIO_DR CONFIG_ESP_SPI_GPIO_DATA_READY
-
-
-#define GPIO_MASK_DATA_READY (1 << GPIO_DR)
-#define GPIO_MASK_HANDSHAKE (1 << GPIO_HS)
+#define H_HS_PULL_REGISTER GPIO_PULLDOWN_ONLY
+#define H_DR_PULL_REGISTER GPIO_PULLDOWN_ONLY
-
-/* SPI internal configs */
-#define SPI_BUFFER_SIZE 1600
#define SPI_DRIVER_QUEUE_SIZE 3
#ifdef CONFIG_ESP_ENABLE_TX_PRIORITY_QUEUES
- #define SPI_TX_WIFI_QUEUE_SIZE CONFIG_ESP_SPI_TX_WIFI_Q_SIZE
- #define SPI_TX_BT_QUEUE_SIZE CONFIG_ESP_SPI_TX_BT_Q_SIZE
- #define SPI_TX_SERIAL_QUEUE_SIZE CONFIG_ESP_SPI_TX_SERIAL_Q_SIZE
+ #define SPI_TX_WIFI_QUEUE_SIZE CONFIG_ESP_TX_WIFI_Q_SIZE
+ #define SPI_TX_BT_QUEUE_SIZE CONFIG_ESP_TX_BT_Q_SIZE
+ #define SPI_TX_SERIAL_QUEUE_SIZE CONFIG_ESP_TX_SERIAL_Q_SIZE
#define SPI_TX_TOTAL_QUEUE_SIZE (SPI_TX_WIFI_QUEUE_SIZE+SPI_TX_BT_QUEUE_SIZE+SPI_TX_SERIAL_QUEUE_SIZE)
#else
- #define SPI_TX_QUEUE_SIZE CONFIG_ESP_SPI_TX_Q_SIZE
+ #define SPI_TX_QUEUE_SIZE CONFIG_ESP_TX_Q_SIZE
#define SPI_TX_TOTAL_QUEUE_SIZE SPI_TX_QUEUE_SIZE
#endif
#ifdef CONFIG_ESP_ENABLE_RX_PRIORITY_QUEUES
- #define SPI_RX_WIFI_QUEUE_SIZE CONFIG_ESP_SPI_RX_WIFI_Q_SIZE
- #define SPI_RX_BT_QUEUE_SIZE CONFIG_ESP_SPI_RX_BT_Q_SIZE
- #define SPI_RX_SERIAL_QUEUE_SIZE CONFIG_ESP_SPI_RX_SERIAL_Q_SIZE
+ #define SPI_RX_WIFI_QUEUE_SIZE CONFIG_ESP_RX_WIFI_Q_SIZE
+ #define SPI_RX_BT_QUEUE_SIZE CONFIG_ESP_RX_BT_Q_SIZE
+ #define SPI_RX_SERIAL_QUEUE_SIZE CONFIG_ESP_RX_SERIAL_Q_SIZE
#define SPI_RX_TOTAL_QUEUE_SIZE (SPI_RX_WIFI_QUEUE_SIZE+SPI_RX_BT_QUEUE_SIZE+SPI_RX_SERIAL_QUEUE_SIZE)
#else
- #define SPI_RX_QUEUE_SIZE CONFIG_ESP_SPI_RX_Q_SIZE
+ #define SPI_RX_QUEUE_SIZE CONFIG_ESP_RX_Q_SIZE
#define SPI_RX_TOTAL_QUEUE_SIZE SPI_RX_QUEUE_SIZE
#endif
-
static interface_context_t context;
static interface_handle_t if_handle_g;
@@ -178,6 +127,9 @@ static interface_handle_t if_handle_g;
static QueueHandle_t spi_rx_queue;
#endif
+#if HS_DEASSERT_ON_CS
+static SemaphoreHandle_t wait_cs_deassert_sem;
+#endif
static interface_handle_t * esp_spi_init(void);
static int32_t esp_spi_write(interface_handle_t *handle,
interface_buffer_handle_t *buf_handle);
@@ -195,81 +147,116 @@ if_ops_t if_ops = {
.deinit = esp_spi_deinit,
};
-#define SPI_MEMPOOL_NUM_BLOCKS ((SPI_TX_TOTAL_QUEUE_SIZE+SPI_DRIVER_QUEUE_SIZE*2+SPI_RX_TOTAL_QUEUE_SIZE))
static struct hosted_mempool * buf_mp_tx_g;
static struct hosted_mempool * buf_mp_rx_g;
static struct hosted_mempool * trans_mp_g;
+/* Full size dummy buffer for no-data transactions */
+static DRAM_ATTR uint8_t dummy_buffer[SPI_BUFFER_SIZE] __attribute__((aligned(4)));
+
static inline void spi_mempool_create()
{
+#ifdef CONFIG_ESP_CACHE_MALLOC
+ /* Create separate pools for TX and RX with optimized sizes */
buf_mp_tx_g = hosted_mempool_create(NULL, 0,
- SPI_MEMPOOL_NUM_BLOCKS, SPI_BUFFER_SIZE);
- /* re-use the mempool, as same size, can be seperate, if needed */
- buf_mp_rx_g = buf_mp_tx_g;
+ (SPI_TX_TOTAL_QUEUE_SIZE + SPI_DRIVER_QUEUE_SIZE + 1), SPI_BUFFER_SIZE);
+
+ buf_mp_rx_g = hosted_mempool_create(NULL, 0,
+ (SPI_RX_TOTAL_QUEUE_SIZE + SPI_DRIVER_QUEUE_SIZE + SPI_DRIVER_QUEUE_SIZE), SPI_BUFFER_SIZE);
+
trans_mp_g = hosted_mempool_create(NULL, 0,
- SPI_MEMPOOL_NUM_BLOCKS, sizeof(spi_slave_transaction_t));
-#if CONFIG_ESP_CACHE_MALLOC
+ SPI_DRIVER_QUEUE_SIZE, sizeof(spi_slave_transaction_t));
+
+
assert(buf_mp_tx_g);
assert(buf_mp_rx_g);
assert(trans_mp_g);
+#else
+ ESP_LOGI(TAG, "Using dynamic heap for mem alloc");
#endif
}
static inline void spi_mempool_destroy()
{
+#ifdef CONFIG_ESP_CACHE_MALLOC
hosted_mempool_destroy(buf_mp_tx_g);
+ if (buf_mp_tx_g!=buf_mp_rx_g) {
+ hosted_mempool_destroy(buf_mp_rx_g);
+ }
hosted_mempool_destroy(trans_mp_g);
+#endif
}
static inline void *spi_buffer_tx_alloc(uint need_memset)
{
+#ifdef CONFIG_ESP_CACHE_MALLOC
return hosted_mempool_alloc(buf_mp_tx_g, SPI_BUFFER_SIZE, need_memset);
+#else
+ void *buf = MEM_ALLOC(SPI_BUFFER_SIZE);
+ if (buf && need_memset) {
+ memset(buf, 0, SPI_BUFFER_SIZE);
+ }
+ return buf;
+#endif
}
static inline void *spi_buffer_rx_alloc(uint need_memset)
{
+#ifdef CONFIG_ESP_CACHE_MALLOC
return hosted_mempool_alloc(buf_mp_rx_g, SPI_BUFFER_SIZE, need_memset);
+#else
+ void *buf = MEM_ALLOC(SPI_BUFFER_SIZE);
+ if (buf && need_memset) {
+ memset(buf, 0, SPI_BUFFER_SIZE);
+ }
+ return buf;
+#endif
}
static inline spi_slave_transaction_t *spi_trans_alloc(uint need_memset)
{
+#ifdef CONFIG_ESP_CACHE_MALLOC
return hosted_mempool_alloc(trans_mp_g, sizeof(spi_slave_transaction_t), need_memset);
+#else
+ spi_slave_transaction_t *trans = MEM_ALLOC(sizeof(spi_slave_transaction_t));
+ if (trans && need_memset) {
+ memset(trans, 0, sizeof(spi_slave_transaction_t));
+ }
+ return trans;
+#endif
}
static inline void spi_buffer_tx_free(void *buf)
{
+#ifdef CONFIG_ESP_CACHE_MALLOC
hosted_mempool_free(buf_mp_tx_g, buf);
+#else
+ FREE(buf);
+#endif
}
static inline void spi_buffer_rx_free(void *buf)
{
+#ifdef CONFIG_ESP_CACHE_MALLOC
hosted_mempool_free(buf_mp_rx_g, buf);
+#else
+ FREE(buf);
+#endif
}
static inline void spi_trans_free(spi_slave_transaction_t *trans)
{
+#ifdef CONFIG_ESP_CACHE_MALLOC
hosted_mempool_free(trans_mp_g, trans);
+#else
+ FREE(trans);
+#endif
}
-static inline void set_handshake_gpio(void)
-{
- WRITE_PERI_REG(GPIO_OUT_W1TS_REG, GPIO_MASK_HANDSHAKE);
-}
-
-static inline void reset_handshake_gpio(void)
-{
- WRITE_PERI_REG(GPIO_OUT_W1TC_REG, GPIO_MASK_HANDSHAKE);
-}
-
-static inline void set_dataready_gpio(void)
-{
- WRITE_PERI_REG(GPIO_OUT_W1TS_REG, GPIO_MASK_DATA_READY);
-}
-
-static inline void reset_dataready_gpio(void)
-{
- WRITE_PERI_REG(GPIO_OUT_W1TC_REG, GPIO_MASK_DATA_READY);
-}
+#define set_handshake_gpio() gpio_set_level(GPIO_HANDSHAKE, 1);
+#define reset_handshake_gpio() gpio_set_level(GPIO_HANDSHAKE, 0);
+#define set_dataready_gpio() gpio_set_level(GPIO_DATA_READY, 1);
+#define reset_dataready_gpio() gpio_set_level(GPIO_DATA_READY, 0);
interface_context_t *interface_insert_driver(int (*event_handler)(uint8_t val))
{
@@ -323,6 +310,7 @@ void generate_startup_event(uint8_t cap)
/* TLVs start */
/* TLV - Board type */
+ ESP_LOGI(TAG, "Slave chip Id[%x]", ESP_PRIV_FIRMWARE_CHIP_ID);
*pos = ESP_PRIV_FIRMWARE_CHIP_ID; pos++;len++;
*pos = LENGTH_1_BYTE; pos++;len++;
*pos = CONFIG_IDF_FIRMWARE_CHIP_ID; pos++;len++;
@@ -395,98 +383,108 @@ static void IRAM_ATTR spi_post_setup_cb(spi_slave_transaction_t *trans)
* Use this to set the handshake line low */
static void IRAM_ATTR spi_post_trans_cb(spi_slave_transaction_t *trans)
{
+#if !HS_DEASSERT_ON_CS
/* Clear handshake line */
reset_handshake_gpio();
+#endif
}
static uint8_t * get_next_tx_buffer(uint32_t *len)
{
interface_buffer_handle_t buf_handle = {0};
esp_err_t ret = ESP_OK;
- uint8_t *sendbuf = NULL;
- struct esp_payload_header *header = NULL;
- /* Get or create new tx_buffer
- * 1. Check if SPI TX queue has pending buffers. Return if valid buffer is obtained.
- * 2. Create a new empty tx buffer and return */
- /* Get buffer from SPI Tx queue */
-#ifdef CONFIG_ESP_ENABLE_TX_PRIORITY_QUEUES
+ #ifdef CONFIG_ESP_ENABLE_TX_PRIORITY_QUEUES
ret = xSemaphoreTake(spi_tx_sem, 0);
- if (pdTRUE == ret)
+ if (pdTRUE == ret) {
+
if (pdFALSE == xQueueReceive(spi_tx_queue[PRIO_Q_SERIAL], &buf_handle, 0))
if (pdFALSE == xQueueReceive(spi_tx_queue[PRIO_Q_BT], &buf_handle, 0))
if (pdFALSE == xQueueReceive(spi_tx_queue[PRIO_Q_OTHERS], &buf_handle, 0))
ret = pdFALSE;
-#else
+ }
+ #else
ret = xQueueReceive(spi_tx_queue, &buf_handle, 0);
-#endif
+ #endif
if (ret == pdTRUE && buf_handle.payload) {
- if (len)
+ struct esp_payload_header *header = (struct esp_payload_header *)buf_handle.payload;
+ ESP_LOGD(TAG, "[TX] Real data queued - if_type: %d, len: %d",
+ header->if_type, le16toh(header->len));
+ if (len) {
+#if ESP_PKT_STATS
+ if (buf_handle.if_type == ESP_SERIAL_IF)
+ pkt_stats.serial_tx_total++;
+#endif
*len = buf_handle.payload_len;
- /* Return real data buffer from queue */
+ }
return buf_handle.payload;
}
- /* No real data pending, clear ready line and indicate host an idle state */
+ /* No real data, using dummy buffer */
+ ESP_LOGV(TAG, "[TX] No data - using dummy buffer");
reset_dataready_gpio();
-
- /* Create empty dummy buffer */
- sendbuf = spi_buffer_tx_alloc(MEMSET_REQUIRED);
- if (!sendbuf) {
- ESP_LOGE(TAG, "Failed to allocate memory for dummy transaction");
- if (len)
- *len = 0;
- return NULL;
- }
-
- /* Initialize header */
- header = (struct esp_payload_header *) sendbuf;
-
- /* Populate header to indicate it as a dummy buffer */
- header->if_type = ESP_MAX_IF;
- header->if_num = 0xF;
- header->len = 0;
-
- if (len)
- *len = 0;
-
- return sendbuf;
+ return dummy_buffer;
}
static int process_spi_rx(interface_buffer_handle_t *buf_handle)
{
- struct esp_payload_header *header = NULL;
- uint16_t len = 0, offset = 0;
-#if CONFIG_ESP_SPI_CHECKSUM
- uint16_t rx_checksum = 0, checksum = 0;
-#endif
-
- /* Validate received buffer. Drop invalid buffer. */
+ struct esp_payload_header *header;
if (!buf_handle || !buf_handle->payload) {
- ESP_LOGE(TAG, "%s: Invalid params", __func__);
+ ESP_LOGE(TAG, "Invalid RX buffer");
return -1;
}
header = (struct esp_payload_header *) buf_handle->payload;
- len = le16toh(header->len);
- offset = le16toh(header->offset);
- if (!len)
+ /* Log packet info */
+ ESP_LOGV(TAG, "[RX] if_type: %d, len: %d, offset: %d",
+ header->if_type, le16toh(header->len), le16toh(header->offset));
+
+ UPDATE_HEADER_RX_PKT_NO(header);
+
+ ESP_HEXLOGV("spi_rx:", header, 16, 16);
+
+ uint16_t len = le16toh(header->len);
+ uint16_t offset = le16toh(header->offset);
+ uint8_t flags = header->flags;
+
+ if (!len) {
+ ESP_LOGV(TAG, "Rx pkt len:0, drop");
return -1;
+ }
+
+ if (!offset) {
+ ESP_LOGD(TAG, "Rx pkt offset:0, drop");
+ return -1;
+ }
- if (len+offset > SPI_BUFFER_SIZE) {
+ if ((len+offset) > SPI_BUFFER_SIZE) {
ESP_LOGE(TAG, "rx_pkt len+offset[%u]>max[%u], dropping it", len+offset, SPI_BUFFER_SIZE);
return -1;
}
+ ESP_LOGV(TAG, "RX: len=%u offset=%u flags=0x%x payload_addr=%p",
+ len, offset, flags, buf_handle->payload);
+
+ if (flags & FLAG_POWER_SAVE_STARTED) {
+ ESP_LOGI(TAG, "Host informed starting to power sleep");
+ if (context.event_handler) {
+ context.event_handler(ESP_POWER_SAVE_ON);
+ }
+ } else if (flags & FLAG_POWER_SAVE_STOPPED) {
+ ESP_LOGI(TAG, "Host informed that it waken up");
+ if (context.event_handler) {
+ context.event_handler(ESP_POWER_SAVE_OFF);
+ }
+ }
+
#if CONFIG_ESP_SPI_CHECKSUM
- rx_checksum = le16toh(header->checksum);
+ uint16_t rx_checksum = le16toh(header->checksum);
header->checksum = 0;
-
- checksum = compute_checksum(buf_handle->payload, len+offset);
+ uint16_t checksum = compute_checksum(buf_handle->payload, (len + offset));
if (checksum != rx_checksum) {
ESP_LOGE(TAG, "%s: cal_chksum[%u] != exp_chksum[%u], drop len[%u] offset[%u]",
@@ -499,12 +497,12 @@ static int process_spi_rx(interface_buffer_handle_t *buf_handle)
buf_handle->if_type = header->if_type;
buf_handle->if_num = header->if_num;
buf_handle->free_buf_handle = esp_spi_read_done;
- buf_handle->payload_len = le16toh(header->len) + offset;
+ buf_handle->payload_len = len + offset;
buf_handle->priv_buffer_handle = buf_handle->payload;
#if ESP_PKT_STATS
if (buf_handle->if_type == ESP_STA_IF)
- pkt_stats.sta_rx_in++;
+ pkt_stats.hs_bus_sta_in++;
#endif
#ifdef CONFIG_ESP_ENABLE_RX_PRIORITY_QUEUES
if (header->if_type == ESP_SERIAL_IF) {
@@ -519,6 +517,7 @@ static int process_spi_rx(interface_buffer_handle_t *buf_handle)
#else
xQueueSend(spi_rx_queue, buf_handle, portMAX_DELAY);
#endif
+
return 0;
}
@@ -536,14 +535,12 @@ static void queue_next_transaction(void)
spi_trans = spi_trans_alloc(MEMSET_REQUIRED);
assert(spi_trans);
- /* Attach Rx Buffer */
- spi_trans->rx_buffer = spi_buffer_rx_alloc(MEMSET_REQUIRED);
- assert(spi_trans->rx_buffer);
+ /* Use RX mempool instead of direct heap allocation */
+ uint8_t *rx_buffer = spi_buffer_rx_alloc(MEMSET_REQUIRED);
+ assert(rx_buffer);
- /* Attach Tx Buffer */
+ spi_trans->rx_buffer = rx_buffer;
spi_trans->tx_buffer = tx_buffer;
-
- /* Transaction len */
spi_trans->length = SPI_BUFFER_SIZE * SPI_BITS_PER_WORD;
spi_slave_queue_trans(ESP_SPI_CONTROLLER, spi_trans, portMAX_DELAY);
@@ -557,42 +554,63 @@ static void spi_transaction_post_process_task(void* pvParameters)
for (;;) {
memset(&rx_buf_handle, 0, sizeof(rx_buf_handle));
-
- /* Await transmission result, after any kind of transmission a new packet
- * (dummy or real) must be placed in SPI slave
+ /* Wait for transaction completion */
+ ESP_ERROR_CHECK(spi_slave_get_trans_result(ESP_SPI_CONTROLLER, &spi_trans, portMAX_DELAY));
+
+#if HS_DEASSERT_ON_CS
+ /* Wait until CS has been deasserted before we queue a new transaction.
+ *
+ * Some MCUs delay deasserting CS at the end of a transaction.
+ * If we queue a new transaction without waiting for CS to deassert,
+ * the slave SPI can start (since CS is still asserted), and data is lost
+ * as host is not expecting any data.
*/
- spi_slave_get_trans_result(ESP_SPI_CONTROLLER, &spi_trans,
- portMAX_DELAY);
+ xSemaphoreTake(wait_cs_deassert_sem, portMAX_DELAY);
+#endif
/* Queue new transaction to get ready as soon as possible */
queue_next_transaction();
- assert(spi_trans);
-
- /* Free any tx buffer, data is not relevant anymore */
- spi_buffer_tx_free((void *)spi_trans->tx_buffer);
/* Process received data */
if (spi_trans->rx_buffer) {
rx_buf_handle.payload = spi_trans->rx_buffer;
-
ret = process_spi_rx(&rx_buf_handle);
+ }
- /* free rx_buffer if process_spi_rx returns an error
- * In success case it will be freed later */
- if (ret != ESP_OK) {
- spi_buffer_rx_free((void *)spi_trans->rx_buffer);
- }
- } else {
- ESP_LOGI(TAG, "no rx_buf");
+ ESP_HEXLOGV("spi_tx:", (uint8_t*)spi_trans->tx_buffer, 16, 16);
+ /* Free buffers */
+ if (spi_trans->tx_buffer != dummy_buffer) {
+ spi_buffer_tx_free((void *)spi_trans->tx_buffer);
+ }
+
+#if ESP_PKT_STATS
+ struct esp_payload_header *header =
+ (struct esp_payload_header *)spi_trans->tx_buffer;
+ if (header->if_type == ESP_STA_IF)
+ pkt_stats.sta_sh_out++;
+#endif
+ if (ret != ESP_OK && spi_trans->rx_buffer) {
+ spi_buffer_rx_free((void *)spi_trans->rx_buffer);
}
- /* Free Transfer structure */
spi_trans_free(spi_trans);
}
}
static void IRAM_ATTR gpio_disable_hs_isr_handler(void* arg)
{
+#if HS_DEASSERT_ON_CS
+ int level = gpio_get_level(GPIO_CS);
+ if (level == 0) {
+ /* CS is asserted, disable HS */
+ reset_handshake_gpio();
+ } else {
+ /* Last transaction complete, populate next one */
+ if (wait_cs_deassert_sem)
+ xSemaphoreGive(wait_cs_deassert_sem);
+ }
+#else
reset_handshake_gpio();
+#endif
}
static void register_hs_disable_pin(uint32_t gpio_num)
@@ -603,12 +621,11 @@ static void register_hs_disable_pin(uint32_t gpio_num)
gpio_config_t slave_disable_hs_pin_conf={
.intr_type=GPIO_INTR_DISABLE,
.mode=GPIO_MODE_INPUT,
- .pull_up_en=1,
- .pin_bit_mask=(1<if_type = ESP_MAX_IF;
+ header->if_num = 0xF;
+ header->len = 0;
+
+
/* Enable pull-ups on SPI lines
* so that no rogue pulses when no master is connected
*/
- gpio_set_pull_mode(CONFIG_ESP_SPI_GPIO_HANDSHAKE, GPIO_PULLDOWN_ONLY);
- gpio_set_pull_mode(CONFIG_ESP_SPI_GPIO_DATA_READY, GPIO_PULLDOWN_ONLY);
+ gpio_set_pull_mode(CONFIG_ESP_SPI_GPIO_HANDSHAKE, H_HS_PULL_REGISTER);
+ gpio_set_pull_mode(CONFIG_ESP_SPI_GPIO_DATA_READY, H_DR_PULL_REGISTER);
gpio_set_pull_mode(GPIO_MOSI, GPIO_PULLUP_ONLY);
gpio_set_pull_mode(GPIO_SCLK, GPIO_PULLUP_ONLY);
gpio_set_pull_mode(GPIO_CS, GPIO_PULLUP_ONLY);
- ESP_LOGI(TAG, "SPI Ctrl:%u mode: %u, GPIOs: MOSI: %u, MISO: %u, CS: %u, CLK: %u HS: %u DR: %u\n",
+ ESP_LOGI(TAG, "SPI Ctrl:%u mode: %u, Freq:ConfigAtHost\nGPIOs: MOSI: %u, MISO: %u, CS: %u, CLK: %u HS: %u DR: %u\n",
ESP_SPI_CONTROLLER, slvcfg.mode,
- GPIO_MOSI, GPIO_MISO, GPIO_CS, GPIO_SCLK, GPIO_HS, GPIO_DR);
+ GPIO_MOSI, GPIO_MISO, GPIO_CS, GPIO_SCLK,
+ GPIO_HANDSHAKE, GPIO_DATA_READY);
#ifdef CONFIG_ESP_ENABLE_TX_PRIORITY_QUEUES
- ESP_LOGI(TAG, "TX Queues :Wifi[%u] bt[%u] serial[%u]",
- SPI_TX_WIFI_QUEUE_SIZE, SPI_TX_BT_QUEUE_SIZE, SPI_TX_SERIAL_QUEUE_SIZE);
+ ESP_LOGI(TAG, "TX Queues :Wifi[%u]+bt[%u]+serial[%u] = %u",
+ SPI_TX_WIFI_QUEUE_SIZE, SPI_TX_BT_QUEUE_SIZE, SPI_TX_SERIAL_QUEUE_SIZE,
+ SPI_TX_TOTAL_QUEUE_SIZE);
#else
- ESP_LOGI(TAG, "TX Queues:%u", SPI_TX_QUEUE_SIZE);
+ ESP_LOGI(TAG, "TX Queues:%u", SPI_TX_TOTAL_QUEUE_SIZE);
#endif
#ifdef CONFIG_ESP_ENABLE_RX_PRIORITY_QUEUES
- ESP_LOGI(TAG, "RX Queues :Wifi[%u] bt[%u] serial[%u]",
- SPI_RX_WIFI_QUEUE_SIZE, SPI_RX_BT_QUEUE_SIZE, SPI_RX_SERIAL_QUEUE_SIZE);
+ ESP_LOGI(TAG, "RX Queues :Wifi[%u]+bt[%u]+serial[%u] = %u",
+ SPI_RX_WIFI_QUEUE_SIZE, SPI_RX_BT_QUEUE_SIZE, SPI_RX_SERIAL_QUEUE_SIZE,
+ SPI_RX_TOTAL_QUEUE_SIZE);
#else
- ESP_LOGI(TAG, "RX Queues:%u", SPI_RX_QUEUE_SIZE);
+ ESP_LOGI(TAG, "RX Queues:%u", SPI_RX_TOTAL_QUEUE_SIZE);
#endif
register_hs_disable_pin(GPIO_CS);
@@ -709,6 +739,13 @@ static interface_handle_t * esp_spi_init(void)
memset(&if_handle_g, 0, sizeof(if_handle_g));
if_handle_g.state = INIT;
+#if HS_DEASSERT_ON_CS
+ wait_cs_deassert_sem = xSemaphoreCreateBinary();
+ assert(wait_cs_deassert_sem!= NULL);
+ /* Clear the semaphore */
+ xSemaphoreTake(wait_cs_deassert_sem, 0);
+#endif
+
#ifdef CONFIG_ESP_ENABLE_TX_PRIORITY_QUEUES
spi_tx_sem = xSemaphoreCreateCounting(SPI_TX_TOTAL_QUEUE_SIZE, 0);
assert(spi_tx_sem);
@@ -742,7 +779,7 @@ static interface_handle_t * esp_spi_init(void)
assert(xTaskCreate(spi_transaction_post_process_task , "spi_post_process_task" ,
CONFIG_ESP_DEFAULT_TASK_STACK_SIZE, NULL,
- CONFIG_ESP_DEFAULT_TASK_PRIO, NULL) == pdTRUE);
+ CONFIG_ESP_HOSTED_TASK_PRIORITY_DEFAULT, NULL) == pdTRUE);
usleep(500);
@@ -752,65 +789,72 @@ static interface_handle_t * esp_spi_init(void)
static int32_t esp_spi_write(interface_handle_t *handle, interface_buffer_handle_t *buf_handle)
{
int32_t total_len = 0;
- uint16_t offset = 0;
- struct esp_payload_header *header = NULL;
+ struct esp_payload_header *header;
interface_buffer_handle_t tx_buf_handle = {0};
- if (!handle || !buf_handle) {
- ESP_LOGE(TAG , "Invalid arguments\n");
+ /* Basic validation */
+ if (!handle || !buf_handle || !buf_handle->payload) {
+ ESP_LOGE(TAG, "Invalid args - handle:%p buf:%p payload:%p",
+ handle, buf_handle, buf_handle ? buf_handle->payload : NULL);
return ESP_FAIL;
}
- if (!buf_handle->payload_len || !buf_handle->payload) {
- ESP_LOGE(TAG , "Invalid arguments, len:%d\n", buf_handle->payload_len);
+ /* Length validation */
+ if (!buf_handle->payload_len || buf_handle->payload_len > (SPI_BUFFER_SIZE-sizeof(struct esp_payload_header))) {
+ ESP_LOGE(TAG, "Invalid payload length:%d", buf_handle->payload_len);
return ESP_FAIL;
}
- total_len = buf_handle->payload_len + sizeof (struct esp_payload_header);
+ /* Calculate total length */
+ total_len = buf_handle->payload_len + sizeof(struct esp_payload_header);
- /* make the adresses dma aligned */
+ /* DMA alignment check */
if (!IS_SPI_DMA_ALIGNED(total_len)) {
MAKE_SPI_DMA_ALIGNED(total_len);
}
if (total_len > SPI_BUFFER_SIZE) {
-#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
- ESP_LOGE(TAG, "Max frame length exceeded %ld.. drop it\n", total_len);
-#else
- ESP_LOGE(TAG, "Max frame length exceeded %d.. drop it\n", total_len);
-#endif
+ ESP_LOGE(TAG, "Total length %" PRId32 " exceeds max %d", total_len, SPI_BUFFER_SIZE);
return ESP_FAIL;
}
- tx_buf_handle.if_type = buf_handle->if_type;
- tx_buf_handle.if_num = buf_handle->if_num;
- tx_buf_handle.payload_len = total_len;
-
- tx_buf_handle.payload = spi_buffer_tx_alloc(MEMSET_REQUIRED);
- assert(tx_buf_handle.payload);
-
- header = (struct esp_payload_header *) tx_buf_handle.payload;
+ /* Allocate and validate TX buffer */
+ tx_buf_handle.payload = spi_buffer_tx_alloc(MEMSET_NOT_REQUIRED);
+ if (!tx_buf_handle.payload) {
+ ESP_LOGE(TAG, "TX buffer allocation failed");
+ return ESP_FAIL;
+ }
- memset (header, 0, sizeof(struct esp_payload_header));
+ /* Setup header */
+ header = (struct esp_payload_header *)tx_buf_handle.payload;
+ memset(header, 0, sizeof(struct esp_payload_header));
- /* Initialize header */
header->if_type = buf_handle->if_type;
header->if_num = buf_handle->if_num;
header->len = htole16(buf_handle->payload_len);
- offset = sizeof(struct esp_payload_header);
- header->offset = htole16(offset);
+ header->offset = htole16(sizeof(struct esp_payload_header));
header->seq_num = htole16(buf_handle->seq_num);
header->flags = buf_handle->flag;
- /* copy the data from caller */
- memcpy(tx_buf_handle.payload + offset, buf_handle->payload, buf_handle->payload_len);
+ /* Copy payload data */
+ memcpy(tx_buf_handle.payload + sizeof(struct esp_payload_header),
+ buf_handle->payload, buf_handle->payload_len);
+ tx_buf_handle.if_type = buf_handle->if_type;
+ tx_buf_handle.if_num = buf_handle->if_num;
+ tx_buf_handle.payload_len = total_len;
#if CONFIG_ESP_SPI_CHECKSUM
- header->checksum = htole16(compute_checksum(tx_buf_handle.payload,
- offset+buf_handle->payload_len));
+ /* Calculate checksum with header checksum field zeroed */
+ header->checksum = 0;
+ uint16_t checksum = compute_checksum(tx_buf_handle.payload,
+ sizeof(struct esp_payload_header)+buf_handle->payload_len);
+ header->checksum = htole16(checksum);
#endif
+ ESP_LOGV(TAG, "[TX] Packet - type:%u len:%" PRIu16 " total:% " PRId32,
+ header->if_type, buf_handle->payload_len, total_len);
+
#ifdef CONFIG_ESP_ENABLE_TX_PRIORITY_QUEUES
if (header->if_type == ESP_SERIAL_IF)
xQueueSend(spi_tx_queue[PRIO_Q_SERIAL], &tx_buf_handle, portMAX_DELAY);
@@ -824,10 +868,9 @@ static int32_t esp_spi_write(interface_handle_t *handle, interface_buffer_handle
xQueueSend(spi_tx_queue, &tx_buf_handle, portMAX_DELAY);
#endif
- /* indicate waiting data on ready pin */
set_dataready_gpio();
- return buf_handle->payload_len;
+ return tx_buf_handle.payload_len;
}
static void IRAM_ATTR esp_spi_read_done(void *handle)
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/stats.c b/esp_hosted_fg/esp/esp_driver/network_adapter/main/stats.c
index 7240d0924b..65678b7cf4 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/main/stats.c
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/stats.c
@@ -17,136 +17,231 @@
#include "stats.h"
#include
#include "esp_log.h"
+#include
+#include
-#if TEST_RAW_TP
+#if TEST_RAW_TP || ESP_PKT_STATS || CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS || ESP_PKT_NUM_DEBUG
static const char TAG[] = "stats";
-#endif
+#endif /* TEST_RAW_TP || ESP_PKT_STATS || CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS || ESP_PKT_NUM_DEBUG */
+
+#if ESP_PKT_NUM_DEBUG
+struct dbg_stats_t dbg_stats;
+#endif /* ESP_PKT_NUM_DEBUG */
+
+#if ESP_PKT_STATS
+ #define ESP_PKT_STATS_REPORT_INTERVAL CONFIG_ESP_PKT_STATS_INTERVAL_SEC
+ struct pkt_stats_t pkt_stats;
+#endif /* ESP_PKT_STATS */
+
+#ifdef ESP_FUNCTION_PROFILING
+/* Define the global variables */
+struct timing_stats_entry timing_entries[CONFIG_ESP_HOSTED_FUNCTION_PROFILING_MAX_ENTRIES] = {0};
+int num_timing_entries = 0;
+
+/* Function to register new timing stats */
+struct timing_stats* register_prof_stats(const char *func_name)
+{
+ if (num_timing_entries >= CONFIG_ESP_HOSTED_FUNCTION_PROFILING_MAX_ENTRIES) {
+ ESP_LOGE(TAG, "Max timing stats reached");
+ return NULL;
+ }
+
+ /* Check if already registered */
+ for (int i = 0; i < num_timing_entries; i++) {
+ if (strcmp(timing_entries[i].name, func_name) == 0) {
+ return &timing_entries[i].stats;
+ }
+ }
+
+ /* Add new entry */
+ timing_entries[num_timing_entries].name = func_name;
+ timing_entries[num_timing_entries].active = true;
+ num_timing_entries++;
+
+ return &timing_entries[num_timing_entries-1].stats;
+}
+
+/* Function to get timing measure for a stats entry */
+struct timing_measure* get_prof_data(struct timing_stats *s)
+{
+ for (int i = 0; i < num_timing_entries; i++) {
+ if (&timing_entries[i].stats == s) {
+ return &timing_entries[i].measure;
+ }
+ }
+ return NULL;
+}
+
+/* Print timing stats function */
+static void print_timing_stats(struct timing_measure *t, struct timing_stats *s, const char *name)
+{
+ if (!t || !s || !name) {
+ ESP_LOGE(TAG, "Invalid arguments");
+ return;
+ }
+
+ s->avg_time = t->total_time / t->count;
+
+ ESP_LOGI(TAG, "[%s] Timing Stats - Count: %" PRIu32 ", Min: %" PRIu32 " us, Max: %" PRIu32 " us, Avg: %" PRIu32 " us",
+ name,
+ t->count,
+ s->min_time,
+ s->max_time,
+ s->avg_time);
+}
+#endif /* ESP_FUNCTION_PROFILING */
#ifdef CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
/* These functions are only for debugging purpose
* Please do not enable in production environments
*/
-static esp_err_t log_real_time_stats(TickType_t xTicksToWait) {
- TaskStatus_t *start_array = NULL, *end_array = NULL;
- UBaseType_t start_array_size, end_array_size;
- uint32_t start_run_time, end_run_time;
- esp_err_t ret;
-
- /*Allocate array to store current task states*/
- start_array_size = uxTaskGetNumberOfTasks() + ARRAY_SIZE_OFFSET;
- start_array = malloc(sizeof(TaskStatus_t) * start_array_size);
- if (start_array == NULL) {
- ret = ESP_ERR_NO_MEM;
- goto exit;
- }
- /*Get current task states*/
- start_array_size = uxTaskGetSystemState(start_array, start_array_size, &start_run_time);
- if (start_array_size == 0) {
- ret = ESP_ERR_INVALID_SIZE;
- goto exit;
- }
-
- vTaskDelay(xTicksToWait);
-
- /*Allocate array to store tasks states post delay*/
- end_array_size = uxTaskGetNumberOfTasks() + ARRAY_SIZE_OFFSET;
- end_array = malloc(sizeof(TaskStatus_t) * end_array_size);
- if (end_array == NULL) {
- ret = ESP_ERR_NO_MEM;
- goto exit;
- }
- /*Get post delay task states*/
- end_array_size = uxTaskGetSystemState(end_array, end_array_size, &end_run_time);
- if (end_array_size == 0) {
- ret = ESP_ERR_INVALID_SIZE;
- goto exit;
- }
-
- /*Calculate total_elapsed_time in units of run time stats clock period.*/
- uint32_t total_elapsed_time = (end_run_time - start_run_time);
- if (total_elapsed_time == 0) {
- ret = ESP_ERR_INVALID_STATE;
- goto exit;
- }
-
- printf("| Task | Run Time | Percentage\n");
- /*Match each task in start_array to those in the end_array*/
- for (int i = 0; i < start_array_size; i++) {
- int k = -1;
- for (int j = 0; j < end_array_size; j++) {
- if (start_array[i].xHandle == end_array[j].xHandle) {
- k = j;
- /*Mark that task have been matched by overwriting their handles*/
- start_array[i].xHandle = NULL;
- end_array[j].xHandle = NULL;
- break;
- }
- }
- /*Check if matching task found*/
- if (k >= 0) {
- uint32_t task_elapsed_time = end_array[k].ulRunTimeCounter - start_array[i].ulRunTimeCounter;
- uint32_t percentage_time = (task_elapsed_time * 100UL) / (total_elapsed_time * portNUM_PROCESSORS);
- printf("| %s | %d | %d%%\n", start_array[i].pcTaskName, task_elapsed_time, percentage_time);
- }
- }
-
- /*Print unmatched tasks*/
- for (int i = 0; i < start_array_size; i++) {
- if (start_array[i].xHandle != NULL) {
- printf("| %s | Deleted\n", start_array[i].pcTaskName);
- }
- }
- for (int i = 0; i < end_array_size; i++) {
- if (end_array[i].xHandle != NULL) {
- printf("| %s | Created\n", end_array[i].pcTaskName);
- }
- }
- ret = ESP_OK;
+static esp_err_t log_real_time_stats(TickType_t xTicksToWait)
+{
+ TaskStatus_t *start_array = NULL, *end_array = NULL;
+ UBaseType_t start_array_size, end_array_size;
+ uint32_t start_run_time, end_run_time;
+ esp_err_t ret;
+
+ /*Allocate array to store current task states*/
+ start_array_size = uxTaskGetNumberOfTasks() + ARRAY_SIZE_OFFSET;
+ start_array = malloc(sizeof(TaskStatus_t) * start_array_size);
+ if (start_array == NULL) {
+ ret = ESP_ERR_NO_MEM;
+ goto exit;
+ }
+ /*Get current task states*/
+ start_array_size = uxTaskGetSystemState(start_array, start_array_size, &start_run_time);
+ if (start_array_size == 0) {
+ ret = ESP_ERR_INVALID_SIZE;
+ goto exit;
+ }
+
+ vTaskDelay(xTicksToWait);
+
+ /*Allocate array to store tasks states post delay*/
+ end_array_size = uxTaskGetNumberOfTasks() + ARRAY_SIZE_OFFSET;
+ end_array = malloc(sizeof(TaskStatus_t) * end_array_size);
+ if (end_array == NULL) {
+ ret = ESP_ERR_NO_MEM;
+ goto exit;
+ }
+ /*Get post delay task states*/
+ end_array_size = uxTaskGetSystemState(end_array, end_array_size, &end_run_time);
+ if (end_array_size == 0) {
+ ret = ESP_ERR_INVALID_SIZE;
+ goto exit;
+ }
+
+ /*Calculate total_elapsed_time in units of run time stats clock period.*/
+ uint32_t total_elapsed_time = (end_run_time - start_run_time);
+ if (total_elapsed_time == 0) {
+ ret = ESP_ERR_INVALID_STATE;
+ goto exit;
+ }
+
+ ESP_LOGI(TAG,"| Task | Run Time | Percentage\n");
+ /*Match each task in start_array to those in the end_array*/
+ for (int i = 0; i < start_array_size; i++) {
+ int k = -1;
+ for (int j = 0; j < end_array_size; j++) {
+ if (start_array[i].xHandle == end_array[j].xHandle) {
+ k = j;
+ /*Mark that task have been matched by overwriting their handles*/
+ start_array[i].xHandle = NULL;
+ end_array[j].xHandle = NULL;
+ break;
+ }
+ }
+ /*Check if matching task found*/
+ if (k >= 0) {
+ uint32_t task_elapsed_time = end_array[k].ulRunTimeCounter - start_array[i].ulRunTimeCounter;
+ uint32_t percentage_time = (task_elapsed_time * 100UL) / (total_elapsed_time * portNUM_PROCESSORS);
+ ESP_LOGI(TAG,"| %s | %d | %d%%\n", start_array[i].pcTaskName, (int)task_elapsed_time, (int)percentage_time);
+ }
+ }
+
+ /*Print unmatched tasks*/
+ for (int i = 0; i < start_array_size; i++) {
+ if (start_array[i].xHandle != NULL) {
+ ESP_LOGI(TAG,"| %s | Deleted\n", start_array[i].pcTaskName);
+ }
+ }
+ for (int i = 0; i < end_array_size; i++) {
+ if (end_array[i].xHandle != NULL) {
+ ESP_LOGI(TAG,"| %s | Created\n", end_array[i].pcTaskName);
+ }
+ }
+ ret = ESP_OK;
exit: /*Common return path*/
if (start_array)
free(start_array);
if (end_array)
free(end_array);
- return ret;
+ return ret;
}
-static void log_runtime_stats_task(void* pvParameters) {
- while (1) {
- printf("\n\nGetting real time stats over %d ticks\n", STATS_TICKS);
- if (log_real_time_stats(STATS_TICKS) == ESP_OK) {
- printf("Real time stats obtained\n");
- } else {
- printf("Error getting real time stats\n");
- }
- vTaskDelay(pdMS_TO_TICKS(1000*2));
- }
+static void print_mem_stats()
+{
+ uint32_t freeSize = esp_get_free_heap_size();
+ printf("The available total size of heap:%" PRIu32 "\n", freeSize);
+
+ printf("\tDescription\tInternal\tSPIRAM\n");
+ printf("Current Free Memory\t%d\t\t%d\n",
+ heap_caps_get_free_size(MALLOC_CAP_8BIT) - heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
+ heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
+ printf("Largest Free Block\t%d\t\t%d\n",
+ heap_caps_get_largest_free_block(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL),
+ heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM));
+ printf("Min. Ever Free Size\t%d\t\t%d\n",
+ heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL),
+ heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM));
}
-#endif
+
+static void log_runtime_stats_task(void* pvParameters)
+{
+ while (1) {
+ ESP_LOGI(TAG, "\n\nGetting real time stats over %d ticks\n", (int)STATS_TICKS);
+ if (log_real_time_stats(STATS_TICKS) == ESP_OK) {
+ ESP_LOGI(TAG, "Real time stats obtained\n");
+ } else {
+ ESP_LOGE(TAG, "Error getting real time stats\n");
+ }
+ print_mem_stats();
+ vTaskDelay(STATS_TICKS);
+ }
+}
+#endif /* CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS */
#if TEST_RAW_TP
-uint8_t raw_tp_tx_buf[TEST_RAW_TP__BUF_SIZE] = {0};
uint64_t test_raw_tp_rx_len;
+uint64_t test_raw_tp_tx_len;
void debug_update_raw_tp_rx_count(uint16_t len)
{
test_raw_tp_rx_len += len;
}
+/* static buffer to hold tx data during test */
+DMA_ATTR static uint8_t tx_buf[TEST_RAW_TP__BUF_SIZE];
+
static void raw_tp_timer_func(void* arg)
{
static int32_t cur = 0;
- double actual_bandwidth = 0;
+ double actual_bandwidth_rx = 0;
+ double actual_bandwidth_tx = 0;
int32_t div = 1024;
- actual_bandwidth = (test_raw_tp_rx_len*8);
+ actual_bandwidth_tx = (test_raw_tp_tx_len*8);
+ actual_bandwidth_rx = (test_raw_tp_rx_len*8);
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
- printf("%lu-%lu sec %.2f kbits/sec\n\r", cur, cur + 1, actual_bandwidth/div);
-#else
- printf("%u-%u sec %.2f kbits/sec\n\r", cur, cur + 1, actual_bandwidth/div);
-#endif
+ ESP_LOGI(TAG,"%lu-%lu sec Rx: %.2f Tx: %.2f kbps", cur, cur + 1, actual_bandwidth_rx/div, actual_bandwidth_tx/div);
+#else /* ESP_IDF_VERSION */
+ ESP_LOGI(TAG,"%u-%u sec Rx: %.2f Tx: %.2f kbps", cur, cur + 1, actual_bandwidth_rx/div, actual_bandwidth_tx/div);
+#endif /* ESP_IDF_VERSION */
+
cur++;
- test_raw_tp_rx_len = 0;
+ test_raw_tp_rx_len = test_raw_tp_tx_len = 0;
}
#if TEST_RAW_TP__ESP_TO_HOST
@@ -154,16 +249,19 @@ extern volatile uint8_t datapath;
static void raw_tp_tx_task(void* pvParameters)
{
int ret;
- unsigned int *ptr = raw_tp_tx_buf;
interface_buffer_handle_t buf_handle = {0};
+ uint8_t *raw_tp_tx_buf = NULL;
+ uint32_t *ptr = NULL;
+ uint16_t i = 0;
sleep(5);
- for(int i=0;icount / CONFIG_ESP_PKT_STATS_INTERVAL_SEC);
+ s->avg_time = t->total_time / t->count;
+
+ ESP_LOGI(TAG, "[%s] Stats - Count: %" PRIu32 ", Min: %" PRIu32 ", Max: %" PRIu32 ", Avg: %" PRIu32 " us, Rate: %" PRIu32 "/s",
+ timing_entries[i].name,
+ t->count,
+ s->min_time,
+ s->max_time,
+ s->avg_time,
+ rate);
+ }
+#endif /* ESP_FUNCTION_PROFILING */
+}
+
+static void start_timer_to_display_stats(int periodic_time_sec)
+{
+ test_args_t args = {0};
+ esp_timer_handle_t raw_tp_timer = {0};
+ esp_timer_create_args_t create_args = {
+ .callback = &stats_timer_func,
+ .arg = &args,
+ .name = "raw_tp_timer",
+ };
+ ESP_ERROR_CHECK(esp_timer_create(&create_args, &raw_tp_timer));
+
+ args.timer = raw_tp_timer;
+
+ ESP_ERROR_CHECK(esp_timer_start_periodic(raw_tp_timer, SEC_TO_USEC(periodic_time_sec)));
+}
+#endif /* ESP_PKT_STATS */
+
+#if TEST_RAW_TP
static void start_timer_to_display_raw_tp(void)
{
test_args_t args = {0};
@@ -203,27 +363,29 @@ static void start_timer_to_display_raw_tp(void)
args.timer = raw_tp_timer;
- ESP_ERROR_CHECK(esp_timer_start_periodic(raw_tp_timer, TEST_RAW_TP__TIMEOUT));
+ ESP_ERROR_CHECK(esp_timer_start_periodic(raw_tp_timer, SEC_TO_USEC(TEST_RAW_TP__TIMEOUT)));
}
-
-#endif
+#endif /* TEST_RAW_TP */
void create_debugging_tasks(void)
{
#ifdef CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
assert(xTaskCreate(log_runtime_stats_task, "log_runtime_stats_task",
CONFIG_ESP_DEFAULT_TASK_STACK_SIZE, NULL,
- CONFIG_ESP_DEFAULT_TASK_PRIO, NULL) == pdTRUE);
-#endif
+ CONFIG_ESP_HOSTED_TASK_PRIORITY_LOW, NULL) == pdTRUE);
+#endif /* CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS */
#if TEST_RAW_TP
start_timer_to_display_raw_tp();
#if TEST_RAW_TP__ESP_TO_HOST
assert(xTaskCreate(raw_tp_tx_task , "raw_tp_tx_task",
CONFIG_ESP_DEFAULT_TASK_STACK_SIZE, NULL ,
- CONFIG_ESP_DEFAULT_TASK_PRIO, NULL) == pdTRUE);
+ CONFIG_ESP_HOSTED_TASK_PRIORITY_LOW, NULL) == pdTRUE);
#endif
#endif
+#if ESP_PKT_STATS
+ start_timer_to_display_stats(ESP_PKT_STATS_REPORT_INTERVAL);
+#endif /* ESP_PKT_STATS */
}
uint8_t debug_get_raw_tp_conf(void) {
@@ -241,48 +403,3 @@ uint8_t debug_get_raw_tp_conf(void) {
return raw_tp_cap;
}
-void debug_set_wifi_logging(void) {
- /* set WiFi log level and module */
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_ENABLE
- uint32_t g_wifi_log_level = WIFI_LOG_INFO;
- uint32_t g_wifi_log_module = 0;
- uint32_t g_wifi_log_submodule = 0;
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_DEBUG
- g_wifi_log_level = WIFI_LOG_DEBUG;
-#endif
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_VERBOSE
- g_wifi_log_level = WIFI_LOG_VERBOSE;
-#endif
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_MODULE_ALL
- g_wifi_log_module = WIFI_LOG_MODULE_ALL;
-#endif
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_MODULE_WIFI
- g_wifi_log_module = WIFI_LOG_MODULE_WIFI;
-#endif
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_MODULE_COEX
- g_wifi_log_module = WIFI_LOG_MODULE_COEX;
-#endif
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_MODULE_MESH
- g_wifi_log_module = WIFI_LOG_MODULE_MESH;
-#endif
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_SUBMODULE_ALL
- g_wifi_log_submodule |= WIFI_LOG_SUBMODULE_ALL;
-#endif
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_SUBMODULE_INIT
- g_wifi_log_submodule |= WIFI_LOG_SUBMODULE_INIT;
-#endif
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_SUBMODULE_IOCTL
- g_wifi_log_submodule |= WIFI_LOG_SUBMODULE_IOCTL;
-#endif
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_SUBMODULE_CONN
- g_wifi_log_submodule |= WIFI_LOG_SUBMODULE_CONN;
-#endif
-#if CONFIG_ESP32_WIFI_DEBUG_LOG_SUBMODULE_SCAN
- g_wifi_log_submodule |= WIFI_LOG_SUBMODULE_SCAN;
-#endif
- esp_wifi_internal_set_log_level(g_wifi_log_level);
- esp_wifi_internal_set_log_mod(g_wifi_log_module, g_wifi_log_submodule, true);
-
-#endif /* CONFIG_ESP32_WIFI_DEBUG_LOG_ENABLE*/
-
-}
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/main/stats.h b/esp_hosted_fg/esp/esp_driver/network_adapter/main/stats.h
index 3a28d0fac2..4ce34ee34a 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/main/stats.h
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/main/stats.h
@@ -23,11 +23,17 @@
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
+#include "esp_timer.h"
#define SEC_TO_MSEC(x) (x*1000)
#define MSEC_TO_USEC(x) (x*1000)
#define SEC_TO_USEC(x) (x*1000*1000)
+/* Change the feature flag definition */
+#ifdef CONFIG_ESP_HOSTED_FUNCTION_PROFILING
+#define ESP_FUNCTION_PROFILING 1
+#endif
+
/* Stats CONFIG:
*
@@ -45,11 +51,15 @@
* This is opposite of TEST_RAW_TP__ESP_TO_HOST. when (a) TEST_RAW_TP__ESP_TO_HOST
* is disabled, it will automatically mean throughput to be measured from host to ESP
*/
-#define TEST_RAW_TP 0
+#define TEST_RAW_TP CONFIG_ESP_RAW_THROUGHPUT_TRANSPORT
+
+#ifdef CONFIG_ESP_PKT_STATS
+#define ESP_PKT_STATS 1
+#endif
#ifdef CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
/* Stats to show task wise CPU utilization */
- #define STATS_TICKS pdMS_TO_TICKS(1000*2)
+ #define STATS_TICKS pdMS_TO_TICKS(4 * 1000)
#define ARRAY_SIZE_OFFSET 5
void debug_runtime_stats_task(void* pvParameters);
@@ -63,9 +73,7 @@ void debug_runtime_stats_task(void* pvParameters);
* at a time
*/
-#if TEST_RAW_TP
-
-#include "esp_timer.h"
+#if TEST_RAW_TP || ESP_PKT_STATS
#include "interface.h"
/* Raw throughput is supported only one direction
@@ -76,9 +84,6 @@ void debug_runtime_stats_task(void* pvParameters);
#define TEST_RAW_TP__ESP_TO_HOST 1
#define TEST_RAW_TP__HOST_TO_ESP !TEST_RAW_TP__ESP_TO_HOST
-#define TEST_RAW_TP__BUF_SIZE 1460
-#define TEST_RAW_TP__TIMEOUT SEC_TO_USEC(1)
-
typedef struct {
esp_timer_handle_t timer;
size_t cur_interval;
@@ -86,11 +91,118 @@ typedef struct {
SemaphoreHandle_t done;
} test_args_t;
+#define TEST_RAW_TP__BUF_SIZE CONFIG_ESP_RAW_TP_ESP_TO_HOST_PKT_LEN
+#define TEST_RAW_TP__TIMEOUT CONFIG_ESP_RAW_TP_REPORT_INTERVAL
+
void debug_update_raw_tp_rx_count(uint16_t len);
#endif
+#if ESP_PKT_STATS
+struct pkt_stats_t {
+ uint32_t sta_sh_in;
+ uint32_t sta_sh_out;
+ uint32_t hs_bus_sta_in;
+ uint32_t hs_bus_sta_out;
+ uint32_t hs_bus_sta_fail;
+ uint32_t serial_rx;
+ uint32_t serial_tx_total;
+ uint32_t serial_tx_evt;
+ uint32_t sta_flowctrl_on;
+ uint32_t sta_flowctrl_off;
+ uint32_t sta_lwip_in;
+ uint32_t sta_slave_lwip_out;
+ uint32_t sta_host_lwip_out;
+ uint32_t sta_both_lwip_out;
+};
+
+extern struct pkt_stats_t pkt_stats;
+
+#endif
+
+
void create_debugging_tasks(void);
uint8_t debug_get_raw_tp_conf(void);
-void debug_set_wifi_logging(void);
+
+/* Add these declarations before the macros */
+
+#ifdef ESP_FUNCTION_PROFILING
+
+/* Timing measurement stats */
+struct timing_measure {
+ uint32_t start_time;
+ uint32_t end_time;
+ uint32_t total_time;
+ uint32_t count;
+};
+
+struct timing_stats {
+ uint32_t min_time;
+ uint32_t max_time;
+ uint32_t avg_time;
+};
+
+/* Move struct definition to header file */
+struct timing_stats_entry {
+ const char *name;
+ struct timing_measure measure;
+ struct timing_stats stats;
+ bool active;
+};
+
+
+#define ESP_HOSTED_FUNC_PROF_START(func_name) do { \
+ struct timing_stats *s = register_prof_stats(func_name); \
+ if (!s) { \
+ ESP_LOGE(TAG, "Failed to register timing stats for %s", func_name); \
+ break; \
+ } \
+ struct timing_measure *t = get_prof_data(s); \
+ if (!t) { \
+ ESP_LOGE(TAG, "Failed to get timing measure for %s", func_name); \
+ break; \
+ } \
+ t->start_time = esp_timer_get_time(); \
+} while(0)
+
+#define ESP_HOSTED_FUNC_PROF_END(func_name) do { \
+ struct timing_stats *s = NULL; \
+ struct timing_measure *t = NULL; \
+ for (int i = 0; i < num_timing_entries; i++) { \
+ if (strcmp(timing_entries[i].name, func_name) == 0) { \
+ s = &timing_entries[i].stats; \
+ t = &timing_entries[i].measure; \
+ break; \
+ } \
+ } \
+ if (!s || !t) { \
+ ESP_LOGE(TAG, "Failed to find timing stats for %s", func_name); \
+ break; \
+ } \
+ t->end_time = esp_timer_get_time(); \
+ t->count++; \
+ int64_t elapsed = t->end_time - t->start_time; \
+ t->total_time += elapsed; \
+ if (s->min_time == 0 || elapsed < s->min_time) { \
+ s->min_time = elapsed; \
+ } \
+ if (elapsed > s->max_time) { \
+ s->max_time = elapsed; \
+ } \
+ if (t->count > 0) { \
+ s->avg_time = t->total_time / t->count; \
+ } \
+} while(0)
+
+extern struct timing_stats_entry timing_entries[CONFIG_ESP_HOSTED_FUNCTION_PROFILING_MAX_ENTRIES];
+extern int num_timing_entries;
+
+/* Function declarations */
+struct timing_stats* register_prof_stats(const char *func_name);
+struct timing_measure* get_prof_data(struct timing_stats *s);
+#else
+#define ESP_HOSTED_FUNC_PROF_START(func_name)
+#define ESP_HOSTED_FUNC_PROF_END(func_name)
+#endif
+
#endif /*__STATS__H__*/
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/partitions.esp32.csv b/esp_hosted_fg/esp/esp_driver/network_adapter/partitions.esp32.csv
index 519f37720d..674558e547 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/partitions.esp32.csv
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/partitions.esp32.csv
@@ -3,5 +3,5 @@
nvs,data,nvs,0x9000,16K,
otadata,data,ota,0xd000,8K,
phy_init,data,phy,0xf000,4K,
-ota_0,app,ota_0,0x110000,1M,
-ota_1,app,ota_1,0x210000,1M,
+ota_0,app,ota_0,0x10000,1792K,
+ota_1,app,ota_1,0x1D0000,1792K,
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/partitions.esp32c3.csv b/esp_hosted_fg/esp/esp_driver/network_adapter/partitions.esp32c3.csv
new file mode 100644
index 0000000000..0252a55182
--- /dev/null
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/partitions.esp32c3.csv
@@ -0,0 +1,7 @@
+# ESP-IDF Partition Table
+# Name, Type, SubType, Offset, Size, Flags
+nvs,data,nvs,0x9000,16K,
+otadata,data,ota,0xd000,8K,
+phy_init,data,phy,0xf000,4K,
+ota_0,app,ota_0,0x10000,1536K,
+ota_1,app,ota_1,0x190000,1536K,
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/partitions.esp32c5.csv b/esp_hosted_fg/esp/esp_driver/network_adapter/partitions.esp32c5.csv
new file mode 100644
index 0000000000..0252a55182
--- /dev/null
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/partitions.esp32c5.csv
@@ -0,0 +1,7 @@
+# ESP-IDF Partition Table
+# Name, Type, SubType, Offset, Size, Flags
+nvs,data,nvs,0x9000,16K,
+otadata,data,ota,0xd000,8K,
+phy_init,data,phy,0xf000,4K,
+ota_0,app,ota_0,0x10000,1536K,
+ota_1,app,ota_1,0x190000,1536K,
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/partitions.esp32s2.csv b/esp_hosted_fg/esp/esp_driver/network_adapter/partitions.esp32s2.csv
new file mode 100644
index 0000000000..0252a55182
--- /dev/null
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/partitions.esp32s2.csv
@@ -0,0 +1,7 @@
+# ESP-IDF Partition Table
+# Name, Type, SubType, Offset, Size, Flags
+nvs,data,nvs,0x9000,16K,
+otadata,data,ota,0xd000,8K,
+phy_init,data,phy,0xf000,4K,
+ota_0,app,ota_0,0x10000,1536K,
+ota_1,app,ota_1,0x190000,1536K,
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/partitions.esp32s3.csv b/esp_hosted_fg/esp/esp_driver/network_adapter/partitions.esp32s3.csv
new file mode 100644
index 0000000000..0252a55182
--- /dev/null
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/partitions.esp32s3.csv
@@ -0,0 +1,7 @@
+# ESP-IDF Partition Table
+# Name, Type, SubType, Offset, Size, Flags
+nvs,data,nvs,0x9000,16K,
+otadata,data,ota,0xd000,8K,
+phy_init,data,phy,0xf000,4K,
+ota_0,app,ota_0,0x10000,1536K,
+ota_1,app,ota_1,0x190000,1536K,
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults b/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults
index 758a6acb58..2d97b1700e 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults
@@ -1,7 +1,3 @@
-CONFIG_ESP32_DEFAULT_CPU_FREQ_160=y
-CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=160
-CONFIG_FREERTOS_HZ=1000
-
# BT Configuration
CONFIG_BT_ENABLED=y
CONFIG_BT_CONTROLLER_ONLY=y
@@ -10,7 +6,12 @@ CONFIG_BT_CONTROLLER_ONLY=y
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_PARTITION_TABLE_TWO_OTA=y
-# Wifi NVS
+# OS
+CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_WIFI_NVS_ENABLED=y
-
+# Linux Host Deep Sleep allowed?
+#-------------------------------
+# Linux host power save is not yet supported on FG
+CONFIG_HOST_DEEP_SLEEP_ALLOWED=n
+CONFIG_HOST_WAKEUP_GPIO=-1
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32 b/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32
index 65bc55f2a9..aa3f684394 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32
@@ -1,5 +1,4 @@
CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
-CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240
CONFIG_SDIO_DAT2_DISABLED=
# BT Configuration
@@ -11,8 +10,6 @@ CONFIG_BTDM_CONTROLLER_HCI_MODE_VHCI=y
CONFIG_BTDM_CTRL_AUTO_LATENCY=y
CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=y
CONFIG_BTDM_CTRL_MODEM_SLEEP=y
-CONFIG_BTDM_CTRL_MODE_BTDM=y
-CONFIG_BTDM_CTRL_HCI_MODE_VHCI=y
# BT over UART
#CONFIG_BTDM_CONTROLLER_HCI_MODE_UART_H4=y
@@ -22,7 +19,6 @@ CONFIG_BTDM_CTRL_HCI_MODE_VHCI=y
#CO-EX config
CONFIG_FREERTOS_UNICORE=n
-CONFIG_FREERTOS_HZ=1000
CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1=y
CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE=0
CONFIG_BTDM_CTRL_PINNED_TO_CORE=0
@@ -40,5 +36,12 @@ CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.esp32.csv"
-# iram text optimization
+# iram optimization
+CONFIG_ESP_WIFI_RX_IRAM_OPT=y
+CONFIG_ESP_WIFI_IRAM_OPT=y
CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
+CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH=y
+CONFIG_ESP_SYSTEM_ESP32_SRAM1_REGION_AS_IRAM=y
+
+CONFIG_COMPILER_OPTIMIZATION_PERF=y
+#CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32c2 b/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32c2
index 29e7ae4bec..7a5d5c84a2 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32c2
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32c2
@@ -1,27 +1,89 @@
-CONFIG_ESP_DEFAULT_CPU_FREQ_120=y
-CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=120
-CONFIG_FREERTOS_UNICORE=y
-CONFIG_SDIO_DAT2_DISABLED=
+# 1. CPU
+#--------
+CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_120=y
-# BT Configuration
-CONFIG_BT_ENABLED=y
+# 2. BT Configuration
+#---------------------
+CONFIG_BT_ENABLED=n
CONFIG_BT_CONTROLLER_ONLY=y
-CONFIG_BT_BLUEDROID_ENABLED=
CONFIG_BT_LE_SLEEP_ENABLE=y
+# 2.1 BLE over SPI/SDIO
+#-----------------------
+CONFIG_BT_LE_HCI_INTERFACE_USE_RAM=y
+
+# 2.2 BLE over UART
+#-------------------
#UART pins, Enable below config, delete sdkconfig and rebuild
#CONFIG_BT_LE_HCI_INTERFACE_USE_UART=y
#CONFIG_BT_LE_HCI_UART_FLOWCTRL=n
#CONFIG_BT_LE_HCI_UART_TX_PIN=5
#CONFIG_BT_LE_HCI_UART_RX_PIN=18
-CONFIG_ESPTOOLPY_FLASHSIZE_4MB=n
-CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y
-CONFIG_PARTITION_TABLE_TWO_OTA=y
+
+# 3. Partition Table
+#--------------------
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.esp32c2.csv"
-CONFIG_PARTITION_TABLE_FILENAME="partitions.esp32c2.csv"
-CONFIG_ESP_SPI_RX_Q_SIZE=6
-CONFIG_ESP_SPI_TX_Q_SIZE=6
+# 4. Mempool
+#------------
+CONFIG_ESP_CACHE_MALLOC=y
+
+
+# 5 LWIP split
+#---------------
+
+CONFIG_NETWORK_SPLIT_ENABLED=n
+
+
+# 6. Wifi config
+#----------------
+#CONFIG_WIFI_CMD_BASIC_ONLY=y
+
+CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=8
+CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=16
+CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=16
+CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=y
+CONFIG_ESP_WIFI_TX_BA_WIN=8
+#CONFIG_ESP_WIFI_TX_BA_WIN=16
+CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y
+CONFIG_ESP_WIFI_RX_BA_WIN=8
+#CONFIG_ESP_WIFI_RX_BA_WIN=14
+
+CONFIG_ESP_WIFI_RX_IRAM_OPT=y
+CONFIG_ESP_WIFI_IRAM_OPT=y
+
+
+# 7. Optimizations
+#-------------------
+CONFIG_COMPILER_OPTIMIZATION_SIZE=y
+#CONFIG_COMPILER_OPTIMIZATION_PERF=y
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
+
+
+# 8. Stats
+#-----------
+CONFIG_ESP_PKT_STATS=y
+
+
+# 9. Mem optimizations
+#---------------------
+CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
+CONFIG_ESP32_DEFAULT_CPU_FREQ_120=y
+CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=120
+CONFIG_FREERTOS_UNICORE=y
+
+#10. C2 specific opts
+#---------------------
+CONFIG_ESPTOOLPY_FLASHSIZE_4MB=n
+CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y
+
CONFIG_ESP_DEFAULT_TASK_STACK_SIZE=2048
+
+#11. C2 26 MHz XTAL chips
+# C2 generally in MP has 26MHz.
+# If your C2 has 40MHz, just comment below lines
+#---------------------------------
+CONFIG_SOC_XTAL_SUPPORT_26M=y
+CONFIG_XTAL_FREQ_26=y
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32c3 b/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32c3
index 3f8bab9aa2..057600ff26 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32c3
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32c3
@@ -1,10 +1,112 @@
-CONFIG_ESP32_DEFAULT_CPU_FREQ_160=y
-CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=160
-CONFIG_FREERTOS_UNICORE=y
-CONFIG_SDIO_DAT2_DISABLED=
+# 1. CPU
+#--------
+CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y
-# BT Configuration
+# 2. BT Configuration
+#---------------------
CONFIG_BT_ENABLED=y
CONFIG_BT_CONTROLLER_ONLY=y
CONFIG_BT_BLUEDROID_ENABLED=
CONFIG_BT_LE_SLEEP_ENABLE=y
+
+# 3.1 BLE over SPI/SDIO
+#-----------------------
+CONFIG_BT_LE_HCI_INTERFACE_USE_RAM=y
+
+# 3.2 BLE over UART
+#-------------------
+# Enable below config, delete sdkconfig, build/ and rebuild
+# CONFIG_BT_LE_HCI_INTERFACE_USE_UART=y
+# CONFIG_BT_LE_HCI_UART_TX_PIN=5
+# CONFIG_BT_LE_HCI_UART_RX_PIN=18
+# CONFIG_BT_LE_HCI_UART_FLOWCTRL=n
+# #CONFIG_BT_LE_HCI_UART_RTS_PIN=19
+# #CONFIG_BT_LE_HCI_UART_CTS_PIN=8
+
+
+# 4. Partition Table
+#--------------------
+CONFIG_PARTITION_TABLE_CUSTOM=y
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.esp32c3.csv"
+
+# 5. Mempool
+#------------
+CONFIG_ESP_CACHE_MALLOC=y
+
+
+# 6.1 LWIP split
+#---------------
+
+CONFIG_NETWORK_SPLIT_ENABLED=y
+CONFIG_LWIP_TCP_LOCAL_PORT_RANGE_START=61440
+CONFIG_LWIP_TCP_LOCAL_PORT_RANGE_END=65535
+CONFIG_LWIP_UDP_LOCAL_PORT_RANGE_START=61440
+CONFIG_LWIP_UDP_LOCAL_PORT_RANGE_END=65535
+
+CONFIG_ESP_DEFAULT_LWIP_SLAVE=y
+
+# 6.2 LWIP split examples
+#-------------------------
+CONFIG_ESP_HOSTED_COPROCESSOR_EXAMPLE_MQTT=n
+
+
+# 7. Transport config
+#---------------------
+# CONFIG_ESP_SDIO_NSEND_PSAMPLE=y
+# CONFIG_ESP_SDIO_DEFAULT_SPEED=y
+# CONFIG_ESP_SDIO_STREAMING_MODE=n
+
+# For SPI Full duplex C6 on ESP32-P4-Function-EV-Board, please uncomment below
+#CONFIG_C6_SPI_WITH_P4=y
+
+
+# 8. Wifi config
+#----------------
+CONFIG_WIFI_CMD_BASIC_ONLY=y
+
+CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=10
+CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=32
+CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=32
+CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=y
+CONFIG_ESP_WIFI_TX_BA_WIN=16
+CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y
+CONFIG_ESP_WIFI_RX_BA_WIN=16
+
+CONFIG_ESP_WIFI_RX_IRAM_OPT=y
+CONFIG_ESP_WIFI_IRAM_OPT=y
+
+# 9. LWIP config
+#----------------
+CONFIG_LWIP_TCP_SND_BUF_DEFAULT=11520
+CONFIG_LWIP_TCP_WND_DEFAULT=11520
+CONFIG_LWIP_TCP_RECVMBOX_SIZE=16
+CONFIG_LWIP_UDP_RECVMBOX_SIZE=16
+CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32
+CONFIG_LWIP_TCP_SACK_OUT=y
+CONFIG_LWIP_TCPIP_CORE_LOCKING=y
+CONFIG_LWIP_TCPIP_CORE_LOCKING_INPUT=y
+
+
+# 10. Optimizations
+#-------------------
+CONFIG_COMPILER_OPTIMIZATION_PERF=y
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
+CONFIG_SPI_MASTER_ISR_IN_IRAM=n
+
+
+# 11. Stats
+#-----------
+#CONFIG_ESP_HOSTED_FUNCTION_PROFILING=y
+CONFIG_ESP_PKT_STATS=y
+
+# 12. Priorities
+----------------
+CONFIG_IPERF_TRAFFIC_TASK_PRIORITY=18
+CONFIG_IPERF_REPORT_TASK_PRIORITY=18
+CONFIG_ESP_DEFAULT_TASK_PRIO=18
+
+
+#13. Mem optimizations
+#---------------------
+CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32c5 b/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32c5
new file mode 100644
index 0000000000..62ce76f086
--- /dev/null
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32c5
@@ -0,0 +1,110 @@
+# 1. CPU
+#--------
+CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
+
+# 2. BT Configuration
+#---------------------
+CONFIG_BT_ENABLED=y
+CONFIG_BT_CONTROLLER_ONLY=y
+CONFIG_BT_BLUEDROID_ENABLED=
+CONFIG_BT_LE_SLEEP_ENABLE=y
+
+# 3.1 BLE over SPI/SDIO
+#-----------------------
+CONFIG_BT_LE_HCI_INTERFACE_USE_RAM=y
+
+# 3.2 BLE over UART
+#-------------------
+# Enable below config, delete sdkconfig, build/ and rebuild
+# CONFIG_BT_LE_HCI_INTERFACE_USE_UART=y
+# CONFIG_BT_LE_HCI_UART_TX_PIN=5
+# CONFIG_BT_LE_HCI_UART_RX_PIN=18
+# CONFIG_BT_LE_HCI_UART_FLOWCTRL=n
+# #CONFIG_BT_LE_HCI_UART_RTS_PIN=19
+# #CONFIG_BT_LE_HCI_UART_CTS_PIN=8
+
+
+# 4. Partition Table
+#--------------------
+CONFIG_PARTITION_TABLE_CUSTOM=y
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.esp32c5.csv"
+
+# 5. Mempool
+#------------
+CONFIG_ESP_CACHE_MALLOC=y
+
+
+# 6.1 LWIP split
+#---------------
+
+CONFIG_NETWORK_SPLIT_ENABLED=y
+CONFIG_LWIP_TCP_LOCAL_PORT_RANGE_START=61440
+CONFIG_LWIP_TCP_LOCAL_PORT_RANGE_END=65535
+CONFIG_LWIP_UDP_LOCAL_PORT_RANGE_START=61440
+CONFIG_LWIP_UDP_LOCAL_PORT_RANGE_END=65535
+
+CONFIG_ESP_DEFAULT_LWIP_SLAVE=y
+
+# 6.2 LWIP split examples
+#-------------------------
+CONFIG_ESP_HOSTED_COPROCESSOR_EXAMPLE_MQTT=n
+
+
+# 7. Transport config
+#---------------------
+# CONFIG_ESP_SDIO_NSEND_PSAMPLE=y
+# CONFIG_ESP_SDIO_DEFAULT_SPEED=y
+# CONFIG_ESP_SDIO_STREAMING_MODE=n
+
+# For SPI Full duplex C6 on ESP32-P4-Function-EV-Board, please uncomment below
+#CONFIG_C6_SPI_WITH_P4=y
+
+
+# 8. Wifi config
+#----------------
+CONFIG_WIFI_CMD_BASIC_ONLY=y
+
+CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=10
+CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=32
+CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=32
+CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=y
+CONFIG_ESP_WIFI_TX_BA_WIN=16
+CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y
+CONFIG_ESP_WIFI_RX_BA_WIN=16
+
+CONFIG_ESP_WIFI_RX_IRAM_OPT=y
+CONFIG_ESP_WIFI_IRAM_OPT=y
+
+# 9. LWIP config
+#----------------
+CONFIG_LWIP_TCP_SND_BUF_DEFAULT=11520
+CONFIG_LWIP_TCP_WND_DEFAULT=11520
+CONFIG_LWIP_TCP_RECVMBOX_SIZE=16
+CONFIG_LWIP_UDP_RECVMBOX_SIZE=16
+CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32
+CONFIG_LWIP_TCP_SACK_OUT=y
+CONFIG_LWIP_TCPIP_CORE_LOCKING=y
+CONFIG_LWIP_TCPIP_CORE_LOCKING_INPUT=y
+
+# 10. Optimizations
+#-------------------
+CONFIG_COMPILER_OPTIMIZATION_PERF=y
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
+
+
+# 11. Stats
+#-----------
+#CONFIG_ESP_HOSTED_FUNCTION_PROFILING=y
+CONFIG_ESP_PKT_STATS=y
+
+# 12. Priorities
+----------------
+CONFIG_IPERF_TRAFFIC_TASK_PRIORITY=18
+CONFIG_IPERF_REPORT_TASK_PRIORITY=18
+CONFIG_ESP_DEFAULT_TASK_PRIO=18
+
+
+#13. Mem optimizations
+#---------------------
+CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32c6 b/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32c6
index 8e97a13b68..86f690f475 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32c6
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32c6
@@ -1,35 +1,108 @@
-CONFIG_SDIO_DAT2_DISABLED=
+# 1. CPU
+#--------
+CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y
-# BT Configuration
+# 2. BT Configuration
+#---------------------
CONFIG_BT_ENABLED=y
CONFIG_BT_CONTROLLER_ONLY=y
CONFIG_BT_BLUEDROID_ENABLED=
CONFIG_BT_LE_SLEEP_ENABLE=y
-# SPI/SDIO only
+# 3.1 BLE over SPI/SDIO
+#-----------------------
CONFIG_BT_LE_HCI_INTERFACE_USE_RAM=y
-# BLE over UART:
+# 3.2 BLE over UART
+#-------------------
# Enable below config, delete sdkconfig, build/ and rebuild
# CONFIG_BT_LE_HCI_INTERFACE_USE_UART=y
-CONFIG_BT_LE_HCI_UART_TX_PIN=5
-CONFIG_BT_LE_HCI_UART_RX_PIN=12
+# CONFIG_BT_LE_HCI_UART_TX_PIN=5
+# CONFIG_BT_LE_HCI_UART_RX_PIN=12
# CONFIG_BT_LE_HCI_UART_FLOWCTRL=n
# # 4 pin solution is not working yet for c6
# #CONFIG_BT_LE_HCI_UART_RTS_PIN=9
# #CONFIG_BT_LE_HCI_UART_CTS_PIN=13
+
+# 4. Partition Table
+#--------------------
+CONFIG_PARTITION_TABLE_CUSTOM=y
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.esp32c6.csv"
+
+# 5. Mempool
+#------------
CONFIG_ESP_CACHE_MALLOC=y
-CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=40
-CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=60
-CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=40
+
+
+# 6.1 LWIP split
+#---------------
+
+CONFIG_NETWORK_SPLIT_ENABLED=y
+CONFIG_LWIP_TCP_LOCAL_PORT_RANGE_START=61440
+CONFIG_LWIP_TCP_LOCAL_PORT_RANGE_END=65535
+CONFIG_LWIP_UDP_LOCAL_PORT_RANGE_START=61440
+CONFIG_LWIP_UDP_LOCAL_PORT_RANGE_END=65535
+
+CONFIG_ESP_DEFAULT_LWIP_SLAVE=y
+
+# 6.2 LWIP split examples
+#-------------------------
+#CONFIG_ESP_HOSTED_COPROCESSOR_EXAMPLE_MQTT=y
+
+
+# 7. Transport config
+#---------------------
+# CONFIG_ESP_SDIO_NSEND_PSAMPLE=y
+# CONFIG_ESP_SDIO_DEFAULT_SPEED=y
+#CONFIG_ESP_SDIO_STREAMING_MODE=y
+CONFIG_ESP_SDIO_HOST_INTERFACE=y
+
+# For SPI Full duplex C6 on ESP32-P4-Function-EV-Board, please uncomment below
+#CONFIG_ESP_HOST_DEV_BOARD_P4_FUNC_BOARD=y
+#CONFIG_ESP_SPI_HOST_INTERFACE=y
+
+
+# 8. Wifi config
+#----------------
+CONFIG_WIFI_CMD_BASIC_ONLY=y
+
+CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=20
+CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=64
+CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=64
CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=y
CONFIG_ESP_WIFI_TX_BA_WIN=32
CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y
CONFIG_ESP_WIFI_RX_BA_WIN=32
-CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS=n
-CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS=n
-# partitions
-CONFIG_PARTITION_TABLE_CUSTOM=y
-CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.esp32c6.csv"
+CONFIG_ESP_WIFI_RX_IRAM_OPT=y
+CONFIG_ESP_WIFI_IRAM_OPT=y
+
+# 9. LWIP config
+#----------------
+CONFIG_LWIP_TCP_SND_BUF_DEFAULT=65535
+CONFIG_LWIP_TCP_WND_DEFAULT=65535
+CONFIG_LWIP_TCP_RECVMBOX_SIZE=64
+CONFIG_LWIP_UDP_RECVMBOX_SIZE=64
+CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=64
+CONFIG_LWIP_TCP_SACK_OUT=y
+#CONFIG_LWIP_TCPIP_CORE_LOCKING=y
+#CONFIG_LWIP_TCPIP_CORE_LOCKING_INPUT=y
+
+
+# 10. Optimizations
+#-------------------
+CONFIG_COMPILER_OPTIMIZATION_PERF=y
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
+
+
+# 11. Stats
+#-----------
+#CONFIG_ESP_HOSTED_FUNCTION_PROFILING=y
+CONFIG_ESP_PKT_STATS=y
+
+# 12 iperf task
+#--------------
+CONFIG_IPERF_TRAFFIC_TASK_PRIORITY=17
+CONFIG_IPERF_REPORT_TASK_PRIORITY=17
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32s2 b/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32s2
new file mode 100644
index 0000000000..3150be8ec9
--- /dev/null
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32s2
@@ -0,0 +1,90 @@
+# 1. CPU
+#--------
+CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=240
+
+# 2. Partition Table
+#--------------------
+CONFIG_PARTITION_TABLE_CUSTOM=y
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.esp32s2.csv"
+
+# 3. Mempool
+#------------
+CONFIG_ESP_CACHE_MALLOC=y
+
+
+# 4.1 LWIP split
+#---------------
+
+CONFIG_NETWORK_SPLIT_ENABLED=y
+CONFIG_LWIP_TCP_LOCAL_PORT_RANGE_START=61440
+CONFIG_LWIP_TCP_LOCAL_PORT_RANGE_END=65535
+CONFIG_LWIP_UDP_LOCAL_PORT_RANGE_START=61440
+CONFIG_LWIP_UDP_LOCAL_PORT_RANGE_END=65535
+
+CONFIG_ESP_DEFAULT_LWIP_SLAVE=y
+
+# 4.2 LWIP split examples
+#-------------------------
+CONFIG_ESP_HOSTED_COPROCESSOR_EXAMPLE_MQTT=n
+
+
+# 5. Transport config
+#---------------------
+# CONFIG_ESP_SDIO_NSEND_PSAMPLE=y
+# CONFIG_ESP_SDIO_DEFAULT_SPEED=y
+# CONFIG_ESP_SDIO_STREAMING_MODE=n
+
+# For SPI Full duplex C6 on ESP32-P4-Function-EV-Board, please uncomment below
+#CONFIG_C6_SPI_WITH_P4=y
+
+
+# 6. Wifi config
+#----------------
+CONFIG_WIFI_CMD_BASIC_ONLY=y
+
+CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=10
+CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=32
+CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=32
+CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=y
+CONFIG_ESP_WIFI_TX_BA_WIN=16
+CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y
+CONFIG_ESP_WIFI_RX_BA_WIN=16
+
+CONFIG_ESP_WIFI_RX_IRAM_OPT=y
+CONFIG_ESP_WIFI_IRAM_OPT=y
+
+# 7. LWIP config
+#----------------
+CONFIG_LWIP_TCP_SND_BUF_DEFAULT=11520
+CONFIG_LWIP_TCP_WND_DEFAULT=11520
+CONFIG_LWIP_TCP_RECVMBOX_SIZE=16
+CONFIG_LWIP_UDP_RECVMBOX_SIZE=16
+CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32
+CONFIG_LWIP_TCP_SACK_OUT=y
+CONFIG_LWIP_TCPIP_CORE_LOCKING=y
+CONFIG_LWIP_TCPIP_CORE_LOCKING_INPUT=y
+
+
+# 8. Optimizations
+#-------------------
+CONFIG_COMPILER_OPTIMIZATION_PERF=y
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
+CONFIG_SPI_MASTER_ISR_IN_IRAM=n
+
+
+# 9. Stats
+#-----------
+#CONFIG_ESP_HOSTED_FUNCTION_PROFILING=y
+CONFIG_ESP_PKT_STATS=y
+
+# 10. Priorities
+----------------
+CONFIG_IPERF_TRAFFIC_TASK_PRIORITY=18
+CONFIG_IPERF_REPORT_TASK_PRIORITY=18
+CONFIG_ESP_DEFAULT_TASK_PRIO=18
+
+
+# 11. Mem optimizations
+#---------------------
+CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
diff --git a/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32s3 b/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32s3
index e137797c5c..ad86b5508a 100644
--- a/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32s3
+++ b/esp_hosted_fg/esp/esp_driver/network_adapter/sdkconfig.defaults.esp32s3
@@ -1,9 +1,112 @@
-#For battery sensitive usage, can reduce the CPU frequency
-CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
-CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240
+# 1. CPU
+#--------
+CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=240
-# BT Configuration
+# 2. BT Configuration
+#---------------------
CONFIG_BT_ENABLED=y
CONFIG_BT_CONTROLLER_ONLY=y
CONFIG_BT_BLUEDROID_ENABLED=
CONFIG_BT_LE_SLEEP_ENABLE=y
+
+# 3.1 BLE over SPI/SDIO
+#-----------------------
+CONFIG_BT_LE_HCI_INTERFACE_USE_RAM=y
+
+# 3.2 BLE over UART
+#-------------------
+# Enable below config, delete sdkconfig, build/ and rebuild
+# CONFIG_BT_LE_HCI_INTERFACE_USE_UART=y
+# CONFIG_BT_LE_HCI_UART_TX_PIN=5
+# CONFIG_BT_LE_HCI_UART_RX_PIN=18
+# CONFIG_BT_LE_HCI_UART_FLOWCTRL=n
+# #CONFIG_BT_LE_HCI_UART_RTS_PIN=19
+# #CONFIG_BT_LE_HCI_UART_CTS_PIN=8
+
+
+# 4. Partition Table
+#--------------------
+CONFIG_PARTITION_TABLE_CUSTOM=y
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.esp32s3.csv"
+
+# 5. Mempool
+#------------
+CONFIG_ESP_CACHE_MALLOC=y
+
+
+# 6.1 LWIP split
+#---------------
+
+CONFIG_NETWORK_SPLIT_ENABLED=y
+CONFIG_LWIP_TCP_LOCAL_PORT_RANGE_START=61440
+CONFIG_LWIP_TCP_LOCAL_PORT_RANGE_END=65535
+CONFIG_LWIP_UDP_LOCAL_PORT_RANGE_START=61440
+CONFIG_LWIP_UDP_LOCAL_PORT_RANGE_END=65535
+
+CONFIG_ESP_DEFAULT_LWIP_SLAVE=y
+
+# 6.2 LWIP split examples
+#-------------------------
+CONFIG_ESP_HOSTED_COPROCESSOR_EXAMPLE_MQTT=n
+
+
+# 7. Transport config
+#---------------------
+# CONFIG_ESP_SDIO_NSEND_PSAMPLE=y
+# CONFIG_ESP_SDIO_DEFAULT_SPEED=y
+# CONFIG_ESP_SDIO_STREAMING_MODE=n
+
+# For SPI Full duplex C6 on ESP32-P4-Function-EV-Board, please uncomment below
+#CONFIG_C6_SPI_WITH_P4=y
+
+
+# 8. Wifi config
+#----------------
+CONFIG_WIFI_CMD_BASIC_ONLY=y
+
+CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=10
+CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=32
+CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=32
+CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=y
+CONFIG_ESP_WIFI_TX_BA_WIN=16
+CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y
+CONFIG_ESP_WIFI_RX_BA_WIN=16
+
+CONFIG_ESP_WIFI_RX_IRAM_OPT=y
+CONFIG_ESP_WIFI_IRAM_OPT=y
+
+# 9. LWIP config
+#----------------
+CONFIG_LWIP_TCP_SND_BUF_DEFAULT=11520
+CONFIG_LWIP_TCP_WND_DEFAULT=11520
+CONFIG_LWIP_TCP_RECVMBOX_SIZE=16
+CONFIG_LWIP_UDP_RECVMBOX_SIZE=16
+CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32
+CONFIG_LWIP_TCP_SACK_OUT=y
+CONFIG_LWIP_TCPIP_CORE_LOCKING=y
+CONFIG_LWIP_TCPIP_CORE_LOCKING_INPUT=y
+
+
+# 10. Optimizations
+#-------------------
+CONFIG_COMPILER_OPTIMIZATION_PERF=y
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
+CONFIG_SPI_MASTER_ISR_IN_IRAM=n
+
+
+# 11. Stats
+#-----------
+#CONFIG_ESP_HOSTED_FUNCTION_PROFILING=y
+CONFIG_ESP_PKT_STATS=y
+
+# 12. Priorities
+----------------
+CONFIG_IPERF_TRAFFIC_TASK_PRIORITY=18
+CONFIG_IPERF_REPORT_TASK_PRIORITY=18
+CONFIG_ESP_DEFAULT_TASK_PRIO=18
+
+
+#13. Mem optimizations
+#---------------------
+CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
diff --git a/esp_hosted_fg/host/control_lib/Makefile b/esp_hosted_fg/host/control_lib/Makefile
new file mode 100644
index 0000000000..7948b8a227
--- /dev/null
+++ b/esp_hosted_fg/host/control_lib/Makefile
@@ -0,0 +1,63 @@
+CC = gcc
+
+# Compiler and linker flags
+CROSS_COMPILE :=
+CFLAGS = -Wall -g -fPIC
+LDFLAGS = -lpthread -lrt
+
+# Directory paths
+DIR_ROOT = $(CURDIR)/../..
+DIR_COMMON = $(DIR_ROOT)/common
+DIR_COMPONENTS = $(DIR_ROOT)/host/components
+DIR_SERIAL = $(DIR_ROOT)/host/virtual_serial_if
+DIR_LINUX_PORT = $(DIR_ROOT)/host/linux/port
+DIR_CONTROL_LIB = $(DIR_ROOT)/host/control_lib
+
+# Include paths
+INCLUDE += -I$(DIR_COMMON)/protobuf-c
+INCLUDE += -I$(DIR_COMMON)/include
+INCLUDE += -I$(DIR_CONTROL_LIB)/include
+INCLUDE += -I$(DIR_CONTROL_LIB)/src/include
+INCLUDE += -I$(DIR_SERIAL)/include
+INCLUDE += -I$(DIR_COMPONENTS)/include
+INCLUDE += -I$(DIR_LINUX_PORT)/include
+
+# Source files for the core library
+CORE_SRC = $(DIR_COMMON)/protobuf-c/protobuf-c/protobuf-c.c
+CORE_SRC += $(DIR_COMMON)/esp_hosted_config.pb-c.c
+CORE_SRC += $(DIR_CONTROL_LIB)/src/ctrl_core.c
+CORE_SRC += $(DIR_CONTROL_LIB)/src/ctrl_api.c
+CORE_SRC += $(DIR_SERIAL)/src/serial_if.c
+CORE_SRC += $(DIR_COMPONENTS)/src/esp_queue.c
+CORE_SRC += $(DIR_LINUX_PORT)/src/platform_wrapper.c
+
+# Target library
+LIBCONTROL = libesp_hosted_rpc.so
+LIBCONTROL_STATIC = libesp_hosted_rpc.a
+
+.PHONY: all clean shared static
+
+all: shared static
+
+shared: $(LIBCONTROL)
+
+static: $(LIBCONTROL_STATIC)
+
+# Build the shared library
+$(LIBCONTROL): $(CORE_SRC)
+ $(CROSS_COMPILE)$(CC) $(CFLAGS) $(INCLUDE) -shared -o $@ $^ $(LDFLAGS)
+
+# Build the static library
+$(LIBCONTROL_STATIC): $(CORE_SRC:.c=.o)
+ ar rcs $@ $^
+
+%.o: %.c
+ $(CROSS_COMPILE)$(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
+
+install: all
+ @mkdir -p $(DIR_ROOT)/lib
+ @cp -f $(LIBCONTROL) $(LIBCONTROL_STATIC) $(DIR_ROOT)/lib/
+
+clean:
+ rm -f $(LIBCONTROL) $(LIBCONTROL_STATIC) $(CORE_SRC:.c=.o)
+
diff --git a/esp_hosted_fg/host/control_lib/include/ctrl_api.h b/esp_hosted_fg/host/control_lib/include/ctrl_api.h
index 8626886134..d549775eb5 100644
--- a/esp_hosted_fg/host/control_lib/include/ctrl_api.h
+++ b/esp_hosted_fg/host/control_lib/include/ctrl_api.h
@@ -34,10 +34,10 @@
* another request is pending, time period for
* which new request will wait in seconds
* */
-#define WAIT_TIME_B2B_CTRL_REQ 5
-#define DEFAULT_CTRL_RESP_TIMEOUT 30
+#define WAIT_TIME_B2B_CTRL_REQ 3
+#define DEFAULT_CTRL_RESP_TIMEOUT 5
#define DEFAULT_CTRL_RESP_AP_SCAN_TIMEOUT (60*3)
-#define DEFAULT_CTRL_RESP_CONNECT_AP_TIMEOUT (15*3)
+#define DEFAULT_CTRL_RESP_CONNECT_AP_TIMEOUT (10)
#ifndef MAC2STR
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
@@ -48,6 +48,20 @@
#define FAILURE_STR "failure"
#define NOT_CONNECTED_STR "not_connected"
+
+#define CLEANUP_CTRL_MSG(msg) do { \
+ if (msg) { \
+ if (msg->free_buffer_handle) { \
+ if (msg->free_buffer_func) { \
+ msg->free_buffer_func(msg->free_buffer_handle); \
+ msg->free_buffer_handle = NULL; \
+ } \
+ } \
+ free(msg); \
+ msg = NULL; \
+ } \
+} while(0);
+
/*---- Control structures ----*/
enum {
@@ -120,6 +134,11 @@ typedef enum {
CTRL_REQ_SET_COUNTRY_CODE = CTRL_MSG_ID__Req_SetCountryCode, //0x7c
CTRL_REQ_GET_COUNTRY_CODE = CTRL_MSG_ID__Req_GetCountryCode, //0x7d
+ CTRL_REQ_SET_DHCP_DNS_STATUS = CTRL_MSG_ID__Req_SetDhcpDnsStatus,
+ CTRL_REQ_GET_DHCP_DNS_STATUS = CTRL_MSG_ID__Req_GetDhcpDnsStatus,
+
+ CTRL_REQ_CUSTOM_RPC_UNSERIALISED_MSG = CTRL_MSG_ID__Req_Custom_RPC_Unserialised_Msg,
+
/*
* Add new control path command response before Req_Max
* and update Req_Max
@@ -162,8 +181,13 @@ typedef enum {
CTRL_RESP_SET_COUNTRY_CODE = CTRL_MSG_ID__Resp_SetCountryCode, //0x7c -> 0xe0
CTRL_RESP_GET_COUNTRY_CODE = CTRL_MSG_ID__Resp_GetCountryCode, //0x7d -> 0xe1
+
+ CTRL_RESP_SET_DHCP_DNS_STATUS = CTRL_MSG_ID__Resp_SetDhcpDnsStatus,
+ CTRL_RESP_GET_DHCP_DNS_STATUS = CTRL_MSG_ID__Resp_GetDhcpDnsStatus,
+
+ CTRL_RESP_CUSTOM_RPC_UNSERIALISED_MSG = CTRL_MSG_ID__Resp_Custom_RPC_Unserialised_Msg,
/*
- * Add new control path comm and response before Resp_Max
+ * Add new control path command and response before Resp_Max
* and update Resp_Max
*/
CTRL_RESP_MAX = CTRL_MSG_ID__Resp_Max,
@@ -181,6 +205,10 @@ typedef enum {
CTRL_MSG_ID__Event_StationConnectedToAP,
CTRL_EVENT_STATION_CONNECTED_TO_ESP_SOFTAP =
CTRL_MSG_ID__Event_StationConnectedToESPSoftAP,
+ CTRL_EVENT_DHCP_DNS_STATUS =
+ CTRL_MSG_ID__Event_SetDhcpDnsStatus,
+ CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG =
+ CTRL_MSG_ID__Event_Custom_RPC_Unserialised_Msg,
/*
* Add new control path command notification before Event_Max
* and update Event_Max
@@ -214,6 +242,7 @@ typedef enum {
} wifi_bandwidth_e;
typedef enum {
+ WIFI_PS_NONE = CTRL__WIFI_POWER_SAVE__NO_PS,
WIFI_PS_MIN_MODEM = CTRL__WIFI_POWER_SAVE__MIN_MODEM,
WIFI_PS_MAX_MODEM = CTRL__WIFI_POWER_SAVE__MAX_MODEM,
WIFI_PS_INVALID,
@@ -236,6 +265,7 @@ typedef enum {
enum hosted_features_t {
HOSTED_WIFI = HOSTED_FEATURE__Hosted_Wifi,
HOSTED_BT = HOSTED_FEATURE__Hosted_Bluetooth,
+ HOSTED_IS_NETWORK_SPLIT_ON = HOSTED_FEATURE__Hosted_Is_Network_Split_On,
};
typedef struct {
@@ -392,6 +422,27 @@ typedef struct {
uint32_t reason;
} event_softap_sta_disconn_t;
+typedef struct {
+ int iface;
+ int net_link_up;
+ int dhcp_up;
+ uint8_t dhcp_ip[64];
+ uint8_t dhcp_nm[64];
+ uint8_t dhcp_gw[64];
+ int dns_up;
+ uint8_t dns_ip[64];
+ int dns_type;
+} dhcp_dns_status_t;
+
+typedef void (*custom_data_free_func_t)(void *data);
+
+typedef struct {
+ uint32_t custom_msg_id;
+ uint16_t data_len;
+ custom_data_free_func_t free_func;
+ uint8_t *data;
+} custom_rpc_unserialised_data_t;
+
typedef struct Ctrl_cmd_t {
/* msg type could be 1. req 2. resp 3. notification */
uint8_t msg_type;
@@ -434,6 +485,8 @@ typedef struct Ctrl_cmd_t {
event_sta_disconn_t e_sta_disconn;
event_softap_sta_conn_t e_softap_sta_conn;
event_softap_sta_disconn_t e_softap_sta_disconn;
+ dhcp_dns_status_t dhcp_dns_status;
+ custom_rpc_unserialised_data_t custom_rpc_unserialised_data;
}u;
/* By default this callback is set to NULL.
@@ -499,6 +552,15 @@ typedef int (*ctrl_event_cb_t) (ctrl_cmd_t * event);
**/
int set_event_callback(int event, ctrl_resp_cb_t event_cb);
+
+/* Get control event callback
+ *
+ * Returns:
+ * > NULL - If event is not registered with hosted control lib
+ * > Function pointer - Returns the registered event callback
+ **/
+ctrl_resp_cb_t get_event_callback(int event);
+
/* Reset control event callback
*
* when user sets event callback, user provided function pointer
@@ -539,103 +601,97 @@ int init_hosted_control_lib(void);
int deinit_hosted_control_lib(void);
/* Get the MAC address of station or softAP interface of ESP32 */
-ctrl_cmd_t * wifi_get_mac(ctrl_cmd_t req);
+ctrl_cmd_t * wifi_get_mac(ctrl_cmd_t *req);
/* Set MAC address of ESP32 interface for given wifi mode */
-ctrl_cmd_t * wifi_set_mac(ctrl_cmd_t req);
+ctrl_cmd_t * wifi_set_mac(ctrl_cmd_t *req);
/* Get Wi-Fi mode of ESP32 */
-ctrl_cmd_t * wifi_get_mode(ctrl_cmd_t req);
+ctrl_cmd_t * wifi_get_mode(ctrl_cmd_t *req);
/* Set the Wi-Fi mode of ESP32 */
-ctrl_cmd_t * wifi_set_mode(ctrl_cmd_t req);
+ctrl_cmd_t * wifi_set_mode(ctrl_cmd_t *req);
/* Set Wi-Fi power save mode of ESP32 */
-ctrl_cmd_t * wifi_set_power_save_mode(ctrl_cmd_t req);
+ctrl_cmd_t * wifi_set_power_save_mode(ctrl_cmd_t *req);
/* Get the Wi-Fi power save mode of ESP32 */
-ctrl_cmd_t * wifi_get_power_save_mode(ctrl_cmd_t req);
+ctrl_cmd_t * wifi_get_power_save_mode(ctrl_cmd_t *req);
/* Get list of available neighboring APs of ESP32 */
-ctrl_cmd_t * wifi_ap_scan_list(ctrl_cmd_t req);
+ctrl_cmd_t * wifi_ap_scan_list(ctrl_cmd_t *req);
/* Get the AP config to which ESP32 station is connected */
-ctrl_cmd_t * wifi_get_ap_config(ctrl_cmd_t req);
+ctrl_cmd_t * wifi_get_ap_config(ctrl_cmd_t *req);
/* Set the AP config to which ESP32 station should connect to */
-ctrl_cmd_t * wifi_connect_ap(ctrl_cmd_t req);
+ctrl_cmd_t * wifi_connect_ap(ctrl_cmd_t *req);
/* Disconnect ESP32 station from AP */
-ctrl_cmd_t * wifi_disconnect_ap(ctrl_cmd_t req);
+ctrl_cmd_t * wifi_disconnect_ap(ctrl_cmd_t *req);
/* Set configuration of ESP32 softAP and start broadcasting */
-ctrl_cmd_t * wifi_start_softap(ctrl_cmd_t req);
+ctrl_cmd_t * wifi_start_softap(ctrl_cmd_t *req);
/* Get configuration of ESP32 softAP */
-ctrl_cmd_t * wifi_get_softap_config(ctrl_cmd_t req);
+ctrl_cmd_t * wifi_get_softap_config(ctrl_cmd_t *req);
/* Stop ESP32 softAP */
-ctrl_cmd_t * wifi_stop_softap(ctrl_cmd_t req);
+ctrl_cmd_t * wifi_stop_softap(ctrl_cmd_t *req);
/* Get list of connected stations to ESP32 softAP */
-ctrl_cmd_t * wifi_get_softap_connected_station_list(ctrl_cmd_t req);
+ctrl_cmd_t * wifi_get_softap_connected_station_list(ctrl_cmd_t *req);
/* Function set 802.11 Vendor-Specific Information Element.
* It needs to get called before starting of ESP32 softAP */
-ctrl_cmd_t * wifi_set_vendor_specific_ie(ctrl_cmd_t req);
+ctrl_cmd_t * wifi_set_vendor_specific_ie(ctrl_cmd_t *req);
/* Sets maximum WiFi transmitting power at ESP32 */
-ctrl_cmd_t * wifi_set_max_tx_power(ctrl_cmd_t req);
+ctrl_cmd_t * wifi_set_max_tx_power(ctrl_cmd_t *req);
/* Gets current WiFi transmiting power at ESP32 */
-ctrl_cmd_t * wifi_get_curr_tx_power(ctrl_cmd_t req);
+ctrl_cmd_t * wifi_get_curr_tx_power(ctrl_cmd_t *req);
/* Sets the Country Code */
-ctrl_cmd_t * wifi_set_country_code(ctrl_cmd_t req);
+ctrl_cmd_t * wifi_set_country_code(ctrl_cmd_t *req);
/* Gets the Country Code */
-ctrl_cmd_t * wifi_get_country_code(ctrl_cmd_t req);
+ctrl_cmd_t * wifi_get_country_code(ctrl_cmd_t *req);
/* Configure heartbeat event. Be default heartbeat is not enabled.
* To enable heartbeats, user need to use this API in addition
* to setting event callback for heartbeat event */
-ctrl_cmd_t * config_heartbeat(ctrl_cmd_t req);
+ctrl_cmd_t * config_heartbeat(ctrl_cmd_t *req);
/* Performs an OTA begin operation for ESP32 which erases and
* prepares existing flash partition for new flash writing */
-ctrl_cmd_t * ota_begin(ctrl_cmd_t req);
+ctrl_cmd_t * ota_begin(ctrl_cmd_t *req);
/* Performs an OTA write operation for ESP32, It writes bytes from `ota_data`
* buffer with `ota_data_len` number of bytes to OTA partition in flash. Number
* of bytes can be small than size of complete binary to be flashed. In that
* case, this caller is expected to repeatedly call this function till
- * total size written equals size of complete binary */
-ctrl_cmd_t * ota_write(ctrl_cmd_t req);
+ * total size written equals size of complete binary to be flashed */
+ctrl_cmd_t * ota_write(ctrl_cmd_t *req);
/* Performs an OTA end operation for ESP32, It validates written OTA image,
* sets newly written OTA partition as boot partition for next boot,
* Creates timer which reset ESP32 after 5 sec */
-ctrl_cmd_t * ota_end(ctrl_cmd_t req);
+ctrl_cmd_t * ota_end(ctrl_cmd_t *req);
/* Enable or disable specific feautures from hosted_features_t */
-ctrl_cmd_t * feature_config(ctrl_cmd_t req);
+ctrl_cmd_t * feature_config(ctrl_cmd_t *req);
/* Get FW Version */
-ctrl_cmd_t * get_fw_version(ctrl_cmd_t req);
-
-/* Get the interface up for interface `iface` */
-int interface_up(int sockfd, char* iface);
-
-/* Get the interface down for interface `iface` */
-int interface_down(int sockfd, char* iface);
+ctrl_cmd_t * get_fw_version(ctrl_cmd_t *req);
-/* Set ethernet interface MAC address `mac` to interface `iface` */
-int set_hw_addr(int sockfd, char* iface, char* mac);
+/* Get DHCP DNS status */
+ctrl_cmd_t * get_dhcp_dns_status(ctrl_cmd_t *req);
-/* Create an endpoint for communication */
-int create_socket(int domain, int type, int protocol, int *sock);
+/* Set DHCP DNS status */
+ctrl_cmd_t * set_dhcp_dns_status(ctrl_cmd_t *req);
-/* Close an endpoint of the communication */
-int close_socket(int sock);
+/* Send custom RPC unserialised message */
+ctrl_cmd_t * send_custom_rpc_unserialised_req_to_slave(ctrl_cmd_t *req);
#endif
diff --git a/esp_hosted_fg/host/control_lib/src/ctrl_api.c b/esp_hosted_fg/host/control_lib/src/ctrl_api.c
index 4b1a380f52..4777c4cd9e 100644
--- a/esp_hosted_fg/host/control_lib/src/ctrl_api.c
+++ b/esp_hosted_fg/host/control_lib/src/ctrl_api.c
@@ -6,19 +6,21 @@
*/
#include "ctrl_api.h"
#include "ctrl_core.h"
-
-#define CTRL_SEND_REQ(msGiD) do { \
- req.msg_id = msGiD; \
- if(SUCCESS != ctrl_app_send_req(&req)) { \
- printf("Failed to send control req %u\n", req.msg_id); \
- return NULL; \
- } \
+#include
+
+#define CTRL_SEND_REQ(msGiD) do { \
+ req->msg_id = msGiD; \
+ if(SUCCESS != ctrl_app_send_req(req)) { \
+ printf("RPC req [%u] Failed to send\n", req->msg_id); \
+ return NULL; \
+ } \
} while(0);
#define CTRL_DECODE_RESP_IF_NOT_ASYNC() do { \
- if (CALLBACK_AVAILABLE == is_async_resp_callback_registered(req)) \
+ if (CALLBACK_AVAILABLE == is_async_resp_callback_registered(req)) { \
return NULL; \
- return ctrl_wait_and_parse_sync_resp(&req); \
+ } \
+ return ctrl_wait_and_parse_sync_resp(req); \
} while(0);
extern int init_hosted_control_lib_internal(void);
@@ -36,152 +38,171 @@ int deinit_hosted_control_lib(void)
}
/** Control Req->Resp APIs **/
-ctrl_cmd_t * wifi_get_mac(ctrl_cmd_t req)
+ctrl_cmd_t * wifi_get_mac(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_GET_MAC_ADDR);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * wifi_set_mac(ctrl_cmd_t req)
+ctrl_cmd_t * wifi_set_mac(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_SET_MAC_ADDR);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * wifi_get_mode(ctrl_cmd_t req)
+ctrl_cmd_t * wifi_get_mode(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_GET_WIFI_MODE);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * wifi_set_mode(ctrl_cmd_t req)
+ctrl_cmd_t * wifi_set_mode(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_SET_WIFI_MODE);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * wifi_set_power_save_mode(ctrl_cmd_t req)
+ctrl_cmd_t * wifi_set_power_save_mode(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_SET_PS_MODE);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * wifi_get_power_save_mode(ctrl_cmd_t req)
+ctrl_cmd_t * wifi_get_power_save_mode(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_GET_PS_MODE);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * wifi_ap_scan_list(ctrl_cmd_t req)
+ctrl_cmd_t * wifi_ap_scan_list(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_GET_AP_SCAN_LIST);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * wifi_get_ap_config(ctrl_cmd_t req)
+ctrl_cmd_t * wifi_get_ap_config(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_GET_AP_CONFIG);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * wifi_connect_ap(ctrl_cmd_t req)
+ctrl_cmd_t * wifi_connect_ap(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_CONNECT_AP);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * wifi_disconnect_ap(ctrl_cmd_t req)
+ctrl_cmd_t * wifi_disconnect_ap(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_DISCONNECT_AP);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * wifi_start_softap(ctrl_cmd_t req)
+ctrl_cmd_t * wifi_start_softap(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_START_SOFTAP);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * wifi_get_softap_config(ctrl_cmd_t req)
+ctrl_cmd_t * wifi_get_softap_config(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_GET_SOFTAP_CONFIG);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * wifi_stop_softap(ctrl_cmd_t req)
+ctrl_cmd_t * wifi_stop_softap(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_STOP_SOFTAP);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * wifi_get_softap_connected_station_list(ctrl_cmd_t req)
+ctrl_cmd_t * wifi_get_softap_connected_station_list(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_GET_SOFTAP_CONN_STA_LIST);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * wifi_set_vendor_specific_ie(ctrl_cmd_t req)
+ctrl_cmd_t * wifi_set_vendor_specific_ie(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_SET_SOFTAP_VND_IE);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * wifi_set_max_tx_power(ctrl_cmd_t req)
+ctrl_cmd_t * wifi_set_max_tx_power(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_SET_WIFI_MAX_TX_POWER);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * wifi_get_curr_tx_power(ctrl_cmd_t req)
+ctrl_cmd_t * wifi_get_curr_tx_power(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_GET_WIFI_CURR_TX_POWER);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * wifi_set_country_code(ctrl_cmd_t req)
+ctrl_cmd_t * wifi_set_country_code(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_SET_COUNTRY_CODE);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * wifi_get_country_code(ctrl_cmd_t req)
+ctrl_cmd_t * wifi_get_country_code(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_GET_COUNTRY_CODE);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * config_heartbeat(ctrl_cmd_t req)
+ctrl_cmd_t * config_heartbeat(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_CONFIG_HEARTBEAT);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * ota_begin(ctrl_cmd_t req)
+ctrl_cmd_t * ota_begin(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_OTA_BEGIN);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * ota_write(ctrl_cmd_t req)
+ctrl_cmd_t * ota_write(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_OTA_WRITE);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * ota_end(ctrl_cmd_t req)
+ctrl_cmd_t * ota_end(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_OTA_END);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * feature_config(ctrl_cmd_t req)
+ctrl_cmd_t * feature_config(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_ENABLE_DISABLE);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
-ctrl_cmd_t * get_fw_version(ctrl_cmd_t req)
+ctrl_cmd_t * get_fw_version(ctrl_cmd_t *req)
{
CTRL_SEND_REQ(CTRL_REQ_GET_FW_VERSION);
CTRL_DECODE_RESP_IF_NOT_ASYNC();
}
+
+ctrl_cmd_t * get_dhcp_dns_status(ctrl_cmd_t *req)
+{
+ CTRL_SEND_REQ(CTRL_REQ_GET_DHCP_DNS_STATUS);
+ CTRL_DECODE_RESP_IF_NOT_ASYNC();
+}
+
+ctrl_cmd_t * set_dhcp_dns_status(ctrl_cmd_t *req)
+{
+ CTRL_SEND_REQ(CTRL_REQ_SET_DHCP_DNS_STATUS);
+ CTRL_DECODE_RESP_IF_NOT_ASYNC();
+}
+
+ctrl_cmd_t * send_custom_rpc_unserialised_req_to_slave(ctrl_cmd_t *req)
+{
+ CTRL_SEND_REQ(CTRL_REQ_CUSTOM_RPC_UNSERIALISED_MSG);
+ CTRL_DECODE_RESP_IF_NOT_ASYNC();
+}
+
diff --git a/esp_hosted_fg/host/control_lib/src/ctrl_core.c b/esp_hosted_fg/host/control_lib/src/ctrl_core.c
index bcb75a401b..93a8d12afc 100644
--- a/esp_hosted_fg/host/control_lib/src/ctrl_core.c
+++ b/esp_hosted_fg/host/control_lib/src/ctrl_core.c
@@ -4,25 +4,26 @@
#include
#include
#include
+#include
#include "ctrl_core.h"
#include "serial_if.h"
#include "platform_wrapper.h"
#include "esp_queue.h"
#include
+#include
+#include
+#include
#ifdef MCU_SYS
#include "common.h"
#define command_log(...) printf(__VA_ARGS__); printf("\r");
#else
-#define command_log(...) printf("%s:%u ",__func__,__LINE__); \
- printf(__VA_ARGS__);
+#define command_log(...) do { printf("%s:%u ",__func__,__LINE__); printf(__VA_ARGS__); } while(0)
#define min(X, Y) (((X) < (Y)) ? (X) : (Y))
#endif
-#ifndef MCU_SYS
-#define MAX_INTERFACE_LEN IFNAMSIZ
-#define MAC_SIZE_BYTES 6
-#define MIN_MAC_STR_LEN 17
+#ifndef MIN_MAC_STR_LEN
+#define MIN_MAC_STR_LEN 18 /* Minimum length of a MAC address string (xx:xx:xx:xx:xx:xx) */
#endif
#define SUCCESS 0
@@ -68,12 +69,14 @@
}
#define CHECK_CTRL_MSG_FAILED(msGparaM) \
- app_resp->resp_event_status = ctrl_msg->msGparaM->resp; \
+ app_resp->resp_event_status = ctrl_msg->msGparaM->resp; \
if (ctrl_msg->msGparaM->resp) { \
- command_log("Failure[%d] resp/event: possibly precondition not met\n", (int)app_resp->resp_event_status); \
+ command_log("Failed resp/event id[%d]: err[%d]\n", \
+ (int)ctrl_msg->msg_id, (int)ctrl_msg->msGparaM->resp); \
goto fail_parse_ctrl_msg; \
}
+
#define CTRL_ALLOC_ASSIGN(TyPe,MsG_StRuCt) \
TyPe *req_payload = (TyPe *) \
hosted_calloc(1, sizeof(TyPe)); \
@@ -168,50 +171,6 @@ static inline int is_ctrl_lib_state(int state)
}
-#ifndef MCU_SYS
- /* Function converts mac string to byte stream */
-static int convert_mac_to_bytes(uint8_t *out, size_t out_size, char *s)
-{
- int mac[MAC_SIZE_BYTES] = {0};
- int num_bytes = 0;
- if (!s || (strlen(s) < MIN_MAC_STR_LEN) || (out_size < MAC_SIZE_BYTES)) {
- if (!s) {
- command_log("empty input mac str\n");
- } else if (strlen(s) 0xFF) ||
- (mac[1] > 0xFF) ||
- (mac[2] > 0xFF) ||
- (mac[3] > 0xFF) ||
- (mac[4] > 0xFF) ||
- (mac[5] > 0xFF)) {
- command_log("failed\n");
- return FAILURE;
- }
-
- out[0] = mac[0]&0xff;
- out[1] = mac[1]&0xff;
- out[2] = mac[2]&0xff;
- out[3] = mac[3]&0xff;
- out[4] = mac[4]&0xff;
- out[5] = mac[5]&0xff;
- return SUCCESS;
-}
-#endif
-
-
/* This will copy control event from `CtrlMsg` into
* application structure `ctrl_cmd_t`
@@ -222,7 +181,7 @@ static int convert_mac_to_bytes(uint8_t *out, size_t out_size, char *s)
static int ctrl_app_parse_event(CtrlMsg *ctrl_msg, ctrl_cmd_t *app_ntfy)
{
if (!ctrl_msg || !app_ntfy) {
- printf("NULL Ctrl event or App struct\n");
+ command_log("NULL Ctrl event or App struct\n");
goto fail_parse_ctrl_msg;
}
@@ -233,28 +192,31 @@ static int ctrl_app_parse_event(CtrlMsg *ctrl_msg, ctrl_cmd_t *app_ntfy)
switch (ctrl_msg->msg_id) {
case CTRL_EVENT_ESP_INIT: {
app_ntfy->resp_event_status = SUCCESS;
- /*printf("EVENT: ESP INIT\n");*/
+ //command_log("EVENT: ESP INIT\n");
break;
} case CTRL_EVENT_HEARTBEAT: {
- /*printf("EVENT: Heartbeat\n");*/
+ //command_log("EVENT: Heartbeat\n");
app_ntfy->resp_event_status = SUCCESS;
CHECK_CTRL_MSG_NON_NULL(event_heartbeat);
app_ntfy->u.e_heartbeat.hb_num = ctrl_msg->event_heartbeat->hb_num;
break;
} case CTRL_EVENT_STATION_CONNECTED_TO_AP: {
CHECK_CTRL_MSG_NON_NULL(event_station_connected_to_ap);
- /*printf("EVENT: Station mode: Disconnect with reason [%u]\n",
- ctrl_msg->event_station_connected_to_ap->resp);*/
app_ntfy->resp_event_status = ctrl_msg->event_station_connected_to_ap->resp;
if(SUCCESS==app_ntfy->resp_event_status) {
- strncpy((char *)app_ntfy->u.e_sta_conn.ssid,
+ if (ctrl_msg->event_station_connected_to_ap->ssid.len && ctrl_msg->event_station_connected_to_ap->ssid.data) {
+ strncpy((char *)app_ntfy->u.e_sta_conn.ssid,
(char *)ctrl_msg->event_station_connected_to_ap->ssid.data,
ctrl_msg->event_station_connected_to_ap->ssid.len);
+ }
app_ntfy->u.e_sta_conn.ssid_len = ctrl_msg->event_station_connected_to_ap->ssid_len;
+ //command_log("EVENT: Station mode: Connected to AP SSID[%s] len[%d]\n", app_ntfy->u.e_sta_conn.ssid, app_ntfy->u.e_sta_conn.ssid_len);
- strncpy((char *)app_ntfy->u.e_sta_conn.bssid,
- (char *)ctrl_msg->event_station_connected_to_ap->bssid.data,
- ctrl_msg->event_station_connected_to_ap->bssid.len);
+ if (ctrl_msg->event_station_connected_to_ap->bssid.len && ctrl_msg->event_station_connected_to_ap->bssid.data) {
+ strncpy((char *)app_ntfy->u.e_sta_conn.bssid,
+ (char *)ctrl_msg->event_station_connected_to_ap->bssid.data,
+ ctrl_msg->event_station_connected_to_ap->bssid.len);
+ }
app_ntfy->u.e_sta_conn.channel = ctrl_msg->event_station_connected_to_ap->channel;
app_ntfy->u.e_sta_conn.authmode = ctrl_msg->event_station_connected_to_ap->authmode;
@@ -263,18 +225,22 @@ static int ctrl_app_parse_event(CtrlMsg *ctrl_msg, ctrl_cmd_t *app_ntfy)
break;
} case CTRL_EVENT_STATION_DISCONNECT_FROM_AP: {
CHECK_CTRL_MSG_NON_NULL(event_station_disconnect_from_ap);
- /*printf("EVENT: Station mode: Disconnect with reason [%u]\n",
- ctrl_msg->event_station_disconnect_from_ap->resp);*/
+ //command_log("EVENT: Station mode: Disconnect with reason [%u]\n",
+ // ctrl_msg->event_station_disconnect_from_ap->resp);
app_ntfy->resp_event_status = ctrl_msg->event_station_disconnect_from_ap->resp;
if(SUCCESS==app_ntfy->resp_event_status) {
- strncpy((char *)app_ntfy->u.e_sta_disconn.ssid,
- (char *)ctrl_msg->event_station_disconnect_from_ap->ssid.data,
- ctrl_msg->event_station_disconnect_from_ap->ssid.len);
+ if (ctrl_msg->event_station_disconnect_from_ap->ssid.len && ctrl_msg->event_station_disconnect_from_ap->ssid.data) {
+ strncpy((char *)app_ntfy->u.e_sta_disconn.ssid,
+ (char *)ctrl_msg->event_station_disconnect_from_ap->ssid.data,
+ ctrl_msg->event_station_disconnect_from_ap->ssid.len);
+ }
app_ntfy->u.e_sta_disconn.ssid_len = ctrl_msg->event_station_disconnect_from_ap->ssid_len;
- strncpy((char *)app_ntfy->u.e_sta_disconn.bssid,
- (char *)ctrl_msg->event_station_disconnect_from_ap->bssid.data,
- ctrl_msg->event_station_disconnect_from_ap->bssid.len);
+ if (ctrl_msg->event_station_disconnect_from_ap->bssid.len && ctrl_msg->event_station_disconnect_from_ap->bssid.data) {
+ strncpy((char *)app_ntfy->u.e_sta_disconn.bssid,
+ (char *)ctrl_msg->event_station_disconnect_from_ap->bssid.data,
+ ctrl_msg->event_station_disconnect_from_ap->bssid.len);
+ }
app_ntfy->u.e_sta_disconn.reason = ctrl_msg->event_station_disconnect_from_ap->reason;
app_ntfy->u.e_sta_disconn.rssi = ctrl_msg->event_station_disconnect_from_ap->rssi;
@@ -289,11 +255,13 @@ static int ctrl_app_parse_event(CtrlMsg *ctrl_msg, ctrl_cmd_t *app_ntfy)
CHECK_CTRL_MSG_NON_NULL_VAL(
ctrl_msg->event_station_connected_to_esp_softap->mac.data,
"NULL mac");
- strncpy((char *)app_ntfy->u.e_softap_sta_conn.mac,
- (char *)ctrl_msg->event_station_connected_to_esp_softap->mac.data,
- ctrl_msg->event_station_connected_to_esp_softap->mac.len);
- /*printf("EVENT: SoftAP mode: Disconnect MAC[%s]\n",
- app_ntfy->u.e_softap_sta_conn.mac);*/
+ if (ctrl_msg->event_station_connected_to_esp_softap->mac.len && ctrl_msg->event_station_connected_to_esp_softap->mac.data) {
+ strncpy((char *)app_ntfy->u.e_softap_sta_conn.mac,
+ (char *)ctrl_msg->event_station_connected_to_esp_softap->mac.data,
+ ctrl_msg->event_station_connected_to_esp_softap->mac.len);
+ }
+ //command_log("EVENT: SoftAP mode: Disconnect MAC[%s]\n",
+ // app_ntfy->u.e_softap_sta_conn.mac);
app_ntfy->u.e_softap_sta_conn.aid =
ctrl_msg->event_station_connected_to_esp_softap->aid;
app_ntfy->u.e_softap_sta_conn.is_mesh_child =
@@ -309,11 +277,13 @@ static int ctrl_app_parse_event(CtrlMsg *ctrl_msg, ctrl_cmd_t *app_ntfy)
CHECK_CTRL_MSG_NON_NULL_VAL(
ctrl_msg->event_station_disconnect_from_esp_softap->mac.data,
"NULL mac");
- strncpy((char *)app_ntfy->u.e_softap_sta_disconn.mac,
- (char *)ctrl_msg->event_station_disconnect_from_esp_softap->mac.data,
- ctrl_msg->event_station_disconnect_from_esp_softap->mac.len);
- /*printf("EVENT: SoftAP mode: Disconnect MAC[%s]\n",
- app_ntfy->u.e_softap_sta_disconn.mac);*/
+ if (ctrl_msg->event_station_disconnect_from_esp_softap->mac.len && ctrl_msg->event_station_disconnect_from_esp_softap->mac.data) {
+ strncpy((char *)app_ntfy->u.e_softap_sta_disconn.mac,
+ (char *)ctrl_msg->event_station_disconnect_from_esp_softap->mac.data,
+ ctrl_msg->event_station_disconnect_from_esp_softap->mac.len);
+ }
+ //command_log("EVENT: SoftAP mode: Disconnect MAC[%s]\n",
+ // app_ntfy->u.e_softap_sta_disconn.mac);
app_ntfy->u.e_softap_sta_disconn.aid =
ctrl_msg->event_station_disconnect_from_esp_softap->aid;
app_ntfy->u.e_softap_sta_disconn.is_mesh_child =
@@ -322,8 +292,63 @@ static int ctrl_app_parse_event(CtrlMsg *ctrl_msg, ctrl_cmd_t *app_ntfy)
ctrl_msg->event_station_disconnect_from_esp_softap->reason;
}
break;
+ } case CTRL_EVENT_DHCP_DNS_STATUS: {
+ CHECK_CTRL_MSG_NON_NULL(event_set_dhcp_dns_status);
+ app_ntfy->resp_event_status = ctrl_msg->event_set_dhcp_dns_status->resp;
+ app_ntfy->u.dhcp_dns_status.iface = ctrl_msg->event_set_dhcp_dns_status->iface;
+ app_ntfy->u.dhcp_dns_status.dhcp_up = ctrl_msg->event_set_dhcp_dns_status->dhcp_up;
+ app_ntfy->u.dhcp_dns_status.dns_up = ctrl_msg->event_set_dhcp_dns_status->dns_up;
+ app_ntfy->u.dhcp_dns_status.dns_type = ctrl_msg->event_set_dhcp_dns_status->dns_type;
+ app_ntfy->u.dhcp_dns_status.net_link_up = ctrl_msg->event_set_dhcp_dns_status->net_link_up;
+
+ if (ctrl_msg->event_set_dhcp_dns_status->dhcp_up) {
+ memcpy(app_ntfy->u.dhcp_dns_status.dhcp_ip,
+ ctrl_msg->event_set_dhcp_dns_status->dhcp_ip.data,
+ ctrl_msg->event_set_dhcp_dns_status->dhcp_ip.len);
+ memcpy(app_ntfy->u.dhcp_dns_status.dhcp_nm,
+ ctrl_msg->event_set_dhcp_dns_status->dhcp_nm.data,
+ ctrl_msg->event_set_dhcp_dns_status->dhcp_nm.len);
+ memcpy(app_ntfy->u.dhcp_dns_status.dhcp_gw,
+ ctrl_msg->event_set_dhcp_dns_status->dhcp_gw.data,
+ ctrl_msg->event_set_dhcp_dns_status->dhcp_gw.len);
+ }
+
+ if (ctrl_msg->event_set_dhcp_dns_status->dns_up) {
+ memcpy(app_ntfy->u.dhcp_dns_status.dns_ip,
+ ctrl_msg->event_set_dhcp_dns_status->dns_ip.data,
+ ctrl_msg->event_set_dhcp_dns_status->dns_ip.len);
+ }
+ break;
+ } case CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG: {
+ CHECK_CTRL_MSG_NON_NULL(event_custom_rpc_unserialised_msg);
+ app_ntfy->resp_event_status = ctrl_msg->event_custom_rpc_unserialised_msg->resp;
+ app_ntfy->u.custom_rpc_unserialised_data.custom_msg_id = ctrl_msg->event_custom_rpc_unserialised_msg->custom_evt_id;
+ app_ntfy->u.custom_rpc_unserialised_data.data_len = ctrl_msg->event_custom_rpc_unserialised_msg->data.len;
+
+ /* Properly allocate memory and copy data */
+ if (ctrl_msg->event_custom_rpc_unserialised_msg->data.data &&
+ ctrl_msg->event_custom_rpc_unserialised_msg->data.len > 0) {
+
+ app_ntfy->u.custom_rpc_unserialised_data.data = hosted_malloc(ctrl_msg->event_custom_rpc_unserialised_msg->data.len);
+ if (!app_ntfy->u.custom_rpc_unserialised_data.data) {
+ command_log("Failed to allocate memory for custom RPC event data\n");
+ app_ntfy->resp_event_status = CTRL_ERR_MEMORY_FAILURE;
+ goto fail_parse_ctrl_msg;
+ }
+
+ memcpy(app_ntfy->u.custom_rpc_unserialised_data.data,
+ ctrl_msg->event_custom_rpc_unserialised_msg->data.data,
+ ctrl_msg->event_custom_rpc_unserialised_msg->data.len);
+
+ /* Set free function to handle memory cleanup */
+ app_ntfy->free_buffer_func = hosted_free;
+ app_ntfy->free_buffer_handle = app_ntfy->u.custom_rpc_unserialised_data.data;
+ } else {
+ app_ntfy->u.custom_rpc_unserialised_data.data = NULL;
+ }
+ break;
} default: {
- printf("Invalid/unsupported event[%u] received\n",ctrl_msg->msg_id);
+ command_log("Invalid/unsupported event[%u] received\n",ctrl_msg->msg_id);
goto fail_parse_ctrl_msg;
break;
}
@@ -350,7 +375,7 @@ static int ctrl_app_parse_resp(CtrlMsg *ctrl_msg, ctrl_cmd_t *app_resp)
/* 1. Check non NULL */
if (!ctrl_msg || !app_resp) {
- printf("NULL Ctrl resp or NULL App Resp\n");
+ command_log("NULL Ctrl resp or NULL App Resp\n");
goto fail_parse_ctrl_msg2;
}
@@ -375,9 +400,11 @@ static int ctrl_app_parse_resp(CtrlMsg *ctrl_msg, ctrl_cmd_t *app_resp)
CHECK_CTRL_MSG_NON_NULL(resp_get_mac_address->mac.data);
CHECK_CTRL_MSG_FAILED(resp_get_mac_address);
- strncpy(app_resp->u.wifi_mac.mac,
- (char *)ctrl_msg->resp_get_mac_address->mac.data, len_l);
- app_resp->u.wifi_mac.mac[len_l] = '\0';
+ if (ctrl_msg->resp_get_mac_address->mac.len && ctrl_msg->resp_get_mac_address->mac.data) {
+ strncpy(app_resp->u.wifi_mac.mac,
+ (char *)ctrl_msg->resp_get_mac_address->mac.data, len_l);
+ app_resp->u.wifi_mac.mac[len_l] = '\0';
+ }
break;
} case CTRL_RESP_SET_MAC_ADDRESS : {
CHECK_CTRL_MSG_NON_NULL(resp_set_mac_address);
@@ -448,13 +475,13 @@ static int ctrl_app_parse_resp(CtrlMsg *ctrl_msg, ctrl_cmd_t *app_resp)
case SUCCESS:
strncpy(p->status, SUCCESS_STR, STATUS_LENGTH);
p->status[STATUS_LENGTH-1] = '\0';
- if (ctrl_msg->resp_get_ap_config->ssid.data) {
+ if (ctrl_msg->resp_get_ap_config->ssid.data && ctrl_msg->resp_get_ap_config->ssid.len) {
strncpy((char *)p->ssid,
(char *)ctrl_msg->resp_get_ap_config->ssid.data,
MAX_SSID_LENGTH-1);
p->ssid[MAX_SSID_LENGTH-1] ='\0';
}
- if (ctrl_msg->resp_get_ap_config->bssid.data) {
+ if (ctrl_msg->resp_get_ap_config->bssid.data && ctrl_msg->resp_get_ap_config->bssid.len) {
uint8_t len_l = 0;
len_l = min(ctrl_msg->resp_get_ap_config->bssid.len,
@@ -488,7 +515,7 @@ static int ctrl_app_parse_resp(CtrlMsg *ctrl_msg, ctrl_cmd_t *app_resp)
app_resp->resp_event_status = ctrl_msg->resp_connect_ap->resp;
if (ctrl_msg->resp_connect_ap->resp) {
- command_log("Connect AP failed, Reason[%d]\n", ctrl_msg->resp_connect_ap->resp);
+ //command_log("Connect AP Req failed, Reason[%d]\n", ctrl_msg->resp_connect_ap->resp);
}
switch(ctrl_msg->resp_connect_ap->resp) {
case CTRL_ERR_INVALID_PASSWORD:
@@ -500,20 +527,21 @@ static int ctrl_app_parse_resp(CtrlMsg *ctrl_msg, ctrl_cmd_t *app_resp)
goto fail_parse_ctrl_msg;
break;
case SUCCESS:
- command_log("Info: Connect band_mode is %d\n", ctrl_msg->resp_connect_ap->band_mode);
- CHECK_CTRL_MSG_NON_NULL(resp_connect_ap->mac.data);
+ //command_log("Info: Connect band_mode is %d\n", ctrl_msg->resp_connect_ap->band_mode);
+ //CHECK_CTRL_MSG_NON_NULL(resp_connect_ap->mac.data);
CHECK_CTRL_MSG_FAILED(resp_connect_ap);
break;
default:
- command_log("Connect AP failed, Reason[%u]\n", ctrl_msg->resp_connect_ap->resp);
CHECK_CTRL_MSG_FAILED(resp_connect_ap);
goto fail_parse_ctrl_msg;
break;
}
len_l = min(ctrl_msg->resp_connect_ap->mac.len, MAX_MAC_STR_SIZE-1);
- strncpy(app_resp->u.wifi_ap_config.out_mac,
- (char *)ctrl_msg->resp_connect_ap->mac.data, len_l);
- app_resp->u.wifi_ap_config.out_mac[len_l] = '\0';
+ if (ctrl_msg->resp_connect_ap->mac.data && ctrl_msg->resp_connect_ap->mac.len) {
+ strncpy(app_resp->u.wifi_ap_config.out_mac,
+ (char *)ctrl_msg->resp_connect_ap->mac.data, len_l);
+ app_resp->u.wifi_ap_config.out_mac[len_l] = '\0';
+ }
break;
} case CTRL_RESP_DISCONNECT_AP : {
CHECK_CTRL_MSG_NON_NULL(resp_disconnect_ap);
@@ -567,9 +595,11 @@ static int ctrl_app_parse_resp(CtrlMsg *ctrl_msg, ctrl_cmd_t *app_resp)
CHECK_CTRL_MSG_NON_NULL(resp_start_softap->mac.data);
len_l = min(ctrl_msg->resp_connect_ap->mac.len, MAX_MAC_STR_SIZE-1);
- strncpy(app_resp->u.wifi_softap_config.out_mac,
- (char *)ctrl_msg->resp_connect_ap->mac.data, len_l);
- app_resp->u.wifi_softap_config.out_mac[len_l] = '\0';
+ if (ctrl_msg->resp_connect_ap->mac.data && ctrl_msg->resp_connect_ap->mac.len) {
+ strncpy(app_resp->u.wifi_softap_config.out_mac,
+ (char *)ctrl_msg->resp_connect_ap->mac.data, len_l);
+ app_resp->u.wifi_softap_config.out_mac[len_l] = '\0';
+ }
app_resp->u.wifi_softap_config.band_mode = ctrl_msg->resp_connect_ap->band_mode;
break;
} case CTRL_RESP_GET_SOFTAP_CONN_STA_LIST : {
@@ -671,21 +701,84 @@ static int ctrl_app_parse_resp(CtrlMsg *ctrl_msg, ctrl_cmd_t *app_resp)
break;
} case CTRL_RESP_ENABLE_DISABLE: {
CHECK_CTRL_MSG_NON_NULL(resp_enable_disable_feat);
- CHECK_CTRL_MSG_FAILED(resp_enable_disable_feat);
+ //CHECK_CTRL_MSG_FAILED(resp_enable_disable_feat);
+ app_resp->resp_event_status = ctrl_msg->resp_enable_disable_feat->resp;
break;
} case CTRL_RESP_GET_FW_VERSION: {
CHECK_CTRL_MSG_NON_NULL(resp_get_fw_version);
CHECK_CTRL_MSG_FAILED(resp_get_fw_version);
- strncpy(app_resp->u.fw_version.project_name,
- ctrl_msg->resp_get_fw_version->name,
- sizeof(app_resp->u.fw_version.project_name) - 1);
+ if (ctrl_msg->resp_get_fw_version->name) {
+ strncpy(app_resp->u.fw_version.project_name,
+ ctrl_msg->resp_get_fw_version->name,
+ sizeof(app_resp->u.fw_version.project_name) - 1);
+ }
app_resp->u.fw_version.major_1 = ctrl_msg->resp_get_fw_version->major1;
app_resp->u.fw_version.major_2 = ctrl_msg->resp_get_fw_version->major2;
app_resp->u.fw_version.minor = ctrl_msg->resp_get_fw_version->minor;
app_resp->u.fw_version.revision_patch_1 = ctrl_msg->resp_get_fw_version->rev_patch1;
app_resp->u.fw_version.revision_patch_2 = ctrl_msg->resp_get_fw_version->rev_patch2;
break;
+ } case CTRL_RESP_SET_DHCP_DNS_STATUS: {
+ CHECK_CTRL_MSG_NON_NULL(resp_set_dhcp_dns_status);
+ CHECK_CTRL_MSG_FAILED(resp_set_dhcp_dns_status);
+ break;
+ } case CTRL_RESP_GET_DHCP_DNS_STATUS: {
+ CtrlMsgRespGetDhcpDnsStatus *p_c = ctrl_msg->resp_get_dhcp_dns_status;
+ dhcp_dns_status_t *p_a = &app_resp->u.dhcp_dns_status;
+ CHECK_CTRL_MSG_NON_NULL(resp_get_dhcp_dns_status);
+
+ app_resp->resp_event_status = ctrl_msg->resp_get_dhcp_dns_status->resp;
+
+ if (app_resp->resp_event_status != SUCCESS) {
+ /* Do not print error, as slave may be built without network split, just escape */
+ break;
+ }
+ p_a->dhcp_up = p_c->dhcp_up;
+ p_a->dns_up = p_c->dns_up;
+ p_a->net_link_up = p_c->net_link_up;
+ p_a->dns_type = p_c->dns_type;
+
+ if (p_c->dhcp_up) {
+ if (p_c->dhcp_ip.data) {
+ strncpy((char *)p_a->dhcp_ip, (char *)p_c->dhcp_ip.data, sizeof(p_a->dhcp_ip));
+ p_a->dhcp_ip[sizeof(p_a->dhcp_ip)-1] = '\0';
+ }
+ if (p_c->dhcp_nm.data) {
+ strncpy((char *)p_a->dhcp_nm, (char *)p_c->dhcp_nm.data, sizeof(p_a->dhcp_nm));
+ p_a->dhcp_nm[sizeof(p_a->dhcp_nm)-1] = '\0';
+ }
+ if (p_c->dhcp_gw.data) {
+ strncpy((char *)p_a->dhcp_gw, (char *)p_c->dhcp_gw.data, sizeof(p_a->dhcp_gw));
+ p_a->dhcp_gw[sizeof(p_a->dhcp_gw)-1] = '\0';
+ }
+ }
+
+ if (p_c->dns_up) {
+ if (p_c->dns_ip.data) {
+ strncpy((char *)p_a->dns_ip, (char *)p_c->dns_ip.data, sizeof(p_a->dns_ip));
+ p_a->dns_ip[sizeof(p_a->dns_ip)-1] = '\0';
+ }
+ }
+ break;
+ } case CTRL_RESP_CUSTOM_RPC_UNSERIALISED_MSG: {
+ CtrlMsgRespCustomRpcUnserialisedMsg *p_c = ctrl_msg->resp_custom_rpc_unserialised_msg;
+ custom_rpc_unserialised_data_t *p_a = &app_resp->u.custom_rpc_unserialised_data;
+ CHECK_CTRL_MSG_NON_NULL(resp_custom_rpc_unserialised_msg);
+ CHECK_CTRL_MSG_FAILED(resp_custom_rpc_unserialised_msg);
+ p_a->custom_msg_id = p_c->custom_msg_id;
+ p_a->data_len = p_c->data.len;
+ if (p_a->data_len && p_c->data.data) {
+ p_a->data = hosted_malloc(p_a->data_len);
+ if (!p_a->data) {
+ command_log("Failed to allocate data for custom RPC unserialised message\n");
+ goto fail_parse_ctrl_msg;
+ }
+ memcpy(p_a->data, p_c->data.data, p_a->data_len);
+ app_resp->free_buffer_func = hosted_free;
+ app_resp->free_buffer_handle = p_a->data;
+ }
+ break;
} default: {
command_log("Unsupported Control Resp[%u]\n", ctrl_msg->msg_id);
goto fail_parse_ctrl_msg;
@@ -730,7 +823,7 @@ static int is_event_callback_registered(int event)
int event_cb_tbl_idx = event - CTRL_EVENT_BASE;
if ((event<=CTRL_EVENT_BASE) || (event>=CTRL_EVENT_MAX)) {
- printf("Could not identify event[%u]\n", event);
+ command_log("Could not identify event[%u]\n", event);
return MSG_ID_OUT_OF_ORDER;
}
@@ -770,7 +863,7 @@ static int process_ctrl_rx_msg(CtrlMsg * proto_msg, ctrl_rx_ind_t ctrl_rx_func)
/* Allocate app struct for event */
app_event = (ctrl_cmd_t *)hosted_malloc(sizeof(ctrl_cmd_t));
if (!app_event) {
- printf("Failed to allocate app_event\n");
+ command_log("Failed to allocate app_event\n");
goto free_buffers;
}
memset(app_event, 0, sizeof(ctrl_cmd_t));
@@ -797,7 +890,7 @@ static int process_ctrl_rx_msg(CtrlMsg * proto_msg, ctrl_rx_ind_t ctrl_rx_func)
/* Allocate app struct for response */
app_resp = (ctrl_cmd_t *)hosted_malloc(sizeof(ctrl_cmd_t));
if (!app_resp) {
- printf("Failed to allocate app_resp\n");
+ command_log("Failed to allocate app_resp\n");
goto free_buffers;
}
memset(app_resp, 0, sizeof(ctrl_cmd_t));
@@ -813,12 +906,7 @@ static int process_ctrl_rx_msg(CtrlMsg * proto_msg, ctrl_rx_ind_t ctrl_rx_func)
/* Decode protobuf buffer of response and
* copy into app structures */
- if (ctrl_app_parse_resp(proto_msg, app_resp)) {
- // failed to parse response into app_resp
- if (app_resp)
- mem_free(app_resp);
- return FAILURE;
- }
+ ctrl_app_parse_resp(proto_msg, app_resp);
/* Is callback is available,
* progress as async response */
@@ -830,6 +918,7 @@ static int process_ctrl_rx_msg(CtrlMsg * proto_msg, ctrl_rx_ind_t ctrl_rx_func)
* so call to that function should be done and
* return to select
*/
+ //command_log("async_resp_callback for msg_id [%d] available: %p\n", app_resp->msg_id, ctrl_resp_cb_table[app_resp->msg_id-CTRL_RESP_BASE]);
call_async_resp_callback(app_resp);
//CLEANUP_APP_MSG(app_resp);
@@ -841,10 +930,11 @@ static int process_ctrl_rx_msg(CtrlMsg * proto_msg, ctrl_rx_ind_t ctrl_rx_func)
* synchronous response. forward this response to app
* using 'esp_queue' and help of semaphore
**/
+ //command_log("async_resp_callback for msg_id [%d] NOT available\n", app_resp->msg_id);
elem = (esp_queue_elem_t*)hosted_malloc(sizeof(esp_queue_elem_t));
if (!elem) {
- printf("%s %u: Malloc failed\n",__func__,__LINE__);
+ command_log("%s %u: Malloc failed\n",__func__,__LINE__);
goto free_buffers;
}
@@ -855,7 +945,7 @@ static int process_ctrl_rx_msg(CtrlMsg * proto_msg, ctrl_rx_ind_t ctrl_rx_func)
elem->buf = app_resp;
elem->buf_len = sizeof(ctrl_cmd_t);
if (esp_queue_put(ctrl_msg_Q, (void*)elem)) {
- printf("%s %u: ctrl Q put fail\n",__func__,__LINE__);
+ command_log("%s %u: ctrl Q put fail\n",__func__,__LINE__);
goto free_buffers;
}
@@ -867,7 +957,7 @@ static int process_ctrl_rx_msg(CtrlMsg * proto_msg, ctrl_rx_ind_t ctrl_rx_func)
} else {
/* 4. some unsupported msg, drop it */
- printf("Incorrect Ctrl Msg Type[%u]\n",proto_msg->msg_type);
+ command_log("Incorrect Ctrl Msg Type[%u]\n",proto_msg->msg_type);
goto free_buffers;
}
return SUCCESS;
@@ -895,14 +985,14 @@ static void ctrl_rx_thread(void const *arg)
/* 1. Get callback for synchronous procedure
* for semaphore post */
if (!ctrl_rx_func) {
- printf("ERROR: NULL rx async cb for esp_queue,sem\n");
+ command_log("ERROR: NULL rx async cb for esp_queue,sem\n");
return;
}
/* 2. This queue should already be created
* if NULL, exit here */
if (!ctrl_msg_Q) {
- printf("Ctrl msg Q is not created\n");
+ command_log("Ctrl msg Q is not created\n");
return;
}
@@ -919,7 +1009,7 @@ static void ctrl_rx_thread(void const *arg)
buf = transport_pserial_read(&buf_len);
if (!buf_len || !buf) {
- printf("%s buf_len read = 0\n",__func__);
+ command_log("%s buf_len read = 0\n",__func__);
goto free_bufs;
}
@@ -951,7 +1041,7 @@ static int spawn_ctrl_rx_thread(void)
{
ctrl_rx_thread_handle = hosted_thread_create(ctrl_rx_thread, ctrl_rx_ind);
if (!ctrl_rx_thread_handle) {
- printf("Thread creation failed for ctrl_rx_thread\n");
+ command_log("Thread creation failed for ctrl_rx_thread\n");
return FAILURE;
}
return SUCCESS;
@@ -962,7 +1052,7 @@ static int cancel_ctrl_rx_thread(void)
{
int s = hosted_thread_cancel(ctrl_rx_thread_handle);
if (s != 0) {
- printf("pthread_cancel failed\n");
+ command_log("pthread_cancel failed\n");
return FAILURE;
}
@@ -985,7 +1075,7 @@ static ctrl_cmd_t * get_response(int *read_len, int timeout_sec)
/* 1. Any problems in response, return NULL */
if (!read_len) {
- printf("Invalid input parameter\n");
+ command_log("Invalid input parameter\n");
return NULL;
}
@@ -997,9 +1087,9 @@ static ctrl_cmd_t * get_response(int *read_len, int timeout_sec)
ret = hosted_get_semaphore(read_sem, timeout_sec);
if (ret) {
if (errno == ETIMEDOUT)
- printf("Control response timed out after %u sec\n", timeout_sec);
+ command_log("Control response timed out after %u sec\n", timeout_sec);
else
- printf("ctrl lib error[%u] in sem of timeout[%u]\n", errno, timeout_sec);
+ command_log("ctrl lib error[%u] in sem of timeout[%u]\n", errno, timeout_sec);
/* Unlock semaphore in negative case */
hosted_post_semaphore(ctrl_req_sem);
return NULL;
@@ -1019,7 +1109,7 @@ static ctrl_cmd_t * get_response(int *read_len, int timeout_sec)
return (ctrl_cmd_t*)buf;
} else {
- printf("Ctrl Q empty or uninitialised\n");
+ command_log("Ctrl Q empty or uninitialised\n");
return NULL;
}
@@ -1058,6 +1148,7 @@ static int call_event_callback(ctrl_cmd_t *app_event)
}
if (ctrl_event_cb_table[app_event->msg_id-CTRL_EVENT_BASE]) {
+ //command_log("Calling event callback for msg_id [%d]\n", app_event->msg_id);
return ctrl_event_cb_table[app_event->msg_id-CTRL_EVENT_BASE](app_event);
}
@@ -1074,7 +1165,7 @@ static int set_async_resp_callback(int req_msg_id, ctrl_resp_cb_t resp_cb)
/* Assign(Replace) response callback passed */
int exp_resp_msg_id = (req_msg_id - CTRL_REQ_BASE + CTRL_RESP_BASE);
if (exp_resp_msg_id >= CTRL_RESP_MAX) {
- printf("Not able to map new request to resp id\n");
+ command_log("Not able to map new request to resp id\n");
return MSG_ID_OUT_OF_ORDER;
} else {
ctrl_resp_cb_table[exp_resp_msg_id-CTRL_RESP_BASE] = resp_cb;
@@ -1090,7 +1181,7 @@ static int set_async_resp_callback(int req_msg_id, ctrl_resp_cb_t resp_cb)
static int is_async_resp_callback_registered_by_resp_msg_id(int resp_msg_id)
{
if ((resp_msg_id <= CTRL_RESP_BASE) || (resp_msg_id >= CTRL_RESP_MAX)) {
- printf("resp id[%u] out of range\n", resp_msg_id);
+ command_log("resp id[%u] out of range\n", resp_msg_id);
return MSG_ID_OUT_OF_ORDER;
}
@@ -1109,11 +1200,16 @@ static int is_async_resp_callback_registered_by_resp_msg_id(int resp_msg_id)
* MSG_ID_OUT_OF_ORDER - if request msg id is unsupported
* CALLBACK_NOT_REGISTERED - if aync callback is not available
**/
-int is_async_resp_callback_registered(ctrl_cmd_t req)
+int is_async_resp_callback_registered(ctrl_cmd_t *req)
{
- int exp_resp_msg_id = (req.msg_id - CTRL_REQ_BASE + CTRL_RESP_BASE);
+ if (!req) {
+ command_log("Invalid request pointer\n");
+ return MSG_ID_OUT_OF_ORDER;
+ }
+
+ int exp_resp_msg_id = (req->msg_id - CTRL_REQ_BASE + CTRL_RESP_BASE);
if (exp_resp_msg_id >= CTRL_RESP_MAX) {
- printf("Not able to map new request to resp id, using sync path\n");
+ command_log("Not able to map new request to resp id, using sync path\n");
return MSG_ID_OUT_OF_ORDER;
}
@@ -1136,13 +1232,29 @@ int set_event_callback(int event, ctrl_resp_cb_t event_cb)
int event_cb_tbl_idx = event - CTRL_EVENT_BASE;
if ((event<=CTRL_EVENT_BASE) || (event>=CTRL_EVENT_MAX)) {
- printf("Could not identify event[%u]\n", event);
+ command_log("Could not identify event[%u]\n", event);
return MSG_ID_OUT_OF_ORDER;
}
ctrl_event_cb_table[event_cb_tbl_idx] = event_cb;
return CALLBACK_SET_SUCCESS;
}
+/* Get control event callback
+ * Returns:
+ * > NULL - If event is not registered with hosted control lib
+ * > Function pointer - Returns the registered event callback
+ **/
+ctrl_resp_cb_t get_event_callback(int event)
+{
+ int event_cb_tbl_idx = event - CTRL_EVENT_BASE;
+ if ((event<=CTRL_EVENT_BASE) || (event>=CTRL_EVENT_MAX)) {
+ command_log("Could not identify event[%u]\n", event);
+ return NULL;
+ }
+ return ctrl_event_cb_table[event_cb_tbl_idx];
+}
+
+
/* Assign NULL event callback */
int reset_event_callback(int event)
{
@@ -1158,9 +1270,11 @@ ctrl_cmd_t * ctrl_wait_and_parse_sync_resp(ctrl_cmd_t *app_req)
ctrl_cmd_t * rx_buf = NULL;
int rx_buf_len = 0;
+ //command_log("ctrl_wait_and_parse_sync_resp for msg_id [%d]\n", app_req->msg_id);
+
rx_buf = get_response(&rx_buf_len, app_req->cmd_timeout_sec);
if (!rx_buf || !rx_buf_len) {
- printf("Response not received\n");
+ command_log("Response not received\n");
if (rx_buf) {
mem_free(rx_buf);
}
@@ -1185,14 +1299,14 @@ static void ctrl_async_timeout_handler(void const *arg)
{
ctrl_resp_cb_t func = arg;
if (!func) {
- printf("NULL func, failed to call callback\n");
+ command_log("NULL func, failed to call callback\n");
hosted_post_semaphore(ctrl_req_sem);
return;
}
ctrl_cmd_t *app_resp = NULL;
app_resp = (ctrl_cmd_t *)hosted_calloc(1, sizeof(ctrl_cmd_t));
if (!app_resp) {
- printf("Failed to allocate app_resp\n");
+ command_log("Failed to allocate app_resp\n");
hosted_post_semaphore(ctrl_req_sem);
return;
}
@@ -1240,6 +1354,7 @@ int ctrl_app_send_req(ctrl_cmd_t *app_req)
if (!app_req) {
failure_status = CTRL_ERR_INCORRECT_ARG;
+ command_log("Invalid request pointer\n");
goto fail_req;
}
@@ -1248,6 +1363,7 @@ int ctrl_app_send_req(ctrl_cmd_t *app_req)
ret = hosted_get_semaphore(ctrl_req_sem, WAIT_TIME_B2B_CTRL_REQ);
if (ret) {
failure_status = CTRL_ERR_REQ_IN_PROG;
+ command_log("Request already in progress\n");
goto fail_req;
} else {
got_ctrl_req_sem = 1;
@@ -1287,7 +1403,8 @@ int ctrl_app_send_req(ctrl_cmd_t *app_req)
case CTRL_REQ_OTA_END:
case CTRL_REQ_GET_WIFI_CURR_TX_POWER:
case CTRL_REQ_GET_FW_VERSION:
- case CTRL_REQ_GET_COUNTRY_CODE: {
+ case CTRL_REQ_GET_COUNTRY_CODE:
+ case CTRL_REQ_GET_DHCP_DNS_STATUS: {
/* Intentional fallthrough & empty */
break;
} case CTRL_REQ_GET_AP_SCAN_LIST: {
@@ -1475,7 +1592,7 @@ int ctrl_app_send_req(ctrl_cmd_t *app_req)
wifi_power_save_t * p = &app_req->u.wifi_ps;
CTRL_ALLOC_ASSIGN(CtrlMsgReqSetMode, req_set_power_save_mode);
- if ((p->ps_mode < WIFI_PS_MIN_MODEM) ||
+ if ((p->ps_mode < WIFI_PS_NONE) ||
(p->ps_mode >= WIFI_PS_INVALID)) {
command_log("Invalid power save mode\n");
failure_status = CTRL_ERR_INCORRECT_ARG;
@@ -1522,11 +1639,11 @@ int ctrl_app_send_req(ctrl_cmd_t *app_req)
req_payload->enable = app_req->u.e_heartbeat.enable;
req_payload->duration = app_req->u.e_heartbeat.duration;
if (req_payload->enable) {
- printf("Enable heartbeat with duration %ld\n", (long int)req_payload->duration);
+ command_log("Enable heartbeat with duration %ld\n", (long int)req_payload->duration);
if (CALLBACK_AVAILABLE != is_event_callback_registered(CTRL_EVENT_HEARTBEAT))
- printf("Note: ** Subscribe heartbeat event to get notification **\n");
+ command_log("Note: ** Subscribe heartbeat event to get notification **\n");
} else {
- printf("Disable Heartbeat\n");
+ command_log("Disable Heartbeat\n");
}
break;
} case CTRL_REQ_ENABLE_DISABLE: {
@@ -1534,11 +1651,18 @@ int ctrl_app_send_req(ctrl_cmd_t *app_req)
ctrl_msg__req__enable_disable__init(req_payload);
req_payload->feature = app_req->u.feat_ena_disable.feature;
req_payload->enable = app_req->u.feat_ena_disable.enable;
- printf("%sable feature [%d]\n", (req_payload->enable)? "en": "dis", req_payload->feature);
+ //command_log("%sable feature [%d]\n", (req_payload->enable)? "en": "dis", req_payload->feature);
+ break;
+ } case CTRL_REQ_CUSTOM_RPC_UNSERIALISED_MSG: {
+ CTRL_ALLOC_ASSIGN(CtrlMsgReqCustomRpcUnserialisedMsg, req_custom_rpc_unserialised_msg);
+ ctrl_msg__req__custom_rpc_unserialised_msg__init(req_payload);
+ req_payload->custom_msg_id = app_req->u.custom_rpc_unserialised_data.custom_msg_id;
+ req_payload->data.data = app_req->u.custom_rpc_unserialised_data.data;
+ req_payload->data.len = app_req->u.custom_rpc_unserialised_data.data_len;
break;
} default: {
failure_status = CTRL_ERR_UNSUPPORTED_MSG;
- printf("Unsupported Control Req[%u]",req.msg_id);
+ command_log("RPC Req[%u] unsupported\n",req.msg_id);
goto fail_req;
break;
}
@@ -1567,7 +1691,7 @@ int ctrl_app_send_req(ctrl_cmd_t *app_req)
* callback to user defined callback function */
ret = set_async_resp_callback(app_req->msg_id, app_req->ctrl_resp_cb);
if (ret < 0) {
- printf("could not set callback for req[%u]\n",req.msg_id);
+ command_log("could not set callback for req[%u]\n",req.msg_id);
failure_status = CTRL_ERR_SET_ASYNC_CB;
goto fail_req;
}
@@ -1579,7 +1703,7 @@ int ctrl_app_send_req(ctrl_cmd_t *app_req)
async_timer_handle = hosted_timer_start(app_req->cmd_timeout_sec, CTRL__TIMER_ONESHOT,
ctrl_async_timeout_handler, app_req->ctrl_resp_cb);
if (!async_timer_handle) {
- printf("Failed to start async resp timer\n");
+ command_log("Failed to start async resp timer\n");
goto fail_req;
}
/* For async, clearing semaphore on failed cases done on above timer expiry */
@@ -1595,15 +1719,7 @@ int ctrl_app_send_req(ctrl_cmd_t *app_req)
}
-
- /* 9. Free hook for application */
- if (app_req->free_buffer_handle) {
- if (app_req->free_buffer_func) {
- app_req->free_buffer_func(app_req->free_buffer_handle);
- }
- }
-
- /* 10. Cleanup */
+ /* 9. Cleanup */
mem_free(tx_data);
mem_free(buff_to_free2);
mem_free(buff_to_free1);
@@ -1618,13 +1734,13 @@ int ctrl_app_send_req(ctrl_cmd_t *app_req)
//TODO: need to test below and possibly remove redundant code
// if(!async_timer_handle && app_req->ctrl_resp_cb) {
if (app_req->ctrl_resp_cb) {
- /* 11. In case of async procedure,
+ /* 10. In case of async procedure,
* Let application know of failure using callback itself
**/
ctrl_cmd_t *app_resp = NULL;
app_resp = (ctrl_cmd_t *)hosted_malloc(sizeof(ctrl_cmd_t));
if (!app_resp) {
- printf("Failed to allocate app_resp\n");
+ command_log("Failed to allocate app_resp\n");
goto fail_req2;
}
memset(app_resp, 0, sizeof(ctrl_cmd_t));
@@ -1632,19 +1748,13 @@ int ctrl_app_send_req(ctrl_cmd_t *app_req)
app_resp->msg_id = (app_req->msg_id - CTRL_REQ_BASE + CTRL_RESP_BASE);
app_resp->resp_event_status = failure_status;
- /* 12. In async procedure, it is important to get
+ /* 11. In async procedure, it is important to get
* some kind of acknowledgement to user */
app_req->ctrl_resp_cb(app_resp);
}
fail_req2:
- /* 13. Cleanup */
- if (app_req->free_buffer_handle) {
- if (app_req->free_buffer_func) {
- app_req->free_buffer_func(app_req->free_buffer_handle);
- }
- }
-
+ /* 12. Cleanup */
mem_free(tx_data);
mem_free(buff_to_free2);
mem_free(buff_to_free1);
@@ -1656,6 +1766,10 @@ int deinit_hosted_control_lib_internal(void)
{
int ret = SUCCESS;
+ if (is_ctrl_lib_state(CTRL_LIB_STATE_INACTIVE)) {
+ return SUCCESS;
+ }
+
set_ctrl_lib_state(CTRL_LIB_STATE_INACTIVE);
if (ctrl_msg_Q) {
@@ -1664,12 +1778,12 @@ int deinit_hosted_control_lib_internal(void)
if (ctrl_req_sem && hosted_destroy_semaphore(ctrl_req_sem)) {
ret = FAILURE;
- printf("ctrl req sem deinit failed\n");
+ command_log("ctrl req sem deinit failed\n");
}
if (read_sem && hosted_destroy_semaphore(read_sem)) {
ret = FAILURE;
- printf("read sem deinit failed\n");
+ command_log("read sem deinit failed\n");
}
if (async_timer_handle) {
@@ -1680,12 +1794,12 @@ int deinit_hosted_control_lib_internal(void)
if (serial_deinit()) {
ret = FAILURE;
- printf("Serial de-init failed\n");
+ //command_log("Serial de-init failed\n");
}
if (ctrl_rx_thread_handle && cancel_ctrl_rx_thread()) {
ret = FAILURE;
- printf("cancel ctrl rx thread failed\n");
+ command_log("cancel ctrl rx thread failed\n");
}
return ret;
@@ -1695,31 +1809,25 @@ int deinit_hosted_control_lib_internal(void)
int init_hosted_control_lib_internal(void)
{
int ret = SUCCESS;
-#ifndef MCU_SYS
- if(getuid()) {
- printf("Please re-run program with superuser access\n");
- return FAILURE;
- }
-#endif
/* semaphore init */
read_sem = hosted_create_semaphore(1);
ctrl_req_sem = hosted_create_semaphore(1);
if (!read_sem || !ctrl_req_sem) {
- printf("sem init failed, exiting\n");
+ command_log("sem init failed, exiting\n");
goto free_bufs;
}
/* serial init */
if (serial_init()) {
- printf("Failed to serial_init\n");
+ //command_log("Failed to serial_init\n");
goto free_bufs;
}
/* queue init */
ctrl_msg_Q = create_esp_queue();
if (!ctrl_msg_Q) {
- printf("Failed to create app ctrl msg Q\n");
+ command_log("Failed to create app ctrl msg Q\n");
goto free_bufs;
}
@@ -1738,138 +1846,4 @@ int init_hosted_control_lib_internal(void)
free_bufs:
deinit_hosted_control_lib_internal();
return FAILURE;
-
-}
-
-
-
-#ifndef MCU_SYS
-
- /* Function ups in given interface */
-int interface_up(int sockfd, char* iface)
-{
- int ret = SUCCESS;
- struct ifreq req = {0};
- size_t if_name_len = strnlen(iface, MAX_INTERFACE_LEN-1);
-
- if (!iface) {
- command_log("Invalid parameter\n");
- return FAILURE;
- }
-
- if (if_name_len < sizeof(req.ifr_name)) {
- memcpy(req.ifr_name,iface,if_name_len);
- req.ifr_name[if_name_len]='\0';
- } else {
- printf("Failed: Max interface len allowed: %zu \n", sizeof(req.ifr_name)-1);
- return FAILURE;
- }
-
- req.ifr_flags |= IFF_UP;
- ret = ioctl(sockfd, SIOCSIFFLAGS, &req);
- if (ret < 0) {
- return FAILURE;
- }
- return SUCCESS;
-}
-
- /* Function downs in given interface */
-int interface_down(int sockfd, char* iface)
-{
- int ret = SUCCESS;
- struct ifreq req = {0};
- size_t if_name_len = strnlen(iface, MAX_INTERFACE_LEN-1);
-
- if (!iface) {
- command_log("Invalid parameter\n");
- return FAILURE;
- }
-
- if (if_name_len < sizeof(req.ifr_name)) {
- memcpy(req.ifr_name,iface,if_name_len);
- req.ifr_name[if_name_len]='\0';
- } else {
- printf("Failed: Max interface len allowed- %zu \n", sizeof(req.ifr_name)-1);
- return FAILURE;
- }
-
- req.ifr_flags &= ~IFF_UP;
- ret = ioctl(sockfd, SIOCSIFFLAGS, &req);
- if (ret < 0) {
- perror("interface down:");
- return FAILURE;
- }
- return SUCCESS;
-}
-
- /* Function sets mac address to given interface */
-int set_hw_addr(int sockfd, char* iface, char* mac)
-{
- int ret = SUCCESS;
- struct ifreq req = {0};
- char mac_bytes[MAC_SIZE_BYTES] = "";
- size_t if_name_len = strnlen(iface, MAX_INTERFACE_LEN-1);
-
- if (!iface || !mac) {
- command_log("Invalid parameter\n");
- return FAILURE;
- }
-
- if (if_name_len < sizeof(req.ifr_name)) {
- memcpy(req.ifr_name,iface,if_name_len);
- req.ifr_name[if_name_len]='\0';
- } else {
- printf("Failed: Max interface len allowed: %zu \n", sizeof(req.ifr_name)-1);
- return FAILURE;
- }
-
- memset(mac_bytes, '\0', MAC_SIZE_BYTES);
- ret = convert_mac_to_bytes((uint8_t *)&mac_bytes, sizeof(mac_bytes), mac);
-
- if (ret) {
- printf("Failed to convert mac address \n");
- return FAILURE;
- }
-
- req.ifr_hwaddr.sa_family = ARPHRD_ETHER;
- memcpy(req.ifr_hwaddr.sa_data, mac_bytes, MAC_SIZE_BYTES);
- ret = ioctl(sockfd, SIOCSIFHWADDR, &req);
-
- if (ret < 0) {
- return FAILURE;
- }
- return SUCCESS;
}
-
- /* Function creates an endpoint for communication and
- * returns a file descriptor (integer number) that
- * refers to that endpoint */
-int create_socket(int domain, int type, int protocol, int *sock)
-{
- if (!sock) {
- command_log("Invalid parameter\n");
- return FAILURE;
- }
-
- *sock = socket(domain, type, protocol);
- if (*sock < 0)
- {
- printf("Failure to open socket\n");
- return FAILURE;
- }
- return SUCCESS;
-}
-
- /* Function closes an endpoint for communication */
-int close_socket(int sock)
-{
- int ret;
- ret = close(sock);
- if (ret < 0) {
- printf("Failure to close socket\n");
- return FAILURE;
- }
- return SUCCESS;
-}
-
-#endif
diff --git a/esp_hosted_fg/host/control_lib/src/include/ctrl_core.h b/esp_hosted_fg/host/control_lib/src/include/ctrl_core.h
index d8da90f24e..60c2d4e79c 100644
--- a/esp_hosted_fg/host/control_lib/src/include/ctrl_core.h
+++ b/esp_hosted_fg/host/control_lib/src/include/ctrl_core.h
@@ -55,5 +55,5 @@ ctrl_cmd_t * ctrl_wait_and_parse_sync_resp(ctrl_cmd_t *req);
* > MSG_ID_OUT_OF_ORDER - if request msg id is unsupported
* > CALLBACK_NOT_REGISTERED - if aync callback is not available
**/
-int is_async_resp_callback_registered(ctrl_cmd_t req);
+int is_async_resp_callback_registered(ctrl_cmd_t *req);
#endif /* __CTRL_CORE_H */
diff --git a/esp_hosted_fg/host/linux/host_control/c_support/Makefile b/esp_hosted_fg/host/linux/host_control/c_support/Makefile
index 660482d9f5..86b77492a7 100644
--- a/esp_hosted_fg/host/linux/host_control/c_support/Makefile
+++ b/esp_hosted_fg/host/linux/host_control/c_support/Makefile
@@ -1,19 +1,34 @@
CC = gcc
+# IMX8mm
+# SDKTARGETSYSROOT := /opt/fsl-imx-wayland/5.15-kirkstone/sysroots/armv8a-poky-linux
+# CROSS_COMPILE := "/opt/fsl-imx-wayland/5.15-kirkstone/sysroots/x86_64-pokysdk-linux/usr/bin/aarch64-poky-linux/aarch64-poky-linux-"
+# CFLAGS = -Wall --sysroot=$(SDKTARGETSYSROOT) -g
+# LINKER = --sysroot=$(SDKTARGETSYSROOT) -lpthread -lrt
+
+SDKTARGETSYSROOT :=
CROSS_COMPILE :=
+CFLAGS = -Wall -g
+LINKER = -lpthread -lrt
-CFLAGS = -C -Wall --sysroot=$(SDKTARGETSYSROOT)
+# Enable only when memory check (like valgrind) need to perform. This slows down the application and cleanup
+#CFLAGS_SANITIZE = -fsanitize=undefined -fsanitize-address-use-after-scope -fsanitize-undefined-trap-on-error -fstack-protector-all -fstack-check -fsanitize=address -fsanitize=pointer-compare -fno-omit-frame-pointer -static-libasan
-CFLAGS_SANITIZE = -fsanitize=undefined -fsanitize-address-use-after-scope -fsanitize-undefined-trap-on-error -fstack-protector-all -fstack-check -fsanitize=address -fsanitize=pointer-compare -fno-omit-frame-pointer -static-libasan
+# Root directory
+DIR_ROOT = $(CURDIR)/../../../../
+LIB_DIR = $(DIR_ROOT)/host/control_lib
-LINKER = -lpthread -lrt
+# Get the control library path
+CONTROL_LIB = $(LIB_DIR)/libesp_hosted_rpc.a
-DIR_COMMON = $(PWD)/../../../../common
-DIR_CTRL_LIB = $(PWD)/../../../control_lib
-DIR_SERIAL = $(PWD)/../../../virtual_serial_if
-DIR_COMPONENTS = $(PWD)/../../../components
-DIR_LINUX_PORT = $(PWD)/../../port
+# Directory structure
+DIR_COMMON = $(DIR_ROOT)/common
+DIR_CTRL_LIB = $(DIR_ROOT)/host/control_lib
+DIR_SERIAL = $(DIR_ROOT)/host/virtual_serial_if
+DIR_COMPONENTS = $(DIR_ROOT)/host/components
+DIR_LINUX_PORT = $(DIR_ROOT)/host/linux/port
+# Include directories
INCLUDE += -I$(DIR_COMMON)/protobuf-c
INCLUDE += -I$(DIR_COMMON)/include
INCLUDE += -I$(DIR_CTRL_LIB)/include
@@ -21,28 +36,64 @@ INCLUDE += -I$(DIR_CTRL_LIB)/src/include
INCLUDE += -I$(DIR_SERIAL)/include
INCLUDE += -I$(DIR_COMPONENTS)/include
INCLUDE += -I$(DIR_LINUX_PORT)/include
+INCLUDE += -I/usr/local/include
INCLUDE += -I.
+# Set library path
+LIBPATH = -L$(LIB_DIR)
+LIBS = -Wl,--whole-archive $(CONTROL_LIB) -Wl,--no-whole-archive
+
+# Check if replxx is installed by looking for the header file
+REPLXX_INSTALLED := $(shell if [ -f /usr/include/replxx.h ] || [ -f /usr/local/include/replxx.h ]; then echo "yes"; else echo "no"; fi)
+
+ifeq ($(REPLXX_INSTALLED), yes)
+ BUILD_SHELL := hosted_shell
+else
+ # Skipping `hosted_shell` silently as rpi_init.sh prints a warning and help how to install replxx
+ BUILD_SHELL :=
+endif
+
+USR_CUSTOM_RPC_OBJS = app_custom_rpc.o
+
+COMMON_OBJS = test_utils.o nw_helper_func.o $(USR_CUSTOM_RPC_OBJS)
+
+.PHONY: test stress hosted_daemon hosted_shell all clean ensure_libs
+
+all: ensure_libs test stress hosted_daemon $(BUILD_SHELL)
+
+# Ensure control library is built
+ensure_libs:
+ $(MAKE) -C $(DIR_CTRL_LIB) install
+
+TEST_OBJS = test.o $(COMMON_OBJS)
+
+test: ensure_libs test.out
+
+test.out: $(TEST_OBJS)
+ $(CROSS_COMPILE)$(CC) $(CFLAGS) $(INCLUDE) $(LIBPATH) $^ $(LINKER) $(LIBS) -o $(@)
+
+STRESS_OBJS = stress.o $(COMMON_OBJS)
+
+stress: ensure_libs stress.out
+
+stress.out: $(STRESS_OBJS)
+ $(CROSS_COMPILE)$(CC) $(CFLAGS) $(CFLAGS_SANITIZE) $(INCLUDE) $(LIBPATH) $^ $(LINKER) $(LIBS) -o $(@)
-SRC += $(DIR_COMMON)/protobuf-c/protobuf-c/protobuf-c.c
-SRC += $(DIR_COMMON)/esp_hosted_config.pb-c.c
-SRC += $(DIR_CTRL_LIB)/src/ctrl_core.c
-SRC += $(DIR_CTRL_LIB)/src/ctrl_api.c
-SRC += $(DIR_SERIAL)/src/serial_if.c
-SRC += $(DIR_COMPONENTS)/src/esp_queue.c
-SRC += $(DIR_LINUX_PORT)/src/platform_wrapper.c
+HOSTED_DAEMON_OBJS = hosted_daemon.o $(COMMON_OBJS)
-PWD := $(shell pwd)
+hosted_daemon: ensure_libs hosted_daemon.out
-SRC += ./test_utils.c
+hosted_daemon.out: $(HOSTED_DAEMON_OBJS)
+ $(CROSS_COMPILE)$(CC) $(CFLAGS) $(CFLAGS_SANITIZE) $(INCLUDE) $(LIBPATH) $^ $(LINKER) $(LIBS) -o $(@)
-all: test
+hosted_shell: ensure_libs hosted_shell.out
-test:
- $(CROSS_COMPILE)$(CC) $(CFLAGS) $(INCLUDE) $(SRC) $(LINKER) $(@).c -o $(@).out
+hosted_shell.out: hosted_shell.o $(COMMON_OBJS)
+ $(CROSS_COMPILE)$(CC) $(CFLAGS) $(CFLAGS_SANITIZE) $(INCLUDE) $(LIBPATH) -o $(@) $^ $(LINKER) $(LIBS) -lreplxx -lstdc++
-stress:
- $(CROSS_COMPILE)$(CC) $(CFLAGS) $(CFLAGS_SANITIZE) $(INCLUDE) $(SRC) $(LINKER) $(@).c -o $(@).out -ggdb3 -g
+%.o: %.c
+ $(CROSS_COMPILE)$(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
clean:
rm -f *.out *.o
+ $(MAKE) -C $(DIR_CTRL_LIB) clean
diff --git a/esp_hosted_fg/host/linux/host_control/c_support/app_custom_rpc.c b/esp_hosted_fg/host/linux/host_control/c_support/app_custom_rpc.c
new file mode 100644
index 0000000000..aea6e9fe6c
--- /dev/null
+++ b/esp_hosted_fg/host/linux/host_control/c_support/app_custom_rpc.c
@@ -0,0 +1,352 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Espressif Systems Wireless LAN device driver
+ *
+ * Copyright (C) 2015-2025 Espressif Systems (Shanghai) PTE LTD
+ *
+ * This software file (the "File") is distributed by Espressif Systems (Shanghai)
+ * PTE LTD under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "test.h"
+#include "ctrl_api.h"
+#include "app_custom_rpc.h"
+#include "esp_hosted_custom_rpc.h"
+
+/* Global variable for verification results in demo3 */
+static volatile int g_verification_result = 0;
+static uint8_t *g_original_data = NULL;
+static uint32_t g_original_data_len = 0;
+
+/* -------------- Demo 1 : Send packed RPC request. Slave acknowledges. -------------- */
+int custom_rpc_demo1_request_only_ack(void) {
+ uint8_t *recv_data = NULL;
+ uint32_t recv_data_len = 0;
+ void (*recv_data_free_func)(void*) = NULL;
+
+ /* Create a byte stream with a specific pattern */
+ uint32_t send_data_len = 1500;
+ uint8_t *send_data = calloc(1, send_data_len);
+ if (!send_data) {
+ printf("Failed to allocate memory for send data\n");
+ return FAILURE;
+ }
+
+ /* Fill with a simple pattern */
+ for (uint32_t i = 0; i < send_data_len; i++) {
+ send_data[i] = ((i * 2) % 256);
+ }
+
+ printf("[Demo 1] Sending packed RPC request (custom req num: %u). No Response expected. Only Ack expected.\n",
+ CUSTOM_RPC_REQ_ID__ONLY_ACK);
+
+ /* Use a message ID that doesn't expect echo back */
+ uint32_t custom_msg_id = CUSTOM_RPC_REQ_ID__ONLY_ACK;
+
+ int ret = test_custom_rpc_unserialised_request(custom_msg_id, send_data, send_data_len,
+ &recv_data, &recv_data_len, &recv_data_free_func);
+
+ if (ret != SUCCESS) {
+ free(send_data);
+ return FAILURE;
+ }
+
+ /* For this demo, we don't expect a meaningful response */
+ printf("[Demo 1] Slave Ack for RPC request.\n");
+
+ /* Clean up */
+ free(send_data);
+
+ /* As safe measure, free the received data, if any */
+ if (recv_data_free_func && recv_data) {
+ recv_data_free_func(recv_data);
+ }
+
+ return SUCCESS;
+}
+
+/* -------------- Demo 2 : Send packed RPC request. Slave echoes back as response. -------------- */
+int custom_rpc_demo2_request_echo_back_as_response(void) {
+ uint8_t *recv_data = NULL;
+ uint32_t recv_data_len = 0;
+ void (*recv_data_free_func)(void*) = NULL;
+ int ret = SUCCESS;
+
+ /* Create a byte stream with a specific pattern for verification */
+ uint32_t send_data_len = 1500;
+ uint8_t *send_data = calloc(1, send_data_len);
+ if (!send_data) {
+ printf("Failed to allocate memory for send data\n");
+ return FAILURE;
+ }
+
+ /* Fill with a recognizable pattern */
+ for (uint32_t i = 0; i < send_data_len; i++) {
+ send_data[i] = (i % 256);
+ }
+
+ /* Use echo back response to verify data integrity */
+ uint32_t custom_msg_id = CUSTOM_RPC_REQ_ID__ECHO_BACK_RESPONSE;
+
+ printf("[Demo 2] Sending a demo byte buffer of %u size to slave, expecting echo back as response.\n",
+ send_data_len);
+
+ if (test_custom_rpc_unserialised_request(custom_msg_id, send_data, send_data_len,
+ &recv_data, &recv_data_len, &recv_data_free_func) != SUCCESS) {
+ printf("Failed to send custom RPC unserialised message\n");
+ free(send_data);
+ return FAILURE;
+ }
+
+ /* Verify received data matches what was sent */
+ printf("Received %u bytes of data back as response\n", recv_data_len);
+
+ if (recv_data_len != send_data_len) {
+ printf("Data length mismatch! Sent: %u, Received: %u\n",
+ send_data_len, recv_data_len);
+ free(send_data);
+ if (recv_data_free_func && recv_data) {
+ recv_data_free_func(recv_data);
+ }
+ return FAILURE;
+ }
+
+ /* Compare byte by byte */
+ int mismatch = 0;
+ for (uint32_t i = 0; i < send_data_len; i++) {
+ if (send_data[i] != recv_data[i]) {
+ printf("Data mismatch at byte %u: sent 0x%02x, received 0x%02x\n",
+ i, send_data[i], recv_data[i]);
+ mismatch = 1;
+ break;
+ }
+ }
+
+ if (!mismatch) {
+ printf("Data verification successful - [All %u TX bytes] = [All %u RX bytes]!\n",
+ send_data_len, recv_data_len);
+ } else {
+ ret = FAILURE;
+ }
+
+ /* Clean up */
+ free(send_data);
+ if (recv_data_free_func && recv_data) {
+ recv_data_free_func(recv_data);
+ }
+
+ return ret;
+}
+
+/* -------------- Demo 3 : Send packed RPC request. Slave echoes back as event. -------------- */
+/* Function to set the reference data for verification */
+static void custom_rpc_set_verification_reference(uint8_t *data, uint32_t len) {
+ g_original_data = data;
+ g_original_data_len = len;
+ g_verification_result = 0; /* Reset result */
+}
+
+/* Custom event handler to verify the data received in the event */
+
+int custom_rpc_event_handler(ctrl_cmd_t *app_event) {
+ if (test_validate_ctrl_event(app_event)) {
+ printf("%s invalid event[%u]\n", __func__, app_event->msg_id);
+ CLEANUP_CTRL_MSG(app_event);
+ return FAILURE;
+ }
+
+ if (app_event->msg_id == CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG) {
+ custom_rpc_unserialised_data_t *p_e = &app_event->u.custom_rpc_unserialised_data;
+
+ /* Process based on custom event ID */
+ switch (p_e->custom_msg_id) {
+ case CUSTOM_RPC_EVENT_ID__DEMO_ECHO_BACK_REQUEST:
+ printf("[Demo 3] Received echo back event with %u bytes of data\n", p_e->data_len);
+
+#if 0
+ /* Print data hexdump */
+ printf("Data: ");
+ for (size_t i = 0; i < p_e->data_len && i < 32; i++) {
+ printf("%02X ", p_e->data[i]);
+ if ((i + 1) % 8 == 0) {
+ printf(" ");
+ }
+ }
+ if (p_e->data_len > 32) {
+ printf("... (%u more bytes)", p_e->data_len - 32);
+ }
+ printf("\n");
+#endif
+
+ /* Verify the data if we have a reference */
+ if (!g_original_data || !g_original_data_len) {
+ printf("[Demo 3] Verification reference data not set!\n");
+ g_verification_result = -1;
+ break;
+ }
+
+ if (g_original_data_len != p_e->data_len) {
+ printf("[Demo 3] Data length mismatch! Sent: %u, Received: %u\n",
+ g_original_data_len, p_e->data_len);
+ g_verification_result = -1;
+ break;
+ }
+
+ /* Verify received data matches what was sent originally */
+ int mismatch = 0;
+ for (uint32_t i = 0; i < p_e->data_len && i < g_original_data_len; i++) {
+ if (g_original_data[i] != p_e->data[i]) {
+ printf("Data mismatch at byte %" PRIu32 ": sent 0x%02x, received 0x%02x\n",
+ i, g_original_data[i], p_e->data[i]);
+ mismatch = 1;
+ g_verification_result = -1;
+ break;
+ }
+ }
+
+ if (!mismatch) {
+ printf("[Demo 3] Verified success: (All Rx bytes in event) = (All Tx bytes in request)\n");
+ g_verification_result = 1;
+ }
+ break;
+
+ default:
+ printf("[Demo 3] Unhandled custom RPC event ID [%u] with data length: %u bytes\n",
+ p_e->custom_msg_id, p_e->data_len);
+
+#if 0
+ /* Print data hexdump */
+ printf("Data: ");
+ for (size_t i = 0; i < p_e->data_len && i < 32; i++) {
+ printf("%02X ", p_e->data[i]);
+ }
+ if (p_e->data_len > 32) {
+ printf("... (%u more bytes)", p_e->data_len - 32);
+ }
+ printf("\n");
+#endif
+ break;
+ }
+ } else {
+ printf("Unhandled base RPC message: %u\n", app_event->msg_id);
+ }
+
+ CLEANUP_CTRL_MSG(app_event);
+ return SUCCESS;
+}
+
+int custom_rpc_demo3_request_echo_back_as_event(void) {
+ uint8_t *recv_data = NULL;
+ uint32_t recv_data_len = 0;
+ void (*recv_data_free_func)(void*) = NULL;
+ int ret = SUCCESS;
+ int verification_timeout = 5; /* seconds */
+
+ /* Create a byte stream with a specific pattern for verification */
+ uint32_t send_data_len = 1500;
+ uint8_t *send_data = calloc(1, send_data_len);
+ if (!send_data) {
+ printf("[Demo 3] Failed to allocate memory for send data\n");
+ return FAILURE;
+ }
+
+ /* Fill with a pattern that can be verified at event receipt */
+ for (uint32_t i = 0; i < send_data_len; i++) {
+ send_data[i] = ((i * 3) % 256);
+ }
+
+ /* Store the original callback before setting our custom one */
+ ctrl_resp_cb_t original_handler = NULL;
+
+ original_handler = get_event_callback(CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG);
+ if (!original_handler) {
+ printf("[Demo 3] No original event handler registered for CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG\n");
+ }
+
+ /* Set reference data for verification handler */
+ custom_rpc_set_verification_reference(send_data, send_data_len);
+
+ /* Register custom handler */
+ printf("[Demo 3] Setting custom event handler for verification\n");
+ if (set_event_callback(CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG, custom_rpc_event_handler) != CALLBACK_SET_SUCCESS) {
+ printf("[Demo 3] Failed to set custom event handler\n");
+ free(send_data);
+ return FAILURE;
+ }
+
+ printf("[Demo 3] Sending Custom Packed RPC request to slave. Expecting ack response. The data sent should be echoed back as an custom RPC event\n");
+
+ /* Use a message ID that will trigger an event response */
+ /* Slave is coded to respond with 'CUSTOM_RPC_EVENT_ID__DEMO_ECHO_BACK_REQUEST' when 'CUSTOM_RPC_REQ_ID__ECHO_BACK_AS_EVENT' is received
+ * You can change both sides as you wish */
+ uint32_t custom_msg_id = CUSTOM_RPC_REQ_ID__ECHO_BACK_AS_EVENT;
+
+ if (test_custom_rpc_unserialised_request(custom_msg_id, send_data, send_data_len,
+ &recv_data, &recv_data_len, &recv_data_free_func) != SUCCESS) {
+ printf("Failed to send custom RPC unserialised message\n");
+ ret = FAILURE;
+ goto cleanup;
+ }
+
+ /*
+ * For this demo, we don't need to verify the response data since we're expecting
+ * an event to be triggered. The event will be handled by the event callback.
+ */
+ printf("[Demo 3] Request sent successfully. Waiting for event callback verification...\n");
+
+ /* Clean up response data */
+ if (recv_data_free_func && recv_data) {
+ recv_data_free_func(recv_data);
+ }
+
+ /* Wait for verification to complete with timeout */
+ time_t start_time = time(NULL);
+ while (g_verification_result == 0 && (time(NULL) - start_time) < verification_timeout) {
+ sleep(1);
+ printf("Waiting for event verification...\n");
+ }
+
+ if (g_verification_result == 0) {
+ printf("Verification timed out - event might not have been received\n");
+ ret = FAILURE;
+ } else if (g_verification_result < 0) {
+ printf("Verification failed - data mismatch\n");
+ ret = FAILURE;
+ } else {
+ printf("Verification completed successfully\n");
+ }
+
+cleanup:
+ /* Reset data reference */
+ custom_rpc_set_verification_reference(NULL, 0);
+
+ /* Restore original handler */
+ printf("[Demo 3] Restoring original event handler\n");
+
+ /* Re-register the original event handler */
+ if (set_event_callback(CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG, original_handler) != CALLBACK_SET_SUCCESS) {
+ printf("[Demo 3] Failed to restore original event handlers\n");
+ ret = FAILURE;
+ }
+
+ /* Clean up send data */
+ free(send_data);
+
+ return ret;
+}
diff --git a/esp_hosted_fg/host/linux/host_control/c_support/app_custom_rpc.h b/esp_hosted_fg/host/linux/host_control/c_support/app_custom_rpc.h
new file mode 100644
index 0000000000..2761dcc6e8
--- /dev/null
+++ b/esp_hosted_fg/host/linux/host_control/c_support/app_custom_rpc.h
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Espressif Systems Wireless LAN device driver
+ *
+ * Copyright (C) 2015-2025 Espressif Systems (Shanghai) PTE LTD
+ *
+ * This software file (the "File") is distributed by Espressif Systems (Shanghai)
+ * PTE LTD under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef __APP_CUSTOM_RPC_H__
+#define __APP_CUSTOM_RPC_H__
+
+#include
+#include "ctrl_api.h"
+#include "esp_hosted_custom_rpc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Custom RPC Demo 1: Send a request with only acknowledgement
+ *
+ * This demo shows how to send a custom RPC request with packed data
+ * and receive only an acknowledgement. No specific data is expected in response.
+ *
+ * @return SUCCESS if the operation was successful, FAILURE otherwise
+ */
+int custom_rpc_demo1_request_only_ack(void);
+
+/**
+ * @brief Custom RPC Demo 2: Send a request and get echo back as response
+ *
+ * This demo shows how to send a custom RPC request with packed data
+ * and receive an echo back response. The response is verified to be
+ * the same as the sent data.
+ *
+ * @return SUCCESS if the operation was successful, FAILURE otherwise
+ */
+int custom_rpc_demo2_request_echo_back_as_response(void);
+
+/**
+ * @brief Custom RPC Demo 3: Send a request and get echo back as event
+ *
+ * This demo shows how to send a custom RPC request with packed data
+ * and receive an echo back as an event. The event data is verified
+ * in the event handler.
+ *
+ * @return SUCCESS if the operation was successful, FAILURE otherwise
+ */
+int custom_rpc_demo3_request_echo_back_as_event(void);
+
+/**
+ * @brief Custom RPC Event Handler
+ *
+ * This function is called when a custom RPC event is received.
+ *
+ * @param app_event The custom RPC event
+ */
+int custom_rpc_event_handler(ctrl_cmd_t *app_event);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __APP_CUSTOM_RPC_H__ */
diff --git a/esp_hosted_fg/host/linux/host_control/c_support/ctrl_config.h b/esp_hosted_fg/host/linux/host_control/c_support/ctrl_config.h
index 4747826160..a0299cacae 100644
--- a/esp_hosted_fg/host/linux/host_control/c_support/ctrl_config.h
+++ b/esp_hosted_fg/host/linux/host_control/c_support/ctrl_config.h
@@ -55,6 +55,7 @@
#define DISABLE_BT "disable_bt"
#define GET_FW_VERSION "get_fw_version"
+#define GET_DHCP_DNS_STATUS "get_dhcp_dns_status"
#define SET_COUNTRY_CODE "set_country_code"
/* ENABLED means ieee80211d ("additional regulatory domains") enabled */
@@ -62,6 +63,10 @@
#define GET_COUNTRY_CODE "get_country_code"
+#define CUSTOM_RPC_DEMO1 "send_packed_data__only_ack"
+#define CUSTOM_RPC_DEMO2 "send_packed_data__echo_back_as_response"
+#define CUSTOM_RPC_DEMO3 "send_packed_data__echo_back_as_event"
+
#ifndef SSID_LENGTH
#define SSID_LENGTH 33
#endif
diff --git a/esp_hosted_fg/host/linux/host_control/c_support/hosted_daemon.c b/esp_hosted_fg/host/linux/host_control/c_support/hosted_daemon.c
new file mode 100644
index 0000000000..5ece4499b5
--- /dev/null
+++ b/esp_hosted_fg/host/linux/host_control/c_support/hosted_daemon.c
@@ -0,0 +1,519 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Espressif Systems Wireless LAN device driver
+ *
+ * Copyright (C) 2015-2021 Espressif Systems (Shanghai) PTE LTD
+ *
+ */
+
+
+#include "test.h"
+#include "serial_if.h"
+#include
+#include "ctrl_api.h"
+#include
+#include
+#include
+#include
+#include
+#include "nw_helper_func.h"
+
+
+#define STA_INTERFACE "ethsta0"
+
+
+#define YES 1
+#define NO 0
+#define MIN_TIMESTAMP_STR_SIZE 30
+
+#define MAC_ADDR_LENGTH 18
+
+
+#define LOG_MSG(level, fmt, ...) \
+ do { \
+ if (!run_in_foreground) { \
+ syslog(level, fmt, ##__VA_ARGS__); \
+ } else { \
+ printf(fmt "\n", ##__VA_ARGS__); \
+ } \
+ } while(0)
+
+#define EXIT_SUCCESS 0
+#define EXIT_FAILURE 1
+
+#define CONFIG_FILE "/etc/esp-hosted/config.conf"
+
+#define LOCK_FILE "/var/run/hosted_daemon.lock"
+static int lock_fd = -1;
+
+
+static network_info_t sta_network;
+
+static uint8_t local_network_up = 0;
+
+static int run_in_foreground = 0;
+static const char *config_file = CONFIG_FILE;
+
+static inline ctrl_cmd_t * CTRL_CMD_DEFAULT_REQ()
+{
+ ctrl_cmd_t *req = (ctrl_cmd_t *)calloc(1, sizeof(ctrl_cmd_t));
+ req->msg_type = CTRL_REQ;
+ req->ctrl_resp_cb = NULL;
+ req->cmd_timeout_sec = DEFAULT_CTRL_RESP_TIMEOUT /*5 sec*/;
+ return req;
+}
+
+static char * get_timestamp(char *str, uint16_t str_size)
+{
+ if (str && str_size>=MIN_TIMESTAMP_STR_SIZE) {
+ time_t t = time(NULL);
+ struct tm tm = *localtime(&t);
+ sprintf(str, "%d-%02d-%02d %02d:%02d:%02d > ", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
+ return str;
+ }
+ return NULL;
+}
+
+static int event_cb(ctrl_cmd_t * app_event)
+{
+ /* Note: event_cb is callback run by rx-thread
+ * Do not trigger any blocking or time consuming opearations
+ * */
+ char ts[MIN_TIMESTAMP_STR_SIZE] = {'\0'};
+
+ if (test_validate_ctrl_event(app_event)) {
+ CLEANUP_CTRL_MSG(app_event);
+ return FAILURE;
+ }
+
+ switch(app_event->msg_id) {
+
+ case CTRL_EVENT_ESP_INIT: {
+ LOG_MSG(LOG_INFO, "%s App EVENT: ESP INIT",
+ get_timestamp(ts, MIN_TIMESTAMP_STR_SIZE));
+ break;
+ } case CTRL_EVENT_DHCP_DNS_STATUS: {
+ dhcp_dns_status_t *p_e = &app_event->u.dhcp_dns_status;
+ LOG_MSG(LOG_INFO, "%s App EVENT: DHCP DNS status: iface[%d] dhcp_up[%d] dns_up[%d]",
+ get_timestamp(ts, MIN_TIMESTAMP_STR_SIZE), p_e->iface, p_e->dhcp_up, p_e->dns_up);
+ if (p_e->dhcp_up) {
+ strncpy(sta_network.ip_addr, (const char *)p_e->dhcp_ip, MAC_ADDR_LENGTH);
+ strncpy(sta_network.netmask, (const char *)p_e->dhcp_nm, MAC_ADDR_LENGTH);
+ strncpy(sta_network.gateway, (const char *)p_e->dhcp_gw, MAC_ADDR_LENGTH);
+ strncpy(sta_network.default_route, (const char *)p_e->dhcp_gw, MAC_ADDR_LENGTH);
+ sta_network.ip_valid = 1;
+ } else {
+ local_network_up = 0;
+ sta_network.ip_valid = 0;
+ }
+ if (p_e->dns_up) {
+ strncpy(sta_network.dns_addr, (const char *)p_e->dns_ip, MAC_ADDR_LENGTH);
+ sta_network.dns_valid = 1;
+ } else {
+ sta_network.dns_valid = 0;
+ }
+
+ if (sta_network.dns_valid && sta_network.ip_valid) {
+ LOG_MSG(LOG_INFO, "Network identified as up");
+ up_sta_netdev__with_static_ip_dns_route(&sta_network);
+ add_dns(sta_network.dns_addr);
+ local_network_up = 1;
+ } else {
+ LOG_MSG(LOG_INFO, "Network identified as down");
+ down_sta_netdev(&sta_network);
+ remove_dns(sta_network.dns_addr);
+ local_network_up = 0;
+ }
+
+
+
+ break;
+ } default: {
+ LOG_MSG(LOG_ERR, "%s Invalid event[%u] to parse",
+ get_timestamp(ts, MIN_TIMESTAMP_STR_SIZE), app_event->msg_id);
+ break;
+ }
+ }
+ CLEANUP_CTRL_MSG(app_event);
+ return SUCCESS;
+}
+
+int resp_cb(ctrl_cmd_t * app_resp)
+{
+
+ if (test_validate_ctrl_resp(app_resp)) {
+ CLEANUP_CTRL_MSG(app_resp);
+ return FAILURE;
+ }
+
+ switch(app_resp->msg_id) {
+
+ case CTRL_RESP_GET_MAC_ADDR: {
+ LOG_MSG(LOG_INFO, "mac address is %s", app_resp->u.wifi_mac.mac);
+ break;
+
+ } case CTRL_RESP_GET_DHCP_DNS_STATUS: {
+ dhcp_dns_status_t *p = &app_resp->u.dhcp_dns_status;
+ if (p->dhcp_up) {
+ LOG_MSG(LOG_INFO, "DHCP IP: %s", p->dhcp_ip);
+ LOG_MSG(LOG_INFO, "DHCP NM: %s", p->dhcp_nm);
+ LOG_MSG(LOG_INFO, "DHCP GW: %s", p->dhcp_gw);
+ strncpy(sta_network.ip_addr, (const char *)p->dhcp_ip, MAC_ADDR_LENGTH);
+ strncpy(sta_network.netmask, (const char *)p->dhcp_nm, MAC_ADDR_LENGTH);
+ strncpy(sta_network.gateway, (const char *)p->dhcp_gw, MAC_ADDR_LENGTH);
+ sta_network.ip_valid = 1;
+ } else {
+ LOG_MSG(LOG_INFO, "DHCP is not up");
+ sta_network.ip_valid = 0;
+ }
+ if (p->dns_up) {
+ LOG_MSG(LOG_INFO, "DNS IP: %s", p->dns_ip);
+ strncpy(sta_network.dns_addr, (const char *)p->dns_ip, MAC_ADDR_LENGTH);
+ sta_network.dns_valid = 1;
+ } else {
+ LOG_MSG(LOG_INFO, "DNS is not up");
+ sta_network.dns_valid = 0;
+ }
+
+ break;
+ } default: {
+ LOG_MSG(LOG_ERR, "Unsupported Response[%u] to parse", app_resp->msg_id);
+ break;
+ }
+ }
+
+ CLEANUP_CTRL_MSG(app_resp);
+ return SUCCESS;
+}
+
+
+
+static int subscribe_events(void)
+{
+ /* Please note, the event_cb would be called asyncronously by underlying rx-thread
+ * 1. Do not do any blocking operation in event_cb.
+ * 2. Do not trigger any 'sync' rpc control request, as they are blocking in nature.
+ * 3. 'async' rpc control requests are allowed.
+ * 4. Be restrictive of code or execution time in event_cb,
+ * as it would block rx-thread for any next incoming messages
+ * */
+ int ret = SUCCESS;
+ int evt = 0;
+
+ typedef struct {
+ int event;
+ ctrl_resp_cb_t fun;
+ } event_callback_table_t;
+
+ event_callback_table_t events[] = {
+ { CTRL_EVENT_ESP_INIT, event_cb },
+ { CTRL_EVENT_DHCP_DNS_STATUS, event_cb },
+ };
+
+ for (evt=0; evtu.wifi_mac.mode = WIFI_MODE_STA;
+ resp = wifi_get_mac(req);
+
+ if (resp && resp->resp_event_status == SUCCESS) {
+ strncpy(sta_network.mac_addr, resp->u.wifi_mac.mac, MAC_ADDR_LENGTH);
+ }
+ free(req);
+
+ return resp_cb(resp);
+}
+
+static int fetch_ip_addr_from_slave(void)
+{
+ ctrl_cmd_t *resp = NULL;
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ req->cmd_timeout_sec = 1;
+
+ resp = get_dhcp_dns_status(req);
+ free(req);
+ return resp_cb(resp);
+}
+
+static uint8_t app_init_done = 0;
+static int init_app(void)
+{
+ if (app_init_done) {
+ return SUCCESS;
+ }
+
+ if (init_hosted_control_lib()) {
+ //printf("init hosted control lib failed\n");
+ return FAILURE;
+ }
+
+ test_is_network_split_on();
+
+ subscribe_events();
+
+ app_init_done = 1;
+ LOG_MSG(LOG_INFO, "RPC at host is ready");
+ return 0;
+}
+
+static void cleanup_app(void)
+{
+ if (!app_init_done) {
+ return;
+ }
+
+ LOG_MSG(LOG_INFO, "Cleaning up application");
+
+ unsubscribe_events();
+
+ control_path_platform_deinit();
+ deinit_hosted_control_lib();
+ app_init_done = 0;
+
+ /* Release lock file */
+ if (lock_fd >= 0) {
+ close(lock_fd);
+ unlink(LOCK_FILE);
+ }
+}
+
+static void reload_config(void)
+{
+ /* Add any configuration reload logic here */
+ LOG_MSG(LOG_INFO, "Configuration reloaded");
+}
+
+static void sig_handler(int signum)
+{
+ switch (signum) {
+ case SIGHUP:
+ reload_config();
+ break;
+ case SIGUSR1:
+ LOG_MSG(LOG_INFO, "SIGUSR1 received, cleaning up application");
+ cleanup_app();
+ break;
+ case SIGTERM:
+ case SIGINT:
+ LOG_MSG(LOG_INFO, "Clean-up and exit");
+ cleanup_app();
+ if (!run_in_foreground) {
+ closelog();
+ }
+ unlink("/var/run/hosted_daemon.pid");
+ exit(0);
+ break;
+ }
+}
+
+static void daemonize(void)
+{
+ pid_t pid;
+
+ /* Fork off the parent process */
+ pid = fork();
+ if (pid < 0) {
+ exit(EXIT_FAILURE);
+ }
+ if (pid > 0) {
+ exit(EXIT_SUCCESS);
+ }
+
+ /* Create new session */
+ if (setsid() < 0) {
+ exit(EXIT_FAILURE);
+ }
+
+ /* Fork off for the second time */
+ pid = fork();
+ if (pid < 0) {
+ exit(EXIT_FAILURE);
+ }
+ if (pid > 0) {
+ exit(EXIT_SUCCESS);
+ }
+
+ /* Set new file permissions */
+ umask(0);
+
+ /* Change the working directory */
+ chdir("/");
+
+ /* Close all open file descriptors */
+ int x;
+ for (x = sysconf(_SC_OPEN_MAX); x>=0; x--) {
+ close(x);
+ }
+
+ /* Open the log file */
+ openlog("hosted_daemon", LOG_PID, LOG_DAEMON);
+
+ /* Write PID file */
+ FILE *pid_fp = fopen("/var/run/hosted_daemon.pid", "w");
+ if (pid_fp) {
+ fprintf(pid_fp, "%d\n", getpid());
+ fclose(pid_fp);
+ }
+}
+
+static void print_usage(void) {
+ printf("Usage: hosted_daemon [-f] [-c config_file]\n");
+ printf(" -f Run in foreground (don't daemonize)\n");
+ printf(" -c Use alternate config file\n");
+}
+
+static int ensure_single_instance(void)
+{
+ struct flock fl = {
+ .l_type = F_WRLCK,
+ .l_whence = SEEK_SET,
+ .l_start = 0,
+ .l_len = 0
+ };
+
+ lock_fd = open(LOCK_FILE, O_RDWR | O_CREAT, 0640);
+ if (lock_fd < 0) {
+ LOG_MSG(LOG_ERR, "Cannot open lock file: %s", strerror(errno));
+ return FAILURE;
+ }
+
+ if (fcntl(lock_fd, F_SETLK, &fl) < 0) {
+ if (errno == EACCES || errno == EAGAIN) {
+ LOG_MSG(LOG_ERR, "Another instance is already running");
+ } else {
+ LOG_MSG(LOG_ERR, "Cannot lock file: %s", strerror(errno));
+ }
+ close(lock_fd);
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+
+int main(int argc, char *argv[])
+{
+ if(getuid()) {
+ printf("Please re-run program with superuser access. Exiting\n");
+ return FAILURE;
+ }
+
+ /* Parse arguments first */
+ if (argc > 1) {
+ if (strcmp(argv[1], "-f") == 0) {
+ run_in_foreground = 1;
+ } else if (strcmp(argv[1], "-c") == 0 && argc > 2) {
+ config_file = argv[2];
+ } else {
+ print_usage();
+ return FAILURE;
+ }
+ }
+
+ /* Initialize logging before any LOG_MSG calls */
+ if (!run_in_foreground) {
+ openlog("hosted_daemon", LOG_PID, LOG_DAEMON);
+ }
+
+ /* Now we can use LOG_MSG */
+ if(getuid()) {
+ LOG_MSG(LOG_ERR, "Please re-run program with superuser access");
+ if (!run_in_foreground) {
+ closelog();
+ }
+ return FAILURE;
+ }
+
+ /* Check for another instance before daemonizing */
+ if (ensure_single_instance() != SUCCESS) {
+ if (!run_in_foreground) {
+ closelog();
+ }
+ return FAILURE;
+ }
+
+ if (!run_in_foreground) {
+ /* Daemonize the process */
+ daemonize();
+ /* Note: daemonize() will reopen syslog */
+ }
+
+ /* Register Sig handler */
+ signal(SIGHUP, sig_handler);
+ signal(SIGINT, sig_handler);
+ signal(SIGTERM, sig_handler);
+ signal(SIGUSR1, sig_handler);
+
+ LOG_MSG(LOG_INFO, "Waiting for slave RPC");
+
+ update_host_network_port_range(49152, 61439);
+
+ while (1) {
+
+ if (init_app()) {
+ sleep(1);
+ continue;
+ }
+
+ if (!local_network_up) {
+
+ /* fetch MAC address */
+ fetch_mac_addr_from_slave();
+
+ if (strlen(sta_network.mac_addr)==0) {
+ LOG_MSG(LOG_ERR, "Failed to retrive the MAC address");
+ sleep(1);
+ continue;
+ }
+
+ fetch_ip_addr_from_slave();
+
+ if (sta_network.dns_valid && sta_network.ip_valid) {
+ LOG_MSG(LOG_INFO, "Network identified as up");
+ up_sta_netdev__with_static_ip_dns_route(&sta_network);
+ add_dns(sta_network.dns_addr);
+ local_network_up = 1;
+ } else {
+ LOG_MSG(LOG_INFO, "Network identified as down");
+ down_sta_netdev(&sta_network);
+ remove_dns(sta_network.dns_addr);
+ local_network_up = 0;
+ }
+ }
+
+ sleep(1);
+ }
+
+ cleanup_app();
+ LOG_MSG(LOG_INFO, "Exiting..");
+ if (!run_in_foreground) {
+ closelog();
+ }
+ return 0;
+}
diff --git a/esp_hosted_fg/host/linux/host_control/c_support/hosted_shell.c b/esp_hosted_fg/host/linux/host_control/c_support/hosted_shell.c
new file mode 100644
index 0000000000..bfd4a2111c
--- /dev/null
+++ b/esp_hosted_fg/host/linux/host_control/c_support/hosted_shell.c
@@ -0,0 +1,1728 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Espressif Systems Wireless LAN device driver
+ *
+ * Copyright (C) 2015-2021 Espressif Systems (Shanghai) PTE LTD
+ */
+
+#include "hosted_shell.h"
+#include "test.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "nw_helper_func.h"
+#include "esp_hosted_custom_rpc.h"
+#include "app_custom_rpc.h"
+#include
+
+
+#define MAC_ADDR_LENGTH 18
+#define NETWORK_CHECK_INTERVAL_MS 100
+#define RPC_RETRY_INTERVAL_MS 1000
+
+#define POLL_FOR_IP_RESTORE (0)
+
+/* Define WiFi band mode constants */
+#define WIFI_BAND_MODE_AUTO 3
+#define WIFI_BAND_MODE_24G 1
+#define WIFI_BAND_MODE_5G 2
+
+/* Define WiFi power save mode constants */
+#define WIFI_POWER_SAVE_MODE_NONE 0
+#define WIFI_POWER_SAVE_MODE_MIN 1
+#define WIFI_POWER_SAVE_MODE_MAX 2
+
+#define CHECK_RPC_ACTIVE() \
+ if (!is_rpc_active()) { \
+ printf("%s: rpc is inactive yet, retry later\n", __func__); \
+ return FAILURE; \
+ }
+
+
+extern network_info_t sta_network;
+extern network_info_t ap_network;
+
+/* Lock file handling */
+#define LOCK_FILE "/var/run/hosted_shell.lock"
+static int lock_fd = -1;
+
+/* Thread handling */
+static pthread_t auto_ip_restore_thread;
+static int exit_thread_auto_ip_restore = 0;
+static uint8_t rpc_initialized = 0;
+
+
+/* RPC state management */
+typedef enum {
+ RPC_STATE_INIT = 0,
+ RPC_STATE_ERROR,
+ RPC_STATE_ACTIVE,
+ RPC_STATE_INACTIVE,
+} rpc_state_t;
+
+static rpc_state_t rpc_state = RPC_STATE_INIT;
+
+/* Add state check helper */
+#define is_rpc_active() (rpc_state >= RPC_STATE_ACTIVE)
+
+#define MAX_CMD_ARGS 16
+#define MAX_HINT_COUNT 10
+#define MAX_SUGGESTION_LINES 5
+
+/* Shell context for tracking state */
+static shell_context_t *current_context = NULL;
+
+static void set_shell_context(shell_context_t *ctx) {
+ current_context = ctx;
+}
+
+shell_context_t *get_shell_context(void) {
+ return current_context;
+}
+
+static int ensure_single_instance(void) {
+ struct flock fl = {
+ .l_type = F_WRLCK,
+ .l_whence = SEEK_SET,
+ .l_start = 0,
+ .l_len = 0
+ };
+
+ lock_fd = open(LOCK_FILE, O_RDWR | O_CREAT, 0640);
+ if (lock_fd < 0) {
+ printf("Cannot open lock file: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if (fcntl(lock_fd, F_SETLK, &fl) < 0) {
+ if (errno == EACCES || errno == EAGAIN) {
+ printf("Another instance is already running\n");
+ } else {
+ printf("Cannot lock file: %s\n", strerror(errno));
+ }
+ close(lock_fd);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Helper function to parse arguments */
+static bool is_arg_true(const char *value) {
+ if (!value) return false;
+ return (strcasecmp(value, "true") == 0 ||
+ strcasecmp(value, "yes") == 0 ||
+ strcasecmp(value, "1") == 0);
+}
+
+/* Helper function to get argument value */
+static const char *get_arg_value(int argc, char **argv, const cmd_arg_t *args, int arg_count, const char *arg_name) {
+ for (int i = 1; i < argc - 1; i++) {
+ if (strcmp(argv[i], arg_name) == 0) {
+ return argv[i + 1];
+ }
+ }
+ return NULL;
+}
+
+/* Helper function to parse and validate arguments */
+static bool parse_arguments(int argc, char **argv, const cmd_arg_t *args, int arg_count) {
+ bool result = true;
+
+ /* Check for required arguments */
+ for (int i = 0; i < arg_count; i++) {
+ if (args[i].required) {
+ bool found = false;
+ for (int j = 1; j < argc; j++) {
+ if (strcmp(argv[j], args[i].name) == 0 && j + 1 < argc) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ printf("Missing required argument: %s\n", args[i].name);
+ result = false;
+ }
+ }
+ }
+
+ /* Check argument values */
+ for (int i = 1; i < argc; i++) {
+ if (argv[i][0] == '-' && argv[i][1] == '-') {
+ bool valid_arg = false;
+ int arg_idx = -1;
+
+ /* Find the argument in our definition */
+ for (int j = 0; j < arg_count; j++) {
+ if (strcmp(argv[i], args[j].name) == 0) {
+ valid_arg = true;
+ arg_idx = j;
+ break;
+ }
+ }
+
+ if (!valid_arg) {
+ printf("Unknown argument: %s\n", argv[i]);
+ result = false;
+ continue;
+ }
+
+ /* Skip if no value provided */
+ if (i + 1 >= argc || argv[i + 1][0] == '-') {
+ printf("No value provided for argument: %s\n", argv[i]);
+ result = false;
+ continue;
+ }
+
+ /* Validate value based on type */
+ const char *value = argv[i + 1];
+
+ switch (args[arg_idx].type) {
+ case ARG_TYPE_INT: {
+ char *endptr;
+ strtol(value, &endptr, 10);
+ if (*endptr != '\0') {
+ printf("Invalid integer value for %s: %s\n", argv[i], value);
+ result = false;
+ }
+ break;
+ }
+ case ARG_TYPE_BOOL: {
+ if (strcasecmp(value, "true") != 0 &&
+ strcasecmp(value, "false") != 0 &&
+ strcasecmp(value, "yes") != 0 &&
+ strcasecmp(value, "no") != 0 &&
+ strcasecmp(value, "1") != 0 &&
+ strcasecmp(value, "0") != 0) {
+ printf("Invalid boolean value for %s: %s\n", argv[i], value);
+ printf("Use true/false, yes/no, or 1/0\n");
+ result = false;
+ }
+ break;
+ }
+ case ARG_TYPE_CHOICE: {
+ bool valid_choice = false;
+ for (int j = 0; args[arg_idx].choices[j]; j++) {
+ if (strcasecmp(value, args[arg_idx].choices[j]) == 0) {
+ valid_choice = true;
+ break;
+ }
+ }
+ if (!valid_choice) {
+ printf("Invalid choice for %s: %s\n", argv[i], value);
+ printf("Valid choices are: ");
+ for (int j = 0; args[arg_idx].choices[j]; j++) {
+ printf("%s", args[arg_idx].choices[j]);
+ if (args[arg_idx].choices[j+1]) {
+ printf(", ");
+ }
+ }
+ printf("\n");
+ result = false;
+ }
+ break;
+ }
+ default:
+ /* No validation for string type */
+ break;
+ }
+
+ /* Skip the value in the next iteration */
+ i++;
+ }
+ }
+
+ return result;
+}
+
+/* Define choices for command arguments */
+static const char *wifi_mode_choices[] = {"station", "softap", "station+softap", NULL};
+static const char *wifi_powersave_choices[] = {"none", "min", "max", NULL};
+static const char *wifi_interface_choices[] = {"station", "softap", NULL};
+static const char *wifi_band_mode_choices[] = {"2.4G", "5G", "auto", NULL};
+static const char *wifi_sec_prot_choices[] = {"open", "wpa_psk", "wpa2_psk", "wpa_wpa2_psk", NULL};
+
+/* Define command arguments */
+static const cmd_arg_t wifi_set_mode_args[] = {
+ {"--mode", "WiFi mode [station, softap, station+softap]", ARG_TYPE_CHOICE, true, wifi_mode_choices}
+};
+
+static const cmd_arg_t wifi_set_mac_args[] = {
+ {"--mode", "Interface [station, softap]", ARG_TYPE_CHOICE, true, wifi_interface_choices},
+ {"--mac", "MAC address", ARG_TYPE_STRING, true, NULL}
+};
+
+static const cmd_arg_t connect_ap_args[] = {
+ {"--ssid", "SSID of AP", ARG_TYPE_STRING, true, NULL},
+ {"--password", "Password of AP", ARG_TYPE_STRING, true, NULL},
+ {"--bssid", "MAC address of AP", ARG_TYPE_STRING, false, NULL},
+ {"--use_wpa3", "Use WPA3 security protocol", ARG_TYPE_BOOL, false, NULL},
+ {"--listen_interval", "Number of AP beacons station will sleep", ARG_TYPE_INT, false, NULL},
+ {"--run_dhcp_client", "Request DHCP", ARG_TYPE_BOOL, false, NULL},
+ {"--band_mode", "Connect on 2.4G or 5G band", ARG_TYPE_CHOICE, false, wifi_band_mode_choices}
+};
+
+static const cmd_arg_t disconnect_ap_args[] = {
+ {"--reset_dhcp", "Clean DHCP", ARG_TYPE_BOOL, false, NULL}
+};
+
+static const cmd_arg_t softap_vendor_ie_args[] = {
+ {"--enable", "Set or Reset Vendor IE", ARG_TYPE_BOOL, true, NULL},
+ {"--data", "String to set in softap Wi-Fi broadcast beacon", ARG_TYPE_STRING, false, NULL}
+};
+
+static const cmd_arg_t start_softap_args[] = {
+ {"--ssid", "SSID to configure ESP softAP", ARG_TYPE_STRING, true, NULL},
+ {"--password", "Password to configure ESP softAP", ARG_TYPE_STRING, true, NULL},
+ {"--channel", "Wi-Fi channel [1-11]", ARG_TYPE_INT, false, NULL},
+ {"--sec_prot", "Security Protocol", ARG_TYPE_CHOICE, false, wifi_sec_prot_choices},
+ {"--max_conn", "Max number of stations that can connect", ARG_TYPE_INT, false, NULL},
+ {"--hide_ssid", "Hide SSID broadcasting", ARG_TYPE_BOOL, false, NULL},
+ {"--bw", "Wi-Fi Bandwidth [20|40]", ARG_TYPE_INT, false, NULL},
+ {"--start_dhcp_server", "Start DHCP server", ARG_TYPE_BOOL, false, NULL},
+ {"--band_mode", "Band mode [2.4G, 5G, auto]", ARG_TYPE_CHOICE, false, wifi_band_mode_choices}
+};
+
+static const cmd_arg_t set_wifi_power_save_args[] = {
+ {"--mode", "Power save mode [none, min, max]", ARG_TYPE_CHOICE, false, wifi_powersave_choices}
+};
+
+static const cmd_arg_t set_wifi_max_tx_power_args[] = {
+ {"--map_val", "Set Wi-Fi max power in map value", ARG_TYPE_INT, true, NULL}
+};
+
+static const cmd_arg_t ota_update_args[] = {
+ {"--url", "URL of ESP firmware binary", ARG_TYPE_STRING, true, NULL}
+};
+
+static const cmd_arg_t heartbeat_args[] = {
+ {"--enable", "Enable or disable heartbeat", ARG_TYPE_BOOL, false, NULL},
+ {"--duration", "Heartbeat duration in seconds", ARG_TYPE_INT, false, NULL}
+};
+
+
+static const char *event_choices[] = {
+ "esp_init",
+ "heartbeat",
+ "sta_connected",
+ "sta_disconnected",
+ "softap_sta_connected",
+ "softap_sta_disconnected",
+ "dhcp_dns_status",
+ "custom_packed_event",
+ NULL
+};
+
+static const cmd_arg_t subscribe_event_args[] = {
+ {"--event", "Event to subscribe to", ARG_TYPE_CHOICE, true, event_choices}
+};
+
+static const cmd_arg_t unsubscribe_event_args[] = {
+ {"--event", "Event to unsubscribe from", ARG_TYPE_CHOICE, true, event_choices}
+};
+
+static const cmd_arg_t custom_rpc_request_args[] = {
+ {"--demo", "Demo number (1, 2, or 3)", ARG_TYPE_INT, true, NULL}
+};
+
+static const cmd_arg_t set_country_code_args[] = {
+ {"--code", "Country code (e.g. US, IN, CN)", ARG_TYPE_STRING, true, NULL}
+};
+
+/* Forward declarations for command handlers */
+static int handle_exit(int argc, char **argv);
+static int handle_help(int argc, char **argv);
+static int handle_get_mac(int argc, char **argv);
+static int handle_wifi_get_mode(int argc, char **argv);
+static int handle_wifi_set_mode(int argc, char **argv);
+static int handle_wifi_set_mac(int argc, char **argv);
+static int handle_get_available_ap(int argc, char **argv);
+static int handle_connect(int argc, char **argv);
+static int handle_get_connected_ap_info(int argc, char **argv);
+static int handle_disconnect_ap(int argc, char **argv);
+static int handle_softap_vendor_ie(int argc, char **argv);
+static int handle_start_softap(int argc, char **argv);
+static int handle_get_softap_info(int argc, char **argv);
+static int handle_softap_connected_clients_info(int argc, char **argv);
+static int handle_stop_softap(int argc, char **argv);
+static int handle_set_wifi_power_save(int argc, char **argv);
+static int handle_get_wifi_power_save(int argc, char **argv);
+static int handle_set_wifi_max_tx_power(int argc, char **argv);
+static int handle_get_wifi_curr_tx_power(int argc, char **argv);
+static int handle_enable_wifi(int argc, char **argv);
+static int handle_disable_wifi(int argc, char **argv);
+static int handle_enable_bt(int argc, char **argv);
+static int handle_disable_bt(int argc, char **argv);
+static int handle_get_fw_version(int argc, char **argv);
+static int handle_ota_update(int argc, char **argv);
+static int handle_heartbeat(int argc, char **argv);
+static int handle_subscribe_event(int argc, char **argv);
+static int handle_unsubscribe_event(int argc, char **argv);
+static int handle_set_host_port_range(int argc, char **argv);
+static int handle_custom_demo_rpc_request(int argc, char **argv);
+static int handle_set_country_code(int argc, char **argv);
+static int handle_set_country_code_with_ieee80211d_on(int argc, char **argv);
+static int handle_get_country_code(int argc, char **argv);
+
+
+
+/* Command table */
+static const shell_command_t commands[] = {
+ {"help", "Show this help message", handle_help, NULL, 0},
+ {"get_wifi_mode", "Get Wi-Fi mode", handle_wifi_get_mode, NULL, 0},
+ {"set_wifi_mode", "Set Wi-Fi mode", handle_wifi_set_mode, wifi_set_mode_args, sizeof(wifi_set_mode_args)/sizeof(cmd_arg_t)},
+ {"get_wifi_mac", "Get MAC address", handle_get_mac, NULL, 0},
+ {"set_wifi_mac", "Set MAC address", handle_wifi_set_mac, wifi_set_mac_args, sizeof(wifi_set_mac_args)/sizeof(cmd_arg_t)},
+ {"get_available_ap", "Scan for available networks", handle_get_available_ap, NULL, 0},
+ {"connect_ap", "Connect to a network", handle_connect, connect_ap_args, sizeof(connect_ap_args)/sizeof(cmd_arg_t)},
+ {"get_connected_ap_info", "Get info about connected AP", handle_get_connected_ap_info, NULL, 0},
+ {"disconnect_ap", "Disconnect from network", handle_disconnect_ap, disconnect_ap_args, sizeof(disconnect_ap_args)/sizeof(cmd_arg_t)},
+ {"softap_vendor_ie", "Set vendor specific IE in softap beacon", handle_softap_vendor_ie, softap_vendor_ie_args, sizeof(softap_vendor_ie_args)/sizeof(cmd_arg_t)},
+ {"start_softap", "Start SoftAP", handle_start_softap, start_softap_args, sizeof(start_softap_args)/sizeof(cmd_arg_t)},
+ {"get_softap_info", "Get SoftAP configuration", handle_get_softap_info, NULL, 0},
+ {"softap_connected_clients_info", "Get clients connected to SoftAP", handle_softap_connected_clients_info, NULL, 0},
+ {"stop_softap", "Stop SoftAP", handle_stop_softap, NULL, 0},
+ {"set_wifi_power_save", "Set power save mode", handle_set_wifi_power_save, set_wifi_power_save_args, sizeof(set_wifi_power_save_args)/sizeof(cmd_arg_t)},
+ {"get_wifi_power_save", "Get power save mode", handle_get_wifi_power_save, NULL, 0},
+ {"set_wifi_max_tx_power", "Set maximum TX power", handle_set_wifi_max_tx_power, set_wifi_max_tx_power_args, sizeof(set_wifi_max_tx_power_args)/sizeof(cmd_arg_t)},
+ {"get_wifi_curr_tx_power", "Get current TX power", handle_get_wifi_curr_tx_power, NULL, 0},
+ {"enable_wifi", "Enable Wi-Fi", handle_enable_wifi, NULL, 0},
+ {"disable_wifi", "Disable Wi-Fi", handle_disable_wifi, NULL, 0},
+ {"enable_bt", "Enable Bluetooth", handle_enable_bt, NULL, 0},
+ {"disable_bt", "Disable Bluetooth", handle_disable_bt, NULL, 0},
+ {"get_fw_version", "Get firmware version", handle_get_fw_version, NULL, 0},
+ {"ota_update", "Update firmware via OTA", handle_ota_update, ota_update_args, sizeof(ota_update_args)/sizeof(cmd_arg_t)},
+ {"heartbeat", "Configure heartbeat", handle_heartbeat, heartbeat_args, sizeof(heartbeat_args)/sizeof(cmd_arg_t)},
+ {"subscribe_event", "Subscribe to events", handle_subscribe_event, subscribe_event_args, sizeof(subscribe_event_args)/sizeof(cmd_arg_t)},
+ {"unsubscribe_event", "Unsubscribe from events", handle_unsubscribe_event, unsubscribe_event_args, sizeof(unsubscribe_event_args)/sizeof(cmd_arg_t)},
+ {"custom_demo_rpc_request", "Send custom RPC demo request and wait for response", handle_custom_demo_rpc_request, custom_rpc_request_args, sizeof(custom_rpc_request_args)/sizeof(cmd_arg_t)},
+ {"cli_set_host_port_range", "Set host port range", handle_set_host_port_range, NULL, 0},
+ {"exit", "Exit the shell", handle_exit, NULL, 0},
+ {"quit", "Exit the shell", handle_exit, NULL, 0},
+ {"q", "Exit the shell", handle_exit, NULL, 0},
+ {"set_country_code", "Set Wi-Fi country code", handle_set_country_code, set_country_code_args, sizeof(set_country_code_args)/sizeof(cmd_arg_t)},
+ {"set_country_code_with_ieee80211d_on", "Set Wi-Fi country code with ieee80211d enabled", handle_set_country_code_with_ieee80211d_on, NULL, 0},
+ {"get_country_code", "Get Wi-Fi country code", handle_get_country_code, NULL, 0},
+ {NULL, NULL, NULL, NULL, 0}
+};
+
+/* Command handler implementations */
+static int handle_exit(int argc, char **argv) {
+ printf("Exiting shell\n");
+ exit_thread_auto_ip_restore = 1;
+ return 0;
+}
+
+static int handle_help(int argc, char **argv) {
+ const shell_command_t *cmd;
+
+ if (argc > 1) {
+ /* Detailed help for a specific command */
+ for (cmd = commands; cmd->name; cmd++) {
+ if (strcmp(cmd->name, argv[1]) == 0) {
+ printf("\nCommand: %s\n", cmd->name);
+ printf("Description: %s\n\n", cmd->help);
+
+ if (cmd->args && cmd->arg_count > 0) {
+ printf("Arguments:\n");
+ for (int i = 0; i < cmd->arg_count; i++) {
+ printf(" %-20s %-10s %s\n",
+ cmd->args[i].name,
+ cmd->args[i].required ? "[Required]" : "[Optional]",
+ cmd->args[i].help);
+
+ if (cmd->args[i].type == ARG_TYPE_CHOICE && cmd->args[i].choices) {
+ printf(" Choices: ");
+ for (int j = 0; cmd->args[i].choices[j]; j++) {
+ printf("%s", cmd->args[i].choices[j]);
+ if (cmd->args[i].choices[j+1]) {
+ printf(", ");
+ }
+ }
+ printf("\n");
+ }
+ }
+
+ /* Show default values from ctrl_config.h */
+ if (strcmp(cmd->name, "connect_ap") == 0) {
+ printf("\nDefault values:\n");
+ printf(" SSID: %s\n", STATION_MODE_SSID);
+ printf(" Password: %s\n", STATION_MODE_PWD);
+ printf(" BSSID: %s\n", STATION_MODE_BSSID);
+ printf(" Band Mode: %d\n", STATION_BAND_MODE);
+ printf(" WPA3 Support: %s\n", STATION_MODE_IS_WPA3_SUPPORTED ? "true" : "false");
+ printf(" Listen Interval: %d\n", STATION_MODE_LISTEN_INTERVAL);
+ } else if (strcmp(cmd->name, "start_softap") == 0) {
+ printf("\nDefault values:\n");
+ printf(" SSID: %s\n", SOFTAP_MODE_SSID);
+ printf(" Password: %s\n", SOFTAP_MODE_PWD);
+ printf(" Channel: %d\n", SOFTAP_MODE_CHANNEL);
+ printf(" Max Connections: %d\n", SOFTAP_MODE_MAX_ALLOWED_CLIENTS);
+ printf(" Hidden SSID: %s\n", SOFTAP_MODE_SSID_HIDDEN ? "true" : "false");
+ printf(" Bandwidth: %d\n", SOFTAP_MODE_BANDWIDTH);
+ printf(" Band Mode: %d\n", SOFTAP_BAND_MODE);
+ }
+ }
+ return 0;
+ }
+ }
+ printf("Unknown command: %s\n", argv[1]);
+ return -1;
+ }
+
+ /* General help - list all commands */
+ printf("\nAvailable commands:\n");
+ for (cmd = commands; cmd->name; cmd++) {
+ if (strcmp(cmd->name, "q") == 0 ||
+ strcmp(cmd->name, "exit") == 0 ||
+ strcmp(cmd->name, "quit") == 0) {
+ continue;
+ }
+ printf(" %-30s %s\n", cmd->name, cmd->help);
+
+ /* Show required args inline for important commands */
+ if (cmd->args && cmd->arg_count > 0) {
+ int req_count = 0;
+ for (int i = 0; i < cmd->arg_count; i++) {
+ if (cmd->args[i].required) {
+ req_count++;
+ }
+ }
+
+ if (req_count > 0) {
+ printf(" Required args: ");
+ int printed = 0;
+ for (int i = 0; i < cmd->arg_count; i++) {
+ if (cmd->args[i].required) {
+ printf("%s%s", printed > 0 ? ", " : "", cmd->args[i].name);
+ printed++;
+ }
+ }
+ printf("\n");
+ }
+
+ /* Always show that there are optional args if present */
+ int opt_count = cmd->arg_count - req_count;
+ if (opt_count > 0) {
+ printf(" Optional args: %d (use 'help %s' for details)\n", opt_count, cmd->name);
+ }
+ }
+ }
+
+ printf("\nUse 'help ' for detailed information about a command\n");
+ return 0;
+}
+
+static int handle_get_mac(int argc, char **argv) {
+ if (argc != 2) {
+ printf("Usage: wifi_get_mac \n");
+ return FAILURE;
+ }
+
+ CHECK_RPC_ACTIVE();
+
+ if (strcmp(argv[1], "station") == 0) {
+ if (test_station_mode_get_mac_addr(sta_network.mac_addr) == SUCCESS) {
+ printf("Station MAC address: %s\n", sta_network.mac_addr);
+ return SUCCESS;
+ } else {
+ printf("Failed to get station MAC address\n");
+ return FAILURE;
+ }
+ } else if (strcmp(argv[1], "softap") == 0) {
+ if (test_softap_mode_get_mac_addr(ap_network.mac_addr) == SUCCESS) {
+ printf("SoftAP MAC address: %s\n", ap_network.mac_addr);
+ return SUCCESS;
+ } else {
+ printf("Failed to get SoftAP MAC address\n");
+ return FAILURE;
+ }
+ } else {
+ printf("Invalid mode. Use 'station' or 'softap'\n");
+ return FAILURE;
+ }
+}
+
+static int handle_wifi_set_mac(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+
+ if (!parse_arguments(argc, argv, wifi_set_mac_args, sizeof(wifi_set_mac_args)/sizeof(cmd_arg_t))) {
+ return FAILURE;
+ }
+
+ const char *mode_str = get_arg_value(argc, argv, wifi_set_mac_args,
+ sizeof(wifi_set_mac_args)/sizeof(cmd_arg_t),
+ "--mode");
+ const char *mac = get_arg_value(argc, argv, wifi_set_mac_args,
+ sizeof(wifi_set_mac_args)/sizeof(cmd_arg_t),
+ "--mac");
+
+ int mode;
+ if (strcmp(mode_str, "station") == 0) {
+ mode = WIFI_MODE_STA;
+ } else if (strcmp(mode_str, "softap") == 0) {
+ mode = WIFI_MODE_AP;
+ } else {
+ printf("Invalid mode. Use 'station' or 'softap'\n");
+ return FAILURE;
+ }
+
+ return test_set_mac_addr_with_params(mode, (char *)mac);
+}
+
+static int handle_wifi_get_mode(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+ return test_get_wifi_mode();
+}
+
+static int handle_wifi_set_mode(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+
+ if (!parse_arguments(argc, argv, wifi_set_mode_args, sizeof(wifi_set_mode_args)/sizeof(cmd_arg_t))) {
+ return FAILURE;
+ }
+
+ const char *mode_str = get_arg_value(argc, argv, wifi_set_mode_args,
+ sizeof(wifi_set_mode_args)/sizeof(cmd_arg_t),
+ "--mode");
+
+ int mode;
+ if (strcmp(mode_str, "station") == 0) {
+ mode = WIFI_MODE_STA;
+ } else if (strcmp(mode_str, "softap") == 0) {
+ mode = WIFI_MODE_AP;
+ } else if (strcmp(mode_str, "station+softap") == 0) {
+ mode = WIFI_MODE_APSTA;
+ } else {
+ printf("Invalid mode. Use 'station', 'softap', or 'station+softap'\n");
+ return FAILURE;
+ }
+
+ return test_set_wifi_mode(mode);
+}
+
+static int handle_get_available_ap(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+ return test_get_available_wifi();
+}
+
+static int handle_connect(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+
+ if (!parse_arguments(argc, argv, connect_ap_args, sizeof(connect_ap_args)/sizeof(cmd_arg_t))) {
+ return FAILURE;
+ }
+
+ const char *ssid = get_arg_value(argc, argv, connect_ap_args,
+ sizeof(connect_ap_args)/sizeof(cmd_arg_t),
+ "--ssid");
+ const char *pwd = get_arg_value(argc, argv, connect_ap_args,
+ sizeof(connect_ap_args)/sizeof(cmd_arg_t),
+ "--password");
+ const char *bssid = get_arg_value(argc, argv, connect_ap_args,
+ sizeof(connect_ap_args)/sizeof(cmd_arg_t),
+ "--bssid");
+ const char *use_wpa3 = get_arg_value(argc, argv, connect_ap_args,
+ sizeof(connect_ap_args)/sizeof(cmd_arg_t),
+ "--use_wpa3");
+ const char *listen_interval = get_arg_value(argc, argv, connect_ap_args,
+ sizeof(connect_ap_args)/sizeof(cmd_arg_t),
+ "--listen_interval");
+ const char *band_mode = get_arg_value(argc, argv, connect_ap_args,
+ sizeof(connect_ap_args)/sizeof(cmd_arg_t),
+ "--band_mode");
+
+ /* Use default values from ctrl_config.h if arguments are not provided */
+ if (!ssid || strlen(ssid)==0) {
+ printf("SSID is mandatory\n");
+ return FAILURE;
+ }
+#if 0
+ if (!pwd) {
+ pwd = STATION_MODE_PWD;
+ printf("Using pre-configured password: %s\n", pwd);
+ }
+#endif
+
+ if (!bssid) {
+ bssid = STATION_MODE_BSSID;
+ //printf("Using pre-configured BSSID: %s\n", bssid);
+ }
+
+ bool use_wpa3_value = use_wpa3 ? is_arg_true(use_wpa3) : STATION_MODE_IS_WPA3_SUPPORTED;
+ int listen_interval_value = listen_interval ? atoi(listen_interval) : STATION_MODE_LISTEN_INTERVAL;
+
+ int band_mode_value = STATION_BAND_MODE;
+ if (band_mode) {
+ if (strcmp(band_mode, "2.4G") == 0) {
+ band_mode_value = WIFI_BAND_MODE_24G;
+ } else if (strcmp(band_mode, "5G") == 0) {
+ band_mode_value = WIFI_BAND_MODE_5G;
+ } else if (strcmp(band_mode, "auto") == 0) {
+ band_mode_value = WIFI_BAND_MODE_AUTO;
+ }
+ }
+
+ /*printf("ssid: %s pwd: %s bssid: %s use_wpa3: %s listen_interval: %s band_mode: %s\n",
+ ssid, pwd, bssid, use_wpa3, listen_interval, band_mode);*/
+
+ return test_station_mode_connect_with_params(
+ ssid,
+ pwd,
+ bssid,
+ use_wpa3_value,
+ listen_interval_value,
+ band_mode_value
+ );
+}
+
+static int handle_get_connected_ap_info(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+ return test_station_mode_get_info();
+}
+
+static int handle_disconnect_ap(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+
+ if (!parse_arguments(argc, argv, disconnect_ap_args, sizeof(disconnect_ap_args)/sizeof(cmd_arg_t))) {
+ return FAILURE;
+ }
+
+ const char *reset_dhcp = get_arg_value(argc, argv, disconnect_ap_args,
+ sizeof(disconnect_ap_args)/sizeof(cmd_arg_t),
+ "--reset_dhcp");
+
+ return test_station_mode_disconnect_with_params(reset_dhcp ? is_arg_true(reset_dhcp) : false);
+}
+
+static int handle_softap_vendor_ie(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+
+ if (!parse_arguments(argc, argv, softap_vendor_ie_args, sizeof(softap_vendor_ie_args)/sizeof(cmd_arg_t))) {
+ return FAILURE;
+ }
+
+ const char *enable = get_arg_value(argc, argv, softap_vendor_ie_args,
+ sizeof(softap_vendor_ie_args)/sizeof(cmd_arg_t),
+ "--enable");
+ const char *data = get_arg_value(argc, argv, softap_vendor_ie_args,
+ sizeof(softap_vendor_ie_args)/sizeof(cmd_arg_t),
+ "--data");
+
+ return test_softap_mode_set_vendor_ie(enable ? is_arg_true(enable) : true, data ? data : "");
+}
+
+static int handle_start_softap(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+
+ if (!parse_arguments(argc, argv, start_softap_args, sizeof(start_softap_args)/sizeof(cmd_arg_t))) {
+ return FAILURE;
+ }
+
+ const char *ssid = get_arg_value(argc, argv, start_softap_args,
+ sizeof(start_softap_args)/sizeof(cmd_arg_t),
+ "--ssid");
+ const char *password = get_arg_value(argc, argv, start_softap_args,
+ sizeof(start_softap_args)/sizeof(cmd_arg_t),
+ "--password");
+ const char *channel = get_arg_value(argc, argv, start_softap_args,
+ sizeof(start_softap_args)/sizeof(cmd_arg_t),
+ "--channel");
+ const char *sec_prot = get_arg_value(argc, argv, start_softap_args,
+ sizeof(start_softap_args)/sizeof(cmd_arg_t),
+ "--sec_prot");
+ const char *max_conn = get_arg_value(argc, argv, start_softap_args,
+ sizeof(start_softap_args)/sizeof(cmd_arg_t),
+ "--max_conn");
+ const char *hide_ssid = get_arg_value(argc, argv, start_softap_args,
+ sizeof(start_softap_args)/sizeof(cmd_arg_t),
+ "--hide_ssid");
+ const char *bw = get_arg_value(argc, argv, start_softap_args,
+ sizeof(start_softap_args)/sizeof(cmd_arg_t),
+ "--bw");
+ const char *band_mode = get_arg_value(argc, argv, start_softap_args,
+ sizeof(start_softap_args)/sizeof(cmd_arg_t),
+ "--band_mode");
+
+ /* Use default values from ctrl_config.h if arguments are not provided */
+ if (!ssid) {
+ ssid = SOFTAP_MODE_SSID;
+ printf("Using default SSID: %s\n", ssid);
+ }
+
+ if (!password) {
+ password = SOFTAP_MODE_PWD;
+ printf("Using default password\n");
+ }
+
+ int channel_value = channel ? atoi(channel) : SOFTAP_MODE_CHANNEL;
+ const char *encryption_mode = sec_prot ? sec_prot : "wpa2_psk"; // Default to WPA2
+ int max_conn_value = max_conn ? atoi(max_conn) : SOFTAP_MODE_MAX_ALLOWED_CLIENTS;
+ bool hide_ssid_value = hide_ssid ? is_arg_true(hide_ssid) : SOFTAP_MODE_SSID_HIDDEN;
+ int bw_value = bw ? atoi(bw) : SOFTAP_MODE_BANDWIDTH;
+
+ int band_mode_value = SOFTAP_BAND_MODE;
+ if (band_mode) {
+ if (strcmp(band_mode, "2.4G") == 0) {
+ band_mode_value = WIFI_BAND_MODE_24G;
+ } else if (strcmp(band_mode, "5G") == 0) {
+ band_mode_value = WIFI_BAND_MODE_5G;
+ } else if (strcmp(band_mode, "auto") == 0) {
+ band_mode_value = WIFI_BAND_MODE_AUTO;
+ }
+ }
+
+ return test_softap_mode_start_with_params(
+ ssid,
+ password,
+ channel_value,
+ encryption_mode,
+ max_conn_value,
+ hide_ssid_value,
+ bw_value,
+ band_mode_value
+ );
+}
+
+static int handle_get_softap_info(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+ return test_softap_mode_get_info();
+}
+
+static int handle_softap_connected_clients_info(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+ return test_softap_mode_connected_clients_info();
+}
+
+static int handle_stop_softap(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+ return test_softap_mode_stop();
+}
+
+static int handle_set_wifi_power_save(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+
+ if (!parse_arguments(argc, argv, set_wifi_power_save_args, sizeof(set_wifi_power_save_args)/sizeof(cmd_arg_t))) {
+ return FAILURE;
+ }
+
+ const char *mode = get_arg_value(argc, argv, set_wifi_power_save_args,
+ sizeof(set_wifi_power_save_args)/sizeof(cmd_arg_t),
+ "--mode");
+
+ if (strcmp(mode, "none") == 0) {
+ return test_set_wifi_power_save_mode(WIFI_POWER_SAVE_MODE_NONE);
+ } else if (strcmp(mode, "min") == 0) {
+ return test_set_wifi_power_save_mode(WIFI_POWER_SAVE_MODE_MIN);
+ } else if (strcmp(mode, "max") == 0) {
+ return test_set_wifi_power_save_mode(WIFI_POWER_SAVE_MODE_MAX);
+ }
+
+ return FAILURE;
+}
+
+static int handle_get_wifi_power_save(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+ return test_get_wifi_power_save_mode();
+}
+
+static int handle_set_wifi_max_tx_power(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+
+ if (!parse_arguments(argc, argv, set_wifi_max_tx_power_args, sizeof(set_wifi_max_tx_power_args)/sizeof(cmd_arg_t))) {
+ return FAILURE;
+ }
+
+ const char *map_val = get_arg_value(argc, argv, set_wifi_max_tx_power_args,
+ sizeof(set_wifi_max_tx_power_args)/sizeof(cmd_arg_t),
+ "--map_val");
+
+ int map_value = atoi(map_val);
+ return test_wifi_set_max_tx_power(map_value);
+}
+
+static int handle_get_wifi_curr_tx_power(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+ return test_wifi_get_curr_tx_power();
+}
+
+static int handle_enable_wifi(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+ return test_enable_wifi();
+}
+
+static int handle_disable_wifi(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+ return test_disable_wifi();
+}
+
+static int handle_enable_bt(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+ return test_enable_bt();
+}
+
+static int handle_disable_bt(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+ return test_disable_bt();
+}
+
+static int handle_get_fw_version(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+ char version[100];
+ uint16_t version_size = sizeof(version);
+ int ret = 0;
+ ret = test_get_fw_version_with_params(version, version_size);
+ if (ret != SUCCESS) {
+ printf("Failed to get firmware version\n");
+ return FAILURE;
+ }
+ printf("Firmware version: %s\n", version);
+ return SUCCESS;
+}
+
+static int handle_ota_update(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+
+ if (!parse_arguments(argc, argv, ota_update_args, sizeof(ota_update_args)/sizeof(cmd_arg_t))) {
+ return FAILURE;
+ }
+
+ const char *url = get_arg_value(argc, argv, ota_update_args,
+ sizeof(ota_update_args)/sizeof(cmd_arg_t),
+ "--url");
+
+ printf("Starting OTA update from URL: %s\n", url);
+
+ return test_ota_update_with_params(url);
+}
+
+static int handle_heartbeat(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+
+ if (!parse_arguments(argc, argv, heartbeat_args, sizeof(heartbeat_args)/sizeof(cmd_arg_t))) {
+ return FAILURE;
+ }
+
+ const char *enable = get_arg_value(argc, argv, heartbeat_args,
+ sizeof(heartbeat_args)/sizeof(cmd_arg_t),
+ "--enable");
+ const char *duration = get_arg_value(argc, argv, heartbeat_args,
+ sizeof(heartbeat_args)/sizeof(cmd_arg_t),
+ "--duration");
+
+ bool enable_value = enable ? is_arg_true(enable) : true;
+ int duration_value = duration ? atoi(duration) : 30;
+
+ if (enable_value) {
+ printf("Enabling heartbeat with duration %d seconds\n", duration_value);
+ return test_config_heartbeat();
+ } else {
+ printf("Disabling heartbeat\n");
+ return test_disable_heartbeat();
+ }
+}
+
+static int handle_subscribe_event(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+
+ if (!parse_arguments(argc, argv, subscribe_event_args, sizeof(subscribe_event_args)/sizeof(cmd_arg_t))) {
+ return FAILURE;
+ }
+
+ const char *event = get_arg_value(argc, argv, subscribe_event_args,
+ sizeof(subscribe_event_args)/sizeof(cmd_arg_t),
+ "--event");
+
+ printf("Subscribing to event: %s\n", event);
+
+ return test_subscribe_event(event);
+}
+
+static int handle_unsubscribe_event(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+
+ if (!parse_arguments(argc, argv, unsubscribe_event_args, sizeof(unsubscribe_event_args)/sizeof(cmd_arg_t))) {
+ return FAILURE;
+ }
+
+ const char *event = get_arg_value(argc, argv, unsubscribe_event_args,
+ sizeof(unsubscribe_event_args)/sizeof(cmd_arg_t),
+ "--event");
+
+ printf("Unsubscribing from event: %s\n", event);
+
+ return test_unsubscribe_event(event);
+}
+
+static int handle_set_host_port_range(int argc, char **argv) {
+ if (argc != 3) {
+ printf("Usage: cli_set_host_port_range \n");
+ return -1;
+ }
+
+ int start_port = atoi(argv[1]);
+ int end_port = atoi(argv[2]);
+
+ if (start_port < 0 || start_port > 65535 || end_port < 0 || end_port > 65535) {
+ printf("Ports must be between 0 and 65535\n");
+ return -1;
+ }
+
+ if (start_port >= end_port) {
+ printf("Start port must be less than end port\n");
+ return -1;
+ }
+
+ return update_host_network_port_range(start_port, end_port);
+}
+
+
+/* Shell initialization */
+static int shell_init(shell_context_t *ctx) {
+ if (!ctx) {
+ return -1;
+ }
+
+ /* Initialize shell */
+ ctx->shell_handle = replxx_init();
+ if (!ctx->shell_handle) {
+ return -1;
+ }
+
+ /* Set up completion and hints */
+ replxx_set_completion_callback(ctx->shell_handle, shell_completion_callback, ctx->shell_handle);
+ replxx_set_hint_callback(ctx->shell_handle, shell_hint_callback, ctx->shell_handle);
+
+ /* Load history */
+ replxx_history_load(ctx->shell_handle, ".esp_hosted_history");
+
+ /* Configure replxx */
+ replxx_set_max_history_size(ctx->shell_handle, 1000);
+ replxx_set_completion_count_cutoff(ctx->shell_handle, 128);
+ replxx_set_max_hint_rows(ctx->shell_handle, 5);
+
+ ctx->running = 1;
+ return 0;
+}
+
+/* Shell cleanup */
+static void shell_cleanup(shell_context_t *ctx) {
+ if (!ctx) {
+ return;
+ }
+
+ /* Save history */
+ replxx_history_save(ctx->shell_handle, ".esp_hosted_history");
+
+ /* Cleanup shell */
+ replxx_end(ctx->shell_handle);
+ ctx->running = 0;
+}
+
+
+static int custom_rpc_event_handler_with_packed_data(ctrl_cmd_t *app_event) {
+ /* Call the shared implementation from custom_rpc_msg.c */
+ return custom_rpc_event_handler(app_event);
+}
+
+#define REGISTER_EVENT_CALLBACK(event, callback) \
+ do { \
+ int ret = set_event_callback(event, callback); \
+ if (ret != SUCCESS) { \
+ printf("Failed to set event callback for %s\n", #event); \
+ return FAILURE; \
+ } \
+ } while (0)
+
+static int register_needed_event_callbacks(void) {
+ int ret = SUCCESS;
+ REGISTER_EVENT_CALLBACK(CTRL_EVENT_ESP_INIT, default_rpc_events_handler);
+ REGISTER_EVENT_CALLBACK(CTRL_EVENT_HEARTBEAT, default_rpc_events_handler);
+ REGISTER_EVENT_CALLBACK(CTRL_EVENT_STATION_CONNECTED_TO_AP, default_rpc_events_handler);
+ REGISTER_EVENT_CALLBACK(CTRL_EVENT_STATION_DISCONNECT_FROM_AP, default_rpc_events_handler);
+ REGISTER_EVENT_CALLBACK(CTRL_EVENT_STATION_CONNECTED_TO_ESP_SOFTAP, default_rpc_events_handler);
+ REGISTER_EVENT_CALLBACK(CTRL_EVENT_STATION_DISCONNECT_FROM_ESP_SOFTAP, default_rpc_events_handler);
+ REGISTER_EVENT_CALLBACK(CTRL_EVENT_DHCP_DNS_STATUS, default_rpc_events_handler);
+ REGISTER_EVENT_CALLBACK(CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG, custom_rpc_event_handler_with_packed_data);
+ return ret;
+}
+
+static void *auto_ip_restore_thread_handler(void *arg) {
+ shell_context_t *ctx = (shell_context_t *)arg;
+
+#if POLL_FOR_IP_RESTORE
+ /* Also add the IP variables needed */
+#define MAX_IP_FETCH_RETRIES 5 /* Maximum retries for fetching IP */
+ static int ip_fetch_retry_count = 0; /* Counter for IP fetch retries */
+
+#define IP_FETCH_RETRY_DELAY_MS 500 /* 500ms */
+#endif
+
+ (void)ctx;
+
+ while (!exit_thread_auto_ip_restore) {
+ /* Initialize RPC */
+ rpc_state = RPC_STATE_INIT;
+
+ if (init_hosted_control_lib()) {
+ //printf("rpc lib init failed, retry\n");
+ usleep(RPC_RETRY_INTERVAL_MS * 1000);
+ continue;
+ }
+ rpc_initialized = 1;
+
+ /* Register event callbacks */
+ if (register_needed_event_callbacks() != SUCCESS) {
+ printf("event callback registration failed, retry\n");
+ deinit_hosted_control_lib();
+ rpc_initialized = 0;
+ usleep(RPC_RETRY_INTERVAL_MS * 1000);
+ continue;
+ } else {
+ printf("Subscribed to all events\n");
+ }
+
+ rpc_state = RPC_STATE_ACTIVE;
+ printf("RPC at host is ready\n");
+
+ /* Initialize the network structure fields */
+ memset(&sta_network, 0, sizeof(network_info_t));
+ memset(&ap_network, 0, sizeof(network_info_t));
+
+ /* Fetch MAC addresses first before trying to handle IP */
+ if (test_station_mode_get_mac_addr(sta_network.mac_addr) != SUCCESS) {
+ printf("Failed to get station MAC address, will retry later\n");
+ }
+
+ if (test_softap_mode_get_mac_addr(ap_network.mac_addr) != SUCCESS) {
+ printf("Failed to get SoftAP MAC address, will retry later\n");
+ }
+
+ /* Fetch IP address from slave on bootup */
+ if (test_is_network_split_on()) {
+ if (update_host_network_port_range(49152, 61439) != SUCCESS) {
+ printf("Failed to update host network port range\n");
+ }
+ if (test_fetch_ip_addr_from_slave() != SUCCESS) {
+ //printf("Failed to fetch IP status\n");
+ }
+ }
+ /* Main monitoring loop */
+ while (!exit_thread_auto_ip_restore && rpc_state == RPC_STATE_ACTIVE) {
+
+#if POLL_FOR_IP_RESTORE
+ if (test_is_network_split_on()) {
+ /* Refresh MAC addresses if they're empty */
+ if (sta_network.mac_addr[0] == '\0') {
+ test_station_mode_get_mac_addr(sta_network.mac_addr);
+ }
+
+ if (ap_network.mac_addr[0] == '\0') {
+ test_softap_mode_get_mac_addr(ap_network.mac_addr);
+ }
+
+ /* Check network status */
+ if (!sta_network.ip_valid || !sta_network.dns_valid) {
+ if (test_fetch_ip_addr_from_slave() != SUCCESS) {
+ printf("Failed to fetch IP status, reinitializing RPC\n");
+ break;
+ }
+
+ /* If IP is still all zeros after fetch, retry a few times */
+ if (sta_network.ip_valid && strcmp(sta_network.ip_addr, "0.0.0.0") == 0) {
+ if (ip_fetch_retry_count < MAX_IP_FETCH_RETRIES) {
+ ip_fetch_retry_count++;
+ printf("Got zeroed IP, retrying fetch (%d/%d)...\n",
+ ip_fetch_retry_count, MAX_IP_FETCH_RETRIES);
+ usleep(IP_FETCH_RETRY_DELAY_MS * 1000);
+ continue;
+ } else {
+ ip_fetch_retry_count = 0;
+ }
+ } else {
+ ip_fetch_retry_count = 0;
+ }
+
+ /* If we got valid IP and have a valid MAC, ensure the network is up */
+ if (sta_network.ip_valid && strcmp(sta_network.ip_addr, "0.0.0.0") != 0 &&
+ sta_network.dns_valid && sta_network.mac_addr[0] != '\0') {
+
+ if (!sta_network.network_up) {
+ printf("Setting up station network interface with IP %s\n", sta_network.ip_addr);
+ if (up_sta_netdev__with_static_ip_dns_route(&sta_network) == SUCCESS) {
+ add_dns(sta_network.dns_addr);
+ sta_network.network_up = 1;
+ printf("Station network interface is now up\n");
+ } else {
+ printf("Failed to set up network interface\n");
+ }
+ }
+ }
+ }
+ }
+#endif
+ usleep(NETWORK_CHECK_INTERVAL_MS * 1000);
+ }
+
+ /* Clean up before potential reinitialization */
+ unregister_event_callbacks();
+ deinit_hosted_control_lib();
+ rpc_state = RPC_STATE_INACTIVE;
+ rpc_initialized = 0;
+ }
+
+ return NULL;
+}
+
+
+
+/* RPC initialization */
+static int start_rpc_auto_ip_restore(void) {
+ printf("Waiting local RPC to be ready\n");
+
+ /* Create app thread */
+ if (pthread_create(&auto_ip_restore_thread, NULL, auto_ip_restore_thread_handler, NULL) != 0) {
+ printf("Failed to create app thread\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Simpler rpc_cleanup function */
+static void stop_rpc_auto_ip_restore(void) {
+ static int cleanup_in_progress = 0;
+
+ // Prevent multiple cleanups
+ if (cleanup_in_progress) {
+ printf("RPC cleanup already in progress\n");
+ return;
+ }
+
+ cleanup_in_progress = 1;
+
+ // Set exit flag and notify threads
+ exit_thread_auto_ip_restore = 1;
+ rpc_state = RPC_STATE_INACTIVE;
+
+ //printf("Cleaning up RPC resources...\n");
+
+ // Give app thread a chance to notice exit flag
+ //sleep(1); // Brief pause (removed for faster exit)
+
+ // Join the app thread if it exists
+ if (auto_ip_restore_thread) {
+ if (pthread_join(auto_ip_restore_thread, NULL) == 0) {
+ printf("Application thread joined successfully\n");
+ } else {
+ printf("Error joining application thread: %s\n", strerror(errno));
+ }
+ auto_ip_restore_thread = 0;
+ }
+
+ // Clean up resources
+ unregister_event_callbacks();
+
+ if (rpc_initialized) {
+ deinit_hosted_control_lib();
+ rpc_initialized = 0;
+ }
+
+ cleanup_in_progress = 0;
+ //printf("Cleanup complete\n");
+}
+
+/* Shell main loop */
+static int shell_run(shell_context_t *ctx) {
+ const char *line = NULL;
+ char *args[16] = {0};
+ int argc;
+ const shell_command_t *cmd;
+
+ /* Initialize shell */
+ if (shell_init(ctx) != 0) {
+ return -1;
+ }
+
+ while (ctx->running && !exit_thread_auto_ip_restore) {
+ /* Read line using the correct replxx function */
+ line = replxx_input(ctx->shell_handle, "esp-hosted> ");
+ if (!line) {
+ break;
+ }
+
+ /* Skip empty lines and whitespace-only lines */
+ char *trimmed = (char *)line;
+ while (*trimmed == ' ' || *trimmed == '\t') {
+ trimmed++;
+ }
+ if (*trimmed == '\0' || *trimmed == '\n') {
+ continue;
+ }
+
+ /* Parse command */
+ char *line_copy = strdup((char *)line);
+ if (!line_copy) {
+ printf("Failed to allocate memory for command processing\n");
+ continue;
+ }
+
+ /* Process the command line */
+ argc = 0;
+ char *saveptr = NULL;
+ args[argc] = strtok_r(line_copy, " \t\n", &saveptr);
+ while (args[argc] && argc < 15) {
+ argc++;
+ args[argc] = strtok_r(NULL, " \t\n", &saveptr);
+ }
+ args[argc] = NULL;
+
+ /* Handle special commands */
+ if (strcmp(args[0], "exit") == 0 ||
+ strcmp(args[0], "quit") == 0 ||
+ strcmp(args[0], "q") == 0) {
+ printf("Exiting shell\n");
+ free(line_copy);
+ break;
+ }
+
+ /* Execute command if RPC is active and we have a valid command */
+ if (is_rpc_active() && argc > 0) {
+ /* Find and execute command */
+ for (cmd = commands; cmd->name; cmd++) {
+ if (strcmp(cmd->name, args[0]) == 0) {
+ cmd->handler(argc, args);
+ break;
+ }
+ }
+ if (!cmd->name) {
+ printf("Unknown command: %s\n", args[0]);
+ }
+ } else if (!is_rpc_active()) {
+ printf("retry later, as rpc is not active yet\n");
+ }
+
+ /* Clean up the copy */
+ free(line_copy);
+ line_copy = NULL;
+ }
+
+ /* Shell cleanup */
+ shell_cleanup(ctx);
+ return 0;
+}
+
+/* Stop shell */
+static void shell_stop(shell_context_t *ctx) __attribute__((unused));
+static void shell_stop(shell_context_t *ctx) {
+ if (ctx) {
+ ctx->running = 0;
+ }
+}
+
+/* Signal handling */
+static void sig_handler(int signum) {
+ switch (signum) {
+ case SIGHUP:
+ printf("Configuration reload requested\n");
+ break;
+ case SIGUSR1:
+ printf("Cleanup requested\n");
+ exit_thread_auto_ip_restore = 1;
+ break;
+ case SIGTERM:
+ case SIGINT:
+ // Just set the exit flag
+ exit_thread_auto_ip_restore = 1;
+
+ // Signal the shell to exit if it's still running
+ shell_context_t *ctx = get_shell_context();
+ if (ctx && ctx->running) {
+ ctx->running = 0;
+ }
+
+ printf("Exit requested, cleaning up...\n");
+ break;
+ }
+}
+
+/* Main function */
+int main(int argc, char *argv[]) {
+ shell_context_t ctx = {0};
+ int ret = 0;
+
+ /* Check for root privileges */
+ if (getuid()) {
+ printf("Please run with superuser privileges\n");
+ return -1;
+ }
+
+ /* Ensure single instance */
+ if (ensure_single_instance() != 0) {
+ return -1;
+ }
+
+ /* Set up signal handlers */
+ signal(SIGHUP, sig_handler);
+ signal(SIGINT, sig_handler);
+ signal(SIGTERM, sig_handler);
+ signal(SIGUSR1, sig_handler);
+
+ /* Store context for signal handler */
+ set_shell_context(&ctx);
+
+ /* Initialize RPC first - this creates the app thread */
+ if (start_rpc_auto_ip_restore() != 0) {
+ printf("Failed to initialize RPC\n");
+ return -1;
+ }
+
+ /* Run the shell directly in the main thread */
+ ret = shell_run(&ctx);
+
+ /* The shell has exited - initiate cleanup */
+ //printf("Shell exited, initiating cleanup\n");
+ exit_thread_auto_ip_restore = 1;
+
+ /* Clean up resources */
+ stop_rpc_auto_ip_restore();
+
+ printf("Cleanup complete, exiting\n");
+ return ret;
+}
+
+#define DEBUG_COMPLETION 0
+
+void shell_completion_callback(const char *line, replxx_completions *completions, int *context_len, void *user_data) {
+ char *line_copy = strdup(line);
+ char *tokens[MAX_CMD_ARGS] = {0};
+ int token_count = 0;
+ char *saveptr = NULL;
+
+ if (!line_copy) {
+ return;
+ }
+
+ /* Parse the current line into tokens */
+ tokens[token_count] = strtok_r(line_copy, " \t", &saveptr);
+ while (tokens[token_count] && token_count < MAX_CMD_ARGS - 1) {
+ token_count++;
+ tokens[token_count] = strtok_r(NULL, " \t", &saveptr);
+ }
+
+ if (DEBUG_COMPLETION) {
+ printf("\nDEBUG: Completion for line '%s'\n", line);
+ printf("DEBUG: Token count: %d\n", token_count);
+ for (int i = 0; i < token_count; i++) {
+ printf("DEBUG: Token %d: '%s'\n", i, tokens[i]);
+ }
+ }
+
+ /* Complete command name if we're at the first token */
+ if (token_count == 0 || (token_count == 1 && line[strlen(line) - 1] != ' ')) {
+ const shell_command_t *cmd;
+
+ /* Get prefix to match against */
+ const char *prefix = tokens[0] ? tokens[0] : "";
+ size_t prefix_len = strlen(prefix);
+
+ /* Set context length to length of current token for proper replacement */
+ if (context_len) {
+ *context_len = prefix_len;
+ if (DEBUG_COMPLETION) {
+ printf("DEBUG: Context length: %d\n", *context_len);
+ }
+ }
+
+ /* Add matching commands */
+ for (cmd = commands; cmd->name; cmd++) {
+ if (strncmp(cmd->name, prefix, prefix_len) == 0) {
+ replxx_add_completion(completions, cmd->name);
+ }
+ }
+ } else if (token_count >= 1) {
+ /* Find the command */
+ const shell_command_t *cmd = NULL;
+ for (const shell_command_t *c = commands; c->name; c++) {
+ if (strcmp(c->name, tokens[0]) == 0) {
+ cmd = c;
+ break;
+ }
+ }
+
+ if (cmd && cmd->args) {
+ /* Are we typing an argument name or value? */
+ bool is_arg_value = false;
+ const cmd_arg_t *current_arg = NULL;
+
+ /* Check if the previous token was an argument name */
+ if (token_count >= 2 && tokens[token_count-2][0] == '-' && tokens[token_count-2][1] == '-') {
+ is_arg_value = true;
+
+ /* Find the current argument */
+ for (int i = 0; i < cmd->arg_count; i++) {
+ if (strcmp(cmd->args[i].name, tokens[token_count-2]) == 0) {
+ current_arg = &cmd->args[i];
+ break;
+ }
+ }
+ }
+
+ /* Current token or empty string if at a space */
+ const char *current_token = (token_count > 0 && tokens[token_count-1]) ?
+ tokens[token_count-1] : "";
+ size_t current_token_len = strlen(current_token);
+
+ /* Set context length for proper replacement */
+ if (context_len) {
+ /* If we're at a space, context length should be 0 */
+ if (line[strlen(line) - 1] == ' ') {
+ *context_len = 0;
+ } else {
+ *context_len = current_token_len;
+ }
+
+ if (DEBUG_COMPLETION) {
+ printf("DEBUG: Context length: %d\n", *context_len);
+ }
+ }
+
+ if (is_arg_value && current_arg && current_arg->type == ARG_TYPE_CHOICE) {
+ /* Complete choice values */
+ const char *prefix = tokens[token_count-1] ? tokens[token_count-1] : "";
+ size_t prefix_len = strlen(prefix);
+
+ for (int i = 0; current_arg->choices[i]; i++) {
+ if (strncmp(current_arg->choices[i], prefix, prefix_len) == 0) {
+ replxx_add_completion(completions, current_arg->choices[i]);
+ }
+ }
+ } else if (!is_arg_value) {
+ /* Complete argument names */
+ /* Check if we're in the middle of typing an argument name */
+ if (current_token_len > 0 && current_token[0] == '-') {
+ for (int i = 0; i < cmd->arg_count; i++) {
+ /* Check if this argument has already been provided */
+ bool already_provided = false;
+ for (int j = 1; j < token_count-1; j++) {
+ if (strcmp(tokens[j], cmd->args[i].name) == 0) {
+ already_provided = true;
+ break;
+ }
+ }
+
+ if (!already_provided && strncmp(cmd->args[i].name, current_token, current_token_len) == 0) {
+ replxx_add_completion(completions, cmd->args[i].name);
+ }
+ }
+ } else if (line[strlen(line) - 1] == ' ') {
+ /* We're ready to start a new argument */
+ for (int i = 0; i < cmd->arg_count; i++) {
+ /* Check if this argument has already been provided */
+ bool already_provided = false;
+ for (int j = 1; j < token_count; j++) {
+ if (strcmp(tokens[j], cmd->args[i].name) == 0) {
+ already_provided = true;
+ break;
+ }
+ }
+
+ if (!already_provided) {
+ replxx_add_completion(completions, cmd->args[i].name);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ free(line_copy);
+}
+
+void shell_hint_callback(const char *line, replxx_hints *hints, int *context_len, ReplxxColor *color, void *user_data) {
+ char *line_copy = strdup(line);
+ char *tokens[MAX_CMD_ARGS] = {0};
+ int token_count = 0;
+ char *saveptr = NULL;
+
+ if (!line_copy) {
+ return;
+ }
+
+ /* Parse the current line into tokens */
+ tokens[token_count] = strtok_r(line_copy, " \t", &saveptr);
+ while (tokens[token_count] && token_count < MAX_CMD_ARGS - 1) {
+ token_count++;
+ tokens[token_count] = strtok_r(NULL, " \t", &saveptr);
+ }
+
+ /* Provide hints for commands */
+ if (token_count == 0 || (token_count == 1 && line[strlen(line) - 1] != ' ')) {
+ const shell_command_t *cmd;
+ for (cmd = commands; cmd->name; cmd++) {
+ if (tokens[0] && strncmp(cmd->name, tokens[0], strlen(tokens[0])) == 0) {
+ /* Only show help text for exact matches */
+ if (strcmp(cmd->name, tokens[0]) == 0) {
+ char hint_text[256];
+ snprintf(hint_text, sizeof(hint_text), "%*s", 12, cmd->help);
+ replxx_add_hint(hints, hint_text);
+ }
+ break;
+ }
+ }
+ } else if (token_count >= 1) {
+ /* Find the command */
+ const shell_command_t *cmd = NULL;
+ for (const shell_command_t *c = commands; c->name; c++) {
+ if (strcmp(c->name, tokens[0]) == 0) {
+ cmd = c;
+ break;
+ }
+ }
+
+ if (cmd && cmd->args) {
+ /* Are we typing an argument name or value? */
+ bool is_arg_value = false;
+ const cmd_arg_t *current_arg = NULL;
+
+ /* Check if the previous token was an argument name */
+ if (token_count >= 2 && tokens[token_count-2] &&
+ tokens[token_count-2][0] == '-' && tokens[token_count-2][1] == '-') {
+ is_arg_value = true;
+
+ /* Find the current argument */
+ for (int i = 0; i < cmd->arg_count; i++) {
+ if (strcmp(cmd->args[i].name, tokens[token_count-2]) == 0) {
+ current_arg = &cmd->args[i];
+ break;
+ }
+ }
+ }
+
+ if (is_arg_value && current_arg) {
+ /* Provide hint for argument value */
+ char hint_text[256] = {0};
+ snprintf(hint_text, sizeof(hint_text), "%*s", 12, "");
+
+ switch (current_arg->type) {
+ case ARG_TYPE_STRING:
+ strcat(hint_text, " ");
+ break;
+ case ARG_TYPE_INT:
+ strcat(hint_text, " ");
+ break;
+ case ARG_TYPE_BOOL:
+ strcat(hint_text, " ");
+ break;
+ case ARG_TYPE_CHOICE:
+ strcat(hint_text, "Choices: ");
+ for (int i = 0; current_arg->choices[i]; i++) {
+ if (i > 0) {
+ strcat(hint_text, ", ");
+ }
+ strcat(hint_text, current_arg->choices[i]);
+ }
+ replxx_add_hint(hints, hint_text);
+ free(line_copy);
+ *color = REPLXX_COLOR_CYAN;
+ return;
+ }
+
+ strcat(hint_text, current_arg->help);
+ replxx_add_hint(hints, hint_text);
+ } else if (!is_arg_value && line[strlen(line) - 1] == ' ') {
+ /* We're ready to start a new argument, show available options */
+ int hint_count = 0;
+ for (int i = 0; i < cmd->arg_count && hint_count < MAX_SUGGESTION_LINES; i++) {
+ /* Check if this argument has already been provided */
+ bool already_provided = false;
+ for (int j = 1; j < token_count; j++) {
+ if (tokens[j] && strcmp(tokens[j], cmd->args[i].name) == 0) {
+ already_provided = true;
+ break;
+ }
+ }
+
+ if (!already_provided) {
+ char hint_text[256];
+ snprintf(hint_text, sizeof(hint_text), "%*s%s %s",
+ 12, "",
+ cmd->args[i].name,
+ cmd->args[i].help);
+ replxx_add_hint(hints, hint_text);
+ hint_count++;
+ }
+ }
+ }
+ }
+ }
+
+ free(line_copy);
+
+ /* Set color to cyan */
+ *color = REPLXX_COLOR_CYAN;
+}
+
+
+static int handle_custom_demo_rpc_request(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+
+ if (!parse_arguments(argc, argv, custom_rpc_request_args, sizeof(custom_rpc_request_args)/sizeof(cmd_arg_t))) {
+ return FAILURE;
+ }
+
+ const char *demo_str = get_arg_value(argc, argv, custom_rpc_request_args,
+ sizeof(custom_rpc_request_args)/sizeof(cmd_arg_t),
+ "--demo");
+
+ int demo_num = atoi(demo_str);
+
+ printf("Running custom RPC demo %d\n", demo_num);
+
+ switch(demo_num) {
+ case 1:
+ return custom_rpc_demo1_request_only_ack();
+ case 2:
+ return custom_rpc_demo2_request_echo_back_as_response();
+ case 3:
+ return custom_rpc_demo3_request_echo_back_as_event();
+ default:
+ printf("Invalid demo number. Use 1, 2, or 3.\n");
+ return FAILURE;
+ }
+}
+
+static int handle_set_country_code(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+ if (!parse_arguments(argc, argv, set_country_code_args, sizeof(set_country_code_args)/sizeof(cmd_arg_t))) {
+ return FAILURE;
+ }
+ const char *code = get_arg_value(argc, argv, set_country_code_args,
+ sizeof(set_country_code_args)/sizeof(cmd_arg_t),
+ "--code");
+ if (!code || strlen(code) < 2) {
+ printf("Invalid or missing country code\n");
+ return FAILURE;
+ }
+ return test_set_country_code_with_params(code);
+}
+
+static int handle_set_country_code_with_ieee80211d_on(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+ return test_set_country_code_with_ieee80211d_on();
+}
+
+static int handle_get_country_code(int argc, char **argv) {
+ CHECK_RPC_ACTIVE();
+ return test_get_country_code();
+}
\ No newline at end of file
diff --git a/esp_hosted_fg/host/linux/host_control/c_support/hosted_shell.h b/esp_hosted_fg/host/linux/host_control/c_support/hosted_shell.h
new file mode 100644
index 0000000000..e93f0d64bc
--- /dev/null
+++ b/esp_hosted_fg/host/linux/host_control/c_support/hosted_shell.h
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Espressif Systems Wireless LAN device driver
+ *
+ * Copyright (C) 2015-2021 Espressif Systems (Shanghai) PTE LTD
+ */
+
+#ifndef HOSTED_SHELL_H
+#define HOSTED_SHELL_H
+
+#include "ctrl_api.h"
+#include
+
+#define USE_REPLXX 1
+
+/* Shell interface wrapper macros */
+#ifdef USE_REPLXX
+#include
+#define SHELL_INIT() replxx_init()
+#define SHELL_CLEANUP(replxx) replxx_end(replxx)
+#define SHELL_READ_LINE(replxx) replxx_input(replxx, "esp-hosted> ")
+#define SHELL_ADD_HISTORY(replxx, line) replxx_history_add(replxx, line)
+#define SHELL_SAVE_HISTORY(replxx, file) replxx_history_save(replxx, file)
+#define SHELL_LOAD_HISTORY(replxx, file) replxx_history_load(replxx, file)
+#define SHELL_SET_COMPLETION_CALLBACK(replxx, callback, user_data) replxx_set_completion_callback(replxx, callback, user_data)
+#define SHELL_SET_HINT_CALLBACK(replxx, callback, user_data) replxx_set_hint_callback(replxx, callback, user_data)
+#define SHELL_PRINT(replxx, fmt, ...) replxx_print(replxx, fmt, ##__VA_ARGS__)
+//#define SHELL_FREE(ptr) replxx_free(ptr);
+#else
+/* Add other shell library wrappers here */
+#endif
+
+/* Define command argument types */
+typedef enum {
+ ARG_TYPE_STRING,
+ ARG_TYPE_INT,
+ ARG_TYPE_BOOL,
+ ARG_TYPE_CHOICE
+} arg_type_t;
+
+/* Define command argument structure */
+typedef struct {
+ const char *name; /* Argument name with -- prefix */
+ const char *help; /* Help text */
+ arg_type_t type; /* Argument type */
+ bool required; /* Whether argument is required */
+ const char **choices; /* Valid choices for ARG_TYPE_CHOICE */
+} cmd_arg_t;
+
+/* Command structure */
+typedef struct {
+ const char *name;
+ const char *help;
+ int (*handler)(int argc, char **argv);
+ const cmd_arg_t *args;
+ int arg_count;
+} shell_command_t;
+
+/* Shell context */
+typedef struct {
+ Replxx *shell_handle;
+ int running;
+ pthread_t ip_restore_thread;
+} shell_context_t;
+
+/* Command completion callback */
+void shell_completion_callback(const char *text, replxx_completions *completions, int *context_len, void *user_data);
+
+/* Command hint callback */
+void shell_hint_callback(const char *text, replxx_hints *hints, int *context_len, ReplxxColor *color, void *user_data);
+
+/* Get shell context */
+shell_context_t *get_shell_context(void);
+
+#endif /* HOSTED_SHELL_H */
diff --git a/esp_hosted_fg/host/linux/host_control/c_support/nw_helper_func.c b/esp_hosted_fg/host/linux/host_control/c_support/nw_helper_func.c
new file mode 100644
index 0000000000..35de5b002f
--- /dev/null
+++ b/esp_hosted_fg/host/linux/host_control/c_support/nw_helper_func.c
@@ -0,0 +1,903 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+#include "nw_helper_func.h"
+
+#define ENABLE_DEBUG_LOGS 0
+#define ALLOW_ROUTE_UPDATE 1
+
+#if ENABLE_DEBUG_LOGS
+ #define DEBUG_LOG_VERBOSE(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+ #define DEBUG_LOG_VERBOSE(fmt, ...)
+#endif
+
+int down_sta_netdev(const network_info_t *info) {
+ int ret = SUCCESS, sockfd = 0;
+
+ ret = create_socket(AF_INET, SOCK_DGRAM, IPPROTO_IP, &sockfd);
+ if (ret < 0) {
+ printf("Failure to open socket\n");
+ return FAILURE;
+ }
+
+ ret = interface_down(sockfd, STA_INTERFACE);
+ if (ret == SUCCESS) {
+ DEBUG_LOG_VERBOSE("%s interface down\n", STA_INTERFACE);
+ } else {
+ printf("Unable to down %s interface\n", STA_INTERFACE);
+ goto close_sock;
+ }
+
+#if ALLOW_ROUTE_UPDATE
+ ret = remove_default_gateway(info->default_route);
+ if (ret == SUCCESS) {
+ DEBUG_LOG_VERBOSE("Default gateway removed: Gateway=%s\n", info->default_route);
+ } else {
+ DEBUG_LOG_VERBOSE("Failed to remove default gateway\n");
+ goto close_sock;
+ }
+#endif
+ ret = close_socket(sockfd);
+ if (ret < 0) {
+ printf("Failure to close socket\n");
+ return FAILURE;
+ }
+ return SUCCESS;
+
+close_sock:
+ ret = close_socket(sockfd);
+ if (ret < 0) {
+ printf("Failure to close socket\n");
+ }
+ return FAILURE;
+}
+
+int up_sta_netdev(const network_info_t *info)
+{
+ int ret = SUCCESS, sockfd = 0;
+ char mac_copy[MAC_ADDR_LENGTH];
+
+ if (!info || info->mac_addr[0] == '\0') {
+ printf("Failure: station mac is empty\n");
+ return FAILURE;
+ }
+
+ /* Create local copy to handle const qualifier */
+ strncpy(mac_copy, info->mac_addr, MAC_ADDR_LENGTH);
+
+ ret = create_socket(AF_INET, SOCK_DGRAM, IPPROTO_IP, &sockfd);
+ if (ret < 0) {
+ printf("Failure to open socket\n");
+ return FAILURE;
+ }
+
+ ret = interface_down(sockfd, STA_INTERFACE);
+ if (ret == SUCCESS) {
+ DEBUG_LOG_VERBOSE("%s interface down\n", STA_INTERFACE);
+ } else {
+ printf("Unable to down %s interface\n", STA_INTERFACE);
+ goto close_sock;
+ }
+
+ ret = set_hw_addr(sockfd, STA_INTERFACE, mac_copy);
+ if (ret == SUCCESS) {
+ DEBUG_LOG_VERBOSE("MAC address %s set to %s interface\n", mac_copy, STA_INTERFACE);
+ } else {
+ printf("Unable to set MAC address to %s interface\n", STA_INTERFACE);
+ goto close_sock;
+ }
+
+ ret = interface_up(sockfd, STA_INTERFACE);
+ if (ret == SUCCESS) {
+ DEBUG_LOG_VERBOSE("%s interface up\n", STA_INTERFACE);
+ } else {
+ printf("Unable to up %s interface\n", STA_INTERFACE);
+ goto close_sock;
+ }
+
+ ret = close_socket(sockfd);
+ if (ret < 0) {
+ printf("Failure to close socket\n");
+ return FAILURE;
+ }
+ return SUCCESS;
+
+close_sock:
+ ret = close_socket(sockfd);
+ if (ret < 0) {
+ printf("Failure to close socket\n");
+ }
+ return FAILURE;
+}
+
+int up_sta_netdev__with_static_ip_dns_route(const network_info_t *info)
+{
+ int ret = SUCCESS, sockfd = 0;
+ char mac_copy[MAC_ADDR_LENGTH];
+ char ip_copy[MAC_ADDR_LENGTH];
+ char nm_copy[MAC_ADDR_LENGTH];
+ char gw_copy[MAC_ADDR_LENGTH];
+
+ if (!info || info->mac_addr[0] == '\0') {
+ printf("Failure: station mac is empty\n");
+ return FAILURE;
+ }
+
+ if (info->ip_addr[0] == '\0' || info->netmask[0] == '\0' || info->gateway[0] == '\0' ||
+ strcmp(info->ip_addr, "0.0.0.0") == 0 || strcmp(info->netmask, "0.0.0.0") == 0 ||
+ strcmp(info->gateway, "0.0.0.0") == 0) {
+ printf("Invalid network conf to set\n");
+ return FAILURE;
+ }
+
+ /* Create local copies to handle const qualifiers */
+ strncpy(mac_copy, info->mac_addr, MAC_ADDR_LENGTH);
+ strncpy(ip_copy, info->ip_addr, MAC_ADDR_LENGTH);
+ strncpy(nm_copy, info->netmask, MAC_ADDR_LENGTH);
+ strncpy(gw_copy, info->gateway, MAC_ADDR_LENGTH);
+
+ ret = create_socket(AF_INET, SOCK_DGRAM, IPPROTO_IP, &sockfd);
+ if (ret < 0) {
+ printf("Failure to open socket\n");
+ return FAILURE;
+ }
+
+ ret = interface_down(sockfd, STA_INTERFACE);
+ if (ret == SUCCESS) {
+ DEBUG_LOG_VERBOSE("%s interface down\n", STA_INTERFACE);
+ } else {
+ printf("Unable to down %s interface\n", STA_INTERFACE);
+ goto close_sock;
+ }
+
+ ret = set_hw_addr(sockfd, STA_INTERFACE, mac_copy);
+ if (ret == SUCCESS) {
+ DEBUG_LOG_VERBOSE("MAC address %s set to %s interface\n", mac_copy, STA_INTERFACE);
+ } else {
+ printf("Unable to set MAC address to %s interface\n", STA_INTERFACE);
+ goto close_sock;
+ }
+
+ ret = interface_up(sockfd, STA_INTERFACE);
+ if (ret == SUCCESS) {
+ DEBUG_LOG_VERBOSE("%s interface up\n", STA_INTERFACE);
+ } else {
+ printf("Unable to up %s interface\n", STA_INTERFACE);
+ goto close_sock;
+ }
+
+ ret = set_network_static_ip(sockfd, STA_INTERFACE, ip_copy, nm_copy, gw_copy);
+ if (ret == SUCCESS) {
+ DEBUG_LOG_VERBOSE("Static IP set: IP=%s, Netmask=%s, Gateway=%s\n", ip_copy, nm_copy, gw_copy);
+ } else {
+ printf("Failed to set static IP\n");
+ goto close_sock;
+ }
+
+#if ALLOW_ROUTE_UPDATE
+ ret = add_default_gateway(gw_copy);
+ if (ret == SUCCESS) {
+ DEBUG_LOG_VERBOSE("Default gateway added: Gateway=%s\n", gw_copy);
+ } else {
+ printf("Failed to add default gateway\n");
+ goto close_sock;
+ }
+#endif
+
+ ret = close_socket(sockfd);
+ if (ret < 0) {
+ printf("Failure to close socket\n");
+ return FAILURE;
+ }
+ return SUCCESS;
+
+close_sock:
+ ret = close_socket(sockfd);
+ if (ret < 0) {
+ printf("Failure to close socket\n");
+ }
+ return FAILURE;
+}
+
+int down_softap_netdev(const network_info_t *info)
+{
+ int ret = SUCCESS, sockfd = 0;
+
+ ret = create_socket(AF_INET, SOCK_DGRAM, IPPROTO_IP, &sockfd);
+ if (ret < 0) {
+ printf("Failure to open socket\n");
+ return FAILURE;
+ }
+
+ ret = interface_down(sockfd, AP_INTERFACE);
+ if (ret == SUCCESS) {
+ DEBUG_LOG_VERBOSE("%s interface down\n", AP_INTERFACE);
+ } else {
+ printf("Unable to down %s interface\n", AP_INTERFACE);
+ goto close_sock;
+ }
+
+#if ALLOW_ROUTE_UPDATE
+ ret = remove_default_gateway(info->default_route);
+ if (ret == SUCCESS) {
+ DEBUG_LOG_VERBOSE("Default gateway removed: Gateway=%s", info->default_route);
+ } else {
+ DEBUG_LOG_VERBOSE("Failed to remove default gateway");
+ goto close_sock;
+ }
+#endif
+
+ ret = close_socket(sockfd);
+ if (ret < 0) {
+ printf("Failure to close socket\n");
+ return FAILURE;
+ }
+ return SUCCESS;
+
+close_sock:
+ ret = close_socket(sockfd);
+ if (ret < 0) {
+ printf("Failure to close socket\n");
+ }
+ return FAILURE;
+}
+
+int up_softap_netdev(const network_info_t *info)
+{
+ int ret = SUCCESS, sockfd = 0;
+ char mac_copy[MAC_ADDR_LENGTH];
+
+ if (!info || info->mac_addr[0] == '\0') {
+ printf("Failure: softap mac is empty\n");
+ return FAILURE;
+ }
+
+ /* Create local copy to handle const qualifier */
+ strncpy(mac_copy, info->mac_addr, MAC_ADDR_LENGTH);
+
+ ret = create_socket(AF_INET, SOCK_DGRAM, IPPROTO_IP, &sockfd);
+ if (ret < 0) {
+ printf("Failure to open socket\n");
+ return FAILURE;
+ }
+
+ ret = interface_down(sockfd, AP_INTERFACE);
+ if (ret == SUCCESS) {
+ DEBUG_LOG_VERBOSE("%s interface down\n", AP_INTERFACE);
+ } else {
+ printf("Unable to down %s interface\n", AP_INTERFACE);
+ goto close_sock;
+ }
+
+ ret = set_hw_addr(sockfd, AP_INTERFACE, mac_copy);
+ if (ret == SUCCESS) {
+ DEBUG_LOG_VERBOSE("MAC address %s set to %s interface\n", mac_copy, AP_INTERFACE);
+ } else {
+ printf("Unable to set MAC address to %s interface\n", AP_INTERFACE);
+ goto close_sock;
+ }
+
+ ret = interface_up(sockfd, AP_INTERFACE);
+ if (ret == SUCCESS) {
+ DEBUG_LOG_VERBOSE("%s interface up\n", AP_INTERFACE);
+ } else {
+ printf("Unable to up %s interface\n", AP_INTERFACE);
+ goto close_sock;
+ }
+
+ ret = close_socket(sockfd);
+ if (ret < 0) {
+ printf("Failure to close socket\n");
+ return FAILURE;
+ }
+ return SUCCESS;
+
+close_sock:
+ ret = close_socket(sockfd);
+ if (ret < 0) {
+ printf("Failure to close socket\n");
+ }
+ return FAILURE;
+}
+
+
+#define MAX_INTERFACE_LEN IFNAMSIZ
+#define MAC_SIZE_BYTES 6
+#define MIN_MAC_STR_LEN 17
+
+ /* Function ups in given interface */
+int interface_up(int sockfd, const char* iface)
+{
+ int ret = SUCCESS;
+ struct ifreq req = {0};
+ size_t if_name_len = strnlen(iface, MAX_INTERFACE_LEN-1);
+
+ if (!iface) {
+ printf("Invalid parameter\n");
+ return FAILURE;
+ }
+
+ if (if_name_len < sizeof(req.ifr_name)) {
+ memcpy(req.ifr_name,iface,if_name_len);
+ req.ifr_name[if_name_len]='\0';
+ } else {
+ printf("Failed: Max interface len allowed: %zu \n", sizeof(req.ifr_name)-1);
+ return FAILURE;
+ }
+
+ req.ifr_flags |= IFF_UP;
+ ret = ioctl(sockfd, SIOCSIFFLAGS, &req);
+ if (ret < 0) {
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+
+
+
+/* Function to add default gateway */
+int add_default_gateway(const char* gateway)
+{
+ int ret = SUCCESS;
+ struct rtentry route = {0};
+ int sockfd = 0;
+
+ if (!gateway) {
+ printf("Invalid parameter\n");
+ return FAILURE;
+ }
+
+ /* Create socket */
+ sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sockfd < 0) {
+ perror("socket creation failed:");
+ return FAILURE;
+ }
+
+ /* Setup route entry */
+ struct sockaddr_in *addr = (struct sockaddr_in*) &route.rt_gateway;
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = inet_addr(gateway);
+
+ addr = (struct sockaddr_in*) &route.rt_dst;
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = INADDR_ANY;
+
+ addr = (struct sockaddr_in*) &route.rt_genmask;
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = INADDR_ANY;
+
+ route.rt_flags = RTF_UP | RTF_GATEWAY;
+ route.rt_metric = 0;
+
+ /* Add the route */
+ ret = ioctl(sockfd, SIOCADDRT, &route);
+ if (ret < 0) {
+ #if ENABLE_DEBUG_LOGS
+ perror("add route failed:");
+ #endif
+ close(sockfd);
+ return FAILURE;
+ }
+
+ close(sockfd);
+ return SUCCESS;
+}
+
+/* Function to remove default gateway */
+int remove_default_gateway(const char* gateway)
+{
+ int ret = SUCCESS;
+ struct rtentry route = {0};
+ int sockfd = 0;
+
+ if (!gateway) {
+ printf("Invalid parameter\n");
+ return FAILURE;
+ }
+
+ /* Create socket */
+ sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sockfd < 0) {
+ perror("socket creation failed:");
+ return FAILURE;
+ }
+
+ /* Setup route entry */
+ struct sockaddr_in *addr = (struct sockaddr_in*) &route.rt_gateway;
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = inet_addr(gateway);
+
+ addr = (struct sockaddr_in*) &route.rt_dst;
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = INADDR_ANY;
+
+ addr = (struct sockaddr_in*) &route.rt_genmask;
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = INADDR_ANY;
+
+ route.rt_flags = RTF_UP | RTF_GATEWAY;
+ route.rt_metric = 0;
+
+ /* Remove the route */
+ ret = ioctl(sockfd, SIOCDELRT, &route);
+ if (ret < 0) {
+ #if ENABLE_DEBUG_LOGS
+ perror("remove route failed:");
+ #endif
+ close(sockfd);
+ return FAILURE;
+ }
+
+ close(sockfd);
+ return SUCCESS;
+}
+
+
+int set_network_static_ip(int sockfd, const char* iface, const char* ip, const char* netmask, const char* gateway)
+{
+ int ret = SUCCESS;
+ struct ifreq req = {0};
+ struct sockaddr_in* addr = NULL;
+ size_t if_name_len = strnlen(iface, MAX_INTERFACE_LEN-1);
+
+ if (!iface || !ip || !netmask || !gateway) {
+ printf("Invalid parameter\n");
+ return FAILURE;
+ }
+
+ if (if_name_len < sizeof(req.ifr_name)) {
+ memcpy(req.ifr_name, iface, if_name_len);
+ req.ifr_name[if_name_len] = '\0';
+ } else {
+ printf("Failed: Max interface len allowed: %zu \n", sizeof(req.ifr_name)-1);
+ return FAILURE;
+ }
+
+ /* Set IP address */
+ addr = (struct sockaddr_in*)&req.ifr_addr;
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = inet_addr(ip);
+ ret = ioctl(sockfd, SIOCSIFADDR, &req);
+ if (ret < 0) {
+ perror("set ip address:");
+ return FAILURE;
+ }
+
+ /* Set netmask */
+ addr = (struct sockaddr_in*)&req.ifr_netmask;
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = inet_addr(netmask);
+ ret = ioctl(sockfd, SIOCSIFNETMASK, &req);
+ if (ret < 0) {
+ perror("set netmask:");
+ return FAILURE;
+ }
+
+ /* Set gateway */
+ addr = (struct sockaddr_in*)&req.ifr_dstaddr;
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = inet_addr(gateway);
+ ret = ioctl(sockfd, SIOCSIFDSTADDR, &req);
+ if (ret < 0) {
+ #if ENABLE_DEBUG_LOGS
+ perror("set gateway:");
+ #endif
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+
+/* Function sets static DNS server */
+int add_dns(const char* dns)
+{
+ int ret = SUCCESS;
+ FILE *resolv = NULL;
+ char line[256];
+ char dns_entry[256];
+ int dns_exists = 0;
+
+ if (!dns) {
+ printf("Invalid parameter\n");
+ return FAILURE;
+ }
+
+ /* Format DNS entry string */
+ snprintf(dns_entry, sizeof(dns_entry), "nameserver %s", dns);
+
+ /* First check if DNS entry already exists */
+ resolv = fopen("/etc/resolv.conf", "r");
+ if (resolv) {
+ while (fgets(line, sizeof(line), resolv)) {
+ /* Remove newline */
+ line[strcspn(line, "\n")] = 0;
+ if (strcmp(line, dns_entry) == 0) {
+ dns_exists = 1;
+ break;
+ }
+ }
+ fclose(resolv);
+ }
+
+ if (!dns_exists) {
+ /* Append new DNS entry */
+ resolv = fopen("/etc/resolv.conf", "a");
+ if (!resolv) {
+ perror("open resolv.conf:");
+ return FAILURE;
+ }
+
+ ret = fprintf(resolv, "%s\n", dns_entry);
+ if (ret < 0) {
+ perror("write dns server:");
+ fclose(resolv);
+ return FAILURE;
+ }
+ fclose(resolv);
+ }
+
+ return SUCCESS;
+}
+
+
+/* Function removes DNS entry from resolv.conf */
+int remove_dns(const char *dns)
+{
+ int ret = SUCCESS;
+ FILE *resolv = NULL, *tmp = NULL;
+ char line[256];
+ char dns_entry[256];
+
+ if (!dns) {
+ printf("Invalid parameter\n");
+ return FAILURE;
+ }
+
+ /* Format DNS entry string */
+ snprintf(dns_entry, sizeof(dns_entry), "nameserver %s", dns);
+
+ /* Open original file for reading and temp file for writing */
+ resolv = fopen("/etc/resolv.conf", "r");
+ if (!resolv) {
+ perror("open resolv.conf:");
+ return FAILURE;
+ }
+
+ tmp = fopen("/etc/resolv.conf.tmp", "w");
+ if (!tmp) {
+ perror("open resolv.conf.tmp:");
+ fclose(resolv);
+ return FAILURE;
+ }
+
+ /* Copy all lines except matching DNS entry */
+ while (fgets(line, sizeof(line), resolv)) {
+ /* Remove newline */
+ line[strcspn(line, "\n")] = 0;
+ if (strcmp(line, dns_entry) != 0) {
+ fprintf(tmp, "%s\n", line);
+ }
+ }
+
+ fclose(resolv);
+ fclose(tmp);
+
+ /* Replace original with temp file */
+ ret = rename("/etc/resolv.conf.tmp", "/etc/resolv.conf");
+ if (ret < 0) {
+ perror("rename resolv.conf:");
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+
+
+ /* Function downs in given interface */
+int interface_down(int sockfd, const char* iface)
+{
+ int ret = SUCCESS;
+ struct ifreq req = {0};
+ size_t if_name_len = strnlen(iface, MAX_INTERFACE_LEN-1);
+
+ if (!iface) {
+ printf("Invalid parameter\n");
+ return FAILURE;
+ }
+
+ if (if_name_len < sizeof(req.ifr_name)) {
+ memcpy(req.ifr_name,iface,if_name_len);
+ req.ifr_name[if_name_len]='\0';
+ } else {
+ printf("Failed: Max interface len allowed- %zu \n", sizeof(req.ifr_name)-1);
+ return FAILURE;
+ }
+
+ req.ifr_flags &= ~IFF_UP;
+ ret = ioctl(sockfd, SIOCSIFFLAGS, &req);
+ if (ret < 0) {
+ #if ENABLE_DEBUG_LOGS
+ perror("interface down:");
+ #endif
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+
+
+
+ /* Function converts mac string to byte stream */
+int convert_mac_to_bytes(uint8_t *out, size_t out_size, const char *s)
+{
+ int mac[MAC_SIZE_BYTES] = {0};
+ int num_bytes = 0;
+ if (!s || (strlen(s) < MIN_MAC_STR_LEN) || (out_size < MAC_SIZE_BYTES)) {
+ if (!s) {
+ printf("empty input mac str\n");
+ } else if (strlen(s) 0xFF) ||
+ (mac[1] > 0xFF) ||
+ (mac[2] > 0xFF) ||
+ (mac[3] > 0xFF) ||
+ (mac[4] > 0xFF) ||
+ (mac[5] > 0xFF)) {
+ printf("failed\n");
+ return FAILURE;
+ }
+
+ out[0] = mac[0]&0xff;
+ out[1] = mac[1]&0xff;
+ out[2] = mac[2]&0xff;
+ out[3] = mac[3]&0xff;
+ out[4] = mac[4]&0xff;
+ out[5] = mac[5]&0xff;
+ return SUCCESS;
+}
+
+
+ /* Function sets mac address to given interface */
+int set_hw_addr(int sockfd, const char* iface, const char* mac)
+{
+ int ret = SUCCESS;
+ struct ifreq req = {0};
+ char mac_bytes[MAC_SIZE_BYTES] = "";
+ size_t if_name_len = strnlen(iface, MAX_INTERFACE_LEN-1);
+
+ if (!iface || !mac) {
+ printf("Invalid parameter\n");
+ return FAILURE;
+ }
+
+ if (if_name_len < sizeof(req.ifr_name)) {
+ memcpy(req.ifr_name,iface,if_name_len);
+ req.ifr_name[if_name_len]='\0';
+ } else {
+ printf("Failed: Max interface len allowed: %zu \n", sizeof(req.ifr_name)-1);
+ return FAILURE;
+ }
+
+ memset(mac_bytes, '\0', MAC_SIZE_BYTES);
+ ret = convert_mac_to_bytes((uint8_t *)&mac_bytes, sizeof(mac_bytes), mac);
+
+ if (ret) {
+ printf("Failed to convert mac address \n");
+ return FAILURE;
+ }
+
+ req.ifr_hwaddr.sa_family = ARPHRD_ETHER;
+ memcpy(req.ifr_hwaddr.sa_data, mac_bytes, MAC_SIZE_BYTES);
+ ret = ioctl(sockfd, SIOCSIFHWADDR, &req);
+
+ if (ret < 0) {
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+
+ /* Function creates an endpoint for communication and
+ * returns a file descriptor (integer number) that
+ * refers to that endpoint */
+int create_socket(int domain, int type, int protocol, int *sock)
+{
+ if (!sock) {
+ printf("Invalid parameter\n");
+ return FAILURE;
+ }
+
+ *sock = socket(domain, type, protocol);
+ if (*sock < 0)
+ {
+ printf("Failure to open socket\n");
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+
+ /* Function closes an endpoint for communication */
+int close_socket(int sock)
+{
+ int ret;
+ ret = close(sock);
+ if (ret < 0) {
+ printf("Failure to close socket\n");
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+
+int update_host_network_port_range(uint16_t port_start, uint16_t port_end)
+{
+ FILE *fp = NULL;
+ char line[256];
+ int found = 0;
+ char temp_file[] = "/tmp/sysctl.conf.XXXXXX";
+ int temp_fd;
+ FILE *temp_fp = NULL;
+ char current_start[16], current_end[16];
+
+ /* Open sysctl.conf file */
+ fp = fopen("/etc/sysctl.conf", "r");
+ if (!fp) {
+ printf("Failed to open /etc/sysctl.conf: %s\n", strerror(errno));
+ return FAILURE;
+ }
+
+ /* Check if entry exists with same values */
+ while (fgets(line, sizeof(line), fp)) {
+ if (strstr(line, "net.ipv4.ip_local_port_range")) {
+ if (sscanf(line, "net.ipv4.ip_local_port_range = %s %s", current_start, current_end) == 2) {
+ if (atoi(current_start) == port_start && atoi(current_end) == port_end) {
+ printf("Port range already set to %u-%u\n", port_start, port_end);
+ fclose(fp);
+ return SUCCESS;
+ }
+ }
+ }
+ }
+ rewind(fp);
+
+ /* Create temp file */
+ temp_fd = mkstemp(temp_file);
+ if (temp_fd < 0) {
+ printf("Failed to create temp file: %s\n", strerror(errno));
+ fclose(fp);
+ return FAILURE;
+ }
+
+ temp_fp = fdopen(temp_fd, "w");
+ if (!temp_fp) {
+ printf("Failed to open temp file: %s\n", strerror(errno));
+ close(temp_fd);
+ fclose(fp);
+ return FAILURE;
+ }
+
+ /* Update file contents */
+ while (fgets(line, sizeof(line), fp)) {
+ if (strstr(line, "net.ipv4.ip_local_port_range")) {
+ fprintf(temp_fp, "net.ipv4.ip_local_port_range = %u %u\n", port_start, port_end);
+ found = 1;
+ } else {
+ fputs(line, temp_fp);
+ }
+ }
+
+ /* Add entry if not found */
+ if (!found) {
+ fprintf(temp_fp, "net.ipv4.ip_local_port_range = %u %u\n", port_start, port_end);
+ }
+
+ fclose(fp);
+ fclose(temp_fp);
+
+ /* Replace original with temp file */
+ if (rename(temp_file, "/etc/sysctl.conf") != 0) {
+ printf("Failed to update sysctl.conf: %s\n", strerror(errno));
+ unlink(temp_file);
+ return FAILURE;
+ }
+
+ /* Apply changes */
+ if (system("sysctl -p") != 0) {
+ printf("Failed to apply sysctl changes\n");
+ return FAILURE;
+ }
+
+ printf("Port range updated successfully to %u-%u\n", port_start, port_end);
+ return SUCCESS;
+}
+
+int clear_host_network_port_range(void)
+{
+ FILE *fp = NULL;
+ char line[256];
+ int found = 0;
+ char temp_file[] = "/tmp/sysctl.conf.XXXXXX";
+ int temp_fd;
+ FILE *temp_fp = NULL;
+
+ /* Open sysctl.conf file */
+ fp = fopen("/etc/sysctl.conf", "r");
+ if (!fp) {
+ printf("Failed to open /etc/sysctl.conf: %s\n", strerror(errno));
+ return FAILURE;
+ }
+
+ /* Create temp file */
+ temp_fd = mkstemp(temp_file);
+ if (temp_fd < 0) {
+ printf("Failed to create temp file: %s\n", strerror(errno));
+ fclose(fp);
+ return FAILURE;
+ }
+
+ temp_fp = fdopen(temp_fd, "w");
+ if (!temp_fp) {
+ printf("Failed to open temp file: %s\n", strerror(errno));
+ close(temp_fd);
+ fclose(fp);
+ return FAILURE;
+ }
+
+ /* Copy all lines except port range setting */
+ while (fgets(line, sizeof(line), fp)) {
+ if (strstr(line, "net.ipv4.ip_local_port_range")) {
+ found = 1;
+ } else {
+ fputs(line, temp_fp);
+ }
+ }
+
+ fclose(fp);
+ fclose(temp_fp);
+
+ /* Replace original with temp file only if we found and removed an entry */
+ if (found) {
+ if (rename(temp_file, "/etc/sysctl.conf") != 0) {
+ printf("Failed to update sysctl.conf: %s\n", strerror(errno));
+ unlink(temp_file);
+ return FAILURE;
+ }
+
+ /* Apply changes */
+ if (system("sysctl -p") != 0) {
+ printf("Failed to apply sysctl changes\n");
+ return FAILURE;
+ }
+
+ printf("Host network port range configuration cleared successfully\n");
+ } else {
+ /* No entry found, just remove the temp file */
+ unlink(temp_file);
+ printf("No port range configuration found to clear\n");
+ }
+
+ return SUCCESS;
+}
+
diff --git a/esp_hosted_fg/host/linux/host_control/c_support/nw_helper_func.h b/esp_hosted_fg/host/linux/host_control/c_support/nw_helper_func.h
new file mode 100644
index 0000000000..9842c57c0a
--- /dev/null
+++ b/esp_hosted_fg/host/linux/host_control/c_support/nw_helper_func.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef NW_HELPER_FUNC_H
+#define NW_HELPER_FUNC_H
+
+#define STA_INTERFACE "ethsta0"
+#define AP_INTERFACE "ethap0"
+#define MAC_ADDR_LENGTH 18
+
+#define SUCCESS 0
+#define FAILURE -1
+
+/* Network state structure */
+typedef struct {
+ char mac_addr[MAC_ADDR_LENGTH];
+ char ip_addr[MAC_ADDR_LENGTH];
+ char netmask[MAC_ADDR_LENGTH];
+ char gateway[MAC_ADDR_LENGTH];
+ char dns_addr[MAC_ADDR_LENGTH];
+ char default_route[MAC_ADDR_LENGTH];
+ uint8_t ip_valid;
+ uint8_t dns_valid;
+ uint8_t network_up;
+} network_info_t;
+
+int down_sta_netdev(const network_info_t *info);
+int up_sta_netdev(const network_info_t *info);
+int up_sta_netdev__with_static_ip_dns_route(const network_info_t *info);
+
+int down_softap_netdev(const network_info_t *info);
+int up_softap_netdev(const network_info_t *info);
+
+int remove_default_gateway(const char *gateway);
+int add_default_gateway(const char *gateway);
+int remove_dns(const char *dns);
+int add_dns(const char *dns);
+int set_network_static_ip(int sockfd, const char* iface, const char* ip, const char* netmask, const char* gateway);
+
+int create_socket(int domain, int type, int protocol, int *sock);
+int close_socket(int sock);
+
+int interface_up(int sockfd, const char* iface);
+int interface_down(int sockfd, const char* iface);
+
+int set_hw_addr(int sockfd, const char* iface, const char* mac);
+int convert_mac_to_bytes(uint8_t *out, size_t out_size, const char *s);
+
+int update_host_network_port_range(uint16_t port_start, uint16_t port_end);
+int clear_host_network_port_range(void);
+#endif
diff --git a/esp_hosted_fg/host/linux/host_control/c_support/stress.c b/esp_hosted_fg/host/linux/host_control/c_support/stress.c
index d1407da7a5..352fb896f8 100644
--- a/esp_hosted_fg/host/linux/host_control/c_support/stress.c
+++ b/esp_hosted_fg/host/linux/host_control/c_support/stress.c
@@ -47,6 +47,7 @@ int main(int argc, char *argv[])
int stress_test_count = 0;
int str_args_start = 2;
char version[30] = {'\0'};
+ char mac_address[30] = {'\0'};
if(getuid()) {
printf("Please re-run program with superuser access\n");
@@ -82,11 +83,12 @@ int main(int argc, char *argv[])
str_args_start = 1;
}
+ test_is_network_split_on();
register_event_callbacks();
test_config_heartbeat();
/* Print FW Version by Default */
- printf("------ ESP-Hosted FW [%s] ------\n", test_get_fw_version(version));
+ printf("------ ESP-Hosted FW [%s] ------\n", test_get_fw_version(version, sizeof(version)));
for (int test_count=0; test_count
+#include
+#include
+#include "esp_hosted_custom_rpc.h"
+#include "app_custom_rpc.h"
#define DEMO_SLEEP_DURATION_SEC 50
+
+ /* Heartbeat demo needs to wait for events
+ * For simplicity, we disable heartbeat demo
+ * Anyway fullfledged cli demo is already available in hosted_shell.c
+ */
+#define ENABLE_HEARTBEAT 0
+
#define EXEC_IF_CMD_EQUALS(cmd,func) \
if (0 == strncasecmp(cmd, in_cmd, sizeof(cmd))) { \
func; \
@@ -35,27 +46,32 @@
static void inline usage(char *argv[])
{
- printf("sudo %s \n[\n %s\t\t||\n %s\t\t||\n %s\t\t||\n %s\t\t||\n %s\t\t||\n %s\t\t\t||\n %s\t\t\t||\n %s\t\t\t||\n %s\t\t\t||\n %s\t\t\t||\n %s\t\t||\n %s\t\t||\n %s\t\t\t||\n %s\t\t||\n %s\t||\n %s\t\t\t||\n %s\t||\n %s\t||\n %s\t\t||\n %s\t\t||\n %s ||\n %s\t\t\t||\n %s\t\t\t||\n %s\t\t\t||\n %s\t\t\t||\n %s\t\t\t||\n %s\t\t||\n %s\t||\n %s\t\t||\n]\n",
+ printf("sudo %s \n[\n %s\t\t||\n %s\t\t||\n %s\t\t||\n %s\t\t||\n %s\t\t||\n %s\t\t\t||\n %s\t\t\t||\n %s\t\t\t||\n %s\t\t\t||\n %s\t\t\t||\n %s\t\t||\n %s\t\t||\n %s\t\t\t||\n %s\t\t||\n %s\t||\n %s\t\t\t||\n %s\t||\n %s\t||\n %s\t\t||\n %s\t\t||\n %s ||\n %s\t\t\t||\n %s\t\t\t||\n %s\t\t\t||\n %s\t\t\t||\n %s\t\t\t||\n %s\t\t||\n %s\t||\n %s\t\t||\n]\n||\n %s\t||\n %s\t||\n %s\t]\n",
argv[0], SET_STA_MAC_ADDR, GET_STA_MAC_ADDR, SET_SOFTAP_MAC_ADDR, GET_SOFTAP_MAC_ADDR, GET_AP_SCAN_LIST,
STA_CONNECT, GET_STA_CONFIG, STA_DISCONNECT, SET_WIFI_MODE, GET_WIFI_MODE,
RESET_SOFTAP_VENDOR_IE, SET_SOFTAP_VENDOR_IE, SOFTAP_START, GET_SOFTAP_CONFIG, SOFTAP_CONNECTED_STA_LIST,
SOFTAP_STOP, SET_WIFI_POWERSAVE_MODE, GET_WIFI_POWERSAVE_MODE, SET_WIFI_MAX_TX_POWER, GET_WIFI_CURR_TX_POWER,
OTA, ENABLE_WIFI, DISABLE_WIFI, ENABLE_BT, DISABLE_BT, GET_FW_VERSION, SET_COUNTRY_CODE, SET_COUNTRY_CODE_ENABLED,
- GET_COUNTRY_CODE);
+ GET_COUNTRY_CODE, CUSTOM_RPC_DEMO1, CUSTOM_RPC_DEMO2, CUSTOM_RPC_DEMO3);
printf("\n\nFor example, \nsudo %s %s\n",
argv[0], SET_STA_MAC_ADDR);
}
+/* forward declaration of functions used */
+static int demo1_custom_rpc_unserialised_request_only_ack(void);
+static int demo2_custom_rpc_unserialised_request_and_slave_echo_back_as_response(void);
+static int demo3_custom_rpc_unserialised_request_and_slave_echo_back_as_event(void);
static int parse_cli_cmd(char *in_cmd, char *args[])
{
bool cmd_executed = false;
+ char *mac_address = NULL;
/* TODO: create commands and handler map later */
/* Get and set mac address */
- EXEC_IF_CMD_EQUALS(SET_STA_MAC_ADDR, test_station_mode_set_mac_addr_of_esp());
- EXEC_IF_CMD_EQUALS(GET_STA_MAC_ADDR, test_station_mode_get_mac_addr());
- EXEC_IF_CMD_EQUALS(SET_SOFTAP_MAC_ADDR, test_softap_mode_set_mac_addr_of_esp());
- EXEC_IF_CMD_EQUALS(GET_SOFTAP_MAC_ADDR, test_softap_mode_get_mac_addr());
+ EXEC_IF_CMD_EQUALS(SET_STA_MAC_ADDR, test_station_mode_set_mac_addr_of_esp(STATION_MODE_MAC_ADDRESS));
+ EXEC_IF_CMD_EQUALS(GET_STA_MAC_ADDR, test_station_mode_get_mac_addr(mac_address));
+ EXEC_IF_CMD_EQUALS(SET_SOFTAP_MAC_ADDR, test_softap_mode_set_mac_addr_of_esp(SOFTAP_MODE_MAC_ADDRESS));
+ EXEC_IF_CMD_EQUALS(GET_SOFTAP_MAC_ADDR, test_softap_mode_get_mac_addr(mac_address));
EXEC_IF_CMD_EQUALS(GET_AP_SCAN_LIST, test_get_available_wifi());
EXEC_IF_CMD_EQUALS(STA_CONNECT, test_station_mode_connect());
EXEC_IF_CMD_EQUALS(GET_STA_CONFIG, test_station_mode_get_info());
@@ -79,8 +95,11 @@ static int parse_cli_cmd(char *in_cmd, char *args[])
EXEC_IF_CMD_EQUALS(GET_FW_VERSION, test_print_fw_version());
EXEC_IF_CMD_EQUALS(OTA, test_ota(args[0]));
EXEC_IF_CMD_EQUALS(SET_COUNTRY_CODE, test_set_country_code());
- EXEC_IF_CMD_EQUALS(SET_COUNTRY_CODE_ENABLED, test_set_country_code_enabled());
+ EXEC_IF_CMD_EQUALS(SET_COUNTRY_CODE_ENABLED, test_set_country_code_with_ieee80211d_on());
EXEC_IF_CMD_EQUALS(GET_COUNTRY_CODE, test_get_country_code());
+ EXEC_IF_CMD_EQUALS(CUSTOM_RPC_DEMO1, demo1_custom_rpc_unserialised_request_only_ack());
+ EXEC_IF_CMD_EQUALS(CUSTOM_RPC_DEMO2, demo2_custom_rpc_unserialised_request_and_slave_echo_back_as_response());
+ EXEC_IF_CMD_EQUALS(CUSTOM_RPC_DEMO3, demo3_custom_rpc_unserialised_request_and_slave_echo_back_as_event());
if (cmd_executed)
return SUCCESS;
@@ -97,19 +116,24 @@ static int init_app(void)
return FAILURE;
}
+ test_is_network_split_on();
+
register_event_callbacks();
+ #if ENABLE_HEARTBEAT
test_config_heartbeat();
+ #endif
return 0;
}
static void cleanup_app(void)
{
- // TODO properly disable heartbeat
+ #if ENABLE_HEARTBEAT
test_disable_heartbeat_async();
- // wait for async to complete
+ /* wait for async to complete */
sleep(1);
+ #endif
unregister_event_callbacks();
control_path_platform_deinit();
@@ -157,17 +181,55 @@ int main(int argc, char *argv[])
}
/* Print FW Version by Default */
- printf("------ ESP-Hosted FW [%s] ------\n", test_get_fw_version(version));
+ printf("------ ESP-Hosted FW [%s] ------\n", test_get_fw_version(version, sizeof(version)));
cli_cmd = argv[1];
if (SUCCESS == parse_cli_cmd(cli_cmd, &argv[2])) {
+
+#if ENABLE_HEARTBEAT
sleep(2);
printf("\n\n\nRequested operation complete\n");
printf("Sleeping for some time just to showcase heartbeat\n");
sleep(DEMO_SLEEP_DURATION_SEC);
+#endif
}
cleanup_app();
printf("Exiting..");
return 0;
}
+
+
+/* ------------------- Custom RPC Packed Data DEMO 1 ------------------- */
+/* This demo shows how to send a custom RPC request with packed data
+ * and receive an echo back response.
+ * The response is not verified in this demo (as it is not expected)
+ */
+/* Implementation of demo_custom_rpc_unserialised_request_no_echo_back */
+static int demo1_custom_rpc_unserialised_request_only_ack(void) {
+ /* Call the shared implementation */
+ return custom_rpc_demo1_request_only_ack();
+}
+
+/* ------------------- Custom RPC Packed Data DEMO 2 ------------------- */
+/* This demo shows how to send a custom RPC request with packed data
+ * and receive an echo back response.
+ * The response is verified in this demo to be the same as the sent data.
+ */
+static int demo2_custom_rpc_unserialised_request_and_slave_echo_back_as_response(void) {
+ /* Call the shared implementation */
+ return custom_rpc_demo2_request_echo_back_as_response();
+}
+
+/* ------------------- Custom RPC Packed Data DEMO 3 ------------------- */
+/* This demo shows how to send a custom RPC request with packed data
+ * and receive an echo back the sent data as an event.
+ * The event is verified in this demo to be the same as the sent data.
+ * The response is not verified in this demo (as it is not expected)
+ */
+
+/* Implementation of demo_custom_rpc_unserialised_request_and_slave_echo_back_as_event */
+static int demo3_custom_rpc_unserialised_request_and_slave_echo_back_as_event(void) {
+ /* Call the shared implementation */
+ return custom_rpc_demo3_request_echo_back_as_event();
+}
diff --git a/esp_hosted_fg/host/linux/host_control/c_support/test.h b/esp_hosted_fg/host/linux/host_control/c_support/test.h
index 6f6488ee73..ba06fc019b 100644
--- a/esp_hosted_fg/host/linux/host_control/c_support/test.h
+++ b/esp_hosted_fg/host/linux/host_control/c_support/test.h
@@ -28,26 +28,27 @@
#include
#include
#include
-#include
-#include
#include
#include "ctrl_api.h"
#include "ctrl_config.h"
#include
+
int test_get_wifi_mode(void);
+int test_async_get_wifi_mode(void);
int test_set_wifi_mode(int mode);
int test_set_wifi_mode_station(void);
int test_set_wifi_mode_softap(void);
int test_set_wifi_mode_station_softap(void);
int test_set_wifi_mode_none(void);
-int test_get_wifi_mac_addr(int mode);
-int test_station_mode_get_mac_addr(void);
+int test_get_wifi_mac_addr(int mode, char *mac_str);
+int test_station_mode_get_mac_addr(char *mac_str);
int test_set_mac_addr(int mode, char *mac);
-int test_station_mode_set_mac_addr_of_esp(void);
-int test_softap_mode_set_mac_addr_of_esp(void);
-int test_softap_mode_get_mac_addr(void);
+int test_station_mode_set_mac_addr_of_esp(char *mac_str);
+int test_softap_mode_set_mac_addr_of_esp(char *mac_str);
+int test_softap_mode_get_mac_addr(char *mac_str);
int test_station_mode_connect(void);
+int test_async_station_mode_connect(void);
int test_station_mode_get_info(void);
int test_get_available_wifi(void);
int test_station_mode_disconnect(void);
@@ -76,10 +77,40 @@ int test_disable_bt(void);
int test_enable_bt(void);
int test_disable_wifi(void);
int test_enable_wifi(void);
-char * test_get_fw_version(char *);
+int test_is_network_split_on(void);
+char * test_get_fw_version(char *, uint16_t);
int test_print_fw_version(void);
-int test_set_country_code_enabled();
+int test_set_country_code_with_ieee80211d_on();
int test_set_country_code();
+int test_set_country_code_with_params(const char *code);
int test_get_country_code();
+int test_fetch_ip_addr_from_slave(void);
+int test_set_dhcp_dns_status(char *sta_ip, char *sta_nm, char *sta_gw, char *sta_dns);
+int test_softap_mode_set_vendor_ie(bool enable, const char *data);
+int test_station_mode_connect_with_params(const char *ssid, const char *pwd, const char *bssid,
+ bool use_wpa3, int listen_interval, int band_mode);
+int test_station_mode_disconnect_with_params(bool reset_dhcp);
+int test_softap_mode_start_with_params(const char *ssid, const char *pwd, int channel,
+ const char *sec_prot, int max_conn, bool hide_ssid,
+ int bw, int band_mode);
+int test_wifi_set_power_save_mode_with_params(int psmode);
+int test_get_fw_version_with_params(char *version, uint16_t version_size);
+int test_ota_update_with_params(const char *url);
+int test_heartbeat_with_params(bool enable, int duration);
+int test_set_mac_addr_with_params(int mode, const char *mac);
+int test_set_dhcp_dns_status_with_params(char *sta_ip, char *sta_nm, char *sta_gw, char *sta_dns);
+int test_set_vendor_specific_ie_with_params(bool enable, const char *data);
+int test_set_wifi_power_save_mode_with_params(int psmode);
+int test_get_fw_version_with_params(char *version, uint16_t version_size);
+int test_subscribe_event(const char *event);
+int test_unsubscribe_event(const char *event);
+int test_custom_rpc_unserialised_request(uint32_t custom_msg_id, const uint8_t *send_data, uint32_t send_data_len,
+ uint8_t **recv_data, uint32_t *recv_data_len, void (**recv_data_free_func)(void*));
+
+int default_rpc_events_handler(ctrl_cmd_t *app_event);
+int default_rpc_resp_handler(ctrl_cmd_t *app_resp);
+int test_validate_ctrl_event(ctrl_cmd_t *app_event);
+int test_validate_ctrl_resp(ctrl_cmd_t *app_resp);
+int test_is_network_split_on(void);
#endif
diff --git a/esp_hosted_fg/host/linux/host_control/c_support/test_utils.c b/esp_hosted_fg/host/linux/host_control/c_support/test_utils.c
index f94bb04b2e..d326ac1aff 100644
--- a/esp_hosted_fg/host/linux/host_control/c_support/test_utils.c
+++ b/esp_hosted_fg/host/linux/host_control/c_support/test_utils.c
@@ -18,7 +18,6 @@
* this warranty disclaimer.
*/
-
#include
#include
#include
@@ -31,12 +30,32 @@
#include "ctrl_api.h"
#include "ctrl_config.h"
#include
+#include "test.h"
+#include "nw_helper_func.h"
+#include "esp_hosted_custom_rpc.h"
/***** Please Read *****/
/* Before use : User must enter user configuration parameter in "ctrl_config.h" file */
-#define STA_INTERFACE "ethsta0"
-#define AP_INTERFACE "ethap0"
+/* Network interface definitions */
+
+
+/* Global network information structures */
+network_info_t sta_network = {0};
+network_info_t ap_network = {0};
+
+/* Global network status tracking */
+static bool interface_down_printed = false;
+static bool interface_up_printed = false;
+static bool connected_printed = false;
+static bool disconnected_printed = false;
+
+#define PRINT_IF(cond, ...) \
+ do { \
+ if (cond) { \
+ printf(__VA_ARGS__); \
+ } \
+ } while (0)
#define WIFI_VENDOR_IE_ELEMENT_ID 0xDD
#define OFFSET 4
@@ -45,24 +64,6 @@
#define VENDOR_OUI_2 3
#define VENDOR_OUI_TYPE 22
-#define CTRL_CMD_DEFAULT_REQ() { \
- .msg_type = CTRL_REQ, \
- .ctrl_resp_cb = NULL, \
- .cmd_timeout_sec = DEFAULT_CTRL_RESP_TIMEOUT /*30 sec*/ \
-}
-
-#define CLEANUP_CTRL_MSG(msg) do { \
- if (msg) { \
- if (msg->free_buffer_handle) { \
- if (msg->free_buffer_func) { \
- msg->free_buffer_func(msg->free_buffer_handle); \
- msg->free_buffer_handle = NULL; \
- } \
- } \
- free(msg); \
- msg = NULL; \
- } \
-} while(0);
#define YES 1
#define NO 0
@@ -73,9 +74,21 @@ typedef struct {
ctrl_resp_cb_t fun;
} event_callback_table_t;
-#define MAC_ADDR_LENGTH 18
-static char sta_mac_str[MAC_ADDR_LENGTH];
-static char softap_mac_str[MAC_ADDR_LENGTH];
+static inline bool successful_response(ctrl_cmd_t *resp)
+{
+ return resp && resp->resp_event_status == SUCCESS;
+}
+
+static ctrl_cmd_t * CTRL_CMD_DEFAULT_REQ(void)
+{
+ ctrl_cmd_t *new_req = (ctrl_cmd_t*)calloc(1, sizeof(ctrl_cmd_t));
+ assert(new_req);
+ new_req->msg_type = CTRL_REQ;
+ new_req->ctrl_resp_cb = NULL;
+ new_req->cmd_timeout_sec = 5;
+ return new_req;
+}
+
static char * get_timestamp(char *str, uint16_t str_size)
{
@@ -88,27 +101,63 @@ static char * get_timestamp(char *str, uint16_t str_size)
return NULL;
}
-static int ctrl_app_event_callback(ctrl_cmd_t * app_event)
-{
- char ts[MIN_TIMESTAMP_STR_SIZE] = {'\0'};
-
+int test_validate_ctrl_event(ctrl_cmd_t *app_event) {
if (!app_event || (app_event->msg_type != CTRL_EVENT)) {
if (app_event)
- printf("Msg type is not event[%u]\n",app_event->msg_type);
- goto fail_parsing;
+ printf("Msg type is not event[%u]\n", app_event->msg_type);
+ return FAILURE;
}
if ((app_event->msg_id <= CTRL_EVENT_BASE) ||
- (app_event->msg_id >= CTRL_EVENT_MAX)) {
- printf("Event Msg ID[%u] is not correct\n",app_event->msg_id);
- goto fail_parsing;
+ (app_event->msg_id >= CTRL_EVENT_MAX)) {
+ printf("Event Msg ID[%u] is not correct\n", app_event->msg_id);
+ return FAILURE;
}
+ return SUCCESS;
+}
+
+int test_validate_ctrl_resp(ctrl_cmd_t *app_resp) {
+ int ret = SUCCESS;
+
+ if (!app_resp || (app_resp->msg_type != CTRL_RESP)) {
+ if (app_resp)
+ printf("Msg type is not response[%u]\n", app_resp->msg_type);
+ ret = FAILURE;
+ }
+
+ if (!ret && ((app_resp->msg_id <= CTRL_RESP_BASE) || (app_resp->msg_id >= CTRL_RESP_MAX))) {
+ printf("Response Msg ID[%u] is not correct\n", app_resp->msg_id);
+ ret = FAILURE;
+ }
+
+ if (!ret && (app_resp->resp_event_status != SUCCESS)) {
+ printf("Received NACK in response\n");
+ ret = FAILURE;
+ }
+
+ return ret;
+}
- switch(app_event->msg_id) {
+int ctrl_app_resp_callback(ctrl_cmd_t *app_resp);
+
+static int ctrl_app_event_callback(ctrl_cmd_t *app_event) {
+ char ts[MIN_TIMESTAMP_STR_SIZE] = {'\0'};
+
+ if (test_validate_ctrl_event(app_event)) {
+ printf("%s invalid event[%u]\n", __func__, app_event->msg_id);
+ CLEANUP_CTRL_MSG(app_event);
+ return FAILURE;
+ }
+
+ switch(app_event->msg_id) {
case CTRL_EVENT_ESP_INIT: {
printf("%s App EVENT: ESP INIT\n",
get_timestamp(ts, MIN_TIMESTAMP_STR_SIZE));
+ connected_printed = false;
+ disconnected_printed = false;
+ interface_up_printed = false;
+ interface_down_printed = false;
break;
} case CTRL_EVENT_HEARTBEAT: {
printf("%s App EVENT: Heartbeat event [%d]\n",
@@ -117,15 +166,34 @@ static int ctrl_app_event_callback(ctrl_cmd_t * app_event)
break;
} case CTRL_EVENT_STATION_CONNECTED_TO_AP: {
event_sta_conn_t *p_e = &app_event->u.e_sta_conn;
- printf("%s App EVENT: STA-Connected ssid[%s] bssid[%s] channel[%d] auth[%d] aid[%d]\n",
+ PRINT_IF(!connected_printed, "Station interface is up/connected\n");
+ PRINT_IF(!connected_printed, "%s App EVENT: STA-Connected ssid[%s] bssid[%s] channel[%d] auth[%d] aid[%d]\n",
get_timestamp(ts, MIN_TIMESTAMP_STR_SIZE), p_e->ssid,
p_e->bssid, p_e->channel, p_e->authmode, p_e->aid);
+ if (!test_is_network_split_on()) {
+ PRINT_IF(!connected_printed, "Network iface 'ethsta0' Up! You may run 'dhclient -v ethsta0' to get IP address\n\n");
+ }
+ disconnected_printed = false;
+ connected_printed = true;
+ if (sta_network.mac_addr[0] != '\0') {
+ up_sta_netdev(&sta_network);
+ } else {
+ printf("Interface ethsta0 not made up, as MAC is not set\n");
+ printf("You may consider calling 'test_station_mode_get_mac_addr(sta_network.mac_addr);' to set the STA MAC before\n");
+ }
break;
} case CTRL_EVENT_STATION_DISCONNECT_FROM_AP: {
event_sta_disconn_t *p_e = &app_event->u.e_sta_disconn;
- printf("%s App EVENT: STA-Disconnected reason[%d] ssid[%s] bssid[%s] rssi[%d]\n",
+ PRINT_IF(!disconnected_printed, "Station interface is down/disconnected\n");
+ PRINT_IF(!disconnected_printed, "%s App EVENT: STA-Disconnected reason[%d] ssid[%s] bssid[%s] rssi[%d]\n",
get_timestamp(ts, MIN_TIMESTAMP_STR_SIZE), p_e->reason, p_e->ssid,
p_e->bssid, p_e->rssi);
+ if (!test_is_network_split_on()) {
+ PRINT_IF(!disconnected_printed, "Network iface 'ethsta0' Down! You may 'killall dhclient' to stop dhclient process\n\n");
+ }
+ disconnected_printed = true;
+ connected_printed = false;
+ down_sta_netdev(&sta_network);
break;
} case CTRL_EVENT_STATION_CONNECTED_TO_ESP_SOFTAP: {
event_softap_sta_conn_t *p_e = &app_event->u.e_softap_sta_conn;
@@ -135,6 +203,9 @@ static int ctrl_app_event_callback(ctrl_cmd_t * app_event)
get_timestamp(ts, MIN_TIMESTAMP_STR_SIZE),
p, p_e->aid, p_e->is_mesh_child);
}
+ if (!test_is_network_split_on()) {
+ printf("Network interface ethsta0 brought up. You may run 'dhclient -v ethsta0' to get IP address\n");
+ }
break;
} case CTRL_EVENT_STATION_DISCONNECT_FROM_ESP_SOFTAP: {
event_softap_sta_disconn_t *p_e = &app_event->u.e_softap_sta_disconn;
@@ -145,6 +216,92 @@ static int ctrl_app_event_callback(ctrl_cmd_t * app_event)
p, p_e->reason, p_e->aid, p_e->is_mesh_child);
}
break;
+ } case CTRL_EVENT_DHCP_DNS_STATUS: {
+ dhcp_dns_status_t *p_e = &app_event->u.dhcp_dns_status;
+
+ if (test_is_network_split_on()) {
+
+ if (!successful_response(app_event)) {
+ printf("Slave firmware not compiled with network split. Ignore (DHCP_DNS event)\n");
+ CLEANUP_CTRL_MSG(app_event);
+ return FAILURE;
+ }
+
+ if (p_e->dhcp_up) {
+ strncpy(sta_network.ip_addr, (const char *)p_e->dhcp_ip, MAC_ADDR_LENGTH);
+ strncpy(sta_network.netmask, (const char *)p_e->dhcp_nm, MAC_ADDR_LENGTH);
+ strncpy(sta_network.gateway, (const char *)p_e->dhcp_gw, MAC_ADDR_LENGTH);
+ strncpy(sta_network.default_route, (const char *)p_e->dhcp_gw, MAC_ADDR_LENGTH);
+ sta_network.ip_valid = 1;
+ } else {
+ sta_network.network_up = 0;
+ sta_network.ip_valid = 0;
+ }
+ if (p_e->dns_up) {
+ strncpy(sta_network.dns_addr, (const char *)p_e->dns_ip, MAC_ADDR_LENGTH);
+ sta_network.dns_valid = 1;
+ } else {
+ sta_network.dns_valid = 0;
+ }
+
+ if (p_e->net_link_up) {
+ PRINT_IF(!interface_up_printed, "%s network event %s dhcp %s (%s %s %s) dns %s (%s) ===> Configured as static IP\n",
+ get_timestamp(ts, MIN_TIMESTAMP_STR_SIZE),
+ p_e->net_link_up ? "up" : "down",
+ p_e->dhcp_up ? "up" : "down",
+ p_e->dhcp_ip, p_e->dhcp_nm, p_e->dhcp_gw,
+ p_e->dns_up ? "up" : "down",
+ p_e->dns_ip);
+ interface_up_printed = true;
+ interface_down_printed = false;
+ } else {
+ /* Only print network down message if we haven't already */
+ PRINT_IF(!interface_down_printed, "%s network event %s ===> Interface would be brought down\n",
+ get_timestamp(ts, MIN_TIMESTAMP_STR_SIZE),
+ p_e->net_link_up ? "up" : "down");
+ interface_up_printed = false;
+ interface_down_printed = true;
+ }
+
+ if (sta_network.dns_valid && sta_network.ip_valid) {
+ //printf("Network identified as up\n");
+ if (sta_network.mac_addr[0] != '\0') {
+ up_sta_netdev__with_static_ip_dns_route(&sta_network);
+ add_dns(sta_network.dns_addr);
+ sta_network.network_up = 1;
+ } else {
+ printf("Event ignored as 'ethsta0' yet not assigned MAC\n");
+ printf("You may consider calling 'test_station_mode_get_mac_addr(sta_network.mac_addr);' to set the STA MAC before\n");
+ }
+ } else {
+ //printf("Network identified as down");
+ /* Only print interface down message if we haven't already */
+
+ down_sta_netdev(&sta_network);
+ remove_dns(sta_network.dns_addr);
+ sta_network.network_up = 0;
+ }
+
+ } else {
+ printf("Network split[%d] is disabled. So ignoring the DHCP_DNS event\n",
+ test_is_network_split_on());
+ }
+ break;
+ } case CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG: {
+ printf("%s App EVENT: Custom RPC unserialised message (Default handler)\n",
+ get_timestamp(ts, MIN_TIMESTAMP_STR_SIZE));
+ custom_rpc_unserialised_data_t *p_e = &app_event->u.custom_rpc_unserialised_data;
+ printf("Received custom RPC event id[%u] data len[%u] data: \n",
+ p_e->custom_msg_id, p_e->data_len);
+ for (size_t i = 0; i < p_e->data_len && i < 32; i++) {
+ printf("%02X ", p_e->data[i]);
+ }
+ if (p_e->data_len > 32) {
+ printf(" ... (%u more bytes)", p_e->data_len - 32);
+ }
+ printf("\n");
+ printf("Note: You can set your own event callback instead of this default handler\n");
+ break;
} default: {
printf("%s Invalid event[%u] to parse\n",
get_timestamp(ts, MIN_TIMESTAMP_STR_SIZE), app_event->msg_id);
@@ -153,10 +310,14 @@ static int ctrl_app_event_callback(ctrl_cmd_t * app_event)
}
CLEANUP_CTRL_MSG(app_event);
return SUCCESS;
+}
-fail_parsing:
- CLEANUP_CTRL_MSG(app_event);
- return FAILURE;
+inline int default_rpc_events_handler(ctrl_cmd_t *app_event) {
+ return ctrl_app_event_callback(app_event);
+}
+
+inline int default_rpc_resp_handler(ctrl_cmd_t *app_resp) {
+ return ctrl_app_resp_callback(app_resp);
}
static void process_failed_responses(ctrl_cmd_t *app_msg)
@@ -224,192 +385,23 @@ static void process_failed_responses(ctrl_cmd_t *app_msg)
printf("Failed to start SoftAP\n");
break;
}
+
+ case CTRL_RESP_SET_DHCP_DNS_STATUS:
+ case CTRL_RESP_GET_DHCP_DNS_STATUS: {
+ printf("Possibly network is not up\n");
+ break;
+ }
case CTRL_RESP_STOP_SOFTAP:
case CTRL_RESP_GET_SOFTAP_CONFIG: {
printf("Possibly softap is not running/started\n");
break;
} default: {
- printf("Failed Control Response\n");
+ printf("Failed RPC resp for RPC Req[%u]\n", app_msg->msg_id-CTRL_RESP_BASE+CTRL_REQ_BASE);
break;
}
}
}
-static int down_sta_netdev(void)
-{
- int ret = SUCCESS, sockfd = 0;
-
- ret = create_socket(AF_INET, SOCK_DGRAM, IPPROTO_IP, &sockfd);
- if (ret < 0) {
- printf("Failure to open socket\n");
- return FAILURE;
- }
-
- ret = interface_down(sockfd, STA_INTERFACE);
- if (ret == SUCCESS) {
- printf("%s interface down\n", STA_INTERFACE);
- } else {
- printf("Unable to down %s interface\n", STA_INTERFACE);
- goto close_sock;
- }
-
- ret = close_socket(sockfd);
- if (ret < 0) {
- printf("Failure to close socket\n");
- return FAILURE;
- }
-
- return SUCCESS;
-
-close_sock:
- ret = close_socket(sockfd);
- if (ret < 0) {
- printf("Failure to close socket\n");
- }
- return FAILURE;
-}
-
-static int up_sta_netdev(char *sta_mac)
-{
- int ret = SUCCESS, sockfd = 0;
-
- if (!sta_mac || !strlen(sta_mac)) {
- printf("Failure: station mac is empty\n");
- return FAILURE;
- }
-
- ret = create_socket(AF_INET, SOCK_DGRAM, IPPROTO_IP, &sockfd);
- if (ret < 0) {
- printf("Failure to open socket\n");
- return FAILURE;
- }
-
- ret = interface_down(sockfd, STA_INTERFACE);
- if (ret == SUCCESS) {
- printf("%s interface down\n", STA_INTERFACE);
- } else {
- printf("Unable to down %s interface\n", STA_INTERFACE);
- goto close_sock;
- }
-
- ret = set_hw_addr(sockfd, STA_INTERFACE, sta_mac);
- if (ret == SUCCESS) {
- printf("MAC address %s set to %s interface\n", sta_mac, STA_INTERFACE);
- } else {
- printf("Unable to set MAC address to %s interface\n", STA_INTERFACE);
- goto close_sock;
- }
-
- ret = interface_up(sockfd, STA_INTERFACE);
- if (ret == SUCCESS) {
- printf("%s interface up\n", STA_INTERFACE);
- } else {
- printf("Unable to up %s interface\n", STA_INTERFACE);
- goto close_sock;
- }
-
- ret = close_socket(sockfd);
- if (ret < 0) {
- printf("Failure to close socket\n");
- return FAILURE;
- }
- return SUCCESS;
-
-close_sock:
- ret = close_socket(sockfd);
- if (ret < 0) {
- printf("Failure to close socket\n");
- }
- return FAILURE;
-}
-
-static int down_softap_netdev(void)
-{
- int ret = SUCCESS, sockfd = 0;
-
- ret = create_socket(AF_INET, SOCK_DGRAM, IPPROTO_IP, &sockfd);
- if (ret < 0) {
- printf("Failure to open socket\n");
- return FAILURE;
- }
-
- ret = interface_down(sockfd, AP_INTERFACE);
- if (ret == SUCCESS) {
- printf("%s interface down\n", AP_INTERFACE);
- } else {
- printf("Unable to down %s interface\n", AP_INTERFACE);
- goto close_sock;
- }
-
- ret = close_socket(sockfd);
- if (ret < 0) {
- printf("Failure to close socket\n");
- return FAILURE;
- }
- return SUCCESS;
-
-close_sock:
- ret = close_socket(sockfd);
- if (ret < 0) {
- printf("Failure to close socket\n");
- }
- return FAILURE;
-}
-
-static int up_softap_netdev(char *softap_mac)
-{
- int ret = SUCCESS, sockfd = 0;
-
- if (!softap_mac || !strlen(softap_mac)) {
- printf("Failure: softap mac is empty\n");
- return FAILURE;
- }
-
- ret = create_socket(AF_INET, SOCK_DGRAM, IPPROTO_IP, &sockfd);
- if (ret < 0) {
- printf("Failure to open socket\n");
- return FAILURE;
- }
-
- ret = interface_down(sockfd, AP_INTERFACE);
- if (ret == SUCCESS) {
- printf("%s interface down\n", AP_INTERFACE);
- } else {
- printf("Unable to down %s interface\n", AP_INTERFACE);
- goto close_sock;
- }
-
- ret = set_hw_addr(sockfd, AP_INTERFACE, softap_mac);
- if (ret == SUCCESS) {
- printf("MAC address %s set to %s interface\n", softap_mac, AP_INTERFACE);
- } else {
- printf("Unable to set MAC address to %s interface\n", AP_INTERFACE);
- goto close_sock;
- }
-
- ret = interface_up(sockfd, AP_INTERFACE);
- if (ret == SUCCESS) {
- printf("%s interface up\n", AP_INTERFACE);
- } else {
- printf("Unable to up %s interface\n", AP_INTERFACE);
- goto close_sock;
- }
-
- ret = close_socket(sockfd);
- if (ret < 0) {
- printf("Failure to close socket\n");
- return FAILURE;
- }
- return SUCCESS;
-
-close_sock:
- ret = close_socket(sockfd);
- if (ret < 0) {
- printf("Failure to close socket\n");
- }
- return FAILURE;
-}
-
int unregister_event_callbacks(void)
{
@@ -436,6 +428,8 @@ int register_event_callbacks(void)
{ CTRL_EVENT_STATION_DISCONNECT_FROM_AP, ctrl_app_event_callback },
{ CTRL_EVENT_STATION_CONNECTED_TO_ESP_SOFTAP, ctrl_app_event_callback },
{ CTRL_EVENT_STATION_DISCONNECT_FROM_ESP_SOFTAP, ctrl_app_event_callback },
+ { CTRL_EVENT_DHCP_DNS_STATUS, ctrl_app_event_callback },
+ { CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG, ctrl_app_event_callback },
};
for (evt=0; evtmsg_type != CTRL_RESP)) {
- if (app_resp)
- printf("Msg type is not response[%u]\n",app_resp->msg_type);
+
+ if (test_validate_ctrl_resp(app_resp) == FAILURE) {
goto fail_resp;
}
@@ -465,11 +500,6 @@ int ctrl_app_resp_callback(ctrl_cmd_t * app_resp)
goto fail_resp;
}
- if ((app_resp->msg_id <= CTRL_RESP_BASE) || (app_resp->msg_id >= CTRL_RESP_MAX)) {
- printf("Response Msg ID[%u] is not correct\n",app_resp->msg_id);
- goto fail_resp;
- }
-
switch(app_resp->msg_id) {
case CTRL_RESP_GET_MAC_ADDR: {
@@ -526,12 +556,14 @@ int ctrl_app_resp_callback(ctrl_cmd_t * app_resp)
}
break;
} case CTRL_RESP_CONNECT_AP : {
- if (up_sta_netdev(app_resp->u.wifi_ap_config.out_mac))
- goto fail_resp;
+
+ printf("AP connect req submitted\n");
+ //if (up_sta_netdev(&sta_network))
+ // goto fail_resp;
break;
} case CTRL_RESP_DISCONNECT_AP : {
printf("Disconnected from AP \n");
- if (down_sta_netdev())
+ if (down_sta_netdev(&sta_network))
goto fail_resp;
break;
} case CTRL_RESP_GET_SOFTAP_CONFIG : {
@@ -552,7 +584,7 @@ int ctrl_app_resp_callback(ctrl_cmd_t * app_resp)
break;
} case CTRL_RESP_START_SOFTAP : {
printf("esp32 softAP started with band_mode %d\n", app_resp->u.wifi_softap_config.band_mode);
- if (up_softap_netdev(app_resp->u.wifi_softap_config.out_mac))
+ if (up_softap_netdev(&ap_network))
goto fail_resp;
break;
} case CTRL_RESP_GET_SOFTAP_CONN_STA_LIST : {
@@ -577,7 +609,7 @@ int ctrl_app_resp_callback(ctrl_cmd_t * app_resp)
break;
} case CTRL_RESP_STOP_SOFTAP : {
printf("esp32 softAP stopped\n");
- if (down_softap_netdev())
+ if (down_softap_netdev(&ap_network))
goto fail_resp;
break;
} case CTRL_RESP_SET_PS_MODE : {
@@ -587,12 +619,18 @@ int ctrl_app_resp_callback(ctrl_cmd_t * app_resp)
printf("Wifi power save mode is: ");
switch(app_resp->u.wifi_ps.ps_mode) {
+ case WIFI_PS_NONE:
+ printf("None\n");
+ break;
case WIFI_PS_MIN_MODEM:
printf("Min\n");
break;
case WIFI_PS_MAX_MODEM:
printf("Max\n");
break;
+ case WIFI_PS_INVALID:
+ printf("Invalid\n");
+ break;
default:
printf("Invalid\n");
break;
@@ -602,7 +640,7 @@ int ctrl_app_resp_callback(ctrl_cmd_t * app_resp)
printf("OTA begin success\n");
break;
} case CTRL_RESP_OTA_WRITE : {
- printf("OTA write success\n");
+ //printf("OTA write success\n");
break;
} case CTRL_RESP_OTA_END : {
printf("OTA end success\n");
@@ -621,7 +659,7 @@ int ctrl_app_resp_callback(ctrl_cmd_t * app_resp)
printf("Feature config change successful\n");
break;
} case CTRL_RESP_GET_FW_VERSION: {
- printf("Get Firmware Version successful\n");
+ //printf("Get Firmware Version successful\n");
break;
} case CTRL_RESP_SET_COUNTRY_CODE: {
printf("Set Country Code successful\n");
@@ -629,6 +667,22 @@ int ctrl_app_resp_callback(ctrl_cmd_t * app_resp)
} case CTRL_RESP_GET_COUNTRY_CODE: {
printf("Current Country code is %s\n", app_resp->u.country_code.country);
break;
+ } case CTRL_RESP_GET_DHCP_DNS_STATUS: {
+ //printf("Response for Get DHCP DNS Status received\n");
+ break;
+ } case CTRL_RESP_CUSTOM_RPC_UNSERIALISED_MSG: {
+ printf("Default handler for custom RPC response id[%u] data len[%u] data: \n",
+ app_resp->u.custom_rpc_unserialised_data.custom_msg_id,
+ app_resp->u.custom_rpc_unserialised_data.data_len);
+ for (size_t i = 0; i < app_resp->u.custom_rpc_unserialised_data.data_len && i < 32; i++) {
+ printf("%02X ", app_resp->u.custom_rpc_unserialised_data.data[i]);
+ }
+ if (app_resp->u.custom_rpc_unserialised_data.data_len > 32) {
+ printf(" ... (%u more bytes)", app_resp->u.custom_rpc_unserialised_data.data_len - 32);
+ }
+ printf("\n");
+ printf("You can set your own callback instead of this default handler\n");
+ break;
} default: {
printf("Invalid Response[%u] to parse\n", app_resp->msg_id);
break;
@@ -644,28 +698,42 @@ int ctrl_app_resp_callback(ctrl_cmd_t * app_resp)
return FAILURE;
}
-int test_get_wifi_mode(void)
+int test_async_get_wifi_mode(void)
{
/* implemented Asynchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
/* register callback for reply */
- req.ctrl_resp_cb = ctrl_app_resp_callback;
+ req->ctrl_resp_cb = ctrl_app_resp_callback;
wifi_get_mode(req);
+ CLEANUP_CTRL_MSG(req);
return SUCCESS;
}
+int test_get_wifi_mode(void)
+{
+ /* implemented synchronous */
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *resp = NULL;
+
+ resp = wifi_get_mode(req);
+ CLEANUP_CTRL_MSG(req);
+
+ return ctrl_app_resp_callback(resp);
+}
+
int test_set_wifi_mode(int mode)
{
/* implemented synchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
ctrl_cmd_t *resp = NULL;
- req.u.wifi_mode.mode = mode;
+ req->u.wifi_mode.mode = mode;
resp = wifi_set_mode(req);
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
@@ -690,182 +758,273 @@ int test_set_wifi_mode_none(void)
return test_set_wifi_mode(WIFI_MODE_NONE);
}
-int test_get_wifi_mac_addr(int mode)
+int test_get_wifi_mac_addr(int mode, char *mac_str)
{
+ int ret = SUCCESS;
+ if (mac_str == NULL) {
+ printf("%s invalid argument\n", __func__);
+ return FAILURE;
+ }
/* implemented synchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
ctrl_cmd_t *resp = NULL;
- req.u.wifi_mac.mode = mode;
+ req->u.wifi_mac.mode = mode;
resp = wifi_get_mac(req);
- if (resp->resp_event_status == SUCCESS) {
+ if ((test_validate_ctrl_resp(resp) != FAILURE) && successful_response(resp)) {
if (mode == WIFI_MODE_STA) {
- strncpy(sta_mac_str, resp->u.wifi_mac.mac, MAC_ADDR_LENGTH);
+ if (strlen(resp->u.wifi_mac.mac) > 0) {
+ strncpy(mac_str, resp->u.wifi_mac.mac, MAC_ADDR_LENGTH);
+ } else {
+ printf("%s failed to get mac address\n", __func__);
+ ret = FAILURE;
+ goto cleanup;
+ }
} else if (mode == WIFI_MODE_AP) {
- strncpy(softap_mac_str, resp->u.wifi_mac.mac, MAC_ADDR_LENGTH);
+ if (strlen(resp->u.wifi_mac.mac) > 0) {
+ strncpy(mac_str, resp->u.wifi_mac.mac, MAC_ADDR_LENGTH);
+ } else {
+ printf("%s failed to get mac address\n", __func__);
+ ret = FAILURE;
+ goto cleanup;
+ }
}
}
- return ctrl_app_resp_callback(resp);
+cleanup:
+ CLEANUP_CTRL_MSG(req);
+ CLEANUP_CTRL_MSG(resp);
+ return ret;
}
-int test_station_mode_get_mac_addr(void)
+int test_station_mode_get_mac_addr(char *mac_str)
{
- return test_get_wifi_mac_addr(WIFI_MODE_STA);
+ return test_get_wifi_mac_addr(WIFI_MODE_STA, mac_str);
}
int test_set_mac_addr(int mode, char *mac)
{
/* implemented synchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
ctrl_cmd_t *resp = NULL;
int ret = test_set_wifi_mode(mode);
if (ret == SUCCESS) {
- req.u.wifi_mac.mode = mode;
- strncpy(req.u.wifi_mac.mac, mac, MAX_MAC_STR_SIZE);
- req.u.wifi_mac.mac[MAX_MAC_STR_SIZE-1] = '\0';
+ req->u.wifi_mac.mode = mode;
+ strncpy(req->u.wifi_mac.mac, mac, MAX_MAC_STR_SIZE);
+ req->u.wifi_mac.mac[MAX_MAC_STR_SIZE-1] = '\0';
resp = wifi_set_mac(req);
- return ctrl_app_resp_callback(resp);
+ ret = ctrl_app_resp_callback(resp);
}
+ CLEANUP_CTRL_MSG(req);
return ret;
}
-int test_station_mode_set_mac_addr_of_esp(void)
+int test_station_mode_set_mac_addr_of_esp(char *mac_str)
{
- return test_set_mac_addr(WIFI_MODE_STA, STATION_MODE_MAC_ADDRESS);
+ return test_set_mac_addr(WIFI_MODE_STA, mac_str);
}
-int test_softap_mode_set_mac_addr_of_esp(void)
+int test_softap_mode_set_mac_addr_of_esp(char *mac_str)
{
- return test_set_mac_addr(WIFI_MODE_STA, SOFTAP_MODE_MAC_ADDRESS);
+ return test_set_mac_addr(WIFI_MODE_AP, mac_str);
}
-int test_softap_mode_get_mac_addr(void)
+int test_softap_mode_get_mac_addr(char *mac_str)
{
- return test_get_wifi_mac_addr(WIFI_MODE_AP);
+ if (!mac_str) {
+ printf("%s invalid argument\n", __func__);
+ return FAILURE;
+ }
+ return test_get_wifi_mac_addr(WIFI_MODE_AP, mac_str);
}
-int test_station_mode_connect(void)
+int test_async_station_mode_connect(void)
{
+
+ if (sta_network.mac_addr[0] == '\0') {
+ /* sync procedure to get sta mac first */
+ if (test_station_mode_get_mac_addr(sta_network.mac_addr) != SUCCESS) {
+ printf("Failed to get and set 'ethsta0' MAC address\n");
+ }
+ }
+
/* implemented Asynchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
printf("Connect to AP[%s]", STATION_MODE_SSID);
- strcpy((char *)&req.u.wifi_ap_config.ssid, STATION_MODE_SSID);
- strcpy((char *)&req.u.wifi_ap_config.pwd, STATION_MODE_PWD);
- strcpy((char *)&req.u.wifi_ap_config.bssid, STATION_MODE_BSSID);
- req.u.wifi_ap_config.is_wpa3_supported = STATION_MODE_IS_WPA3_SUPPORTED;
- req.u.wifi_ap_config.listen_interval = STATION_MODE_LISTEN_INTERVAL;
- req.u.wifi_ap_config.band_mode = STATION_BAND_MODE;
+ strcpy((char *)&req->u.wifi_ap_config.ssid, STATION_MODE_SSID);
+ strcpy((char *)&req->u.wifi_ap_config.pwd, STATION_MODE_PWD);
+ strcpy((char *)&req->u.wifi_ap_config.bssid, STATION_MODE_BSSID);
+ req->u.wifi_ap_config.is_wpa3_supported = STATION_MODE_IS_WPA3_SUPPORTED;
+ req->u.wifi_ap_config.listen_interval = STATION_MODE_LISTEN_INTERVAL;
+ req->u.wifi_ap_config.band_mode = STATION_BAND_MODE;
/* register callback for handling asynch reply */
- req.ctrl_resp_cb = ctrl_app_resp_callback;
+ req->ctrl_resp_cb = ctrl_app_resp_callback;
+ connected_printed = false;
+ disconnected_printed = false;
+ interface_up_printed = false;
+ interface_down_printed = false;
wifi_connect_ap(req);
+ CLEANUP_CTRL_MSG(req);
return SUCCESS;
}
+int test_station_mode_connect(void)
+{
+ if (sta_network.mac_addr[0] == '\0') {
+ /* sync procedure to get sta mac first */
+ if (test_station_mode_get_mac_addr(sta_network.mac_addr) != SUCCESS) {
+ printf("Failed to get and set 'ethsta0' MAC address\n");
+ }
+ }
+
+ /* implemented synchronous */
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *resp = NULL;
+
+ printf("Connect to AP[%s]", STATION_MODE_SSID);
+
+ strcpy((char *)req->u.wifi_ap_config.ssid, STATION_MODE_SSID);
+ strcpy((char *)req->u.wifi_ap_config.pwd, STATION_MODE_PWD);
+ strcpy((char *)req->u.wifi_ap_config.bssid, STATION_MODE_BSSID);
+ req->u.wifi_ap_config.is_wpa3_supported = STATION_MODE_IS_WPA3_SUPPORTED;
+ req->u.wifi_ap_config.listen_interval = STATION_MODE_LISTEN_INTERVAL;
+ req->u.wifi_ap_config.band_mode = STATION_BAND_MODE;
+
+ connected_printed = false;
+ disconnected_printed = false;
+ interface_up_printed = false;
+ interface_down_printed = false;
+
+ resp = wifi_connect_ap(req);
+
+ CLEANUP_CTRL_MSG(req);
+ return ctrl_app_resp_callback(resp);
+}
+
int test_station_mode_get_info(void)
{
/* implemented synchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
ctrl_cmd_t *resp = NULL;
resp = wifi_get_ap_config(req);
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
int test_get_available_wifi(void)
{
/* implemented synchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
ctrl_cmd_t *resp = NULL;
resp = wifi_ap_scan_list(req);
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
int test_station_mode_disconnect(void)
{
/* implemented synchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
ctrl_cmd_t *resp = NULL;
+ connected_printed = false;
+ disconnected_printed = false;
+ interface_up_printed = false;
+ interface_down_printed = false;
+
resp = wifi_disconnect_ap(req);
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
int test_softap_mode_start(void)
{
+
+ if (ap_network.mac_addr[0] == '\0') {
+ /* sync procedure to get softap mac first */
+ if (test_softap_mode_get_mac_addr(ap_network.mac_addr) != SUCCESS) {
+ printf("Failed to get and set 'ethap0' MAC address\n");
+ }
+ }
/* implemented synchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
ctrl_cmd_t *resp = NULL;
- strncpy((char *)&req.u.wifi_softap_config.ssid,
+ strncpy((char *)&req->u.wifi_softap_config.ssid,
SOFTAP_MODE_SSID, SSID_LENGTH - 1);
- strncpy((char *)&req.u.wifi_softap_config.pwd,
+ strncpy((char *)&req->u.wifi_softap_config.pwd,
SOFTAP_MODE_PWD, PASSWORD_LENGTH - 1);
- req.u.wifi_softap_config.channel = SOFTAP_MODE_CHANNEL;
- req.u.wifi_softap_config.encryption_mode = SOFTAP_MODE_ENCRYPTION_MODE;
- req.u.wifi_softap_config.max_connections = SOFTAP_MODE_MAX_ALLOWED_CLIENTS;
- req.u.wifi_softap_config.ssid_hidden = SOFTAP_MODE_SSID_HIDDEN;
- req.u.wifi_softap_config.bandwidth = SOFTAP_MODE_BANDWIDTH;
- req.u.wifi_softap_config.band_mode = SOFTAP_BAND_MODE;
+ req->u.wifi_softap_config.channel = SOFTAP_MODE_CHANNEL;
+ req->u.wifi_softap_config.encryption_mode = SOFTAP_MODE_ENCRYPTION_MODE;
+ req->u.wifi_softap_config.max_connections = SOFTAP_MODE_MAX_ALLOWED_CLIENTS;
+ req->u.wifi_softap_config.ssid_hidden = SOFTAP_MODE_SSID_HIDDEN;
+ req->u.wifi_softap_config.bandwidth = SOFTAP_MODE_BANDWIDTH;
+ req->u.wifi_softap_config.band_mode = SOFTAP_BAND_MODE;
resp = wifi_start_softap(req);
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
int test_softap_mode_get_info(void)
{
/* implemented synchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
ctrl_cmd_t *resp = NULL;
resp = wifi_get_softap_config(req);
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
int test_softap_mode_connected_clients_info(void)
{
/* implemented synchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
ctrl_cmd_t *resp = NULL;
resp = wifi_get_softap_connected_station_list(req);
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
int test_softap_mode_stop(void)
{
/* implemented synchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
ctrl_cmd_t *resp = NULL;
resp = wifi_stop_softap(req);
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
int test_set_wifi_power_save_mode(int psmode)
{
/* implemented synchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
ctrl_cmd_t *resp = NULL;
- req.u.wifi_ps.ps_mode = psmode;
+ req->u.wifi_ps.ps_mode = psmode;
resp = wifi_set_power_save_mode(req);
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
@@ -882,45 +1041,48 @@ int test_set_wifi_power_save_mode_min(void)
int test_get_wifi_power_save_mode(void)
{
/* implemented synchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
ctrl_cmd_t *resp = NULL;
resp = wifi_get_power_save_mode(req);
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
int test_reset_vendor_specific_ie(void)
{
/* implemented synchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
ctrl_cmd_t *resp = NULL;
char *data = "Example vendor IE data";
char *v_data = (char*)calloc(1, strlen(data));
if (!v_data) {
+ CLEANUP_CTRL_MSG(req);
printf("Failed to allocate memory \n");
return FAILURE;
}
memcpy(v_data, data, strlen(data));
- req.u.wifi_softap_vendor_ie.enable = false;
- req.u.wifi_softap_vendor_ie.type = WIFI_VND_IE_TYPE_BEACON;
- req.u.wifi_softap_vendor_ie.idx = WIFI_VND_IE_ID_0;
- req.u.wifi_softap_vendor_ie.vnd_ie.element_id = WIFI_VENDOR_IE_ELEMENT_ID;
- req.u.wifi_softap_vendor_ie.vnd_ie.length = strlen(data)+OFFSET;
- req.u.wifi_softap_vendor_ie.vnd_ie.vendor_oui[0] = VENDOR_OUI_0;
- req.u.wifi_softap_vendor_ie.vnd_ie.vendor_oui[1] = VENDOR_OUI_1;
- req.u.wifi_softap_vendor_ie.vnd_ie.vendor_oui[2] = VENDOR_OUI_2;
- req.u.wifi_softap_vendor_ie.vnd_ie.vendor_oui_type = VENDOR_OUI_TYPE;
- req.u.wifi_softap_vendor_ie.vnd_ie.payload = (uint8_t *)v_data;
- req.u.wifi_softap_vendor_ie.vnd_ie.payload_len = strlen(data);
-
- req.free_buffer_func = free;
- req.free_buffer_handle = v_data;
+ req->u.wifi_softap_vendor_ie.enable = false;
+ req->u.wifi_softap_vendor_ie.type = WIFI_VND_IE_TYPE_BEACON;
+ req->u.wifi_softap_vendor_ie.idx = WIFI_VND_IE_ID_0;
+ req->u.wifi_softap_vendor_ie.vnd_ie.element_id = WIFI_VENDOR_IE_ELEMENT_ID;
+ req->u.wifi_softap_vendor_ie.vnd_ie.length = strlen(data)+OFFSET;
+ req->u.wifi_softap_vendor_ie.vnd_ie.vendor_oui[0] = VENDOR_OUI_0;
+ req->u.wifi_softap_vendor_ie.vnd_ie.vendor_oui[1] = VENDOR_OUI_1;
+ req->u.wifi_softap_vendor_ie.vnd_ie.vendor_oui[2] = VENDOR_OUI_2;
+ req->u.wifi_softap_vendor_ie.vnd_ie.vendor_oui_type = VENDOR_OUI_TYPE;
+ req->u.wifi_softap_vendor_ie.vnd_ie.payload = (uint8_t *)v_data;
+ req->u.wifi_softap_vendor_ie.vnd_ie.payload_len = strlen(data);
+
+ req->free_buffer_func = free;
+ req->free_buffer_handle = v_data;
resp = wifi_set_vendor_specific_ie(req);
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
void free_hook(void *ptr)
@@ -935,70 +1097,75 @@ void free_hook(void *ptr)
int test_set_vendor_specific_ie(void)
{
/* implemented synchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
ctrl_cmd_t *resp = NULL;
char *data = "Example vendor IE data";
char *v_data = (char*)calloc(1, strlen(data));
if (!v_data) {
printf("Failed to allocate memory \n");
+ CLEANUP_CTRL_MSG(req);
return FAILURE;
}
memcpy(v_data, data, strlen(data));
- req.u.wifi_softap_vendor_ie.enable = true;
- req.u.wifi_softap_vendor_ie.type = WIFI_VND_IE_TYPE_BEACON;
- req.u.wifi_softap_vendor_ie.idx = WIFI_VND_IE_ID_0;
- req.u.wifi_softap_vendor_ie.vnd_ie.element_id = WIFI_VENDOR_IE_ELEMENT_ID;
- req.u.wifi_softap_vendor_ie.vnd_ie.length = strlen(data)+OFFSET;
- req.u.wifi_softap_vendor_ie.vnd_ie.vendor_oui[0] = VENDOR_OUI_0;
- req.u.wifi_softap_vendor_ie.vnd_ie.vendor_oui[1] = VENDOR_OUI_1;
- req.u.wifi_softap_vendor_ie.vnd_ie.vendor_oui[2] = VENDOR_OUI_2;
- req.u.wifi_softap_vendor_ie.vnd_ie.vendor_oui_type = VENDOR_OUI_TYPE;
- req.u.wifi_softap_vendor_ie.vnd_ie.payload = (uint8_t *)v_data;
- req.u.wifi_softap_vendor_ie.vnd_ie.payload_len = strlen(data);
-
- req.free_buffer_func = free_hook;
- req.free_buffer_handle = v_data;
+ req->u.wifi_softap_vendor_ie.enable = true;
+ req->u.wifi_softap_vendor_ie.type = WIFI_VND_IE_TYPE_BEACON;
+ req->u.wifi_softap_vendor_ie.idx = WIFI_VND_IE_ID_0;
+ req->u.wifi_softap_vendor_ie.vnd_ie.element_id = WIFI_VENDOR_IE_ELEMENT_ID;
+ req->u.wifi_softap_vendor_ie.vnd_ie.length = strlen(data)+OFFSET;
+ req->u.wifi_softap_vendor_ie.vnd_ie.vendor_oui[0] = VENDOR_OUI_0;
+ req->u.wifi_softap_vendor_ie.vnd_ie.vendor_oui[1] = VENDOR_OUI_1;
+ req->u.wifi_softap_vendor_ie.vnd_ie.vendor_oui[2] = VENDOR_OUI_2;
+ req->u.wifi_softap_vendor_ie.vnd_ie.vendor_oui_type = VENDOR_OUI_TYPE;
+ req->u.wifi_softap_vendor_ie.vnd_ie.payload = (uint8_t *)v_data;
+ req->u.wifi_softap_vendor_ie.vnd_ie.payload_len = strlen(data);
+
+ req->free_buffer_func = free_hook;
+ req->free_buffer_handle = v_data;
resp = wifi_set_vendor_specific_ie(req);
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
int test_ota_begin(void)
{
/* implemented synchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
ctrl_cmd_t *resp = NULL;
resp = ota_begin(req);
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
int test_ota_write(uint8_t* ota_data, uint32_t ota_data_len)
{
/* implemented synchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
ctrl_cmd_t *resp = NULL;
- req.u.ota_write.ota_data = ota_data;
- req.u.ota_write.ota_data_len = ota_data_len;
+ req->u.ota_write.ota_data = ota_data;
+ req->u.ota_write.ota_data_len = ota_data_len;
resp = ota_write(req);
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
int test_ota_end(void)
{
/* implemented synchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
ctrl_cmd_t *resp = NULL;
resp = ota_end(req);
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
@@ -1045,41 +1212,44 @@ int test_ota(char* image_path)
int test_wifi_set_max_tx_power(int in_power)
{
/* implemented synchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
ctrl_cmd_t *resp = NULL;
- req.u.wifi_tx_power.power = in_power;
+ req->u.wifi_tx_power.power = in_power;
resp = wifi_set_max_tx_power(req);
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
int test_wifi_get_curr_tx_power()
{
/* implemented synchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
ctrl_cmd_t *resp = NULL;
resp = wifi_get_curr_tx_power(req);
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
static int test_set_country_code_with_domain(bool enabled)
{
/* implemented synchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
ctrl_cmd_t *resp = NULL;
- memcpy(req.u.country_code.country, COUNTRY_CODE, COUNTRY_CODE_LEN);
- req.u.country_code.ieee80211d_enabled = enabled;
+ memcpy(req->u.country_code.country, COUNTRY_CODE, COUNTRY_CODE_LEN);
+ req->u.country_code.ieee80211d_enabled = enabled;
resp = wifi_set_country_code(req);
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
-int test_set_country_code_enabled()
+int test_set_country_code_with_ieee80211d_on()
{
/* implemented synchronous */
return test_set_country_code_with_domain(true);
@@ -1094,11 +1264,12 @@ int test_set_country_code()
int test_get_country_code()
{
/* implemented synchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
ctrl_cmd_t *resp = NULL;
resp = wifi_get_country_code(req);
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
@@ -1106,12 +1277,13 @@ int test_config_heartbeat(void)
{
/* implemented synchronous */
ctrl_cmd_t *resp = NULL;
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
- req.u.e_heartbeat.enable = YES;
- req.u.e_heartbeat.duration = HEARTBEAT_DURATION_SEC;
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ req->u.e_heartbeat.enable = YES;
+ req->u.e_heartbeat.duration = HEARTBEAT_DURATION_SEC;
resp = config_heartbeat(req);
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
@@ -1119,103 +1291,178 @@ int test_disable_heartbeat(void)
{
/* implemented synchronous */
ctrl_cmd_t *resp = NULL;
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
- req.u.e_heartbeat.enable = NO;
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ req->u.e_heartbeat.enable = NO;
resp = config_heartbeat(req);
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
int test_disable_heartbeat_async(void)
{
/* implemented asynchronous */
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
- req.u.e_heartbeat.enable = NO;
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ req->u.e_heartbeat.enable = NO;
/* register callback for handling asynch reply */
- req.ctrl_resp_cb = ctrl_app_resp_callback;
+ req->ctrl_resp_cb = ctrl_app_resp_callback;
config_heartbeat(req);
+ CLEANUP_CTRL_MSG(req);
return SUCCESS;
}
-int test_enable_wifi(void)
-{
+int test_enable_wifi(void) {
/* implemented synchronous */
ctrl_cmd_t *resp = NULL;
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
- req.u.feat_ena_disable.feature = HOSTED_WIFI;
- req.u.feat_ena_disable.enable = YES;
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ int ret = SUCCESS;
+
+ req->u.feat_ena_disable.feature = HOSTED_WIFI;
+ req->u.feat_ena_disable.enable = YES;
resp = feature_config(req);
- if (resp->resp_event_status == SUCCESS) {
- test_station_mode_get_mac_addr();
- up_sta_netdev(sta_mac_str);
- test_softap_mode_get_mac_addr();
- up_softap_netdev(softap_mac_str);
+ if (successful_response(resp)) {
+ /* Get MAC addresses first */
+ if (test_station_mode_get_mac_addr(sta_network.mac_addr) != SUCCESS) {
+ printf("Failed to get station MAC address\n");
+ ret = FAILURE;
+ goto cleanup;
+ }
+
+ if (test_softap_mode_get_mac_addr(ap_network.mac_addr) != SUCCESS) {
+ printf("Failed to get softAP MAC address\n");
+ ret = FAILURE;
+ goto cleanup;
+ }
+
+ printf("Station MAC address: %s\n", sta_network.mac_addr);
+ printf("SoftAP MAC address: %s\n", ap_network.mac_addr);
+
+ /* Set default values for IP-related fields if they're not already set */
+ if (!sta_network.ip_valid) {
+ strncpy(sta_network.ip_addr, "0.0.0.0", MAC_ADDR_LENGTH);
+ strncpy(sta_network.netmask, "255.255.255.0", MAC_ADDR_LENGTH);
+ strncpy(sta_network.gateway, "0.0.0.0", MAC_ADDR_LENGTH);
+ strncpy(sta_network.default_route, "0.0.0.0", MAC_ADDR_LENGTH);
+ }
+
+ /* Now bring up the interfaces with the MAC addresses */
+ if (sta_network.mac_addr[0] != '\0') {
+ up_sta_netdev__with_static_ip_dns_route(&sta_network);
+ }
+
+ if (ap_network.mac_addr[0] != '\0') {
+ up_softap_netdev(&ap_network);
+ }
+
+ ret = SUCCESS;
+ } else {
+ printf("Failed to enable WiFi\n");
+ ret = FAILURE;
}
- return ctrl_app_resp_callback(resp);
+cleanup:
+ CLEANUP_CTRL_MSG(req);
+ CLEANUP_CTRL_MSG(resp);
+
+ return ret;
}
int test_disable_wifi(void)
{
/* implemented synchronous */
ctrl_cmd_t *resp = NULL;
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
- req.u.feat_ena_disable.feature = HOSTED_WIFI;
- req.u.feat_ena_disable.enable = NO;
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ req->u.feat_ena_disable.feature = HOSTED_WIFI;
+ req->u.feat_ena_disable.enable = NO;
resp = feature_config(req);
- if (resp->resp_event_status == SUCCESS) {
- down_sta_netdev();
- down_softap_netdev();
+ if (successful_response(resp)) {
+ down_sta_netdev(&sta_network);
+ down_softap_netdev(&ap_network);
}
-
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
+int test_is_network_split_on(void) {
+ /* This way of usage of API is mandatory NEED to be synchronous */
+
+ static int queried_network_split_on = 0;
+ static int is_network_split_on = 0;
+
+ if (queried_network_split_on) {
+ return is_network_split_on;
+ }
+
+ /* Please note: This API at least need to be called once to cache the network split status
+ because it is a synchronous API and it will block the execution of the program.
+ So, we need to call this API at least once before using in any async APIs, like event callbacks.
+ */
+
+ ctrl_cmd_t *resp = NULL;
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+
+ req->u.feat_ena_disable.feature = HOSTED_IS_NETWORK_SPLIT_ON;
+ resp = feature_config(req);
+
+ queried_network_split_on = 1;
+ if (resp && resp->resp_event_status == SUCCESS) {
+ is_network_split_on = 1;
+ } else {
+ is_network_split_on = 0;
+ }
+
+ CLEANUP_CTRL_MSG(req);
+ CLEANUP_CTRL_MSG(resp);
+
+ return is_network_split_on;
+}
+
#include
#include
static void down_hci_instance(void)
{
#define DOWN_HCI_INSTANCE_CMD "sudo hciconfig | grep 'Bus: SDIO\\| Bus: UART\\| Bus: SPI' | awk -F: '{print $1}' | xargs -I{} sudo hciconfig {} down"
- int result = system(DOWN_HCI_INSTANCE_CMD);
- if (result == 0) {
- printf("Bluetooth interface set down successfully\n");
- } else {
- printf("Failed to bring Bluetooth interface down\n");
- }
+ int result = system(DOWN_HCI_INSTANCE_CMD);
+ if (result == 0) {
+ printf("Bluetooth interface set down successfully\n");
+ } else {
+ printf("Failed to bring Bluetooth interface down\n");
+ }
}
static void reset_hci_instance(void)
{
#define RESET_HCI_INSTANCE_CMD "sudo hciconfig | grep 'Bus: SDIO\\| Bus: UART\\| Bus: SPI' | awk -F: '{print $1}' | xargs -I{} sudo hciconfig {} reset"
- int result = system(RESET_HCI_INSTANCE_CMD);
- if (result == 0) {
- printf("Bluetooth interface reset successfully\n");
- } else {
- printf("Failed to reset Bluetooth interface\n");
- }
+ int result = system(RESET_HCI_INSTANCE_CMD);
+ if (result == 0) {
+ printf("Bluetooth interface reset successfully\n");
+ } else {
+ printf("Failed to reset Bluetooth interface\n");
+ }
}
int test_enable_bt(void)
{
/* implemented synchronous */
ctrl_cmd_t *resp = NULL;
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
- req.u.feat_ena_disable.feature = HOSTED_BT;
- req.u.feat_ena_disable.enable = YES;
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ req->u.feat_ena_disable.feature = HOSTED_BT;
+ req->u.feat_ena_disable.enable = YES;
resp = feature_config(req);
- if (resp->resp_event_status == SUCCESS)
+ if (successful_response(resp))
reset_hci_instance();
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
@@ -1223,29 +1470,33 @@ int test_disable_bt(void)
{
/* implemented synchronous */
ctrl_cmd_t *resp = NULL;
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
- req.u.feat_ena_disable.feature = HOSTED_BT;
- req.u.feat_ena_disable.enable = NO;
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ req->u.feat_ena_disable.feature = HOSTED_BT;
+ req->u.feat_ena_disable.enable = NO;
resp = feature_config(req);
- if (resp->resp_event_status == SUCCESS)
+ if (successful_response(resp))
down_hci_instance();
+ CLEANUP_CTRL_MSG(req);
return ctrl_app_resp_callback(resp);
}
-char * test_get_fw_version(char *version)
+char * test_get_fw_version(char *version, uint16_t version_size)
{
/* implemented synchronous */
ctrl_cmd_t *resp = NULL;
- ctrl_cmd_t req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
resp = get_fw_version(req);
if (!version)
return NULL;
- if (resp->resp_event_status == SUCCESS) {
+ if (version_size < sizeof("XX-111.222.333.444.555"))
+ return NULL;
+
+ if (successful_response(resp)) {
/*printf("FW Version Info: %s-%d.%d.%d.%d.%d\n",
resp->u.fw_version.project_name,
resp->u.fw_version.major_1,
@@ -1253,7 +1504,7 @@ char * test_get_fw_version(char *version)
resp->u.fw_version.minor,
resp->u.fw_version.revision_patch_1,
resp->u.fw_version.revision_patch_2);*/
- snprintf(version, sizeof("XX-111.222.333.444.555"), "%s-%d.%d.%d.%d.%d",
+ snprintf(version, version_size, "%s-%d.%d.%d.%d.%d",
resp->u.fw_version.project_name,
resp->u.fw_version.major_1,
resp->u.fw_version.major_2,
@@ -1262,17 +1513,609 @@ char * test_get_fw_version(char *version)
resp->u.fw_version.revision_patch_2);
}
+ CLEANUP_CTRL_MSG(req);
CLEANUP_CTRL_MSG(resp);
return version;
}
-int test_print_fw_version(char *version, uint16_t version_size)
+int test_print_fw_version(void)
{
char vers[30] = {'\0'};
- printf("Hosted Slave FW Version [%s]\n", test_get_fw_version(vers));
+ printf("Hosted Slave FW Version [%s]\n", test_get_fw_version(vers, sizeof(vers)));
return 0;
}
+int test_fetch_ip_addr_from_slave(void)
+{
+ if (test_is_network_split_on()) {
+ ctrl_cmd_t *resp = NULL;
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ req->cmd_timeout_sec = 5;
+
+ resp = get_dhcp_dns_status(req);
+
+ CLEANUP_CTRL_MSG(req);
+ if (successful_response(resp)) {
+ dhcp_dns_status_t *p = &resp->u.dhcp_dns_status;
+ if (p->dhcp_up) {
+ PRINT_IF(!interface_up_printed, "%s -> Network UP [IP: %s NM: %s GW: %s", STA_INTERFACE, p->dhcp_ip, p->dhcp_nm, p->dhcp_gw);
+ strncpy(sta_network.ip_addr, (const char *)p->dhcp_ip, MAC_ADDR_LENGTH);
+ strncpy(sta_network.netmask, (const char *)p->dhcp_nm, MAC_ADDR_LENGTH);
+ strncpy(sta_network.gateway, (const char *)p->dhcp_gw, MAC_ADDR_LENGTH);
+ strncpy(sta_network.default_route, (const char *)p->dhcp_gw, MAC_ADDR_LENGTH);
+ sta_network.ip_valid = 1;
+
+ interface_up_printed = true;
+ interface_down_printed = false;
+ } else {
+ /* Only print message if this is the first time we're reporting network down */
+ PRINT_IF(!interface_down_printed, "%s -> Network down\n", STA_INTERFACE);
+ interface_down_printed = true;
+ interface_up_printed = false;
+ sta_network.network_up = 0;
+ sta_network.ip_valid = 0;
+ }
+ if (p->dns_up) {
+ printf(" DNS: %s]\n", p->dns_ip);
+ strncpy(sta_network.dns_addr, (const char *)p->dns_ip, MAC_ADDR_LENGTH);
+ sta_network.dns_valid = 1;
+ } else {
+ //printf("DNS is not up");
+ sta_network.dns_valid = 0;
+ }
+
+ if (resp->u.dhcp_dns_status.dns_up && resp->u.dhcp_dns_status.dhcp_up) {
+ //printf("Network identified as up");
+ up_sta_netdev__with_static_ip_dns_route(&sta_network);
+ add_dns(sta_network.dns_addr);
+ sta_network.network_up = 1;
+ } else {
+ //printf("Network identified as down");
+ /* Only print message if this is the first time we're bringing down the interface */
+ if (!interface_down_printed) {
+ printf("%s interface down\n", STA_INTERFACE);
+ interface_down_printed = true;
+ }
+
+ down_sta_netdev(&sta_network);
+ remove_dns(sta_network.dns_addr);
+ sta_network.network_up = 0;
+ }
+ } else {
+ //printf("Slave not built with network split\n");
+ CLEANUP_CTRL_MSG(resp);
+ return FAILURE;
+ }
+
+ return ctrl_app_resp_callback(resp);
+ } else {
+ printf("Network split is disabled at host. So not fetching IP address from slave\n");
+ return FAILURE;
+ }
+}
+
+int test_set_dhcp_dns_status(char *sta_ip, char *sta_nm, char *sta_gw, char *sta_dns)
+{
+ if (test_is_network_split_on()) {
+ ctrl_cmd_t *resp = NULL;
+
+ if (!sta_ip || !sta_nm || !sta_gw || !sta_dns) {
+ printf("Invalid parameters\n");
+ return FAILURE;
+ }
+
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ req->cmd_timeout_sec = 5;
+
+ req->u.dhcp_dns_status.iface = 0;
+ req->u.dhcp_dns_status.dhcp_up = 1;
+ req->u.dhcp_dns_status.dns_up = 1;
+
+ strncpy((char *)req->u.dhcp_dns_status.dhcp_ip, sta_ip, MAC_ADDR_LENGTH);
+ strncpy((char *)req->u.dhcp_dns_status.dhcp_nm, sta_nm, MAC_ADDR_LENGTH);
+ strncpy((char *)req->u.dhcp_dns_status.dhcp_gw, sta_gw, MAC_ADDR_LENGTH);
+ strncpy((char *)req->u.dhcp_dns_status.dns_ip, sta_dns, MAC_ADDR_LENGTH);
+
+ resp = set_dhcp_dns_status(req);
+
+ CLEANUP_CTRL_MSG(req);
+
+ if (!successful_response(resp)) {
+ //printf("Slave not built with network split\n");
+ CLEANUP_CTRL_MSG(resp);
+ return FAILURE;
+ }
+
+ return ctrl_app_resp_callback(resp);
+ } else {
+ printf("Network split is disabled at host. So not setting DHCP/DNS status\n");
+ return FAILURE;
+ }
+}
+
+int test_softap_mode_set_vendor_ie(bool enable, const char *data) {
+ /* implemented synchronous */
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *resp = NULL;
+ char *v_data = NULL;
+
+ if (data && strlen(data) > 0) {
+ v_data = (char*)calloc(1, strlen(data));
+ if (!v_data) {
+ printf("Failed to allocate memory\n");
+ return FAILURE;
+ }
+ memcpy(v_data, data, strlen(data));
+ }
+
+ req->u.wifi_softap_vendor_ie.enable = enable;
+ req->u.wifi_softap_vendor_ie.type = WIFI_VND_IE_TYPE_BEACON;
+ req->u.wifi_softap_vendor_ie.idx = WIFI_VND_IE_ID_0;
+ req->u.wifi_softap_vendor_ie.vnd_ie.element_id = WIFI_VENDOR_IE_ELEMENT_ID;
+
+ if (v_data) {
+ req->u.wifi_softap_vendor_ie.vnd_ie.length = strlen(data) + OFFSET;
+ req->u.wifi_softap_vendor_ie.vnd_ie.vendor_oui[0] = VENDOR_OUI_0;
+ req->u.wifi_softap_vendor_ie.vnd_ie.vendor_oui[1] = VENDOR_OUI_1;
+ req->u.wifi_softap_vendor_ie.vnd_ie.vendor_oui[2] = VENDOR_OUI_2;
+ req->u.wifi_softap_vendor_ie.vnd_ie.vendor_oui_type = VENDOR_OUI_TYPE;
+ req->u.wifi_softap_vendor_ie.vnd_ie.payload = (uint8_t *)v_data;
+ req->u.wifi_softap_vendor_ie.vnd_ie.payload_len = strlen(data);
+
+ req->free_buffer_func = free;
+ req->free_buffer_handle = v_data;
+ }
+
+ resp = wifi_set_vendor_specific_ie(req);
+ CLEANUP_CTRL_MSG(req);
+ return ctrl_app_resp_callback(resp);
+}
+
+/* Updated connect function with parameters */
+int test_station_mode_connect_with_params(const char *ssid, const char *pwd, const char *bssid,
+ bool use_wpa3, int listen_interval, int band_mode)
+{
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *resp = NULL;
+
+ /*printf("Connect to AP[%s] with password[%s] and BSSID[%s] use_wpa3[%d] listen_interval[%d] band_mode[%d]\n",
+ ssid ? ssid : STATION_MODE_SSID,
+ pwd ? pwd : STATION_MODE_PWD,
+ bssid ? bssid : STATION_MODE_BSSID,
+ use_wpa3 ? 1 : 0,
+ listen_interval,
+ band_mode);*/
+
+ /* Use provided parameters or defaults */
+ strcpy((char *)&req->u.wifi_ap_config.ssid, ssid ? ssid : STATION_MODE_SSID);
+ strcpy((char *)&req->u.wifi_ap_config.pwd, pwd ? pwd : STATION_MODE_PWD);
+ strcpy((char *)&req->u.wifi_ap_config.bssid, bssid ? bssid : STATION_MODE_BSSID);
+ req->u.wifi_ap_config.is_wpa3_supported = use_wpa3 ? 1 : STATION_MODE_IS_WPA3_SUPPORTED;
+ req->u.wifi_ap_config.listen_interval = listen_interval ? listen_interval : STATION_MODE_LISTEN_INTERVAL;
+ req->u.wifi_ap_config.band_mode = band_mode ? band_mode : STATION_BAND_MODE;
+
+ connected_printed = false;
+ disconnected_printed = false;
+ interface_up_printed = false;
+ interface_down_printed = false;
+
+
+ resp = wifi_connect_ap(req);
+ CLEANUP_CTRL_MSG(req);
+ return ctrl_app_resp_callback(resp);
+}
+
+/* Updated disconnect function with parameters */
+int test_station_mode_disconnect_with_params(bool reset_dhcp)
+{
+ /* implemented synchronous */
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *resp = NULL;
+
+ resp = wifi_disconnect_ap(req);
+
+ /* If reset_dhcp is true, we should clear the network settings */
+ if (reset_dhcp && resp && resp->resp_event_status == SUCCESS) {
+ memset(&sta_network.ip_addr, 0, MAC_ADDR_LENGTH);
+ memset(&sta_network.netmask, 0, MAC_ADDR_LENGTH);
+ memset(&sta_network.gateway, 0, MAC_ADDR_LENGTH);
+ memset(&sta_network.dns_addr, 0, MAC_ADDR_LENGTH);
+ sta_network.ip_valid = 0;
+ sta_network.dns_valid = 0;
+ sta_network.network_up = 0;
+ }
+ CLEANUP_CTRL_MSG(req);
+ return ctrl_app_resp_callback(resp);
+}
+
+/* Updated softap start function with parameters */
+int test_softap_mode_start_with_params(const char *ssid, const char *pwd, int channel,
+ const char *sec_prot, int max_conn, bool hide_ssid,
+ int bw, int band_mode)
+{
+ /* implemented synchronous */
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *resp = NULL;
+
+ /* Use provided parameters or defaults */
+ strncpy((char *)&req->u.wifi_softap_config.ssid,
+ ssid ? ssid : SOFTAP_MODE_SSID, SSID_LENGTH - 1);
+ strncpy((char *)&req->u.wifi_softap_config.pwd,
+ pwd ? pwd : SOFTAP_MODE_PWD, PASSWORD_LENGTH - 1);
+
+ req->u.wifi_softap_config.channel = channel ? channel : SOFTAP_MODE_CHANNEL;
+
+ /* Set encryption mode based on sec_prot parameter */
+ if (sec_prot) {
+ if (strcmp(sec_prot, "open") == 0) {
+ req->u.wifi_softap_config.encryption_mode = 0; /* WIFI_AUTH_OPEN */
+ } else if (strcmp(sec_prot, "wpa_psk") == 0) {
+ req->u.wifi_softap_config.encryption_mode = 2; /* WIFI_AUTH_WPA_PSK */
+ } else if (strcmp(sec_prot, "wpa2_psk") == 0) {
+ req->u.wifi_softap_config.encryption_mode = 3; /* WIFI_AUTH_WPA2_PSK */
+ } else if (strcmp(sec_prot, "wpa_wpa2_psk") == 0) {
+ req->u.wifi_softap_config.encryption_mode = 4; /* WIFI_AUTH_WPA_WPA2_PSK */
+ } else {
+ req->u.wifi_softap_config.encryption_mode = SOFTAP_MODE_ENCRYPTION_MODE;
+ }
+ } else {
+ req->u.wifi_softap_config.encryption_mode = SOFTAP_MODE_ENCRYPTION_MODE;
+ }
+
+ req->u.wifi_softap_config.max_connections = max_conn ? max_conn : SOFTAP_MODE_MAX_ALLOWED_CLIENTS;
+ req->u.wifi_softap_config.ssid_hidden = hide_ssid ? 1 : SOFTAP_MODE_SSID_HIDDEN;
+ req->u.wifi_softap_config.bandwidth = bw ? bw : SOFTAP_MODE_BANDWIDTH;
+ req->u.wifi_softap_config.band_mode = band_mode ? band_mode : SOFTAP_BAND_MODE;
+
+ resp = wifi_start_softap(req);
+ CLEANUP_CTRL_MSG(req);
+ return ctrl_app_resp_callback(resp);
+}
+
+/* Power save mode with params */
+int test_wifi_set_power_save_mode_with_params(int psmode)
+{
+ /* implemented synchronous */
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *resp = NULL;
+
+ req->u.wifi_ps.ps_mode = psmode;
+ req->cmd_timeout_sec = 2;
+ resp = wifi_set_power_save_mode(req);
+ CLEANUP_CTRL_MSG(req);
+ return ctrl_app_resp_callback(resp);
+}
+
+/* Get firmware version with params */
+int test_get_fw_version_with_params(char *version, uint16_t version_size)
+{
+ int ret = FAILURE;
+ if (!version || version_size == 0) {
+ printf("Invalid buffer for version\n");
+ return FAILURE;
+ }
+
+ if (version_size < sizeof("XX-111.222.333.444.555")) {
+ printf("size of version is too small\n");
+ return FAILURE;
+ }
+
+ /* implemented synchronous */
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *resp = NULL;
+
+ resp = get_fw_version(req);
+
+ if (resp && resp->resp_event_status == SUCCESS) {
+ snprintf(version, version_size, "%s-%d.%d.%d.%d.%d",
+ resp->u.fw_version.project_name,
+ resp->u.fw_version.major_1,
+ resp->u.fw_version.major_2,
+ resp->u.fw_version.minor,
+ resp->u.fw_version.revision_patch_1,
+ resp->u.fw_version.revision_patch_2);
+ ret = SUCCESS;
+ }
+ CLEANUP_CTRL_MSG(req);
+ CLEANUP_CTRL_MSG(resp);
+ return ret;
+}
+
+/* OTA update with params */
+int test_ota_update_with_params(const char *url)
+{
+ if (!url || strlen(url) == 0) {
+ printf("Invalid URL for OTA update\n");
+ return FAILURE;
+ }
+
+ printf("Starting OTA update from URL: %s\n", url);
+
+ /* Make a non-const copy for test_ota */
+ char* url_copy = strdup(url);
+ if (!url_copy) {
+ printf("Memory allocation failed\n");
+ return FAILURE;
+ }
+
+ int result = test_ota(url_copy);
+ free(url_copy);
+ return result;
+}
+
+/* Heartbeat configuration with params */
+int test_heartbeat_with_params(bool enable, int duration)
+{
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *resp = NULL;
+
+ if (enable) {
+ /* Configure heartbeat */
+ req->u.e_heartbeat.enable = 1;
+ req->u.e_heartbeat.duration = duration > 0 ? duration : 30; /* Default 30 seconds */
+ resp = config_heartbeat(req);
+ } else {
+ /* Disable heartbeat */
+ req->u.e_heartbeat.enable = 0;
+ req->u.e_heartbeat.duration = 0;
+ resp = config_heartbeat(req);
+ }
+ CLEANUP_CTRL_MSG(req);
+ return ctrl_app_resp_callback(resp);
+}
+
+int test_set_mac_addr_with_params(int mode, const char *mac) {
+ /* implemented synchronous */
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *resp = NULL;
+
+ req->u.wifi_mac.mode = mode;
+ strncpy((char *)req->u.wifi_mac.mac, mac, MAC_ADDR_LENGTH);
+
+ resp = wifi_set_mac(req);
+ CLEANUP_CTRL_MSG(req);
+ return ctrl_app_resp_callback(resp);
+}
+
+int test_set_dhcp_dns_status_with_params(char *sta_ip, char *sta_nm, char *sta_gw, char *sta_dns) {
+ if (test_is_network_split_on()) {
+ /* implemented synchronous */
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *resp = NULL;
+
+ if (!sta_ip || !sta_nm || !sta_gw || !sta_dns) {
+ printf("Invalid parameters\n");
+ return FAILURE;
+ }
+
+ req->u.dhcp_dns_status.iface = 0;
+ req->u.dhcp_dns_status.dhcp_up = 1;
+ req->u.dhcp_dns_status.dns_up = 1;
+
+ strncpy((char *)req->u.dhcp_dns_status.dhcp_ip, sta_ip, MAC_ADDR_LENGTH);
+ strncpy((char *)req->u.dhcp_dns_status.dhcp_nm, sta_nm, MAC_ADDR_LENGTH);
+ strncpy((char *)req->u.dhcp_dns_status.dhcp_gw, sta_gw, MAC_ADDR_LENGTH);
+ strncpy((char *)req->u.dhcp_dns_status.dns_ip, sta_dns, MAC_ADDR_LENGTH);
+
+ resp = set_dhcp_dns_status(req);
+
+ CLEANUP_CTRL_MSG(req);
+
+ if (!successful_response(resp)) {
+ //printf("Slave not built with network split\n");
+ CLEANUP_CTRL_MSG(resp);
+ return FAILURE;
+ }
+
+ return ctrl_app_resp_callback(resp);
+ } else {
+ printf("Network split is disabled at host. So not setting DHCP/DNS status\n");
+ return FAILURE;
+ }
+}
+
+int test_set_vendor_specific_ie_with_params(bool enable, const char *data) {
+ /* implemented synchronous */
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *resp = NULL;
+ char *v_data = NULL;
+
+ if (data && strlen(data) > 0) {
+ v_data = (char*)calloc(1, strlen(data));
+ if (!v_data) {
+ printf("Failed to allocate memory\n");
+ return FAILURE;
+ }
+ memcpy(v_data, data, strlen(data));
+ }
+
+ req->u.wifi_softap_vendor_ie.enable = enable;
+ req->u.wifi_softap_vendor_ie.type = WIFI_VND_IE_TYPE_BEACON;
+ req->u.wifi_softap_vendor_ie.idx = WIFI_VND_IE_ID_0;
+ req->u.wifi_softap_vendor_ie.vnd_ie.element_id = WIFI_VENDOR_IE_ELEMENT_ID;
+
+ if (v_data) {
+ req->u.wifi_softap_vendor_ie.vnd_ie.length = strlen(data) + OFFSET;
+ req->u.wifi_softap_vendor_ie.vnd_ie.vendor_oui[0] = VENDOR_OUI_0;
+ req->u.wifi_softap_vendor_ie.vnd_ie.vendor_oui[1] = VENDOR_OUI_1;
+ req->u.wifi_softap_vendor_ie.vnd_ie.vendor_oui[2] = VENDOR_OUI_2;
+ req->u.wifi_softap_vendor_ie.vnd_ie.vendor_oui_type = VENDOR_OUI_TYPE;
+ req->u.wifi_softap_vendor_ie.vnd_ie.payload = (uint8_t *)v_data;
+ req->u.wifi_softap_vendor_ie.vnd_ie.payload_len = strlen(data);
+
+ req->free_buffer_func = free;
+ req->free_buffer_handle = v_data;
+ }
+
+ resp = wifi_set_vendor_specific_ie(req);
+ CLEANUP_CTRL_MSG(req);
+ return ctrl_app_resp_callback(resp);
+}
+
+int test_set_wifi_power_save_mode_with_params(int psmode) {
+ /* implemented synchronous */
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *resp = NULL;
+
+ req->u.wifi_ps.ps_mode = psmode;
+ req->cmd_timeout_sec = 2;
+ resp = wifi_set_power_save_mode(req);
+ CLEANUP_CTRL_MSG(req);
+ return ctrl_app_resp_callback(resp);
+}
+
+static int test_custom_rpc_unserialised_request_internal
+(
+ const custom_rpc_unserialised_data_t *usr_req_in,
+ custom_rpc_unserialised_data_t *usr_resp_out
+ ) {
+ int ret = SUCCESS;
+
+ /* Validate parameters */
+ if (!usr_req_in || !usr_resp_out) {
+ printf("Invalid parameters\n");
+ return FAILURE;
+ }
+
+ /* Create a custom RPC request */
+ ctrl_cmd_t *rpc_req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *rpc_resp = NULL;
+
+ /* populate RPC request from higher layer data passed */
+ rpc_req->u.custom_rpc_unserialised_data.custom_msg_id = usr_req_in->custom_msg_id;
+ rpc_req->u.custom_rpc_unserialised_data.data = calloc(1, usr_req_in->data_len);
+ if (!rpc_req->u.custom_rpc_unserialised_data.data) {
+ printf("Failed to allocate memory for custom RPC request\n");
+ ret = FAILURE;
+ goto cleanup;
+ }
+ memcpy(rpc_req->u.custom_rpc_unserialised_data.data, usr_req_in->data, usr_req_in->data_len);
+ rpc_req->u.custom_rpc_unserialised_data.data_len = usr_req_in->data_len;
+
+ /* We are asking lower layer to auto clean above allocated buffer after sending the request */
+ rpc_req->free_buffer_func = free;
+ rpc_req->free_buffer_handle = rpc_req->u.custom_rpc_unserialised_data.data;
+
+ /* Debug before sending */
+ printf("DEBUG: Sending RPC request custom message ID %u, data_len %u\n",
+ rpc_req->u.custom_rpc_unserialised_data.custom_msg_id,
+ rpc_req->u.custom_rpc_unserialised_data.data_len);
+
+ rpc_resp = send_custom_rpc_unserialised_req_to_slave(rpc_req);
+
+ /* Debug after response received */
+ if (!rpc_resp) {
+ printf("DEBUG: Received NULL response\n");
+ ret = FAILURE;
+ goto cleanup;
+ }
+
+ if (rpc_resp->resp_event_status != SUCCESS) {
+ printf("Failed RPC unserialised response for request %u, status: %d\n",
+ rpc_req->u.custom_rpc_unserialised_data.custom_msg_id,
+ rpc_resp->resp_event_status);
+ ret = FAILURE;
+ goto cleanup;
+ }
+
+ usr_resp_out->custom_msg_id = rpc_resp->u.custom_rpc_unserialised_data.custom_msg_id;
+ usr_resp_out->data_len = rpc_resp->u.custom_rpc_unserialised_data.data_len;
+
+ /* Check if there's data to return */
+ if (rpc_resp->u.custom_rpc_unserialised_data.data_len > 0 &&
+ rpc_resp->u.custom_rpc_unserialised_data.data != NULL) {
+
+ /* IMPORTANT: Don't just pass the pointer as is, which can cause issues
+ * when the pointer gets freed. Instead, allocate new memory and copy the data.
+ */
+ usr_resp_out->data = malloc(rpc_resp->u.custom_rpc_unserialised_data.data_len);
+ if (!usr_resp_out->data) {
+ printf("Failed to allocate memory for response data\n");
+ ret = FAILURE;
+ goto cleanup;
+ }
+
+ /* Copy the data */
+ memcpy(usr_resp_out->data, rpc_resp->u.custom_rpc_unserialised_data.data,
+ rpc_resp->u.custom_rpc_unserialised_data.data_len);
+
+ /* Set the free function for the caller to use */
+ usr_resp_out->free_func = free;
+
+ /*printf("DEBUG: Copied %u bytes from response to new buffer at %p\n",
+ usr_resp_out->data_len, (void*)usr_resp_out->data);*/
+ } else {
+ /*printf("DEBUG: No data in response to copy (len=%u, ptr=%p)\n",
+ rpc_resp->u.custom_rpc_unserialised_data.data_len,
+ rpc_resp->u.custom_rpc_unserialised_data.data);*/
+ usr_resp_out->data = NULL;
+ usr_resp_out->free_func = NULL;
+ }
+
+cleanup:
+ CLEANUP_CTRL_MSG(rpc_req);
+ CLEANUP_CTRL_MSG(rpc_resp);
+ return ret;
+}
+
+int test_custom_rpc_unserialised_request(uint32_t custom_msg_id, const uint8_t *send_data, uint32_t send_data_len,
+ uint8_t **recv_data, uint32_t *recv_data_len, void (**recv_data_free_func)(void*)) {
+ custom_rpc_unserialised_data_t usr_req = {0};
+ custom_rpc_unserialised_data_t usr_resp = {0};
+ int ret = SUCCESS;
+
+ /* Validate parameters */
+ if (!send_data || !recv_data || !recv_data_len || !recv_data_free_func) {
+ printf("%s: Invalid parameters\n", __func__);
+ return FAILURE;
+ }
+
+ /* Print debug info */
+ printf("DEBUG: Sending custom RPC message ID %u with %u bytes of data\n",
+ custom_msg_id, send_data_len);
+
+ usr_req.custom_msg_id = custom_msg_id;
+ usr_req.data = (uint8_t *)send_data;
+ usr_req.data_len = send_data_len;
+
+ /* Call internal function */
+ ret = test_custom_rpc_unserialised_request_internal(&usr_req, &usr_resp);
+ if (ret != SUCCESS) {
+ printf("DEBUG: test_custom_rpc_unserialised_request_internal failed with status %d\n", ret);
+ return FAILURE;
+ }
+
+ /* Debug info */
+ /*printf("DEBUG: Received response with data_len=%u, data=%p\n",
+ usr_resp.data_len, (void*)usr_resp.data);*/
+
+ /* Set output parameters */
+ *recv_data = usr_resp.data;
+ *recv_data_len = usr_resp.data_len;
+ *recv_data_free_func = usr_resp.free_func;
+
+ return SUCCESS;
+}
+
+int test_set_country_code_with_params(const char *code)
+{
+ if (!code || strlen(code) < 2) {
+ printf("Invalid country code\n");
+ return FAILURE;
+ }
+ /* implemented synchronous */
+ ctrl_cmd_t *req = CTRL_CMD_DEFAULT_REQ();
+ ctrl_cmd_t *resp = NULL;
+
+ memset(req->u.country_code.country, 0, COUNTRY_CODE_LEN);
+ strncpy(req->u.country_code.country, code, COUNTRY_CODE_LEN - 1);
+ req->u.country_code.ieee80211d_enabled = false;
+
+ resp = wifi_set_country_code(req);
+
+ CLEANUP_CTRL_MSG(req);
+ return ctrl_app_resp_callback(resp);
+}
diff --git a/esp_hosted_fg/host/linux/host_control/python_support/Makefile b/esp_hosted_fg/host/linux/host_control/python_support/Makefile
index 520f28cd4b..9b32287fae 100644
--- a/esp_hosted_fg/host/linux/host_control/python_support/Makefile
+++ b/esp_hosted_fg/host/linux/host_control/python_support/Makefile
@@ -1,16 +1,20 @@
CC = gcc
+CFLAGS = -Wall -fPIC
CROSS_COMPILE :=
-CFLAGS = -C -Wall
+SRCS = $(wildcard *.c)
+OBJS = $(SRCS:.c=.o)
-PWD := $(shell pwd)
+DIR_ROOT = $(CURDIR)/../../../../
+LIB_DIR = $(DIR_ROOT)/host/control_lib
+CONTROL_LIB = $(LIB_DIR)/libesp_hosted_rpc.a
-DIR_COMMON = $(PWD)/../../../../common
-DIR_CTRL_LIB = $(PWD)/../../../control_lib
-DIR_SERIAL = $(PWD)/../../../virtual_serial_if
-DIR_COMPONENTS = $(PWD)/../../../components
-DIR_LINUX_PORT = $(PWD)/../../port
+DIR_COMMON = $(DIR_ROOT)/common
+DIR_CTRL_LIB = $(DIR_ROOT)/host/control_lib
+DIR_SERIAL = $(DIR_ROOT)/host/virtual_serial_if
+DIR_COMPONENTS = $(DIR_ROOT)/host/components
+DIR_LINUX_PORT = $(DIR_ROOT)/host/linux/port
INCLUDE += -I$(DIR_COMMON)/protobuf-c
INCLUDE += -I$(DIR_COMMON)/include
@@ -21,20 +25,28 @@ INCLUDE += -I$(DIR_COMPONENTS)/include
INCLUDE += -I$(DIR_LINUX_PORT)/include
INCLUDE += -I.
-SRC += $(DIR_COMMON)/protobuf-c/protobuf-c/protobuf-c.c
-SRC += $(DIR_COMMON)/esp_hosted_config.pb-c.c
-SRC += $(DIR_CTRL_LIB)/src/ctrl_core.c
-SRC += $(DIR_CTRL_LIB)/src/ctrl_api.c
-SRC += $(DIR_SERIAL)/src/serial_if.c
-SRC += $(DIR_COMPONENTS)/src/esp_queue.c
-SRC += $(DIR_LINUX_PORT)/src/platform_wrapper.c
-
+LIBPATH = -L$(LIB_DIR)
+LIBS = -Wl,--whole-archive $(CONTROL_LIB) -Wl,--no-whole-archive
LINKER = -lrt -lpthread
TARGET = commands.so
-commands.so:
- $(CROSS_COMPILE)$(CC) $(CFLAGS) $(INCLUDE) $(SRC) $(LINKER) -o $(TARGET) -shared -fPIC
+.PHONY: all clean ensure_libs
+
+all: ensure_libs $(TARGET)
+
+ensure_libs:
+ @if [ ! -f $(CONTROL_LIB) ]; then \
+ echo "Building control library first..."; \
+ $(MAKE) -C $(DIR_CTRL_LIB) install; \
+ fi
+
+%.o: %.c
+ $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
+
+$(TARGET): $(OBJS)
+ $(CC) $(CFLAGS) -shared -o $@ $^ $(LIBPATH) $(LIBS) $(LINKER)
clean:
rm -f $(TARGET) *.o
+ $(MAKE) -C $(DIR_CTRL_LIB) clean
diff --git a/esp_hosted_fg/host/linux/host_control/python_support/commands_lib.py b/esp_hosted_fg/host/linux/host_control/python_support/commands_lib.py
index ddb9c63231..f9edae6991 100644
--- a/esp_hosted_fg/host/linux/host_control/python_support/commands_lib.py
+++ b/esp_hosted_fg/host/linux/host_control/python_support/commands_lib.py
@@ -18,6 +18,13 @@
from time import *
import requests
import sys
+from py_parse import nw_helper_func
+from ctypes import c_uint8, POINTER
+import traceback
+
+# import global
+g_sta_network_info = nw_helper_func.g_sta_network_info
+g_network_down_printed = False
WIFI_VENDOR_IE_ELEMENT_ID = 0xDD
OFFSET = 4
@@ -28,15 +35,63 @@
### Enable WiFi Feature needs to get the Mac Addr to configure the interface
### So we store it here after getting the Mac Addr
-global_mac_addr_str = ""
+g_is_network_split_on = False
+g_is_network_split_queried = False
+
+# Define needed memmove function
+def memmove(dest, src, count):
+ """Copy memory area from src to dest for count bytes.
+
+ This is needed for data transfer in custom RPC.
+ """
+ for i in range(count):
+ dest[i] = src[i]
+ return dest
+
+# Define memset function
+def memset(dest, value, count):
+ """Fill memory area with a constant byte.
+
+ Args:
+ dest: Pointer to destination memory area
+ value: Value to be set
+ count: Number of bytes to be set
+
+ Returns:
+ Pointer to the destination memory area
+ """
+ if not dest or count <= 0:
+ return dest
+
+ # Cast to a byte array to be able to set values
+ dest_bytes = cast(dest, POINTER(c_ubyte))
+ for i in range(count):
+ dest_bytes[i] = value
+
+ return dest
+
+# Helper to create event callback
+def make_async_callback(py_callback):
+ """Convert a Python function to a callback function for ctypes.
+
+ This is needed to set event callbacks.
+ """
+ return CTRL_CB(py_callback)
-def get_mac_addr_str():
- global global_mac_addr_str
- return global_mac_addr_str
+# Get current event callback
+def get_event_callback(event_id):
+ """Get the current event callback for the given event ID.
-def store_mac_addr_str(mac_addr_str):
- global global_mac_addr_str
- global_mac_addr_str = mac_addr_str
+ This is helpful when we need to restore original handlers.
+
+ Args:
+ event_id: The event ID to get the callback for
+
+ Returns:
+ The current callback function or None if not set
+ """
+ callback = commands_map_py_to_c.get_event_callback(event_id)
+ return callback
def get_timestamp():
tm = gmtime()
@@ -74,10 +129,15 @@ def cleanup_ctrl_msg(app_resp):
mem_free(app_resp)
app_resp = None
-
+def successful_response(app_resp):
+ if app_resp and (bytes_to_int(app_resp.contents.resp_event_status) == SUCCESS):
+ return True
+ else:
+ return False
def ctrl_app_event_callback(app_event):
- ts = create_string_buffer(b"", MIN_TIMESTAMP_STR_SIZE)
+ global g_sta_network_info
+ global g_network_down_printed
if (not app_event or
not app_event.contents or
bytes_to_int(app_event.contents.msg_type) != CTRL_MSGTYPE.CTRL_EVENT.value):
@@ -92,12 +152,11 @@ def ctrl_app_event_callback(app_event):
cleanup_ctrl_msg(app_event)
return FAILURE
- s = get_timestamp()
if app_event.contents.msg_id == CTRL_MSGID.CTRL_EVENT_ESP_INIT.value:
- print(s +" APP EVENT: ESP INIT")
+ print("Event: ESP INIT")
elif app_event.contents.msg_id == CTRL_MSGID.CTRL_EVENT_HEARTBEAT.value:
- print(s +" APP EVENT: Heartbeat event "+
+ print("Heartbeat event "+
str(app_event.contents.control_data.e_heartbeat.hb_num))
elif app_event.contents.msg_id == CTRL_MSGID.CTRL_EVENT_STATION_CONNECTED_TO_AP.value:
@@ -108,100 +167,129 @@ def ctrl_app_event_callback(app_event):
authmode = app_event.contents.control_data.e_sta_conn.authmode
aid = app_event.contents.control_data.e_sta_conn.aid
- print(s +" APP EVENT: Station mode: Connected to ssid[" + get_str(ssid) + "] bssid [" +
+ print("Connected to ssid[" + get_str(ssid) + "] bssid [" +
get_str(bssid) + "] channel [" + str(channel) + "] authmode [" + str(authmode) +
"] aid [" + str(aid) + "]")
+ if not nw_helper_func.is_valid_mac_bytes(g_sta_network_info.mac_addr):
+ print(" MAC address " + nw_helper_func.mac_bytes_to_str(g_sta_network_info.mac_addr) + " is not valid, skipping up network interface")
+ print("consider setting the MAC address using test_sync_set_mac_addr(mode, mac)")
+ cleanup_ctrl_msg(app_event)
+ return FAILURE
- elif app_event.contents.msg_id == CTRL_MSGID.CTRL_EVENT_STATION_DISCONNECT_FROM_AP.value:
- ssid = app_event.contents.control_data.e_sta_disconn.ssid
- ssid_len = app_event.contents.control_data.e_sta_disconn.ssid_len
- bssid = app_event.contents.control_data.e_sta_disconn.bssid
- reason = app_event.contents.control_data.e_sta_disconn.reason
- rssi = app_event.contents.control_data.e_sta_disconn.rssi
+ nw_helper_func.up_sta_netdev();
+ if g_network_down_printed:
+ g_network_down_printed = False
- print(s +" APP EVENT: Station mode: Disconnected from ssid[" + get_str(ssid) + "] bssid [" +
- get_str(bssid) + "] reason [" + str(reason) + "] rssi [" + str(rssi) + "]")
+ if not is_network_split_on():
+ print("Network " + STA_INTERFACE + " is up -> Start dhcp client -> Check `ifconfig ethsta0` in new terminal")
+ nw_helper_func.run_dhcp_on_connected()
- elif app_event.contents.msg_id == CTRL_MSGID.CTRL_EVENT_STATION_CONNECTED_TO_ESP_SOFTAP.value:
- aid = app_event.contents.control_data.e_softap_sta_conn.aid
- is_mesh_child = app_event.contents.control_data.e_softap_sta_conn.is_mesh_child
- p = app_event.contents.control_data.e_softap_sta_conn.mac
- if p and len(p):
- print(s +" APP EVENT: Connected to SoftAP MAC ["+get_str(p)+"] aid [" +
- str(aid) + "] is_mesh_child [" +str(is_mesh_child) + "]");
- elif app_event.contents.msg_id == CTRL_MSGID.CTRL_EVENT_STATION_DISCONNECT_FROM_ESP_SOFTAP.value:
- aid = app_event.contents.control_data.e_softap_sta_disconn.aid
- is_mesh_child = app_event.contents.control_data.e_softap_sta_disconn.is_mesh_child
- reason = app_event.contents.control_data.e_softap_sta_disconn.reason
- p = app_event.contents.control_data.e_softap_sta_disconn.mac
- if p and len(p):
- print(s +" APP EVENT: Disconnected from SoftAP MAC ["+get_str(p)+"] aid [" +
- str(aid) + "] is_mesh_child [" +str(is_mesh_child) + "] reason [" + str(reason) + "]")
- else:
- print(s+" Invalid event ["+str(app_event.contents.msg_id)+"] to parse")
+ elif app_event.contents.msg_id == CTRL_MSGID.CTRL_EVENT_STATION_DISCONNECT_FROM_AP.value:
+ ssid = app_event.contents.control_data.e_sta_disconn.ssid
- cleanup_ctrl_msg(app_event)
- return SUCCESS
+ if not is_network_split_on():
+ if not g_network_down_printed:
+ print("Network " + STA_INTERFACE + " down -> Stop dhcp client")
+ nw_helper_func.stop_dhclient_on_disconnected()
+
+ if not g_network_down_printed:
+ print(" Station disconnected from AP: ssid[" + get_str(ssid) + "]")
+ g_network_down_printed = True
+
+ nw_helper_func.down_sta_netdev();
+
+ elif app_event.contents.msg_id == CTRL_MSGID.CTRL_EVENT_DHCP_DNS_STATUS.value:
+ ip_addr = app_event.contents.control_data.e_dhcp_dns_status.dhcp_ip.decode('utf-8').rstrip('\x00')
+ subnet_mask = app_event.contents.control_data.e_dhcp_dns_status.dhcp_nm.decode('utf-8').rstrip('\x00')
+ gateway = app_event.contents.control_data.e_dhcp_dns_status.dhcp_gw.decode('utf-8').rstrip('\x00')
+ dns_server = app_event.contents.control_data.e_dhcp_dns_status.dns_ip.decode('utf-8').rstrip('\x00')
+ ifa = app_event.contents.control_data.e_dhcp_dns_status.iface
+ net_link_up = app_event.contents.control_data.e_dhcp_dns_status.net_link_up
+ dhcp_up = app_event.contents.control_data.e_dhcp_dns_status.dhcp_up
+ dns_up = app_event.contents.control_data.e_dhcp_dns_status.dns_up
+ dns_type = app_event.contents.control_data.e_dhcp_dns_status.dns_type
+
+ #print("APP EVENT: DHCP DNS status: Network link [" + str(net_link_up) + "] IP [" +
+ # ip_addr + "] Subnet mask [" + subnet_mask + "] Gateway [" +
+ # gateway + "] DNS server [" + dns_server + "]" +
+ # " DHCP [" + str(dhcp_up) + "] DNS [" + str(dns_up) + "] DNS type [" + str(dns_type) + "]")
+
+ if dhcp_up:
+ g_sta_network_info.ip_addr = ip_addr
+ g_sta_network_info.netmask = subnet_mask
+ g_sta_network_info.gateway = gateway
+ g_sta_network_info.ip_valid = 1
+ else:
+ g_sta_network_info.ip_valid = 0
+ g_sta_network_info.dns_valid = 0
+ if dns_up:
+ g_sta_network_info.dns_addr = dns_server
+ g_sta_network_info.dns_valid = 1
+ else:
+ g_sta_network_info.dns_valid = 0
+ if net_link_up:
+ g_sta_network_info.network_up = 1
+ else:
+ g_sta_network_info.network_up = 0
+
+
+ if is_network_split_on():
+ if not successful_response(app_event):
+ print(" Slave firmware not compiled with network split, skip dhcp/dns event")
+ cleanup_ctrl_msg(app_event)
+ return FAILURE
+
+ if nw_helper_func.is_valid_mac_bytes(g_sta_network_info.mac_addr):
+ if g_sta_network_info.ip_valid and g_sta_network_info.network_up and g_sta_network_info.dns_valid:
+ if nw_helper_func.up_sta_netdev__with_static_ip_dns_route(ip_addr, subnet_mask, gateway, dns_server) == FAILURE:
+ print(" Failed to up static IP, gateway, DNS from event.")
+ else:
+ print(STA_INTERFACE +" up: IP [" + ip_addr + "] Subnet mask [" +
+ subnet_mask + "] Gateway [" +gateway + "] DNS server [" + dns_server + "]")
+ else:
+ nw_helper_func.down_sta_netdev()
+ if not g_network_down_printed:
+ print("Network " + STA_INTERFACE + " brought down!")
+ g_network_down_printed = True
+ else:
+ print("MAC address invalid, skip DHCP/DNS event.")
+ print("consider setting the MAC address using test_sync_set_mac_addr(mode, mac)")
+ else:
+ print("DHCP/DNS event received when network split is off. Use dhclient if needed")
-def process_resp_connect_ap(app_msg) :
- ret = SUCCESS
- sockfd = c_int()
- sockfd.value = 0
- AF_INET = c_int()
- AF_INET.value = 2
- SOCK_DGRAM = c_int()
- SOCK_DGRAM.value = 2
- IPPROTO_IP = c_int()
- IPPROTO_IP.value = 0
-
- sta_interface = create_string_buffer(b"ethsta0", len(STA_INTERFACE))
- if (not len(app_msg.contents.control_data.wifi_ap_config.out_mac)):
- print("Failure: station mac is empty")
- return FAILURE
- ret = commands_map_py_to_c.create_socket(AF_INET, SOCK_DGRAM, IPPROTO_IP, byref(sockfd))
- if (ret < 0):
- print("Failure to open socket")
- return FAILURE
+ elif app_event.contents.msg_id == CTRL_MSGID.CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG.value:
+ custom_msg_id = app_event.contents.control_data.custom_rpc_unserialised_msg.custom_msg_id
+ custom_rpc_data = app_event.contents.control_data.custom_rpc_unserialised_msg.data
+ custom_rpc_data_len = app_event.contents.control_data.custom_rpc_unserialised_msg.data_len
+ print("Custom RPC event [" + str(custom_msg_id) + "] Data length [" + str(custom_rpc_data_len) + "].")
+ print(" Data: " )
- ret = commands_map_py_to_c.interface_down(sockfd, sta_interface)
- if (ret == SUCCESS) :
- print(STA_INTERFACE+" interface down")
- else:
- print("Unable to down "+STA_INTERFACE+" interface")
- close_sock(sockfd)
- return FAILURE
+ for i in range(min(custom_rpc_data_len, 32)):
+ print("{:02X} ".format(custom_rpc_data[i]), end='')
+ if custom_rpc_data_len > 32:
+ print(" ... ({} more bytes)".format(custom_rpc_data_len - 32), end='')
- ret = commands_map_py_to_c.set_hw_addr(sockfd, sta_interface,
- app_msg.contents.control_data.wifi_ap_config.out_mac)
- if (ret == SUCCESS):
- mac_l = get_str(app_msg.contents.control_data.wifi_ap_config.out_mac)
- print("MAC address \""+ mac_l +"\" set to "+STA_INTERFACE+" interface")
- else:
- print("Unable to set MAC address to "+STA_INTERFACE+" interface")
- close_sock(sockfd)
- return FAILURE
+ print()
+ print(" Use your own custom event handler to handle data.")
+ elif app_event.contents.msg_id == CTRL_MSGID.CTRL_EVENT_STATION_CONNECTED_TO_ESP_SOFTAP.value:
+ sta_mac = app_event.contents.control_data.e_softap_sta_conn.mac
+ aid = app_event.contents.control_data.e_softap_sta_conn.aid
+ print("Station connected to ESP SoftAP: MAC [" + get_str(sta_mac) + "] AID [" + str(aid) + "]")
- ret = commands_map_py_to_c.interface_up(sockfd, sta_interface)
- if (ret == SUCCESS) :
- print(STA_INTERFACE+" interface up")
+ elif app_event.contents.msg_id == CTRL_MSGID.CTRL_EVENT_STATION_DISCONNECT_FROM_ESP_SOFTAP.value:
+ sta_mac = app_event.contents.control_data.e_softap_sta_disconn.mac
+ aid = app_event.contents.control_data.e_softap_sta_disconn.aid
+ print("Station disconnected from ESP SoftAP: MAC [" + get_str(sta_mac) + "] AID [" + str(aid) + "]")
else:
- print("Unable to up "+STA_INTERFACE+" interface")
- close_sock(sockfd)
- return FAILURE
-
- ret = commands_map_py_to_c.close_socket(sockfd)
- if (ret < 0):
- print("Failure to close socket")
- return FAILURE
+ print(" Invalid event ["+str(app_event.contents.msg_id)+"] to parse")
+ cleanup_ctrl_msg(app_event)
return SUCCESS
-
-
def process_failed_responses(app_msg):
request_failed_flag = True
if (app_msg.contents.resp_event_status == CTRL_ERR.CTRL_ERR_REQ_IN_PROG.value):
@@ -247,133 +335,6 @@ def process_failed_responses(app_msg):
print("Failed Control Response")
-
-def process_resp_disconnect_ap(app_resp):
- ret = 0
- sockfd = c_int()
- sockfd.value = 0
- AF_INET = c_int()
- AF_INET.value = 2
- SOCK_DGRAM = c_int()
- SOCK_DGRAM.value = 2
- IPPROTO_IP = c_int()
- IPPROTO_IP.value = 0
-
- sta_interface = create_string_buffer(b"ethsta0", len(STA_INTERFACE))
- ret = commands_map_py_to_c.create_socket(AF_INET,
- SOCK_DGRAM, IPPROTO_IP, byref(sockfd))
- if (ret < 0):
- print("Failure to open socket")
- return FAILURE
-
- ret = commands_map_py_to_c.interface_down(sockfd, sta_interface)
- if (ret == SUCCESS):
- print(STA_INTERFACE + " interface down")
- else:
- print("Unable to down " + STA_INTERFACE + "inteface")
- close_sock(sockfd)
- return FAILURE
-
- ret = commands_map_py_to_c.close_socket(sockfd)
- if (ret < 0):
- print("Failure to close socket")
- return FAILURE
-
- return SUCCESS
-
-
-
-def process_resp_start_softap(app_resp):
- ret = SUCCESS
- sockfd = c_int()
- sockfd.value = 0
- AF_INET = c_int()
- AF_INET.value = 2
- SOCK_DGRAM = c_int()
- SOCK_DGRAM.value = 2
- IPPROTO_IP = c_int()
- IPPROTO_IP.value = 0
-
- ap_interface = create_string_buffer(b"ethap0",len(AP_INTERFACE))
- if (not len(app_resp.contents.control_data.wifi_softap_config.out_mac)):
- print("Failure: softap mac is empty")
- return FAILURE
-
- ret = commands_map_py_to_c.create_socket(AF_INET,
- SOCK_DGRAM, IPPROTO_IP, byref(sockfd))
- if (ret < 0):
- print("Failure to open socket")
- return FAILURE
-
- ret = commands_map_py_to_c.interface_down(sockfd, ap_interface)
- if (ret == SUCCESS) :
- print(AP_INTERFACE+" interface down")
- else:
- print("Unable to down "+AP_INTERFACE+" interface")
- close_sock(sockfd)
- return FAILURE
-
- ret = commands_map_py_to_c.set_hw_addr(sockfd, ap_interface,
- app_resp.contents.control_data.wifi_softap_config.out_mac)
- if (ret == SUCCESS):
- mac_l = get_str(app_resp.contents.control_data.wifi_softap_config.out_mac)
- print("MAC address "+ mac_l +" set to "+AP_INTERFACE+" interface")
- else:
- print("Unable to set MAC address to "+AP_INTERFACE+" interface")
- close_sock(sockfd)
- return FAILURE
-
- ret = commands_map_py_to_c.interface_up(sockfd, ap_interface)
- if (ret == SUCCESS) :
- print(AP_INTERFACE+" interface up")
- else:
- print("Unable to up "+AP_INTERFACE+" interface")
- close_sock(sockfd)
- return FAILURE
-
- ret = commands_map_py_to_c.close_socket(sockfd)
- if (ret < 0):
- print("Failure to close socket")
- return FAILURE
-
- return SUCCESS
-
-
-
-def process_resp_stop_softap(app_resp):
- ret = 0
- sockfd = c_int()
- sockfd.value = 0
- AF_INET = c_int()
- AF_INET.value = 2
- SOCK_DGRAM = c_int()
- SOCK_DGRAM.value = 2
- IPPROTO_IP = c_int()
- IPPROTO_IP.value = 0
-
- ap_interface = create_string_buffer(b"ethap0",len(AP_INTERFACE))
- ret = commands_map_py_to_c.create_socket(AF_INET,
- SOCK_DGRAM, IPPROTO_IP, byref(sockfd))
- if (ret < 0):
- print("Failure to open socket")
- return FAILURE
-
- ret = commands_map_py_to_c.interface_down(sockfd, ap_interface)
- if (ret == SUCCESS):
- print(AP_INTERFACE + " interface down")
- else:
- print("Unable to down " + AP_INTERFACE + "inteface")
- close_sock(sockfd)
- return FAILURE
-
- ret = commands_map_py_to_c.close_socket(sockfd)
- if (ret < 0):
- print("Failure to close socket")
- return FAILURE
- return SUCCESS
-
-
-
def unregister_event_callbacks():
ret = SUCCESS
for event in range(CTRL_MSGID.CTRL_EVENT_BASE.value+1, CTRL_MSGID.CTRL_EVENT_MAX.value):
@@ -383,26 +344,38 @@ def unregister_event_callbacks():
return ret
+def CTRL_CMD_DEFAULT_REQ():
+ """Allocate and initialize a new control command request similar to C version.
+
+ This function matches the C implementation by allocating memory for a new request.
+ """
+ new_req = POINTER(CONTROL_COMMAND)()
+ new_req = cast(commands_map_py_to_c.hosted_malloc(sizeof(CONTROL_COMMAND)), POINTER(CONTROL_COMMAND))
+ if not new_req:
+ print("Failed to allocate memory for request")
+ return None
-def CTRL_CMD_DEFAULT_REQ(req):
- req.msg_type = CTRL_MSGTYPE.CTRL_REQ.value
- req.cmd_timeout_sec = CTRL_RESP_TIMEOUT_SEC
+ # Initialize the allocated memory with zeros
+ memset(new_req, 0, sizeof(CONTROL_COMMAND))
+ # Set default values
+ new_req.contents.msg_type = CTRL_MSGTYPE.CTRL_REQ.value
+ new_req.contents.cmd_timeout_sec = CTRL_RESP_TIMEOUT_SEC
+ return new_req
def fail_resp(app_resp) :
cleanup_ctrl_msg(app_resp)
return FAILURE
-
def finish_resp(app_resp) :
cleanup_ctrl_msg(app_resp)
return SUCCESS
-
def ctrl_app_resp_callback(app_resp):
+ global g_network_down_printed
if ((not app_resp) or (not app_resp.contents) or
(bytes_to_int(app_resp.contents.msg_type) != CTRL_MSGTYPE.CTRL_RESP.value)):
@@ -418,7 +391,7 @@ def ctrl_app_resp_callback(app_resp):
fail_resp(app_resp)
return FAILURE
- if (bytes_to_int(app_resp.contents.resp_event_status) != SUCCESS):
+ if not successful_response(app_resp):
process_failed_responses(app_resp)
fail_resp(app_resp)
return FAILURE
@@ -427,7 +400,6 @@ def ctrl_app_resp_callback(app_resp):
if (app_resp.contents.msg_id == CTRL_MSGID.CTRL_RESP_GET_MAC_ADDR.value) :
mac_str = get_str(app_resp.contents.control_data.wifi_mac.mac)
print("mac address is " + mac_str)
- store_mac_addr_str(mac_str)
elif (app_resp.contents.msg_id == CTRL_MSGID.CTRL_RESP_SET_MAC_ADDRESS.value) :
print("MAC address is set")
@@ -449,7 +421,7 @@ def ctrl_app_resp_callback(app_resp):
elif (app_resp.contents.msg_id == CTRL_MSGID.CTRL_RESP_GET_AP_SCAN_LIST.value) :
w_scan_p = POINTER(WIFI_AP_SCAN_LIST)
- w_scan_p = pointer(app_resp.contents.control_data.wifi_ap_scan)
+ w_scan_p = pointer(app_resp.contents.control_data.wifi_ap_scan_list)
list = POINTER(WIFI_SCAN_LIST)
list = w_scan_p.contents.out_list
@@ -474,10 +446,12 @@ def ctrl_app_resp_callback(app_resp):
" auth mode \""+str(list[i].encryption_mode)+"\"")
elif (app_resp.contents.msg_id == CTRL_MSGID.CTRL_RESP_CONNECT_AP.value) :
- if (process_resp_connect_ap(app_resp)):
+ if not successful_response(app_resp):
fail_resp(app_resp)
- print("Returning failure")
+ print("Failed to connect to AP, retry")
return FAILURE
+ else:
+ print("Request to connect to AP submitted")
elif (app_resp.contents.msg_id == CTRL_MSGID.CTRL_RESP_GET_AP_CONFIG.value) :
ap_config_p = POINTER(STA_CONFIG)
@@ -495,15 +469,27 @@ def ctrl_app_resp_callback(app_resp):
elif (app_resp.contents.msg_id == CTRL_MSGID.CTRL_RESP_DISCONNECT_AP.value) :
print("Disconnected from AP")
- if (process_resp_disconnect_ap(app_resp)):
+ if nw_helper_func.down_sta_netdev() != SUCCESS:
+ print("Failed to bring down station network")
fail_resp(app_resp)
return FAILURE
+ else:
+ if not g_network_down_printed:
+ print("Station network brought down")
+ g_network_down_printed = True
elif (app_resp.contents.msg_id == CTRL_MSGID.CTRL_RESP_START_SOFTAP.value) :
print("esp32 softAP started with band_mode "+str(app_resp.contents.control_data.wifi_softap_config.band_mode))
- if (process_resp_start_softap(app_resp)):
+ if (nw_helper_func.up_softap_netdev() != SUCCESS):
+ print("Failed to bring up softap network")
fail_resp(app_resp)
return FAILURE
+ else:
+ print("SoftAP started")
+ if nw_helper_func.run_dhcp_server() != SUCCESS:
+ print("Failed to start DHCP server")
+ fail_resp(app_resp)
+ return FAILURE
elif (app_resp.contents.msg_id == CTRL_MSGID.CTRL_RESP_GET_SOFTAP_CONFIG.value) :
softap_config_p = POINTER(SOFTAP_CONFIG)
@@ -518,9 +504,9 @@ def ctrl_app_resp_callback(app_resp):
print("softAP band mode \""+str(softap_config_p.contents.band_mode)+"\"")
elif (app_resp.contents.msg_id == CTRL_MSGID.CTRL_RESP_GET_SOFTAP_CONN_STA_LIST.value) :
- count = app_resp.contents.control_data.wifi_softap_con_sta.count
+ count = app_resp.contents.control_data.wifi_connected_stations_list.count
stations_list = POINTER(WIFI_CONNECTED_STATIONS_LIST)
- stations_list = pointer(app_resp.contents.control_data.wifi_softap_con_sta.out_list)
+ stations_list = pointer(app_resp.contents.control_data.wifi_connected_stations_list.out_list)
print("sta list count: "+str(count))
if (not count):
@@ -537,10 +523,17 @@ def ctrl_app_resp_callback(app_resp):
elif (app_resp.contents.msg_id == CTRL_MSGID.CTRL_RESP_STOP_SOFTAP.value) :
print("ESP32 softAP stopped")
- if (process_resp_stop_softap(app_resp)):
+ if nw_helper_func.down_softap_netdev() != SUCCESS:
+ fail_resp(app_resp)
+ print("Failed to bring down softap network")
+ return FAILURE
+
+ if nw_helper_func.stop_dhcp_server() != SUCCESS:
+ print("Failed to stop DHCP server")
fail_resp(app_resp)
return FAILURE
+
elif (app_resp.contents.msg_id == CTRL_MSGID.CTRL_RESP_SET_SOFTAP_VND_IE.value) :
print("Success in set vendor specific ie")
@@ -548,21 +541,23 @@ def ctrl_app_resp_callback(app_resp):
print("Wifi power save mode set")
elif (app_resp.contents.msg_id == CTRL_MSGID.CTRL_RESP_GET_PS_MODE.value) :
- if (app_resp.contents.control_data.wifi_ps.ps_mode == WIFI_PS_MODE.WIFI_PS_MIN_MODEM.value):
+ if (app_resp.contents.control_data.wifi_power_save_mode.ps_mode == WIFI_PS_MODE.WIFI_PS_NONE.value):
+ print("Wifi power save mode is: none")
+ elif (app_resp.contents.control_data.wifi_power_save_mode.ps_mode == WIFI_PS_MODE.WIFI_PS_MIN_MODEM.value):
print("Wifi power save mode is: min")
- elif (app_resp.contents.control_data.wifi_ps.ps_mode == WIFI_PS_MODE.WIFI_PS_MAX_MODEM.value):
+ elif (app_resp.contents.control_data.wifi_power_save_mode.ps_mode == WIFI_PS_MODE.WIFI_PS_MAX_MODEM.value):
print("Wifi power save mode is: max")
else:
print("Wifi power save mode is: Invalid")
elif (app_resp.contents.msg_id == CTRL_MSGID.CTRL_RESP_OTA_BEGIN.value) :
- pass
+ print("ota begin ack")
elif (app_resp.contents.msg_id == CTRL_MSGID.CTRL_RESP_OTA_WRITE.value) :
pass
elif (app_resp.contents.msg_id == CTRL_MSGID.CTRL_RESP_OTA_END.value) :
- pass
+ print("ota end ack")
elif (app_resp.contents.msg_id == CTRL_MSGID.CTRL_RESP_SET_WIFI_MAX_TX_POWER.value) :
print("Set wifi max tx power success")
@@ -578,7 +573,7 @@ def ctrl_app_resp_callback(app_resp):
print(version_string, end='')
elif (app_resp.contents.msg_id == CTRL_MSGID.CTRL_RESP_SET_COUNTRY_CODE.value) :
- pass
+ print("ack")
elif (app_resp.contents.msg_id == CTRL_MSGID.CTRL_RESP_GET_COUNTRY_CODE.value) :
country_code = app_resp.contents.control_data.country_code.country.decode('utf-8')
@@ -586,10 +581,81 @@ def ctrl_app_resp_callback(app_resp):
elif (app_resp.contents.msg_id == CTRL_MSGID.CTRL_RESP_ENABLE_DISABLE.value) :
pass
+ elif (app_resp.contents.msg_id == CTRL_MSGID.CTRL_RESP_SET_DHCP_DNS_STATUS.value) :
+ print("set dhcp dns success")
+
+ elif (app_resp.contents.msg_id == CTRL_MSGID.CTRL_RESP_GET_DHCP_DNS_STATUS.value) :
+ #print("DHCP DNS status:")
+ if app_resp.contents.control_data.e_dhcp_dns_status.iface == 0:
+ iface = STA_INTERFACE
+ else:
+ iface = AP_INTERFACE
+
+
+ ip_addr = app_resp.contents.control_data.e_dhcp_dns_status.dhcp_ip.decode('utf-8').rstrip('\x00')
+ subnet_mask = app_resp.contents.control_data.e_dhcp_dns_status.dhcp_nm.decode('utf-8').rstrip('\x00')
+ gateway = app_resp.contents.control_data.e_dhcp_dns_status.dhcp_gw.decode('utf-8').rstrip('\x00')
+ dns_server = app_resp.contents.control_data.e_dhcp_dns_status.dns_ip.decode('utf-8').rstrip('\x00')
+ ifa = app_resp.contents.control_data.e_dhcp_dns_status.iface
+ net_link_up = app_resp.contents.control_data.e_dhcp_dns_status.net_link_up
+ dhcp_up = app_resp.contents.control_data.e_dhcp_dns_status.dhcp_up
+ dns_up = app_resp.contents.control_data.e_dhcp_dns_status.dns_up
+ dns_type = app_resp.contents.control_data.e_dhcp_dns_status.dns_type
+
+ if dhcp_up:
+ g_sta_network_info.ip_addr = ip_addr
+ g_sta_network_info.netmask = subnet_mask
+ g_sta_network_info.gateway = gateway
+ g_sta_network_info.ip_valid = 1
+ else:
+ g_sta_network_info.ip_valid = 0
+ g_sta_network_info.dns_valid = 0
+
+ if dns_up:
+ g_sta_network_info.dns_addr = dns_server
+ g_sta_network_info.dns_valid = 1
+ else:
+ g_sta_network_info.dns_valid = 0
+ if net_link_up:
+ g_sta_network_info.network_up = 1
+ else:
+ g_sta_network_info.network_up = 0
+
+
+ if is_network_split_on():
+ if not successful_response(app_resp):
+ print(" Slave firmware not compiled with network split, skip dhcp/dns event")
+ cleanup_ctrl_msg(app_resp)
+ return FAILURE
+
+ if nw_helper_func.is_valid_mac_bytes(g_sta_network_info.mac_addr):
+ if g_sta_network_info.ip_valid and g_sta_network_info.network_up and g_sta_network_info.dns_valid:
+ if nw_helper_func.up_sta_netdev__with_static_ip_dns_route(ip_addr, subnet_mask, gateway, dns_server) == FAILURE:
+ print(" Failed to up static IP, gateway, DNS from event.")
+ else:
+ print(STA_INTERFACE +" up: IP [" + ip_addr + "] Subnet mask [" +
+ subnet_mask + "] Gateway [" +gateway + "] DNS server [" + dns_server + "]")
+ else:
+ nw_helper_func.down_sta_netdev()
+ if not g_network_down_printed:
+ print("Network " + STA_INTERFACE + " brought down")
+ g_network_down_printed = True
+ else:
+ print("MAC address invalid, skip DHCP/DNS event.")
+ print("consider setting the MAC address using test_sync_set_mac_addr(mode, mac)")
+ else:
+ print("DHCP/DNS event received when network split is off. Use dhclient if needed")
+
+
+ elif (app_resp.contents.msg_id == CTRL_MSGID.CTRL_RESP_CUSTOM_RPC_UNSERIALISED_MSG.value) :
+ custom_rpc_data = app_resp.contents.control_data.custom_rpc_unserialised_msg.data
+ custom_rpc_data_len = app_resp.contents.control_data.custom_rpc_unserialised_msg.data_len
+ print("Custom RPC unserialised msg: Data length [" + str(custom_rpc_data_len) + "]")
else :
print("Invalid Response "+ str(app_resp.contents.msg_id) +" to parse")
+ cleanup_ctrl_msg(app_resp)
return SUCCESS
@@ -602,7 +668,8 @@ def subscribe_event_esp_init():
if (CALLBACK_SET_SUCCESS != commands_map_py_to_c.set_event_callback(
CTRL_MSGID.CTRL_EVENT_ESP_INIT.value, ctrl_app_event_cb)):
print("event not subscribed for esp_init")
- print("notifications enabled for esp_init")
+ return False
+ return True
@@ -610,7 +677,8 @@ def subscribe_event_heartbeat():
if (CALLBACK_SET_SUCCESS != commands_map_py_to_c.set_event_callback(
CTRL_MSGID.CTRL_EVENT_HEARTBEAT.value, ctrl_app_event_cb)):
print("event not subscribed for heartbeat")
- print("notifications enabled for heartbeat")
+ return False
+ return True
@@ -618,7 +686,8 @@ def subscribe_event_sta_connected_to_ap():
if (CALLBACK_SET_SUCCESS != commands_map_py_to_c.set_event_callback(
CTRL_MSGID.CTRL_EVENT_STATION_CONNECTED_TO_AP.value, ctrl_app_event_cb)):
print("event not subscribed for station connected to AP")
- print("notifications enabled for station connected to AP")
+ return False
+ return True
@@ -626,7 +695,8 @@ def subscribe_event_sta_disconnect_from_ap():
if (CALLBACK_SET_SUCCESS != commands_map_py_to_c.set_event_callback(
CTRL_MSGID.CTRL_EVENT_STATION_DISCONNECT_FROM_AP.value, ctrl_app_event_cb)):
print("event not subscribed for station disconnection from AP")
- print("notifications enabled for station disconnection from AP")
+ return False
+ return True
@@ -634,7 +704,8 @@ def subscribe_event_sta_connected_to_softap():
if (CALLBACK_SET_SUCCESS != commands_map_py_to_c.set_event_callback(
CTRL_MSGID.CTRL_EVENT_STATION_CONNECTED_TO_ESP_SOFTAP.value, ctrl_app_event_cb)):
print("event not subscribed for station connected to ESP softAP")
- print("notifications enabled for station connected to ESP softAP")
+ return False
+ return True
@@ -642,15 +713,66 @@ def subscribe_event_sta_disconnect_from_softap():
if (CALLBACK_SET_SUCCESS != commands_map_py_to_c.set_event_callback(
CTRL_MSGID.CTRL_EVENT_STATION_DISCONNECT_FROM_ESP_SOFTAP.value, ctrl_app_event_cb)):
print("event not subscribed for station disconnection from ESP softAP")
- print("notifications enabled for station disconnection from ESP softAP")
+ return False
+ return True
+
+def subscribe_event_dhcp_dns_status():
+ if (CALLBACK_SET_SUCCESS != commands_map_py_to_c.set_event_callback(
+ CTRL_MSGID.CTRL_EVENT_DHCP_DNS_STATUS.value, ctrl_app_event_cb)):
+ print("event not subscribed for DHCP DNS status")
+ return False
+ return True
+
+def subscribe_event_custom_rpc_unserialised_msg():
+ if (CALLBACK_SET_SUCCESS != commands_map_py_to_c.set_event_callback(
+ CTRL_MSGID.CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG.value, ctrl_app_event_cb)):
+ print("event not subscribed for custom RPC unserialised msg")
+ return False
+ return True
+def local_subscribe_event_custom_rpc_handler():
+ """Subscribe to custom RPC events.
+ Returns:
+ SUCCESS if successful, FAILURE otherwise
+ """
+ ret = FAILURE
+
+ ret = commands_map_py_to_c.set_event_callback(
+ CTRL_MSGID.CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG.value,
+ commands_map_py_to_c.make_async_callback(ctrl_app_event_callback))
+
+ if ret != CALLBACK_SET_SUCCESS:
+ print("Failed to subscribe to custom RPC events")
+ return FAILURE
+ else:
+ print("Subscribed to custom RPC events successfully")
+ return SUCCESS
+
+def local_reset_event_custom_rpc_handler():
+ """Unsubscribe from custom RPC events.
+
+ Returns:
+ SUCCESS if successful, FAILURE otherwise
+ """
+ ret = FAILURE
+
+ ret = commands_map_py_to_c.reset_event_callback(
+ CTRL_MSGID.CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG.value)
+
+ if ret != CALLBACK_SET_SUCCESS:
+ print("Failed to unsubscribe from custom RPC events")
+ return FAILURE
+ else:
+ print("Unsubscribed from custom RPC events successfully")
+ return SUCCESS
def unsubscribe_event_esp_init():
if (CALLBACK_SET_SUCCESS != commands_map_py_to_c.reset_event_callback(
CTRL_MSGID.CTRL_EVENT_ESP_INIT.value)):
print("stop subscription failed for esp_init")
- print("notifications disabled for esp_init")
+ return False
+ return True
@@ -658,7 +780,8 @@ def unsubscribe_event_heartbeat():
if (CALLBACK_SET_SUCCESS != commands_map_py_to_c.reset_event_callback(
CTRL_MSGID.CTRL_EVENT_HEARTBEAT.value)):
print("stop subscription failed for heartbeat")
- print("notifications disabled for heartbeat")
+ return False
+ return True
@@ -666,7 +789,8 @@ def unsubscribe_event_sta_connected_to_ap():
if (CALLBACK_SET_SUCCESS != commands_map_py_to_c.reset_event_callback(
CTRL_MSGID.CTRL_EVENT_STATION_CONNECTED_TO_AP.value)):
print("stop subscription failed for station connected to AP")
- print("notifications disabled for station connected to AP")
+ return False
+ return True
@@ -674,7 +798,8 @@ def unsubscribe_event_sta_disconnect_from_ap():
if (CALLBACK_SET_SUCCESS != commands_map_py_to_c.reset_event_callback(
CTRL_MSGID.CTRL_EVENT_STATION_DISCONNECT_FROM_AP.value)):
print("stop subscription failed for station disconnection from AP")
- print("notifications disabled for station disconnection from AP")
+ return False
+ return True
@@ -682,7 +807,8 @@ def unsubscribe_event_sta_connected_to_softap():
if (CALLBACK_SET_SUCCESS != commands_map_py_to_c.reset_event_callback(
CTRL_MSGID.CTRL_EVENT_STATION_CONNECTED_TO_ESP_SOFTAP.value)):
print("stop subscription failed for station connected to ESP softAP")
- print("notifications disabled for station connected to ESP softAP")
+ return False
+ return True
@@ -690,7 +816,23 @@ def unsubscribe_event_sta_disconnect_from_softap():
if (CALLBACK_SET_SUCCESS != commands_map_py_to_c.reset_event_callback(
CTRL_MSGID.CTRL_EVENT_STATION_DISCONNECT_FROM_ESP_SOFTAP.value)):
print("stop subscription failed for station disconnection from ESP softAP")
- print("notifications disabled for station disconnection from ESP softAP")
+ return False
+ return True
+
+def unsubscribe_event_dhcp_dns_status():
+ if (CALLBACK_SET_SUCCESS != commands_map_py_to_c.reset_event_callback(
+ CTRL_MSGID.CTRL_EVENT_DHCP_DNS_STATUS.value)):
+ print("stop subscription failed for DHCP DNS status")
+ return False
+ return True
+
+
+def unsubscribe_event_custom_rpc_unserialised_msg():
+ if (CALLBACK_SET_SUCCESS != commands_map_py_to_c.reset_event_callback(
+ CTRL_MSGID.CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG.value)):
+ print("stop subscription failed for custom RPC unserialised msg")
+ return False
+ return True
@@ -701,6 +843,8 @@ def register_all_event_callbacks():
subscribe_event_sta_disconnect_from_ap()
subscribe_event_sta_connected_to_softap()
subscribe_event_sta_disconnect_from_softap()
+ subscribe_event_dhcp_dns_status()
+ subscribe_event_custom_rpc_unserialised_msg()
def unregister_all_event_callbacks():
@@ -710,7 +854,8 @@ def unregister_all_event_callbacks():
unsubscribe_event_sta_disconnect_from_ap()
unsubscribe_event_sta_connected_to_softap()
unsubscribe_event_sta_disconnect_from_softap()
-
+ unsubscribe_event_dhcp_dns_status()
+ unsubscribe_event_custom_rpc_unserialised_msg()
@@ -723,12 +868,16 @@ def init_hosted_control_lib():
def test_sync_set_wifi_mode(mode) :
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
resp = POINTER(CONTROL_COMMAND)
resp = None
- req.control_data.wifi_mode.mode = mode
+ req.contents.control_data.wifi_mode.mode = mode
resp = commands_map_py_to_c.wifi_set_mode(req)
+
+ cleanup_ctrl_msg(req)
return ctrl_app_resp_callback(resp)
@@ -754,34 +903,82 @@ def test_sync_set_wifi_mode_station_softap() :
def test_async_get_wifi_mode() :
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
- req.ctrl_resp_cb = ctrl_app_resp_cb
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
+ req.contents.ctrl_resp_cb = ctrl_app_resp_cb
commands_map_py_to_c.wifi_get_mode(req)
+
+ cleanup_ctrl_msg(req)
return SUCCESS
def test_sync_get_wifi_mode() :
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
resp = POINTER(CONTROL_COMMAND)
resp = None
resp = commands_map_py_to_c.wifi_get_mode(req)
+
+ cleanup_ctrl_msg(req)
return ctrl_app_resp_callback(resp)
+def test_sync_get_static_ip_from_slave():
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
+
+ resp = POINTER(CONTROL_COMMAND)
+ resp = None
+ resp = commands_map_py_to_c.get_dhcp_dns_status(req)
+ cleanup_ctrl_msg(req)
+ return ctrl_app_resp_callback(resp)
+
+def test_sync_get_wifi_mac_addr(mode):
+ if mode != WIFI_MODE_E.WIFI_MODE_STA.value and mode != WIFI_MODE_E.WIFI_MODE_AP.value:
+ print("Invalid mode for getting MAC address")
+ return FAILURE
-def test_sync_get_wifi_mac_addr(mode) :
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
+ req.contents.control_data.wifi_mac.mode = mode
resp = POINTER(CONTROL_COMMAND)
resp = None
- req.control_data.wifi_mac.mode = mode
resp = commands_map_py_to_c.wifi_get_mac(req)
- return ctrl_app_resp_callback(resp)
+
+ if not successful_response(resp):
+ print("test_sync_get_wifi_mac_addr: Failed to get MAC address 1")
+ cleanup_ctrl_msg(req)
+ cleanup_ctrl_msg(resp)
+ return FAILURE
+
+ mac_bytes = resp.contents.control_data.wifi_mac.mac
+ if not nw_helper_func.is_valid_mac_bytes(mac_bytes):
+ print("test_sync_get_wifi_mac_addr: Failed to get MAC address 2")
+ cleanup_ctrl_msg(req)
+ cleanup_ctrl_msg(resp)
+ return FAILURE
+
+ #print("test_sync_get_wifi_mac_addr: mode: " + str(mode) + " MAC address: " + nw_helper_func.mac_bytes_to_str(mac_bytes))
+
+ if req.contents.control_data.wifi_mac.mode == WIFI_MODE_E.WIFI_MODE_STA.value:
+ nw_helper_func.set_mac_addr(mac_bytes, iface=STA_INTERFACE)
+ else:
+ nw_helper_func.set_mac_addr(mac_bytes, iface=AP_INTERFACE)
+
+ cleanup_ctrl_msg(req)
+ cleanup_ctrl_msg(resp)
+ return SUCCESS
@@ -796,13 +993,17 @@ def test_sync_softap_mode_get_mac_addr() :
def test_sync_set_mac_addr(mode, mac) :
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
+ req.contents.control_data.wifi_mac.mode = mode
+ req.contents.control_data.wifi_mac.mac = bytes(mac, 'utf-8')
resp = POINTER(CONTROL_COMMAND)
resp = None
- req.control_data.wifi_mac.mode = mode
- req.control_data.wifi_mac.mac = bytes(mac, 'utf-8')
resp = commands_map_py_to_c.wifi_set_mac(req)
+
+ cleanup_ctrl_msg(req)
return ctrl_app_resp_callback(resp)
@@ -822,159 +1023,208 @@ def test_sync_softap_mode_set_mac_addr_of_esp(mac) :
def test_sync_get_available_wifi():
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
resp = POINTER(CONTROL_COMMAND)
resp = None
resp = commands_map_py_to_c.wifi_ap_scan_list(req)
+
+ cleanup_ctrl_msg(req)
return ctrl_app_resp_callback(resp)
def test_async_station_mode_connect(ssid,pwd,bssid,use_wpa3,listen_interval,band_mode):
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
- req.control_data.wifi_ap_config.ssid = set_str(ssid)
- req.control_data.wifi_ap_config.pwd = set_str(pwd)
- req.control_data.wifi_ap_config.bssid = set_str(bssid)
- req.control_data.wifi_ap_config.is_wpa3_supported = use_wpa3
- req.control_data.wifi_ap_config.listen_interval = listen_interval
- req.control_data.wifi_ap_config.band_mode = band_mode
- req.ctrl_resp_cb = ctrl_app_resp_cb
+ req.contents.control_data.wifi_ap_config.ssid = set_str(ssid)
+ req.contents.control_data.wifi_ap_config.pwd = set_str(pwd)
+ req.contents.control_data.wifi_ap_config.bssid = set_str(bssid)
+ req.contents.control_data.wifi_ap_config.is_wpa3_supported = use_wpa3
+ req.contents.control_data.wifi_ap_config.listen_interval = listen_interval
+ req.contents.control_data.wifi_ap_config.band_mode = band_mode
+ req.contents.ctrl_resp_cb = ctrl_app_resp_cb
commands_map_py_to_c.wifi_connect_ap(req)
+
+ cleanup_ctrl_msg(req)
return SUCCESS
def test_sync_station_mode_connect(ssid,pwd,bssid,use_wpa3,listen_interval,band_mode):
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
- req.control_data.wifi_ap_config.ssid = set_str(str(ssid))
- req.control_data.wifi_ap_config.pwd = set_str(str(pwd))
- req.control_data.wifi_ap_config.bssid = set_str(bssid)
- req.control_data.wifi_ap_config.is_wpa3_supported = use_wpa3
- req.control_data.wifi_ap_config.listen_interval = listen_interval
- req.control_data.wifi_ap_config.band_mode = band_mode
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
+ req.contents.control_data.wifi_ap_config.ssid = set_str(str(ssid))
+ req.contents.control_data.wifi_ap_config.pwd = set_str(str(pwd))
+ req.contents.control_data.wifi_ap_config.bssid = set_str(bssid)
+ req.contents.control_data.wifi_ap_config.is_wpa3_supported = use_wpa3
+ req.contents.control_data.wifi_ap_config.listen_interval = listen_interval
+ req.contents.control_data.wifi_ap_config.band_mode = band_mode
resp = POINTER(CONTROL_COMMAND)
resp = None
resp = commands_map_py_to_c.wifi_connect_ap(req)
+ cleanup_ctrl_msg(req)
return ctrl_app_resp_callback(resp)
def test_sync_station_mode_get_info():
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
resp = POINTER(CONTROL_COMMAND)
resp = None
resp = commands_map_py_to_c.wifi_get_ap_config(req)
+
+ cleanup_ctrl_msg(req)
return ctrl_app_resp_callback(resp)
def test_sync_station_mode_disconnect():
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
resp = POINTER(CONTROL_COMMAND)
resp = None
resp = commands_map_py_to_c.wifi_disconnect_ap(req)
+
+ cleanup_ctrl_msg(req)
return ctrl_app_resp_callback(resp)
def test_sync_softap_mode_start(ssid, pwd, channel, sec_prot, max_conn, hide_ssid, bw, band_mode):
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
+ req.contents.control_data.wifi_softap_config.ssid = set_str(ssid)
+ req.contents.control_data.wifi_softap_config.pwd = set_str(str(pwd))
+ req.contents.control_data.wifi_softap_config.channel = channel
+ req.contents.control_data.wifi_softap_config.encryption_mode = sec_prot
+ req.contents.control_data.wifi_softap_config.max_connections = max_conn
+ req.contents.control_data.wifi_softap_config.ssid_hidden = hide_ssid
+ req.contents.control_data.wifi_softap_config.bandwidth = bw
+ req.contents.control_data.wifi_softap_config.band_mode = band_mode
resp = POINTER(CONTROL_COMMAND)
resp = None
- req.control_data.wifi_softap_config.ssid = set_str(ssid)
- req.control_data.wifi_softap_config.pwd = set_str(str(pwd))
- req.control_data.wifi_softap_config.channel = channel
- req.control_data.wifi_softap_config.encryption_mode = sec_prot
- req.control_data.wifi_softap_config.max_connections = max_conn
- req.control_data.wifi_softap_config.ssid_hidden = hide_ssid
- req.control_data.wifi_softap_config.bandwidth = bw
- req.control_data.wifi_softap_config.band_mode = band_mode
resp = commands_map_py_to_c.wifi_start_softap(req)
+
+ cleanup_ctrl_msg(req)
return ctrl_app_resp_callback(resp)
def test_sync_softap_mode_get_info():
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
resp = POINTER(CONTROL_COMMAND)
resp = None
resp = commands_map_py_to_c.wifi_get_softap_config(req)
+
+ cleanup_ctrl_msg(req)
return ctrl_app_resp_callback(resp)
+def test_sync_set_vendor_specific_ie(enable, data):
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
-def test_sync_set_vendor_specific_ie(enable,data):
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
- resp = POINTER(CONTROL_COMMAND)
- resp = None
+ # Allocate memory for the data
+ v_data = create_string_buffer(data.encode(), len(data))
+ if not v_data:
+ cleanup_ctrl_msg(req)
+ print("Failed to allocate memory for vendor data")
+ return FAILURE
- vendor_oui = bytearray()
- vendor_oui.append(VENDOR_OUI_0)
- vendor_oui.append(VENDOR_OUI_1)
- vendor_oui.append(VENDOR_OUI_2)
- vnd_ie_t = create_string_buffer(b"", len(data) + 1)
- vnd_ie_t.value = set_str(data)
print("Enable: " + str(enable) + " data: " + data)
- req.control_data.wifi_softap_vendor_ie.enable = enable
- req.control_data.wifi_softap_vendor_ie.type = WIFI_VND_IE_TYPE.WIFI_VND_IE_TYPE_BEACON.value
- req.control_data.wifi_softap_vendor_ie.idx = WIFI_VND_IE_ID.WIFI_VND_IE_ID_0.value
- req.control_data.wifi_softap_vendor_ie.vnd_ie.element_id = WIFI_VENDOR_IE_ELEMENT_ID
- req.control_data.wifi_softap_vendor_ie.vnd_ie.length = len(data) + 1 + OFFSET
- req.control_data.wifi_softap_vendor_ie.vnd_ie.vendor_oui = b'\x01\x02\x03'
- req.control_data.wifi_softap_vendor_ie.vnd_ie.vendor_oui_type = VENDOR_OUI_TYPE
- req.control_data.wifi_softap_vendor_ie.vnd_ie.payload = cast(vnd_ie_t, c_wchar_p)
-
- req.control_data.wifi_softap_vendor_ie.vnd_ie.payload_len = len(data)
+ req.contents.control_data.wifi_softap_vendor_ie.enable = enable
+ req.contents.control_data.wifi_softap_vendor_ie.type = WIFI_VND_IE_TYPE.WIFI_VND_IE_TYPE_BEACON.value
+ req.contents.control_data.wifi_softap_vendor_ie.idx = WIFI_VND_IE_ID.WIFI_VND_IE_ID_0.value
+ req.contents.control_data.wifi_softap_vendor_ie.vnd_ie.element_id = WIFI_VENDOR_IE_ELEMENT_ID
+ req.contents.control_data.wifi_softap_vendor_ie.vnd_ie.length = len(data) + OFFSET
+ req.contents.control_data.wifi_softap_vendor_ie.vnd_ie.vendor_oui[0] = VENDOR_OUI_0
+ req.contents.control_data.wifi_softap_vendor_ie.vnd_ie.vendor_oui[1] = VENDOR_OUI_1
+ req.contents.control_data.wifi_softap_vendor_ie.vnd_ie.vendor_oui[2] = VENDOR_OUI_2
+ req.contents.control_data.wifi_softap_vendor_ie.vnd_ie.vendor_oui_type = VENDOR_OUI_TYPE
+ req.contents.control_data.wifi_softap_vendor_ie.vnd_ie.payload = cast(v_data, POINTER(c_uint8))
+ req.contents.control_data.wifi_softap_vendor_ie.vnd_ie.payload_len = len(data)
+
+ # No free like this for create_string_buffer
+ #req.contents.free_buffer_func = commands_map_py_to_c.get_free_func()
+ #req.contents.free_buffer_handle = cast(v_data, c_void_p)
+ resp = POINTER(CONTROL_COMMAND)
+ resp = None
resp = commands_map_py_to_c.wifi_set_vendor_specific_ie(req)
+
+ cleanup_ctrl_msg(req)
return ctrl_app_resp_callback(resp)
def test_sync_softap_mode_connected_clients_info():
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
resp = POINTER(CONTROL_COMMAND)
resp = None
resp = commands_map_py_to_c.wifi_get_softap_connected_station_list(req)
+ cleanup_ctrl_msg(req)
return ctrl_app_resp_callback(resp)
def test_sync_softap_mode_stop():
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
resp = POINTER(CONTROL_COMMAND)
resp = None
resp = commands_map_py_to_c.wifi_stop_softap(req)
+ cleanup_ctrl_msg(req)
return ctrl_app_resp_callback(resp)
def test_sync_set_wifi_power_save_mode(psmode):
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
+ req.contents.control_data.wifi_power_save_mode.ps_mode = psmode
resp = POINTER(CONTROL_COMMAND)
resp = None
- req.control_data.wifi_ps.ps_mode = psmode
resp = commands_map_py_to_c.wifi_set_power_save_mode(req)
+ cleanup_ctrl_msg(req)
return ctrl_app_resp_callback(resp)
+def test_sync_set_wifi_power_save_mode_none():
+ return test_sync_set_wifi_power_save_mode(WIFI_PS_MODE.WIFI_PS_NONE.value)
+
+
def test_sync_set_wifi_power_save_mode_max():
return test_sync_set_wifi_power_save_mode(WIFI_PS_MODE.WIFI_PS_MAX_MODEM.value)
@@ -986,43 +1236,64 @@ def test_sync_set_wifi_power_save_mode_min():
def test_sync_get_wifi_power_save_mode():
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
resp = POINTER(CONTROL_COMMAND)
resp = None
resp = commands_map_py_to_c.wifi_get_power_save_mode(req)
+ cleanup_ctrl_msg(req)
return ctrl_app_resp_callback(resp)
def test_sync_wifi_set_max_tx_power(in_power):
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
+ req.contents.control_data.wifi_tx_power.power = in_power
resp = POINTER(CONTROL_COMMAND)
resp = None
- req.control_data.wifi_tx_power.power = in_power
resp = commands_map_py_to_c.wifi_set_max_tx_power(req)
+ cleanup_ctrl_msg(req)
return ctrl_app_resp_callback(resp)
def test_sync_wifi_get_curr_tx_power():
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
resp = POINTER(CONTROL_COMMAND)
resp = None
resp = commands_map_py_to_c.wifi_get_curr_tx_power(req)
+ cleanup_ctrl_msg(req)
return ctrl_app_resp_callback(resp)
def test_feature_config(feature, enable):
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
+ req.contents.control_data.feature_config.feature = feature
+ req.contents.control_data.feature_config.enable = enable
resp = POINTER(CONTROL_COMMAND)
resp = None
- req.control_data.feat_ena_disable.feature = feature
- req.control_data.feat_ena_disable.enable = enable
resp = commands_map_py_to_c.feature_config(req)
- return ctrl_app_resp_callback(resp)
+ cleanup_ctrl_msg(req)
+
+ if (feature == HOSTED_FEATURE.HOSTED_FEATURE_NETWORK_SPLIT.value):
+ if successful_response(resp):
+ ret = SUCCESS
+ else:
+ ret = FAILURE
+ cleanup_ctrl_msg(resp)
+ return ret
+ else:
+ return ctrl_app_resp_callback(resp)
def test_feature_enable_wifi():
return test_feature_config(HOSTED_FEATURE.HOSTED_FEATURE_WIFI.value, YES)
@@ -1036,60 +1307,93 @@ def test_feature_enable_bt():
def test_feature_disable_bt():
return test_feature_config(HOSTED_FEATURE.HOSTED_FEATURE_BLUETOOTH.value, NO)
+def is_network_split_on():
+ global g_is_network_split_on
+ global g_is_network_split_queried
+ if (g_is_network_split_queried == False):
+ g_is_network_split_on = test_feature_config(HOSTED_FEATURE.HOSTED_FEATURE_NETWORK_SPLIT.value, YES) == SUCCESS
+ g_is_network_split_queried = True
+
+ if g_is_network_split_on == False:
+ print("Network split is off")
+
+ return g_is_network_split_on
+
def test_get_fw_version():
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
resp = POINTER(CONTROL_COMMAND)
resp = None
resp = commands_map_py_to_c.get_fw_version(req)
+ cleanup_ctrl_msg(req)
+ if not resp:
+ print("Failed to get firmware version")
+ return FAILURE
return ctrl_app_resp_callback(resp)
def test_set_country_code(country, ieee80211d_enabled):
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
+ req.contents.control_data.country_code.country = country.encode('utf-8')
+ req.contents.control_data.country_code.ieee80211d_enabled = ieee80211d_enabled
resp = POINTER(CONTROL_COMMAND)
resp = None
- req.control_data.country_code.country = country.encode('utf-8')
- req.control_data.country_code.ieee80211d_enabled = ieee80211d_enabled
resp = commands_map_py_to_c.set_country_code(req)
+ cleanup_ctrl_msg(req)
return ctrl_app_resp_callback(resp)
def test_get_country_code():
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
resp = POINTER(CONTROL_COMMAND)
resp = None
resp = commands_map_py_to_c.get_country_code(req)
+ cleanup_ctrl_msg(req)
return ctrl_app_resp_callback(resp)
def test_sync_ota_begin():
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
resp = POINTER(CONTROL_COMMAND)
resp = None
resp = commands_map_py_to_c.ota_begin(req)
+ cleanup_ctrl_msg(req)
return ctrl_app_resp_callback(resp)
def test_sync_ota_write(ota_data, ota_data_len):
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
+ req.contents.control_data.ota_write.ota_data = ota_data
+ req.contents.control_data.ota_write.ota_data_len = ota_data_len
resp = POINTER(CONTROL_COMMAND)
resp = None
- req.control_data.ota_write.ota_data = ota_data
- req.control_data.ota_write.ota_data_len = ota_data_len
resp = commands_map_py_to_c.ota_write(req)
+ cleanup_ctrl_msg(req)
return ctrl_app_resp_callback(resp)
def test_sync_ota_end():
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
resp = POINTER(CONTROL_COMMAND)
resp = None
resp = commands_map_py_to_c.ota_end(req)
+ cleanup_ctrl_msg(req)
return ctrl_app_resp_callback(resp)
@@ -1130,11 +1434,321 @@ def test_sync_ota(image_URL):
def test_sync_config_heartbeat(enable, duration):
- req = CONTROL_COMMAND()
- CTRL_CMD_DEFAULT_REQ(req)
+ req = CTRL_CMD_DEFAULT_REQ()
+ if not req:
+ print("Failed to allocate memory for request")
+ return FAILURE
+ req.contents.control_data.e_heartbeat.enable = enable
+ req.contents.control_data.e_heartbeat.duration = duration
resp = POINTER(CONTROL_COMMAND)
resp = None
- req.control_data.e_heartbeat.enable = enable
- req.control_data.e_heartbeat.duration = duration
resp = commands_map_py_to_c.config_heartbeat(req)
+ cleanup_ctrl_msg(req)
return ctrl_app_resp_callback(resp)
+
+
+# Global variables for verification in demo3
+g_original_data = None
+g_original_data_len = 0
+g_verification_result = 0 # 0=not verified, 1=success, -1=failure
+
+# Function to set reference data for verification
+def custom_rpc_set_verification_reference(data, data_len):
+ global g_original_data, g_original_data_len, g_verification_result
+ g_original_data = data
+ g_original_data_len = data_len
+ g_verification_result = 0 # Reset result
+
+# Custom event handler to verify the data received in the event
+def custom_rpc_event_handler(app_event):
+ global g_original_data, g_original_data_len, g_verification_result
+
+ if (not app_event or
+ not app_event.contents or
+ bytes_to_int(app_event.contents.msg_type) != CTRL_MSGTYPE.CTRL_EVENT.value):
+ if (app_event):
+ print("Msg type is not event "+str(app_event.contents.msg_type))
+ cleanup_ctrl_msg(app_event)
+ return FAILURE
+
+ if app_event.contents.msg_id == CTRL_MSGID.CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG.value:
+ p_e = app_event.contents.control_data.custom_rpc_unserialised_data
+
+ # Process based on custom event ID
+ if p_e.custom_msg_id == CUSTOM_RPC_EVENT_ID.DEMO_ECHO_BACK_REQUEST.value:
+ print("[Demo 3] Received echo back event with " + str(p_e.data_len) + " bytes of data")
+
+ # Verify the data against our stored reference
+ if not g_original_data or not g_original_data_len:
+ print(" [Demo 3] Verification reference data not set!")
+ g_verification_result = -1
+ elif g_original_data_len != p_e.data_len:
+ print(" [Demo 3] Data length mismatch! Sent: " + str(g_original_data_len) +
+ ", Received: " + str(p_e.data_len))
+ g_verification_result = -1
+ else:
+ # Compare byte by byte
+ mismatch = False
+ send_data = g_original_data
+ recv_data = string_at(p_e.data, p_e.data_len)
+
+ for i in range(p_e.data_len):
+ #/* send_data[i] is a bytes object of length 1, so use send_data[i][0] */
+ #/* recv_data is a bytes object, so recv_data[i] is int */
+ if send_data[i][0] != recv_data[i]:
+ print("[Demo 2] Data mismatch at byte " + str(i) +
+ ": sent 0x" + format(send_data[i][0], '02x') +
+ ", received 0x" + format(recv_data[i], '02x'))
+ mismatch = True
+ g_verification_result = -1
+ break
+
+ if not mismatch:
+ print("[Demo 3] Verified success: (All Rx bytes in event) = (All Tx bytes in request)")
+ g_verification_result = 1
+ else:
+ print(" [Demo 3] Unhandled custom RPC event ID [" + str(p_e.custom_msg_id) +
+ "] with data length: " + str(p_e.data_len) + " bytes")
+ else:
+ print(" Unhandled base RPC message: " + str(app_event.contents.msg_id))
+
+ cleanup_ctrl_msg(app_event)
+ return SUCCESS
+
+def test_custom_rpc_demo3_request_echo_back_as_event():
+ """Send a custom RPC request and get echo back as event"""
+ global g_verification_result
+
+ # Register custom event handler
+ original_handler = commands_map_py_to_c.get_event_callback(
+ CTRL_MSGID.CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG.value)
+
+ if not original_handler:
+ print("[Demo 3] No original event handler registered for CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG")
+
+ unsubscribe_event_custom_rpc_unserialised_msg()
+
+ custom_rpc_event_cb = CTRL_CB(custom_rpc_event_handler)
+
+ if (CALLBACK_SET_SUCCESS != commands_map_py_to_c.set_event_callback(
+ CTRL_MSGID.CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG.value, custom_rpc_event_cb)):
+ print("Problem while replacing event callback for custom RPC unserialised msg")
+ return FAILURE
+
+ print("[Demo 3] Sending Custom RPC request to slave. Expecting ack response. " +
+ "The data sent should be echoed back as a custom RPC event")
+
+ # Create a byte stream with a specific pattern for verification
+ send_data_len = 4000
+ from ctypes import c_char
+ send_data = (c_char * send_data_len)()
+
+ for i in range(send_data_len):
+ send_data[i] = i*3 % 256
+
+ # Set reference data for verification in event handler
+ custom_rpc_set_verification_reference(send_data, send_data_len)
+
+ # Use a message ID that will trigger an event response
+ custom_msg_id = CUSTOM_RPC_REQ_ID.ECHO_BACK_AS_EVENT.value
+
+ status, recv_data, recv_data_len = FAILURE, None, 0
+
+ status, recv_data, recv_data_len = test_custom_rpc_unserialised_request(
+ custom_msg_id, send_data, send_data_len)
+
+ if status != SUCCESS:
+ print("[Demo 3] Failed to send custom RPC request")
+ # Clean up resources
+ if original_handler:
+ commands_map_py_to_c.set_event_callback(
+ CTRL_MSGID.CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG.value,
+ original_handler)
+ else:
+ commands_map_py_to_c.reset_event_callback(
+ CTRL_MSGID.CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG.value)
+ return FAILURE
+
+ # Wait for event to arrive
+ print("[Demo 3] Waiting for echo event from slave...")
+
+ # Wait for the event to arrive with a timeout
+ verification_timeout = 5 # seconds
+ start_time = time()
+ while g_verification_result == 0 and (time() - start_time) < verification_timeout:
+ sleep(0.1) # Small sleep to avoid CPU spinning
+
+ # Check verification result
+ if g_verification_result == 1:
+ print("[Demo 3] Verification successful!")
+ ret = SUCCESS
+ elif g_verification_result == -1:
+ print("[Demo 3] Verification failed!")
+ ret = FAILURE
+ else:
+ print("[Demo 3] Verification timeout - no event received within " +
+ str(verification_timeout) + " seconds")
+ ret = FAILURE
+
+ # Restore the original event handler and unsubscribe
+ if original_handler:
+ commands_map_py_to_c.set_event_callback(
+ CTRL_MSGID.CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG.value,
+ original_handler)
+ else:
+ commands_map_py_to_c.reset_event_callback(
+ CTRL_MSGID.CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG.value)
+ unsubscribe_event_custom_rpc_unserialised_msg()
+
+ # Reset global verification data
+ custom_rpc_set_verification_reference(None, 0)
+
+ print("[Demo 3] Demo completed!")
+
+ return ret
+
+def test_custom_rpc_unserialised_request(custom_msg_id, send_data, send_data_len):
+ #/* Send a custom RPC request and process the response. */
+ if not send_data or send_data_len <= 0:
+ print("send data seem invalid, ignoring request")
+ return FAILURE, None, 0
+
+ app_req = CTRL_CMD_DEFAULT_REQ()
+ if not app_req:
+ print("Failed to allocate memory for request")
+ return FAILURE, None, 0
+
+ app_req.contents.msg_id = CTRL_MSGID.CTRL_REQ_CUSTOM_RPC_UNSERIALISED.value
+ app_req.contents.control_data.custom_rpc_unserialised_data.custom_msg_id = custom_msg_id
+
+ send_data_ptr = cast(send_data, c_void_p)
+ app_req.contents.control_data.custom_rpc_unserialised_data.data_len = send_data_len
+ app_req.contents.control_data.custom_rpc_unserialised_data.data = send_data_ptr
+
+ resp = commands_map_py_to_c.send_custom_rpc_unserialised_req_to_slave(app_req)
+
+ cleanup_ctrl_msg(app_req)
+ if not resp:
+ print("Failed to get response from slave")
+ return FAILURE, None, 0
+
+ status = FAILURE
+ recv_data = None
+ recv_data_len = 0
+
+ if successful_response(resp):
+ status = SUCCESS
+ #print("success response for " + str(resp.contents.msg_id))
+ if (resp.contents.msg_id != CTRL_MSGID.CTRL_RESP_CUSTOM_RPC_UNSERIALISED.value):
+ print("response received, unexpected response msg id" + str(resp.contents.msg_id))
+ cleanup_ctrl_msg(resp)
+ return FAILURE, None, 0
+ else:
+ print("Failure response")
+ cleanup_ctrl_msg(resp)
+ return FAILURE, None, 0
+
+ rx_custom_id = resp.contents.control_data.custom_rpc_unserialised_data.custom_msg_id
+ data_ptr = resp.contents.control_data.custom_rpc_unserialised_data.data
+ data_len = resp.contents.control_data.custom_rpc_unserialised_data.data_len
+
+ if not data_ptr or data_len == 0:
+ print(">> Rx Ack for custom_data_id: " + str(rx_custom_id))
+ else:
+ print(">> Rx Resp for custom_data_id: " + str(rx_custom_id) +
+ " with data_len: "+ str(resp.contents.control_data.custom_rpc_unserialised_data.data_len))
+
+ from ctypes import string_at
+ recv_data = string_at(data_ptr, data_len)
+ recv_data_len = data_len
+
+ if data_ptr and resp.contents.free_buffer_func:
+ free_func = resp.contents.free_buffer_func
+ free_func(data_ptr)
+ resp.contents.free_buffer_handle = None
+
+ cleanup_ctrl_msg(resp)
+
+ return status, recv_data, recv_data_len
+
+
+def test_custom_rpc_demo1_request_only_ack():
+ #/* Send a custom RPC request with only acknowledgement */
+ print("[Demo 1] Sending packed RPC request. No response expected. Only Ack expected.")
+
+ send_data_len = 4000
+ from ctypes import c_char
+ send_data = (c_char * send_data_len)()
+
+ for i in range(send_data_len):
+ send_data[i] = (i * 2) % 256
+
+ custom_msg_id = CUSTOM_RPC_REQ_ID.ONLY_ACK.value
+
+ status, recv_data, recv_data_len, recv_data_free_func = test_custom_rpc_unserialised_request(
+ custom_msg_id, send_data, send_data_len)
+
+ if status != SUCCESS:
+ print("[Demo 1] Failed to send custom RPC request")
+ return FAILURE
+
+ print("[Demo 1] Slave Ack for RPC request received")
+ return SUCCESS
+
+
+def test_custom_rpc_demo2_request_echo_back_as_response():
+ # /* Send a custom RPC request and get echo back as response */
+ print("[Demo 2] Sending a demo byte buffer to slave, expecting echo back as response.")
+
+ send_data_len = 4000
+ from ctypes import c_char
+ send_data = (c_char * send_data_len)()
+
+ for i in range(send_data_len):
+ send_data[i] = i % 256
+
+ custom_msg_id = CUSTOM_RPC_REQ_ID.ECHO_BACK_RESPONSE.value
+
+ status, recv_data, recv_data_len = FAILURE, None, 0
+
+ try:
+ status, recv_data, recv_data_len = test_custom_rpc_unserialised_request(
+ custom_msg_id, send_data, send_data_len)
+ except:
+ traceback.print_exc()
+
+ if status != SUCCESS:
+ print("[Demo 2] Failed to send custom RPC request")
+ return FAILURE
+
+ print("[Demo 2] Received " + str(recv_data_len) + " bytes of data back as response")
+
+ ret = SUCCESS
+
+ try:
+ if recv_data_len != send_data_len:
+ print("[Demo 2] Data length mismatch! Sent: " + str(send_data_len) +
+ ", Received: " + str(recv_data_len))
+ ret = FAILURE
+ else:
+ print("[Demo 2] Comparing received data with the one sent in request:")
+ mismatch = False
+ for i in range(send_data_len):
+ #/* send_data[i] is a bytes object of length 1, so use send_data[i][0] */
+ #/* recv_data is a bytes object, so recv_data[i] is int */
+ if send_data[i][0] != recv_data[i]:
+ print("[Demo 2] Data mismatch at byte " + str(i) +
+ ": sent 0x" + format(send_data[i][0], '02x') +
+ ", received 0x" + format(recv_data[i], '02x'))
+ mismatch = True
+ break
+
+ if not mismatch:
+ print("[Demo 2] Data verification successful - All " +
+ str(send_data_len) + " TX bytes = All " + str(recv_data_len) + " RX bytes!")
+ else:
+ ret = FAILURE
+ except:
+ traceback.print_exc()
+
+ return ret
diff --git a/esp_hosted_fg/host/linux/host_control/python_support/commands_map_py_to_c.py b/esp_hosted_fg/host/linux/host_control/python_support/commands_map_py_to_c.py
index ad4bb8a47d..86f977a472 100644
--- a/esp_hosted_fg/host/linux/host_control/python_support/commands_map_py_to_c.py
+++ b/esp_hosted_fg/host/linux/host_control/python_support/commands_map_py_to_c.py
@@ -110,20 +110,15 @@
hosted_free = commands_lib.hosted_free
hosted_free.restype = None
-create_socket = commands_lib.create_socket
-create_socket.restype = c_int
+get_dhcp_dns_status = commands_lib.get_dhcp_dns_status
+get_dhcp_dns_status.restype = POINTER(CONTROL_COMMAND)
-close_socket = commands_lib.close_socket
-close_socket.restype = c_int
+set_dhcp_dns_status = commands_lib.set_dhcp_dns_status
+set_dhcp_dns_status.restype = POINTER(CONTROL_COMMAND)
-interface_up = commands_lib.interface_up
-interface_up.restype = c_int
+send_custom_rpc_unserialised_req_to_slave = commands_lib.send_custom_rpc_unserialised_req_to_slave
+send_custom_rpc_unserialised_req_to_slave.restype = POINTER(CONTROL_COMMAND)
-interface_down = commands_lib.interface_down
-interface_down.restype = c_int
-
-set_hw_addr = commands_lib.set_hw_addr
-set_hw_addr.restype = c_int
set_event_callback = commands_lib.set_event_callback
set_event_callback.restype = c_int
@@ -133,3 +128,10 @@
reset_event_callback = commands_lib.reset_event_callback
reset_event_callback.restype = c_int
+
+hosted_malloc = commands_lib.hosted_malloc
+hosted_malloc.restype = c_void_p
+
+get_event_callback = commands_lib.get_event_callback
+get_event_callback.restype = CTRL_CB
+get_event_callback.argtypes = [c_int]
diff --git a/esp_hosted_fg/host/linux/host_control/python_support/hosted_py_header.py b/esp_hosted_fg/host/linux/host_control/python_support/hosted_py_header.py
index 6fc3a2dfe1..1d1add318d 100644
--- a/esp_hosted_fg/host/linux/host_control/python_support/hosted_py_header.py
+++ b/esp_hosted_fg/host/linux/host_control/python_support/hosted_py_header.py
@@ -52,6 +52,17 @@
WIFI_BAND_MODE_5G_ONLY = 2
WIFI_BAND_MODE_AUTO = 3
+# Custom RPC request IDs
+class CUSTOM_RPC_REQ_ID(Enum):
+ ONLY_ACK = 1
+ ECHO_BACK_RESPONSE = 2
+ ECHO_BACK_AS_EVENT = 3
+
+# Custom RPC event IDs
+class CUSTOM_RPC_EVENT_ID(Enum):
+ DEMO_ECHO_BACK_REQUEST = 100
+ DEMO_SIMPLE_EVENT = 101
+
class WIFI_MODE_E(Enum):
WIFI_MODE_NONE = 0
WIFI_MODE_STA = 1
@@ -78,6 +89,7 @@ class WIFI_BW(Enum):
class WIFI_PS_MODE(Enum):
+ WIFI_PS_NONE = 0
WIFI_PS_MIN_MODEM = 1
WIFI_PS_MAX_MODEM = 2
WIFI_PS_INVALID = 3
@@ -99,6 +111,7 @@ class HOSTED_FEATURE(Enum):
HOSTED_FEATURE_INVALID = 0
HOSTED_FEATURE_WIFI = 1
HOSTED_FEATURE_BLUETOOTH = 2
+ HOSTED_FEATURE_NETWORK_SPLIT = 3
class CTRL_ERR(Enum):
CTRL_ERR_NOT_CONNECTED = 1
@@ -154,7 +167,10 @@ class CTRL_MSGID(Enum):
CTRL_REQ_GET_FW_VERSION = 123
CTRL_REQ_SET_COUNTRY_CODE = 124
CTRL_REQ_GET_COUNTRY_CODE = 125
- CTRL_REQ_MAX = 126
+ CTRL_REQ_SET_DhcpDnsStatus = 126
+ CTRL_REQ_GET_DhcpDnsStatus = 127
+ CTRL_REQ_CUSTOM_RPC_UNSERIALISED = 128
+ CTRL_REQ_MAX = 129
CTRL_RESP_BASE = 200
CTRL_RESP_GET_MAC_ADDR = 201
CTRL_RESP_SET_MAC_ADDRESS = 202
@@ -181,7 +197,10 @@ class CTRL_MSGID(Enum):
CTRL_RESP_GET_FW_VERSION = 223
CTRL_RESP_SET_COUNTRY_CODE = 224
CTRL_RESP_GET_COUNTRY_CODE = 225
- CTRL_RESP_MAX = 226
+ CTRL_RESP_SET_DHCP_DNS_STATUS = 226
+ CTRL_RESP_GET_DHCP_DNS_STATUS = 227
+ CTRL_RESP_CUSTOM_RPC_UNSERIALISED = 228
+ CTRL_RESP_MAX = 229
CTRL_EVENT_BASE = 300
CTRL_EVENT_ESP_INIT = 301
CTRL_EVENT_HEARTBEAT = 302
@@ -189,7 +208,9 @@ class CTRL_MSGID(Enum):
CTRL_EVENT_STATION_DISCONNECT_FROM_ESP_SOFTAP = 304
CTRL_EVENT_STATION_CONNECTED_TO_AP = 305
CTRL_EVENT_STATION_CONNECTED_TO_ESP_SOFTAP = 306
- CTRL_EVENT_MAX = 307
+ CTRL_EVENT_DHCP_DNS_STATUS = 307
+ CTRL_EVENT_CUSTOM_RPC_UNSERIALISED_MSG = 308
+ CTRL_EVENT_MAX = 309
class STA_CONFIG(Structure):
@@ -334,27 +355,45 @@ class EVENT_STATION_DISCONN_FROM_SOFTAP(Structure):
("is_mesh_child", c_int),
("reason", c_uint)]
+class EVENT_DHCP_DNS_STATUS(Structure):
+ _fields_ = [("iface", c_int),
+ ("net_link_up", c_int),
+ ("dhcp_up", c_int),
+ ("dhcp_ip", c_char * 64),
+ ("dhcp_nm", c_char * 64),
+ ("dhcp_gw", c_char * 64),
+ ("dns_up", c_int),
+ ("dns_ip", c_char * 64),
+ ("dns_type", c_int)]
+
+class CUSTOM_RPC_UNSERIALISED_MSG(Structure):
+ _fields_ = [("custom_msg_id", c_uint32),
+ ("data_len", c_uint16),
+ ("free_func", c_void_p),
+ ("data", c_void_p)]
class CONTROL_DATA(Union):
_fields_ = [("resp_event_status", c_int),
("wifi_mac", WIFI_MAC),
("wifi_mode", WIFI_MODE),
- ("wifi_ap_scan", WIFI_AP_SCAN_LIST),
+ ("wifi_ap_scan_list", WIFI_AP_SCAN_LIST),
("wifi_ap_config", STA_CONFIG),
("wifi_softap_config", SOFTAP_CONFIG),
("wifi_softap_vendor_ie", WIFI_SOFTAP_VENDOR_IE),
- ("wifi_softap_con_sta", WIFI_CONNECTED_STATIONS_LIST),
- ("wifi_ps", WIFI_POWER_SAVE_MODE),
+ ("wifi_connected_stations_list", WIFI_CONNECTED_STATIONS_LIST),
+ ("wifi_power_save_mode", WIFI_POWER_SAVE_MODE),
("ota_write", OTA_WRITE),
- ("feat_ena_disable", FEATURE_CONFIG),
("wifi_tx_power", WIFI_TX_POWER),
+ ("feature_config", FEATURE_CONFIG),
("fw_version", FW_VERSION),
("country_code", COUNTRY_CODE),
("e_heartbeat", EVENT_HEARTBEAT),
("e_sta_conn", EVENT_STATION_CONN_TO_AP),
("e_sta_disconn", EVENT_STATION_DISCONN_FROM_AP),
("e_softap_sta_conn", EVENT_STATION_CONN_TO_SOFTAP),
- ("e_softap_sta_disconn", EVENT_STATION_DISCONN_FROM_SOFTAP)]
+ ("e_softap_sta_disconn", EVENT_STATION_DISCONN_FROM_SOFTAP),
+ ("e_dhcp_dns_status", EVENT_DHCP_DNS_STATUS),
+ ("custom_rpc_unserialised_data", CUSTOM_RPC_UNSERIALISED_MSG)]
class CONTROL_COMMAND(Structure):
diff --git a/esp_hosted_fg/host/linux/host_control/python_support/py_parse/cmds.py b/esp_hosted_fg/host/linux/host_control/python_support/py_parse/cmds.py
index 48d706d2f7..930a886444 100644
--- a/esp_hosted_fg/host/linux/host_control/python_support/py_parse/cmds.py
+++ b/esp_hosted_fg/host/linux/host_control/python_support/py_parse/cmds.py
@@ -104,7 +104,7 @@ def get_available_ap(self):
return self
- def connect_ap(self, ssid : str = "", pwd : str = "", bssid : str = "", use_wpa3 : bool = False, listen_interval : int = 3, set_dhcp : bool = True, band_mode: int = WIFI_BAND_MODE_AUTO):
+ def connect_ap(self, ssid : str = "", pwd : str = "", bssid : str = "", use_wpa3 : bool = False, listen_interval : int = 3, band_mode: int = WIFI_BAND_MODE_AUTO):
"""Connect to AP (Wi-Fi router or hotspot)
Args:
@@ -113,7 +113,6 @@ def connect_ap(self, ssid : str = "", pwd : str = "", bssid : str = "", use_wpa3
bssid(str, optional): O | MAC addr of AP (useful when multiple AP have same SSID) | Default: ''
use_wpa3(bool, optional): O | Use wpa3 security protocol | Default: False
listen_interval(int, optional) : O | Number of AP beacons station will sleep | Default:3
- set_dhcp(bool, optional): O | Request DHCP | Default: True
band_mode(int, optional): O | Connect on 2.4G (1) or 5G (2) band, or Auto select (3) | Default:3
Returns:
@@ -124,7 +123,7 @@ def connect_ap(self, ssid : str = "", pwd : str = "", bssid : str = "", use_wpa3
self.out = "Missing param " + "--ssid"
return self
- self.out = process_connect_ap(ssid, pwd, bssid, use_wpa3, listen_interval, set_dhcp, band_mode)
+ self.out = process_connect_ap(ssid, pwd, bssid, use_wpa3, listen_interval, band_mode)
return self
@@ -246,7 +245,7 @@ def set_wifi_power_save(self, mode : str = "max"):
"""Set Wi-Fi power save
Args:
- mode(str,optional): O | power save mode ['max','min'] | Default: 'max'
+ mode(str,optional): O | power save mode ['none','min','max'] | Default: 'max'
Returns:
ctrl_cmd: ctrl_cmd object
@@ -432,7 +431,7 @@ def subscribe_event(self, event: str = ""):
"""Subscribe event to get notifications
Args:
- event(str,mandatory): M | Values ['esp_init' | 'heartbeat' | 'sta_connected_to_ap' | 'sta_disconnect_from_ap' | 'sta_connected_to_softap' | 'sta_disconnect_from_softap' | 'all' ]
+ event(str,mandatory): M | Values ['esp_init' | 'heartbeat' | 'sta_connected' | 'sta_disconnected' | 'softap_sta_connected' | 'softap_sta_disconnected' | 'dhcp_dns_status' | 'custom_packed_event' | 'all' ]
Returns:
ctrl_cmd: ctrl_cmd object
@@ -450,7 +449,7 @@ def unsubscribe_event(self, event: str = ""):
"""Unsubscribe event to get notifications
Args:
- event(str,mandatory): M | Values ['esp_init' | 'heartbeat' | 'sta_disconnect_from_ap' | 'sta_disconnect_from_softap' | 'all' ]
+ event(str,mandatory): M | Values ['esp_init' | 'heartbeat' | 'sta_connected' | 'sta_disconnected' | 'softap_sta_connected' | 'softap_sta_disconnected' | 'dhcp_dns_status' | 'custom_packed_event' | 'all' ]
Returns:
ctrl_cmd: ctrl_cmd object
@@ -462,3 +461,38 @@ def unsubscribe_event(self, event: str = ""):
self.out = process_unsubscribe_event(event)
return self
+
+ def custom_rpc_demo1(self):
+ """Send a custom RPC request with only acknowledgement (No echo back response)
+
+ This demo shows how to send a custom RPC request that expects only an acknowledgement.
+ No specific data is expected in response.
+
+ Returns:
+ success/failure: Result of the operation
+ """
+ return process_custom_rpc_demo1()
+
+ def custom_rpc_demo2(self):
+ """Send a custom RPC request and get echo back as response
+
+ This demo shows how to send a custom RPC request with data
+ and receive an echo back response. The response is verified to be
+ the same as the sent data.
+
+ Returns:
+ success/failure: Result of the operation
+ """
+ return process_custom_rpc_demo2()
+
+ def custom_rpc_demo3(self):
+ """Send a custom RPC request and get echo back as event
+
+ This demo shows how to send a custom RPC request with data
+ and receive an echo back as an event. The event data is verified
+ in the event handler.
+
+ Returns:
+ success/failure: Result of the operation
+ """
+ return process_custom_rpc_demo3()
diff --git a/esp_hosted_fg/host/linux/host_control/python_support/py_parse/nw_helper_func.py b/esp_hosted_fg/host/linux/host_control/python_support/py_parse/nw_helper_func.py
new file mode 100644
index 0000000000..d4cc70a54e
--- /dev/null
+++ b/esp_hosted_fg/host/linux/host_control/python_support/py_parse/nw_helper_func.py
@@ -0,0 +1,483 @@
+import os
+import socket
+import re
+from hosted_py_header import *
+
+STA_INTERFACE = "ethsta0"
+AP_INTERFACE = "ethap0"
+MAC_ADDR_LENGTH = 18
+SUCCESS = 0
+FAILURE = -1
+
+MAC_SIZE_BYTES = 6
+MIN_MAC_STR_LEN = 17
+
+# Utility functions for MAC address handling
+nw_debug_logs = 0
+
+def mac_bytes_to_str(mac_bytes):
+ if isinstance(mac_bytes, str):
+ return mac_bytes
+ if hasattr(mac_bytes, 'value'):
+ mac_bytes = mac_bytes.value
+ mac_bytes = bytes(mac_bytes).rstrip(b'\x00')
+ if len(mac_bytes) == 6:
+ return ':'.join(f'{b:02x}' for b in mac_bytes)
+ elif len(mac_bytes) == 17:
+ return mac_bytes.decode('utf-8', errors='ignore').rstrip('\x00')
+ else:
+ return mac_bytes.hex(':')
+
+def mac_str_to_bytes(mac_str):
+ print("mac_str" + mac_str)
+ if isinstance(mac_str, bytes):
+ return mac_str
+ mac_str = mac_str.replace('-', ':').lower()
+ if ':' in mac_str:
+ return bytes(int(b, 16) for b in mac_str.split(':'))
+ else:
+ return bytes.fromhex(mac_str)
+
+def is_valid_mac_bytes(mac_bytes):
+ if isinstance(mac_bytes, str):
+ mac_bytes = mac_bytes.encode()
+ mac_bytes = bytes(mac_bytes).rstrip(b'\x00')
+ # Accept 6-byte binary or 17-byte ASCII MAC
+ if len(mac_bytes) == 6 and any(mac_bytes):
+ return True
+ if len(mac_bytes) == 17:
+ try:
+ # Try to parse as ASCII MAC
+ s = mac_bytes.decode('utf-8')
+ parts = s.split(':')
+ if len(parts) == 6 and all(len(p) == 2 for p in parts):
+ return True
+ except Exception:
+ return False
+ return False
+
+# SoftAP commands
+# os_set_mac = "sudo ifconfig ethsta0 hw ether "
+# os_ifup_cmd = "sudo ifconfig ethsta0 up"
+# os_dhcp_up = "sudo dhclient ethsta0 -v"
+
+#os_run_dhcp_server='sudo bash ./run_dhcp_server.sh'
+#os_ifup_softap_cmd = "sudo ifconfig ethap0 up 192.168.4.5"
+#os_ifdown_softap_cmd = "sudo ifconfig ethap0 down"
+
+os_softap_static_ip = "192.168.4.5"
+os_softap_netmask = "255.255.255.0"
+os_softap_gateway = "192.168.4.1"
+
+g_run_dhcp_on_station_connected = True
+g_stop_dhclient_on_disconnected = True
+g_run_dhcp_server_after_softap_up = True
+g_stop_dhcp_server_after_softap_down = True
+
+# HCI commands
+down_hci_instance_cmd = "sudo hciconfig | grep 'Bus: SDIO\\| Bus: UART\\| Bus: SPI' | awk -F: '{print $1}' | xargs -I{} sudo hciconfig {} down"
+reset_hci_instance_cmd = "sudo hciconfig | grep 'Bus: SDIO\\| Bus: UART\\| Bus: SPI' | awk -F: '{print $1}' | xargs -I{} sudo hciconfig {} reset"
+
+
+class NetworkInfo:
+ def __init__(self, mac_addr=b"", ip_addr="", netmask="", gateway="", dns_addr="", ip_valid=0, dns_valid=0, network_up=0):
+ self.mac_addr = mac_addr # Always store as bytes
+ self.ip_addr = ip_addr
+ self.netmask = netmask
+ self.gateway = gateway
+ self.dns_addr = dns_addr
+ self.ip_valid = ip_valid
+ self.dns_valid = dns_valid
+ self.network_up = network_up
+
+g_sta_network_info = NetworkInfo()
+g_ap_network_info = NetworkInfo()
+
+def convert_mac_to_bytes(mac_str):
+ return mac_str_to_bytes(mac_str)
+
+def set_hw_addr(iface, mac):
+ mac_bytes = mac_str_to_bytes(mac) if isinstance(mac, str) else bytes(mac)
+ if not is_valid_mac_bytes(mac_bytes):
+ return FAILURE
+ if iface == STA_INTERFACE:
+ g_sta_network_info.mac_addr = mac_bytes
+ elif iface == AP_INTERFACE:
+ g_ap_network_info.mac_addr = mac_bytes
+
+ # Use ip link set dev address (as string)
+ mac_str = mac_bytes_to_str(mac_bytes)
+ ret = os.system(f"ip link set dev {iface} address {mac_str}")
+ return SUCCESS if ret == 0 else FAILURE
+
+def interface_up(iface):
+ if iface == STA_INTERFACE:
+ g_sta_network_info.network_up = 1
+ elif iface == AP_INTERFACE:
+ g_ap_network_info.network_up = 1
+
+ # Up interface
+ ret = os.system(f"ip link set dev {iface} up")
+ return SUCCESS if ret == 0 else FAILURE
+
+def interface_down(iface):
+ if iface == STA_INTERFACE:
+ g_sta_network_info.network_up = 0
+ elif iface == AP_INTERFACE:
+ g_ap_network_info.network_up = 0
+
+ # Down interface
+ ret = os.system(f"ip link set dev {iface} down")
+ return SUCCESS if ret == 0 else FAILURE
+
+def set_network_static_ip(iface, ip, netmask, gateway):
+ if iface == STA_INTERFACE:
+ g_sta_network_info.ip_addr = ip
+ g_sta_network_info.netmask = netmask
+ g_sta_network_info.gateway = gateway
+ elif iface == AP_INTERFACE:
+ g_ap_network_info.ip_addr = ip
+ g_ap_network_info.netmask = netmask
+ g_ap_network_info.gateway = gateway
+
+ # Set IP and netmask
+ ret1 = os.system(f"ip addr flush dev {iface} > /dev/null 2>&1")
+ ret2 = os.system(f"ip addr add {ip}/{netmask} dev {iface} > /dev/null 2>&1")
+
+ # Set gateway
+ ret3 = os.system(f"ip route add default via {gateway} dev {iface} > /dev/null 2>&1")
+
+ if ret1:
+ print("Failed to execute: " + f"ip addr flush dev {iface}")
+ elif ret2:
+ print("Failed to execute: " + f"ip addr add {ip}/{netmask} dev {iface}")
+ elif ret3:
+ print("Failed to execute: " + f"ip route add default via {gateway} dev {iface}")
+ else:
+ pass
+
+ if ret1 == 0 and ret2 == 0:
+ return SUCCESS
+ return FAILURE
+
+def add_default_gateway(iface):
+ if iface == STA_INTERFACE:
+ gateway = g_sta_network_info.gateway
+ elif iface == AP_INTERFACE:
+ gateway = g_ap_network_info.gateway
+ if not gateway:
+ return FAILURE
+ ret = os.system(f"ip route add default via {gateway} > /dev/null 2>&1")
+ return SUCCESS if ret == 0 else FAILURE
+
+def remove_default_gateway(iface):
+ if iface == STA_INTERFACE:
+ gateway = g_sta_network_info.gateway
+ elif iface == AP_INTERFACE:
+ gateway = g_ap_network_info.gateway
+ if not gateway:
+ return FAILURE
+ ret = os.system(f"ip route del default via {gateway} > /dev/null 2>&1")
+ return SUCCESS if ret == 0 else FAILURE
+
+def add_dns(iface):
+ if iface == STA_INTERFACE:
+ dns = g_sta_network_info.dns_addr
+ elif iface == AP_INTERFACE:
+ dns = g_ap_network_info.dns_addr
+ if not dns:
+ return FAILURE
+ try:
+ with open("/etc/resolv.conf", "a") as f:
+ f.write(f"nameserver {dns}\n")
+ return SUCCESS
+ except Exception:
+ return FAILURE
+
+def remove_dns(iface):
+ if iface == STA_INTERFACE:
+ dns = g_sta_network_info.dns_addr
+ elif iface == AP_INTERFACE:
+ dns = g_ap_network_info.dns_addr
+ if not dns:
+ return FAILURE
+ try:
+ with open("/etc/resolv.conf", "r") as f:
+ lines = f.readlines()
+ with open("/etc/resolv.conf", "w") as f:
+ for line in lines:
+ if line.strip() != f"nameserver {dns}":
+ f.write(line)
+ return SUCCESS
+ except Exception:
+ return FAILURE
+
+def update_host_network_port_range(port_start, port_end):
+ try:
+ found = False
+ lines = []
+ with open("/etc/sysctl.conf", "r") as f:
+ for line in f:
+ if "net.ipv4.ip_local_port_range" in line:
+ found = True
+ lines.append(f"net.ipv4.ip_local_port_range = {port_start} {port_end}\n")
+ else:
+ lines.append(line)
+ if not found:
+ lines.append(f"net.ipv4.ip_local_port_range = {port_start} {port_end}\n")
+ with open("/etc/sysctl.conf", "w") as f:
+ f.writelines(lines)
+ os.system("sysctl -p")
+ return SUCCESS
+ except Exception:
+ return FAILURE
+
+
+def clear_host_network_port_range():
+ try:
+ found = False
+ lines = []
+ with open("/etc/sysctl.conf", "r") as f:
+ for line in f:
+ if "net.ipv4.ip_local_port_range" in line:
+ found = True
+ else:
+ lines.append(line)
+ if found:
+ with open("/etc/sysctl.conf", "w") as f:
+ f.writelines(lines)
+ os.system("sysctl -p")
+ return SUCCESS
+ except Exception:
+ return FAILURE
+
+
+def up_sta_netdev__with_static_ip_dns_route(static_ip, netmask, gateway, dns):
+ g_sta_network_info.ip_addr = static_ip
+ g_sta_network_info.netmask = netmask
+ g_sta_network_info.gateway = gateway
+ g_sta_network_info.dns_addr = dns
+ g_sta_network_info.ip_valid = 1
+ g_sta_network_info.dns_valid = 1
+ g_sta_network_info.network_up = 1
+
+ if not g_sta_network_info.ip_valid or not g_sta_network_info.dns_valid:
+ print("Invalid STA IP [" + g_sta_network_info.ip_addr + "] or DNS [" + g_sta_network_info.dns_addr + "]")
+ return FAILURE
+
+ if not g_sta_network_info.network_up:
+ print("Network is not up" + g_sta_network_info.network_up)
+ return FAILURE
+
+ if up_sta_netdev() != SUCCESS:
+ return FAILURE
+
+ # Set static IP
+
+ if set_network_static_ip(STA_INTERFACE, g_sta_network_info.ip_addr, g_sta_network_info.netmask, g_sta_network_info.gateway) == FAILURE:
+ print("Failed to set static IP[" + g_sta_network_info.ip_addr + "] NM[" + g_sta_network_info.netmask + "] GW [" + g_sta_network_info.gateway +"]")
+ return FAILURE
+
+ # Add default gateway
+ if add_default_gateway(STA_INTERFACE) == FAILURE:
+ if nw_debug_logs:
+ print("Failed to add default gateway" + g_sta_network_info.gateway)
+
+ # Add DNS
+ if add_dns(STA_INTERFACE) == FAILURE:
+ if nw_debug_logs:
+ print("Failed to add DNS" + g_sta_network_info.dns_addr)
+
+ return SUCCESS
+
+def up_sta_netdev():
+ if not g_sta_network_info:
+ print("Network info is not valid" + g_sta_network_info)
+ return FAILURE
+
+ if not is_valid_mac_bytes(g_sta_network_info.mac_addr):
+ print("MAC address is not valid (bytes):" + mac_bytes_to_str(g_sta_network_info.mac_addr))
+ return FAILURE
+
+ if set_hw_addr(STA_INTERFACE, g_sta_network_info.mac_addr) == FAILURE:
+ print("Failed to set MAC address" + mac_bytes_to_str(g_sta_network_info.mac_addr))
+ return FAILURE
+
+ if interface_up(STA_INTERFACE) == FAILURE:
+ print("Failed to up interface" + STA_INTERFACE)
+ return FAILURE
+ g_sta_network_info.network_up = 1
+ return SUCCESS
+
+def set_mac_addr(mac, iface=STA_INTERFACE):
+ mac_bytes = mac_str_to_bytes(mac) if isinstance(mac, str) else bytes(mac)
+ if iface == STA_INTERFACE:
+ g_sta_network_info.mac_addr = mac_bytes
+ elif iface == AP_INTERFACE:
+ g_ap_network_info.mac_addr = mac_bytes
+ return set_hw_addr(iface, mac_bytes)
+
+def get_printable_mac_addr(mode):
+ if mode == "station":
+ return mac_bytes_to_str(g_sta_network_info.mac_addr)
+ elif mode == "softap":
+ return mac_bytes_to_str(g_ap_network_info.mac_addr)
+ return None
+
+def down_sta_netdev():
+ # Remove DNS
+ if remove_dns(STA_INTERFACE) == FAILURE:
+ if nw_debug_logs:
+ print("Failed to remove DNS" + g_sta_network_info.dns_addr)
+
+ # Remove default gateway
+ if remove_default_gateway(STA_INTERFACE) == FAILURE:
+ if nw_debug_logs:
+ print("Failed to remove default gateway" + g_sta_network_info.gateway)
+
+ # Down interface
+ if interface_down(STA_INTERFACE) == FAILURE:
+ print("Failed to down interface" + STA_INTERFACE)
+ return FAILURE
+ g_sta_network_info.network_up = 0
+ return SUCCESS
+
+def up_softap_netdev():
+ g_ap_network_info.ip_addr = os_softap_static_ip
+ g_ap_network_info.netmask = os_softap_netmask
+ g_ap_network_info.gateway = os_softap_gateway
+
+ g_ap_network_info.ip_valid = 1
+ g_ap_network_info.dns_valid = 1
+ g_ap_network_info.network_up = 1
+
+ if not g_ap_network_info.ip_valid or not g_ap_network_info.dns_valid:
+ print("Invalid AP IP [" + g_ap_network_info.ip_addr + "] or DNS [" + g_ap_network_info.dns_addr + "]")
+ return FAILURE
+
+ if not g_ap_network_info.network_up:
+ print("AP Network is not up" + g_ap_network_info.network_up)
+ return FAILURE
+
+ if not is_valid_mac_bytes(g_ap_network_info.mac_addr):
+ print("AP MAC address is not valid (bytes):" + mac_bytes_to_str(g_ap_network_info.mac_addr))
+ return FAILURE
+
+ # Set MAC address
+ if set_hw_addr(AP_INTERFACE, g_ap_network_info.mac_addr) == FAILURE:
+ print("Failed to set AP MAC address" + mac_bytes_to_str(g_ap_network_info.mac_addr))
+ return FAILURE
+
+ # Up interface
+ if interface_up(AP_INTERFACE) == FAILURE:
+ print("Failed to up AP interface" + AP_INTERFACE)
+ return FAILURE
+ # Set static IP
+ if set_network_static_ip(AP_INTERFACE, g_ap_network_info.ip_addr, g_ap_network_info.netmask, g_ap_network_info.gateway) == FAILURE:
+ print("Failed to set static AP IP[" + g_ap_network_info.ip_addr + "] NM[" + g_ap_network_info.netmask + "] GW [" +g_ap_network_info.gateway +"]")
+ return FAILURE
+
+ g_ap_network_info.network_up = 1
+ return SUCCESS
+
+def down_softap_netdev():
+ if not g_ap_network_info:
+ print("AP Network info is not valid" + g_ap_network_info)
+ return FAILURE
+
+ if not g_ap_network_info.network_up:
+ print("AP Network is not up" + g_ap_network_info.network_up)
+ return FAILURE
+
+ if not g_ap_network_info.mac_addr:
+ print("AP MAC address is not valid" + g_ap_network_info.mac_addr)
+ return FAILURE
+
+ if interface_down(AP_INTERFACE) == FAILURE:
+ print("Failed to down AP interface" + AP_INTERFACE)
+ return FAILURE
+
+ g_ap_network_info.ip_addr = ""
+ g_ap_network_info.netmask = ""
+ g_ap_network_info.gateway = ""
+
+ g_ap_network_info.ip_valid = 0
+ g_ap_network_info.dns_valid = 0
+ g_ap_network_info.network_up = 0
+
+ return SUCCESS
+
+def run_dhcp_on_connected():
+
+ if not g_run_dhcp_on_station_connected:
+ print("Not running DHCP on connected, as requested in nw_helper_func.py")
+ return SUCCESS
+
+ if not g_sta_network_info:
+ print("Network info is not valid" + g_sta_network_info)
+ return FAILURE
+
+ if not g_sta_network_info.network_up:
+ print("Network is not up" + g_sta_network_info.network_up)
+ return FAILURE
+
+ if not g_sta_network_info.mac_addr:
+ print("MAC address is not valid" + g_sta_network_info.mac_addr)
+ return FAILURE
+
+ # Kill existing DHCP client
+ os.system(f"nohup killall dhclient > /dev/null 2>&1 &")
+
+ #print("Starting `dhclient` hook. Check `ifconfig ethsta0` in new terminal for IP")
+ # Run DHCP
+ ret = os.system(f"nohup dhclient -v {STA_INTERFACE} > /dev/null 2>&1 &")
+
+ return SUCCESS if ret == 0 else FAILURE
+
+def stop_dhclient_on_disconnected():
+ #print("Stopping `dhclient` hook")
+ if not g_stop_dhclient_on_disconnected:
+ return SUCCESS
+
+ os.system(f"nohup killall dhclient > /dev/null 2>&1 &")
+ return SUCCESS
+
+
+def run_dhcp_server():
+ if not g_run_dhcp_server_after_softap_up:
+ print("Not running DHCP server, as requested in nw_helper_func.py")
+ return SUCCESS
+
+ if not g_ap_network_info:
+ print("Network info is not valid" + g_ap_network_info)
+ return FAILURE
+
+ if not g_ap_network_info.network_up:
+ print("Network is not up" + g_ap_network_info.network_up)
+ return FAILURE
+
+ ret = os.system("sudo bash ./run_dhcp_server.sh")
+ if ret != 0:
+ print("DHCP server (dnsmasq) not configured/running")
+ print("\033[91m Please review/edit and run 'bash -x run_dhcp_server.sh for your platform' \033[0m")
+ return FAILURE
+ return SUCCESS
+
+def stop_dhcp_server():
+ if not g_stop_dhcp_server_after_softap_down:
+ print("Not stopping DHCP server, as requested in nw_helper_func.py")
+ return SUCCESS
+
+ if not g_ap_network_info:
+ print("Network info is not valid" + g_ap_network_info)
+ return FAILURE
+ ret = os.system("sudo bash ./stop_dhcp_server.sh")
+ return SUCCESS if ret == 0 else FAILURE
+
+def down_hci_instance():
+ os.system(down_hci_instance_cmd)
+ return SUCCESS
+
+def reset_hci_instance():
+ os.system(reset_hci_instance_cmd)
+ return SUCCESS
diff --git a/esp_hosted_fg/host/linux/host_control/python_support/py_parse/process.py b/esp_hosted_fg/host/linux/host_control/python_support/py_parse/process.py
index a817f43dcb..2a913e164b 100644
--- a/esp_hosted_fg/host/linux/host_control/python_support/py_parse/process.py
+++ b/esp_hosted_fg/host/linux/host_control/python_support/py_parse/process.py
@@ -17,56 +17,13 @@
from hosted_py_header import *
import re
import subprocess
-
-os_dhcp_down = "sudo dhclient ethsta0 -r"
-os_ifdown_cmd = "sudo ifconfig ethsta0 down"
-os_set_mac = "sudo ifconfig ethsta0 hw ether "
-os_ifup_cmd = "sudo ifconfig ethsta0 up"
-os_dhcp_up = "sudo dhclient ethsta0 -v"
-
-os_run_dhcp_server='sudo bash ./run_dhcp_server.sh'
-os_ifup_softap_cmd = "sudo ifconfig ethap0 up 192.168.4.5"
+#from ctypes import byref
+from py_parse import nw_helper_func
+import traceback
os_ifdown_softap_cmd = "sudo ifconfig ethap0 down"
-sta_interface = "ethsta0"
-softap_interface = "ethap0"
-
-down_hci_instance_cmd = "sudo hciconfig | grep 'Bus: SDIO\\| Bus: UART\\| Bus: SPI' | awk -F: '{print $1}' | xargs -I{} sudo hciconfig {} down"
-reset_hci_instance_cmd = "sudo hciconfig | grep 'Bus: SDIO\\| Bus: UART\\| Bus: SPI' | awk -F: '{print $1}' | xargs -I{} sudo hciconfig {} reset"
-
heartbeat_started = False
-def down_net_interface(interface):
- result = subprocess.run(["ifconfig", interface, "down"])
- if (result.returncode):
- print("ifconfig " + interface + " down FAILED");
-
-def up_net_interface(interface, mac_addr_str):
- result = subprocess.run(["ifconfig", interface, "down"])
- if (result.returncode):
- print("ifconfig " + interface + " down FAILED");
-
- result = subprocess.run(["ifconfig", interface, "hw", "ether", mac_addr_str])
- if (result.returncode):
- print("ifconfig " + interface + " hw ether " + mac_addr_str + " FAILED");
-
- result = subprocess.run(["ifconfig", interface, "up"])
- if (result.returncode):
- print("ifconfig " + interface + " up FAILED");
-
-def down_hci_instance():
- result = subprocess.run(down_hci_instance_cmd, shell=True)
- if (result.returncode):
- print("Failed to bring Bluetooth interface down")
- else:
- print("Bluetooth interface set down successfully")
-
-def reset_hci_instance():
- result = subprocess.run(reset_hci_instance_cmd, shell=True)
- if (result.returncode):
- print("Failed to reset Bluetooth interface")
- else:
- print("Bluetooth interface reset successfully")
def process_is_param_missing(x):
if not x:
@@ -92,6 +49,19 @@ def process_init_control_lib():
print("init hosted control lib failed")
quit()
+ print("------- ESP-Hosted slave FW [", end='')
+ test_get_fw_version()
+ print("] --------")
+ process_get_mac_addr("station")
+ process_get_mac_addr("softap")
+ register_all_event_callbacks()
+ if is_network_split_on() == True:
+ if nw_helper_func.update_host_network_port_range(49152, 61439) != SUCCESS:
+ print("Failed to update host network port range")
+ if test_sync_get_static_ip_from_slave() != SUCCESS:
+ print("Failed to fetch IP status")
+
+
def process_deinit_control_lib(stop_heartbeat = False):
if stop_heartbeat == True:
@@ -122,12 +92,18 @@ def process_get_mac_addr(mode):
if mode == "station":
if test_sync_station_mode_get_mac_addr():
return "\nfailed to get station mac addr"
+
elif mode == "softap":
if test_sync_softap_mode_get_mac_addr():
return "\nfailed to get softap mac addr"
else:
return "\nIncorrect Wi-Fi mode"
- return ""
+
+ mac = nw_helper_func.get_printable_mac_addr(mode)
+ if mac:
+ return mac
+ else:
+ return ""
def process_set_mac_addr(mode, mac):
@@ -153,31 +129,17 @@ def process_get_available_wifi():
return ""
-def process_connect_ap(ssid, pwd, bssid, use_wpa3, listen_interval, set_dhcp, band_mode):
+def process_connect_ap(ssid, pwd, bssid, use_wpa3, listen_interval, band_mode):
ret_str = ""
if band_mode < WIFI_BAND_MODE_2G_ONLY or band_mode > WIFI_BAND_MODE_AUTO:
return "Invalid band_mode parameter " + get_str(band_mode)
if test_sync_station_mode_connect(ssid, pwd, bssid, use_wpa3, listen_interval, band_mode) != SUCCESS:
- ret_str = "Failed to connect AP"
+ ret_str = "Failed to submit connect AP request"
return ret_str
- print("\n")
-
- if set_dhcp:
- try:
- print(os_dhcp_down)
- os.system(os_dhcp_down)
- print("\n")
- print(os_dhcp_up)
- os.system(os_dhcp_up)
- print("\n")
- except Exception as e:
- ret_str = f"Failed during DHCP operations: {e}"
- return ret_str
-
- ret_str = "\nConnected to " + ssid
+ ret_str = ""
return ret_str
@@ -191,9 +153,7 @@ def process_disconnect_ap(reset_dhcp):
test_sync_station_mode_disconnect()
print("\n")
- if reset_dhcp:
- print(os_dhcp_down)
- os.system(os_dhcp_down)
+ down_sta_netdev(network_info)
return ""
@@ -243,15 +203,6 @@ def process_start_softap(ssid, pwd, channel, sec_prot, max_conn, hide_ssid, bw,
return ret_str
print("\n")
- if start_dhcp_server:
- print("Running " + os_run_dhcp_server)
- exit_code = os.system(os_run_dhcp_server)
- if exit_code != 0:
- print("DHCP server (dnsmasq) not configured/running")
- print("\033[91m Please review/edit and run 'bash -x run_dhcp_server.sh for your platform' \033[0m")
- print("Running " + os_ifup_softap_cmd)
- os.system(os_ifup_softap_cmd)
-
ret_str = "\nSoftAP started"
return ret_str
@@ -281,17 +232,25 @@ def process_stop_softap():
def process_set_power_save(mode):
- if mode =="max":
- test_sync_set_wifi_power_save_mode_max()
- elif mode =="min":
- test_sync_set_wifi_power_save_mode_min()
- else:
- return "Unsupported power save mode " + mode
+ try:
+ if mode == "none":
+ test_sync_set_wifi_power_save_mode_none()
+ elif mode =="max":
+ test_sync_set_wifi_power_save_mode_max()
+ elif mode =="min":
+ test_sync_set_wifi_power_save_mode_min()
+ else:
+ return "Unsupported power save mode " + mode
+ except:
+ traceback.print_exc()
return ""
def process_get_power_save():
- test_sync_get_wifi_power_save_mode()
+ try:
+ test_sync_get_wifi_power_save_mode()
+ except:
+ traceback.print_exc()
return ""
@@ -305,27 +264,24 @@ def process_wifi_curr_tx_power():
return ""
def process_enable_wifi():
- global sta_interface
- global softap_interface
- test_feature_enable_wifi()
- test_sync_station_mode_get_mac_addr()
- sta_mac_addr = get_mac_addr_str()
- up_net_interface(sta_interface, sta_mac_addr)
+ if test_feature_enable_wifi() != SUCCESS:
+ return "Failed to enable Wi-Fi"
- test_sync_softap_mode_get_mac_addr()
- softap_mac_addr = get_mac_addr_str()
- up_net_interface(softap_interface, softap_mac_addr)
- return ""
+ if test_sync_station_mode_get_mac_addr() != SUCCESS:
+ return "Failed to get station MAC address"
+
+ if test_sync_softap_mode_get_mac_addr() != SUCCESS:
+ return "Failed to get softap MAC address"
+
+ return "\nSuccess. connect_ap now"
def process_disable_wifi():
- global sta_interface
- global softap_interface
test_feature_disable_wifi()
- down_net_interface(sta_interface);
- down_net_interface(softap_interface);
- return ""
+ down_sta_netdev()
+ down_softap_netdev()
+ return "\nSuccess"
def process_enable_bluetooth():
test_feature_enable_bt()
@@ -378,18 +334,31 @@ def process_heartbeat(enable, duration = 30):
def process_subscribe_event(event):
if event == 'esp_init':
subscribe_event_esp_init()
+ print("notifications enabled for esp_init")
elif event == 'heartbeat':
subscribe_event_heartbeat()
- elif event == 'sta_connected_to_ap':
- subscribe_event_sta_connected_to_ap()
- elif event == 'sta_disconnect_from_ap':
- subscribe_event_sta_disconnect_from_ap()
- elif event == 'sta_connected_to_softap':
- subscribe_event_sta_connected_to_softap()
- elif event == 'sta_disconnect_from_softap':
- subscribe_event_sta_disconnect_from_softap()
+ print("notifications enabled for heartbeat")
+ elif event == 'sta_connected':
+ subscribe_event_sta_connected()
+ print("notifications enabled for station connected to AP")
+ elif event == 'sta_disconnected':
+ subscribe_event_sta_disconnected()
+ print("notifications enabled for station disconnection from AP")
+ elif event == 'softap_sta_connected':
+ subscribe_event_softap_sta_connected()
+ print("notifications enabled for station connected to ESP softAP")
+ elif event == 'softap_sta_disconnected':
+ subscribe_event_softap_sta_disconnected()
+ print("notifications enabled for station disconnection from ESP softAP")
+ elif event == 'dhcp_dns_status':
+ subscribe_event_dhcp_dns_status()
+ print("notifications enabled for DHCP DNS status")
+ elif event == 'custom_packed_event':
+ subscribe_event_custom_packed_event()
+ print("notifications enabled for custom RPC unserialised msg")
elif event == 'all':
register_all_event_callbacks()
+ print("notifications enabled for all possible events")
else:
return "Unsupported event " + event
return ""
@@ -398,18 +367,44 @@ def process_subscribe_event(event):
def process_unsubscribe_event(event):
if event == 'esp_init':
unsubscribe_event_esp_init()
+ print("notifications disabled for esp_init")
elif event == 'heartbeat':
unsubscribe_event_heartbeat()
- elif event == 'sta_connected_to_ap':
- unsubscribe_event_sta_connected_to_ap()
- elif event == 'sta_disconnect_from_ap':
- unsubscribe_event_sta_disconnect_from_ap()
- elif event == 'sta_connected_to_softap':
- unsubscribe_event_sta_connected_to_softap()
- elif event == 'sta_disconnect_from_softap':
- unsubscribe_event_sta_disconnect_from_softap()
+ print("notifications disabled for heartbeat")
+ elif event == 'sta_connected':
+ unsubscribe_event_sta_connected()
+ print("notifications disabled for station connected to AP (Although, not recommended)")
+ elif event == 'sta_disconnected':
+ unsubscribe_event_sta_disconnected()
+ print("notifications disabled for station disconnection from AP (Although, not recommended)")
+ elif event == 'softap_sta_connected':
+ unsubscribe_event_softap_sta_connected()
+ print("notifications disabled for station connected to ESP softAP")
+ elif event == 'softap_sta_disconnected':
+ unsubscribe_event_softap_sta_disconnected()
+ print("notifications disabled for station disconnection from ESP softAP")
+ elif event == 'dhcp_dns_status':
+ unsubscribe_event_dhcp_dns_status()
+ print("notifications disabled for DHCP DNS status (Although, not recommended)")
+ elif event == 'custom_packed_event':
+ unsubscribe_event_custom_packed_event()
+ print("notifications disabled for custom RPC unserialised msg")
elif event == 'all':
unregister_all_event_callbacks()
+ print("notifications disabled for all possible events")
+ print("Although, we suggest enabling notifications for at least 'sta_connected', 'sta_disconnected', 'dhcp_dns_status'")
else:
return "Unsupported event " + event
return ""
+
+def process_custom_rpc_demo1():
+ test_custom_rpc_demo1_request_only_ack()
+ return ""
+
+def process_custom_rpc_demo2():
+ test_custom_rpc_demo2_request_echo_back_as_response()
+ return ""
+
+def process_custom_rpc_demo3():
+ test_custom_rpc_demo3_request_echo_back_as_event()
+ return ""
diff --git a/esp_hosted_fg/host/linux/host_control/python_support/run_dhcp_server.sh b/esp_hosted_fg/host/linux/host_control/python_support/run_dhcp_server.sh
index 832968c08e..49e1fa8764 100644
--- a/esp_hosted_fg/host/linux/host_control/python_support/run_dhcp_server.sh
+++ b/esp_hosted_fg/host/linux/host_control/python_support/run_dhcp_server.sh
@@ -5,9 +5,11 @@
# If your platform doesn't work with dnsmasq, or you use some other DHCP server
# software, you can skip running this script.
+echo "[run_dhcp_server.sh] Starting DHCP server setup..."
+
# Check if the script is run as root
if [ "$EUID" -ne 0 ]; then
- echo "This script must be run as root. Exiting."
+ echo "[run_dhcp_server.sh] This script must be run as root. Exiting."
exit 1
fi
@@ -18,51 +20,60 @@ fi
# Any dnsmasq or DHCP client-server software is out-of-scope for ESP-Hosted but is showcased anyway for user ease.
install_dnsmasq()
{
- # Install if not installed
+ echo "[run_dhcp_server.sh] Checking if dnsmasq is installed..."
which dnsmasq &>/dev/null
if [ "$?" != "0" ] ; then
- echo "> Installing dnsmasq"
+ echo "[run_dhcp_server.sh] > Installing dnsmasq"
sudo apt install dnsmasq &> /dev/null
+ else
+ echo "[run_dhcp_server.sh] dnsmasq already installed"
fi
- # Verify installation
which dnsmasq &>/dev/null
if [ "$?" != "0" ] ; then
- echo "ERROR: Failed to install dnsmasq, exiting"
+ echo "[run_dhcp_server.sh] ERROR: Failed to install dnsmasq, exiting"
exit 1
+ else
+ echo "[run_dhcp_server.sh] dnsmasq installation verified"
fi
}
is_dnsmasq_running_in_custom_way()
{
- if ps -eaf | grep -i "dnsmasq" | grep -- "--port=40000" &>/dev/null ; then
- return 0 # Running in custom way
+ echo "[run_dhcp_server.sh] Checking if dnsmasq is running in custom way (port 55000)..."
+ if ps -eaf | grep -i "dnsmasq" | grep -- "--port=55000" &>/dev/null ; then
+ echo "[run_dhcp_server.sh] dnsmasq is running in custom way"
+ return 0
else
- return 1 # Not running in custom way
+ echo "[run_dhcp_server.sh] dnsmasq is NOT running in custom way"
+ return 1
fi
}
run_dnsmasq_in_custom_way()
{
- echo "> Killing existing dnsmasq instance"
- # Kill default dnsmasq
- sudo systemctl disable dnsmasq
+ echo "[run_dhcp_server.sh] > Killing existing dnsmasq instance"
+ if systemctl list-unit-files | grep -q '^dnsmasq\.service'; then
+ echo "[run_dhcp_server.sh] Disabling dnsmasq systemd service"
+ sudo systemctl disable dnsmasq
+ fi
sudo killall dnsmasq
-
- echo "> Running dnsmasq in custom way"
- # Run manually in the background
- nohup sudo dnsmasq --port=40000 --no-daemon --no-resolv --no-poll --dhcp-script=/system/bin/dhcp_announce --dhcp-range=192.168.4.1,192.168.4.20,1h &> /dev/null &
+ echo "[run_dhcp_server.sh] > Running dnsmasq in custom way"
+ nohup sudo dnsmasq --port=55000 --no-daemon --no-resolv --no-poll --dhcp-script=/system/bin/dhcp_announce --dhcp-range=192.168.4.1,192.168.4.20,1h &> /dev/null &
+ echo "[run_dhcp_server.sh] dnsmasq started in background with custom options"
}
install_dnsmasq
if ! is_dnsmasq_running_in_custom_way ; then
+ echo "[run_dhcp_server.sh] Attempting to start dnsmasq in custom way..."
run_dnsmasq_in_custom_way
fi
if ! is_dnsmasq_running_in_custom_way ; then
- echo "Failed to run dnsmasq"
+ echo "[run_dhcp_server.sh] Failed to run dnsmasq"
exit 1
fi
+echo "[run_dhcp_server.sh] DHCP server setup complete."
exit 0
diff --git a/esp_hosted_fg/host/linux/host_control/python_support/stop_dhcp_server.sh b/esp_hosted_fg/host/linux/host_control/python_support/stop_dhcp_server.sh
new file mode 100755
index 0000000000..0d1631e799
--- /dev/null
+++ b/esp_hosted_fg/host/linux/host_control/python_support/stop_dhcp_server.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+
+# This script stops the custom dnsmasq instance started by run_dhcp_server.sh
+
+echo "[stop_dhcp_server.sh] Stopping DHCP server..."
+
+# Check if the script is run as root
+if [ "$EUID" -ne 0 ]; then
+ echo "[stop_dhcp_server.sh] This script must be run as root. Exiting."
+ exit 1
+fi
+
+echo "[stop_dhcp_server.sh] Looking for custom dnsmasq instance(s) running on port 40000..."
+PIDS=$(ps -eaf | grep -i "dnsmasq" | grep -- "--port=40000" | grep -v grep | awk '{print $2}')
+if [ -n "$PIDS" ]; then
+ echo "[stop_dhcp_server.sh] > Stopping custom dnsmasq instance(s) with PID(s): $PIDS"
+ sudo kill $PIDS
+ echo "[stop_dhcp_server.sh] Custom dnsmasq instance(s) stopped."
+else
+ echo "[stop_dhcp_server.sh] No custom dnsmasq instance running"
+fi
+
+echo "[stop_dhcp_server.sh] DHCP server stop complete."
+exit 0
diff --git a/esp_hosted_fg/host/linux/host_control/python_support/stress.py b/esp_hosted_fg/host/linux/host_control/python_support/stress.py
index 5037ad3878..5dba68fba9 100644
--- a/esp_hosted_fg/host/linux/host_control/python_support/stress.py
+++ b/esp_hosted_fg/host/linux/host_control/python_support/stress.py
@@ -50,10 +50,12 @@
event1 = 'esp_init'
event2 = 'heartbeat'
-event3 = 'sta_connected_to_ap'
-event4 = 'sta_disconnect_from_ap'
-event5 = 'sta_connected_to_softap'
-event6 = 'sta_disconnect_from_softap'
+event3 = 'sta_connected'
+event4 = 'sta_disconnected'
+event5 = 'softap_sta_connected'
+event6 = 'softap_sta_disconnected'
+event7 = 'dhcp_dns_status'
+event8 = 'custom_packed_event'
argumentList = sys.argv[1:]
if argumentList and len(argumentList):
diff --git a/esp_hosted_fg/host/linux/host_control/python_support/test.py b/esp_hosted_fg/host/linux/host_control/python_support/test.py
index dc098cc39a..9f2e2a16ed 100644
--- a/esp_hosted_fg/host/linux/host_control/python_support/test.py
+++ b/esp_hosted_fg/host/linux/host_control/python_support/test.py
@@ -174,12 +174,6 @@ def main():
process_init_control_lib()
- # Display FW Version
- print("------- ESP-Hosted slave FW [", end='')
- cmd = ctrl_cmd()
- cmd.get_fw_version()
- print("] --------")
-
argumentList = sys.argv[1:]
if argumentList and len(argumentList):
try:
diff --git a/esp_hosted_fg/host/linux/host_control/rpi_init.sh b/esp_hosted_fg/host/linux/host_control/rpi_init.sh
index e82625e87c..38299f5879 100755
--- a/esp_hosted_fg/host/linux/host_control/rpi_init.sh
+++ b/esp_hosted_fg/host/linux/host_control/rpi_init.sh
@@ -21,7 +21,7 @@ spi_bus="0"
# Module param, spi_cs: spi cs instance to use
spi_cs="0"
# Module param, spi_mode: spi mode to use from (1/2/3)
-spi_mode="2"
+spi_mode="3"
# Module param, spi_handshake: spi handshake GPIO to use
spi_handshake="534"
# Module param, spi_dataready: spi dataready GPIO to use
@@ -74,138 +74,153 @@ MODULE_NAME="esp32_${IF_TYPE}.ko"
log() {
- echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"
+ echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"
}
warn() {
- echo "[$(date +'%Y-%m-%d %H:%M:%S')] **Warn** $1"
+ echo "[$(date +'%Y-%m-%d %H:%M:%S')] **Warn** $1"
}
log_enter() {
- log "Entering ${FUNCNAME[1]}"
+ log "Entering ${FUNCNAME[1]}"
}
log_exit() {
- log "Exiting ${FUNCNAME[1]}"
+ log "Exiting ${FUNCNAME[1]}"
}
device_tree_dependency_spi() {
- log_enter
+ log_enter
cd $SCRIPT_DIR
log "Current dir: $PWD"
- rm spidev_disabler.dtbo > /dev/null
- dtc spidev_disabler.dts -O dtb > spidev_disabler.dtbo
- sudo dtoverlay -d . spidev_disabler
+ rm spidev_disabler.dtbo > /dev/null
+ dtc spidev_disabler.dts -O dtb > spidev_disabler.dtbo
+ sudo dtoverlay -d . spidev_disabler
cd $MAKE_DIR
- log_exit
+ log_exit
}
device_tree_dependency_uart_2pins() {
- log_enter
+ log_enter
gpio_pin_ctl=pinctrl
$gpio_pin_ctl 2> /dev/null
if [ $? -ne 0 ]; then
gpio_pin_ctl=raspi-gpio
fi
- sudo $gpio_pin_ctl set 15 a0 pu
- sudo $gpio_pin_ctl set 14 a0 pu
- log_exit
+ sudo $gpio_pin_ctl set 15 a0 pu
+ sudo $gpio_pin_ctl set 14 a0 pu
+ log_exit
}
device_tree_dependency_uart_4pins() {
- log_enter
+ log_enter
gpio_pin_ctl=pinctrl
$gpio_pin_ctl 2> /dev/null
if [ $? -ne 0 ]; then
gpio_pin_ctl=raspi-gpio
fi
- sudo $gpio_pin_ctl set 15 a0 pu
- sudo $gpio_pin_ctl set 14 a0 pu
- sudo $gpio_pin_ctl set 16 a3 pu
- sudo $gpio_pin_ctl set 17 a3 pu
- log_exit
+ sudo $gpio_pin_ctl set 15 a0 pu
+ sudo $gpio_pin_ctl set 14 a0 pu
+ sudo $gpio_pin_ctl set 16 a3 pu
+ sudo $gpio_pin_ctl set 17 a3 pu
+ log_exit
+}
+
+build_esp_hosted_rpc_lib() {
+ log_enter
+ cd $RPC_LIB_DIR
+ make -j8
+ LIB_PATH="$RPC_LIB_DIR/libesp_hosted_rpc.a"
+ if [ ! -f "$LIB_PATH" ]; then
+ log "ERROR: Failed to build libesp_hosted_rpc.a, exiting"
+ exit 1
+ fi
+ cd $SCRIPT_DIR
+ log_exit
}
build_c_demo_app() {
- log_enter
- cd $SCRIPT_DIR/c_support/
- make clean
- make -j8 test
- if [ $? -ne 0 ]; then
- log "Failed to build test app"
- exit 1
- fi
-
- make -j8 stress
- if [ $? -ne 0 ]; then
- log "Failed to build stress app"
- exit 1
- fi
- cd ..
- log_exit
+ log_enter
+
+ # Check if replxx library is available by looking for the header file
+ if [ ! -f /usr/include/replxx.h ] && [ ! -f /usr/local/include/replxx.h ]; then
+ warn "replxx library not found. Skipping hosted_shell build."
+ warn "Install replxx from https://github.com/AmokHuginnsson/replxx"
+ warn "After installing, run 'make -j8' in 'host/linux/host_control/c_support' directory"
+ fi
+
+ cd $SCRIPT_DIR/c_support/
+ make -j8
+ if [ $? -ne 0 ]; then
+ log "Failed to build C demo apps"
+ exit 1
+ fi
+
+ cd ..
+ log_exit
}
build_python_demo_app() {
- log_enter
- cd $SCRIPT_DIR/python_support/
- make clean
- make -j8
- if [ $? -ne 0 ]; then
- log "Failed to build python demo app"
- exit 1
- fi
- cd ..
- log_exit
+ log_enter
+ cd $SCRIPT_DIR/python_support/
+ make -j8
+ if [ $? -ne 0 ]; then
+ log "Failed to build python demo app"
+ exit 1
+ fi
+ cd ..
+ log_exit
}
build_user_space_apps() {
- log_enter
- build_c_demo_app
- build_python_demo_app
- log_exit
+ log_enter
+ build_esp_hosted_rpc_lib
+ build_c_demo_app
+ build_python_demo_app
+ log_exit
}
remove_module() {
- log_enter
- if [ "$(lsmod | grep esp32 | wc -l)" != "0" ]; then
- if [ "$(lsmod | grep esp32_sdio | wc -l)" != "0" ]; then
- sudo rmmod esp32_sdio &> /dev/null
- else
- sudo rmmod esp32_spi &> /dev/null
- fi
- if [ $? -ne 0 ]; then
- log "Failed to remove esp kernel module"
- exit 1
- fi
- log "esp module removed using script"
- fi
- log_exit
+ log_enter
+ if [ "$(lsmod | grep esp32 | wc -l)" != "0" ]; then
+ if [ "$(lsmod | grep esp32_sdio | wc -l)" != "0" ]; then
+ sudo rmmod esp32_sdio &> /dev/null
+ else
+ sudo rmmod esp32_spi &> /dev/null
+ fi
+ if [ $? -ne 0 ]; then
+ log "Failed to remove esp kernel module"
+ exit 1
+ fi
+ log "esp module removed using script"
+ fi
+ log_exit
}
build_module()
{
- if [ "$TEST_RAW_TP" = "0" ] ; then
- VAL_CONFIG_TEST_RAW_TP=n
- else
- VAL_CONFIG_TEST_RAW_TP=y
- fi
+ if [ "$TEST_RAW_TP" = "0" ] ; then
+ VAL_CONFIG_TEST_RAW_TP=n
+ else
+ VAL_CONFIG_TEST_RAW_TP=y
+ fi
- if [ "$BT_CONFIG" != "" ] ; then
- VAL_BT_ENABLED=y
- else
- VAL_BT_ENABLED=n
- fi
+ if [ "$BT_CONFIG" != "" ] ; then
+ VAL_BT_ENABLED=y
+ else
+ VAL_BT_ENABLED=n
+ fi
- # For Linux other than Raspberry Pi, Please uncomment below 'make' line and provide:
- # -> /bin/arm-linux-gnueabihf-
- # -> Place where kernel is checked out and built. For Example, "/lib/modules/$(uname -r)/build"
- # -> Architecture. for example, arm64
+ # For Linux other than Raspberry Pi, Please uncomment below 'make' line and provide:
+ # -> /bin/arm-linux-gnueabihf-
+ # -> Place where kernel is checked out and built. For Example, "/lib/modules/$(uname -r)/build"
+ # -> Architecture. for example, arm64
- #make -j8 target=$IF_TYPE CROSS_COMPILE= KERNEL= ARCH= CONFIG_TEST_RAW_TP="$VAL_CONFIG_TEST_RAW_TP"
+ #make -j8 target=$IF_TYPE CROSS_COMPILE= KERNEL= ARCH= CONFIG_TEST_RAW_TP="$VAL_CONFIG_TEST_RAW_TP"
- # Also, Check detailed doc, esp_hosted_fg/docs/Linux_based_host/porting_guide.md for more details.
+ # Also, Check detailed doc, esp_hosted_fg/docs/Linux_based_host/porting_guide.md for more details.
- # Populate your arch if not populated correctly.
+ # Populate your arch if not populated correctly.
if [ "$ARCH" = "" ]; then
arch_num_bits=$(getconf LONG_BIT)
if [ "$arch_num_bits" = "32" ] ; then arch_found="arm"; else arch_found="arm64"; fi
@@ -219,13 +234,13 @@ build_module()
log "Using KERNEL as $KERNEL_BUILD_DIR"
log "Using CONFIG_TEST_RAW_TP as $CONFIG_TEST_RAW_TP"
- make -j8 target="$IF_TYPE" KERNEL="$KERNEL_BUILD_DIR" ARCH="$ARCH" CONFIG_TEST_RAW_TP="$VAL_CONFIG_TEST_RAW_TP" CONFIG_BT_ENABLED="$VAL_BT_ENABLED"
+ make -j8 target="$IF_TYPE" KERNEL="$KERNEL_BUILD_DIR" ARCH="$ARCH" CONFIG_TEST_RAW_TP="$VAL_CONFIG_TEST_RAW_TP" CONFIG_BT_ENABLED="$VAL_BT_ENABLED"
- # Check the exit status of make
- if [ $? -ne 0 ] ; then
- log "Failed to build the esp kernel module"
- exit -1
- fi
+ # Check the exit status of make
+ if [ $? -ne 0 ] ; then
+ log "Failed to build the esp kernel module"
+ exit -1
+ fi
}
load_bluetooth_module()
@@ -239,57 +254,57 @@ load_bluetooth_module()
}
insert_module() {
- log_enter
- # Check and apply bluetooth config
- if [ "$BT_CONFIG" != "" ]; then
- load_bluetooth_module
+ log_enter
+ # Check and apply bluetooth config
+ if [ "$BT_CONFIG" != "" ]; then
+ load_bluetooth_module
- if [ "$BT_CONFIG" = "bt_using_uart_2pins" ]; then
+ if [ "$BT_CONFIG" = "bt_using_uart_2pins" ]; then
log "Wi-Fi ($IF_TYPE) + Bluetooth (UART-2pins)"
- device_tree_dependency_uart_2pins
- elif [ "$BT_CONFIG" = "bt_using_uart_4pins" ]; then
+ device_tree_dependency_uart_2pins
+ elif [ "$BT_CONFIG" = "bt_using_uart_4pins" ]; then
log "Wi-Fi ($IF_TYPE) + Bluetooth (UART-4pins)"
- device_tree_dependency_uart_4pins
- elif [ "$BT_CONFIG" = "bt_using_hci" ]; then
+ device_tree_dependency_uart_4pins
+ elif [ "$BT_CONFIG" = "bt_using_hci" ]; then
log "$IF_TYPE only setup: Wi-Fi+Bluetooth both over $IF_TYPE"
else
- log "Incorrect bluetooth config"
- exit 1
- fi
- fi
+ log "Incorrect bluetooth config"
+ exit 1
+ fi
+ fi
- # Additional dependency for SPI
- if [ "$IF_TYPE" = "spi" ]; then
- device_tree_dependency_spi
- fi
+ # Additional dependency for SPI
+ if [ "$IF_TYPE" = "spi" ]; then
+ device_tree_dependency_spi
+ fi
# Insert module with parameters
sudo insmod $MODULE_NAME $XTRA_MODULE_PARAMS
- if [ $? -ne 0 ]; then
- log "Failed to insert module"
- exit 1
- fi
-
- if [ "$(lsmod | grep esp32 | wc -l)" != "0" ]; then
- log "esp32 module inserted using script"
- else
- log "Failed to insert esp32 module"
- exit 1
- fi
- log_exit
+ if [ $? -ne 0 ]; then
+ log "Failed to insert module"
+ exit 1
+ fi
+
+ if [ "$(lsmod | grep esp32 | wc -l)" != "0" ]; then
+ log "esp32 module inserted using script"
+ else
+ log "Failed to insert esp32 module"
+ exit 1
+ fi
+ log_exit
}
parse_arguments() {
- log_enter
- while [ "$1" != "" ]; do
- case $1 in
- --help | -h )
- usage
- exit 0
- ;;
+ log_enter
+ while [ "$1" != "" ]; do
+ case $1 in
+ --help | -h )
+ usage
+ exit 0
+ ;;
wifi=*)
- WIFI_TP=${1#*=}
+ WIFI_TP=${1#*=}
if [ "$WIFI_TP" = "spi" ]; then
log "Wi-Fi on SPI"
elif [ "$WIFI_TP" = "sdio" ]; then
@@ -302,13 +317,13 @@ parse_arguments() {
log "Possible transport values: 'spi' / 'sdio' / '-'"
exit 1
fi
- ;;
- resetpin=*)
- log "Recvd Option: $1"
- resetpin=${1#*=}
- ;;
+ ;;
+ resetpin=*)
+ log "Recvd Option: $1"
+ resetpin=${1#*=}
+ ;;
bt=*)
- log "Recvd Option: $1"
+ log "Recvd Option: $1"
BT_TP=${1#*=}
if [ "$BT_TP" = "spi" ]; then
BT_CONFIG="bt_using_hci"
@@ -331,15 +346,15 @@ parse_arguments() {
log "Possible transport values: 'spi' / 'sdio' / 'uart_2pins' / 'uart_4pins' / '-'"
exit 1
fi
- ;;
- rawtp)
- log "Test RAW TP"
- TEST_RAW_TP="1"
- ;;
- clockspeed=*)
- clockspeed=${1#*=}
- log "Clock freq: $clockspeed MHz"
- ;;
+ ;;
+ rawtp)
+ log "Test RAW TP"
+ TEST_RAW_TP="1"
+ ;;
+ clockspeed=*)
+ clockspeed=${1#*=}
+ log "Clock freq: $clockspeed MHz"
+ ;;
spi_bus=*)
spi_bus=${1#*=}
log "SPI bus: $spi_bus"
@@ -364,18 +379,18 @@ parse_arguments() {
cpu_perf=${1#*=}
log "Set CPU performance: $cpu_perf"
;;
- *)
- log "$1 : unknown option"
- usage
- exit 1
- ;;
- esac
- shift
- done
+ *)
+ log "$1 : unknown option"
+ usage
+ exit 1
+ ;;
+ esac
+ shift
+ done
verify_transport_combination
verify_clock_freq
- log_exit
+ log_exit
}
verify_transport_combination()
@@ -429,31 +444,31 @@ add_module_param()
# Example usage function
usage() {
- echo "Usage: $0 [options]"
- echo "Options:"
- echo " --help, -h Show this help message"
- echo " wifi= Set bluetooth transport"
- echo " > 'sdio'