Added WiFi kernel drivers and refactored Wifi service (#557)
+ other improvements
This commit is contained in:
committed by
GitHub
parent
dbb96a891c
commit
1c2806bddf
@@ -26,6 +26,9 @@ CONFIG_LV_USE_WIN=n
|
|||||||
CONFIG_LV_USE_SNAPSHOT=y
|
CONFIG_LV_USE_SNAPSHOT=y
|
||||||
CONFIG_LV_BUILD_EXAMPLES=n
|
CONFIG_LV_BUILD_EXAMPLES=n
|
||||||
CONFIG_LV_BUILD_DEMOS=n
|
CONFIG_LV_BUILD_DEMOS=n
|
||||||
|
# Slot 0 is reserved by ESP-IDF's pthread API (see esp_wifi/lwip pthread_getspecific usage).
|
||||||
|
# Tactility's Thread wrappers use slot 1 for their own self-pointer.
|
||||||
|
CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=2
|
||||||
CONFIG_FREERTOS_HZ=1000
|
CONFIG_FREERTOS_HZ=1000
|
||||||
CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=2
|
CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=2
|
||||||
CONFIG_FREERTOS_SMP=n
|
CONFIG_FREERTOS_SMP=n
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_usbhost.h>
|
#include <tactility/bindings/esp32_usbhost.h>
|
||||||
@@ -11,6 +12,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "BigTreeTech Panda Touch";
|
model = "BigTreeTech Panda Touch";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/dts-v1/;
|
/dts-v1/;
|
||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@@ -11,6 +12,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "CYD 2432S024C";
|
model = "CYD 2432S024C";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
gpio0 {
|
gpio0 {
|
||||||
compatible = "espressif,esp32-gpio";
|
compatible = "espressif,esp32-gpio";
|
||||||
gpio-count = <40>;
|
gpio-count = <40>;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/dts-v1/;
|
/dts-v1/;
|
||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
#include <tactility/bindings/esp32_sdspi.h>
|
#include <tactility/bindings/esp32_sdspi.h>
|
||||||
@@ -12,6 +13,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "CYD 2432S024R";
|
model = "CYD 2432S024R";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
gpio0 {
|
gpio0 {
|
||||||
compatible = "espressif,esp32-gpio";
|
compatible = "espressif,esp32-gpio";
|
||||||
gpio-count = <40>;
|
gpio-count = <40>;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/dts-v1/;
|
/dts-v1/;
|
||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@@ -13,6 +14,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "CYD 2432S028R";
|
model = "CYD 2432S028R";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
gpio0 {
|
gpio0 {
|
||||||
compatible = "espressif,esp32-gpio";
|
compatible = "espressif,esp32-gpio";
|
||||||
gpio-count = <40>;
|
gpio-count = <40>;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/dts-v1/;
|
/dts-v1/;
|
||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_uart.h>
|
#include <tactility/bindings/esp32_uart.h>
|
||||||
@@ -13,6 +14,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "CYD 2432S028R v3";
|
model = "CYD 2432S028R v3";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
gpio0 {
|
gpio0 {
|
||||||
compatible = "espressif,esp32-gpio";
|
compatible = "espressif,esp32-gpio";
|
||||||
gpio-count = <40>;
|
gpio-count = <40>;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#include <driver/gpio.h>
|
#include <driver/gpio.h>
|
||||||
|
|
||||||
#include <Tactility/hal/Configuration.h>
|
#include <Tactility/hal/Configuration.h>
|
||||||
#include <Tactility/kernel/SystemEvents.h>
|
#include <Tactility/SystemEvents.h>
|
||||||
#include <Tactility/lvgl/LvglSync.h>
|
#include <Tactility/lvgl/LvglSync.h>
|
||||||
|
|
||||||
#include <PwmBacklight.h>
|
#include <PwmBacklight.h>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/dts-v1/;
|
/dts-v1/;
|
||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@@ -11,6 +12,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "CYD 2432S032C";
|
model = "CYD 2432S032C";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
gpio0 {
|
gpio0 {
|
||||||
compatible = "espressif,esp32-gpio";
|
compatible = "espressif,esp32-gpio";
|
||||||
gpio-count = <40>;
|
gpio-count = <40>;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/dts-v1/;
|
/dts-v1/;
|
||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@@ -12,6 +13,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "CYD 3248S035C";
|
model = "CYD 3248S035C";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
gpio0 {
|
gpio0 {
|
||||||
compatible = "espressif,esp32-gpio";
|
compatible = "espressif,esp32-gpio";
|
||||||
gpio-count = <40>;
|
gpio-count = <40>;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@@ -11,6 +12,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "CYD 4848S040C";
|
model = "CYD 4848S040C";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_uart.h>
|
#include <tactility/bindings/esp32_uart.h>
|
||||||
@@ -12,6 +13,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "CYD 8048S043C";
|
model = "CYD 8048S043C";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/dts-v1/;
|
/dts-v1/;
|
||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
#include <tactility/bindings/esp32_sdspi.h>
|
#include <tactility/bindings/esp32_sdspi.h>
|
||||||
@@ -11,6 +12,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "CYD E32R28T";
|
model = "CYD E32R28T";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
gpio0 {
|
gpio0 {
|
||||||
compatible = "espressif,esp32-gpio";
|
compatible = "espressif,esp32-gpio";
|
||||||
gpio-count = <40>;
|
gpio-count = <40>;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/dts-v1/;
|
/dts-v1/;
|
||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@@ -12,6 +13,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "CYD E32R32P";
|
model = "CYD E32R32P";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
gpio0 {
|
gpio0 {
|
||||||
compatible = "espressif,esp32-gpio";
|
compatible = "espressif,esp32-gpio";
|
||||||
gpio-count = <40>;
|
gpio-count = <40>;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@@ -13,6 +14,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "Elecrow CrowPanel Advance 2.8";
|
model = "Elecrow CrowPanel Advance 2.8";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@@ -13,6 +14,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "Elecrow CrowPanel Advance 3.5";
|
model = "Elecrow CrowPanel Advance 3.5";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@@ -12,6 +13,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "Elecrow CrowPanel Advance 5.0";
|
model = "Elecrow CrowPanel Advance 5.0";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/dts-v1/;
|
/dts-v1/;
|
||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@@ -13,6 +14,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "Elecrow CrowPanel Basic 2.8";
|
model = "Elecrow CrowPanel Basic 2.8";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
gpio0 {
|
gpio0 {
|
||||||
compatible = "espressif,esp32-gpio";
|
compatible = "espressif,esp32-gpio";
|
||||||
gpio-count = <40>;
|
gpio-count = <40>;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/dts-v1/;
|
/dts-v1/;
|
||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@@ -13,6 +14,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "Elecrow CrowPanel Basic 3.5";
|
model = "Elecrow CrowPanel Basic 3.5";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
gpio0 {
|
gpio0 {
|
||||||
compatible = "espressif,esp32-gpio";
|
compatible = "espressif,esp32-gpio";
|
||||||
gpio-count = <40>;
|
gpio-count = <40>;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@@ -12,6 +13,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "Elecrow CrowPanel Basic 5.0";
|
model = "Elecrow CrowPanel Basic 5.0";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/dts-v1/;
|
/dts-v1/;
|
||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
|
|
||||||
@@ -8,6 +9,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "Generic ESP32";
|
model = "Generic ESP32";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
gpio0 {
|
gpio0 {
|
||||||
compatible = "espressif,esp32-gpio";
|
compatible = "espressif,esp32-gpio";
|
||||||
gpio-count = <49>;
|
gpio-count = <49>;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/dts-v1/;
|
/dts-v1/;
|
||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
|
|
||||||
@@ -8,6 +9,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "Generic ESP32 C6";
|
model = "Generic ESP32 C6";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
gpio0 {
|
gpio0 {
|
||||||
compatible = "espressif,esp32-gpio";
|
compatible = "espressif,esp32-gpio";
|
||||||
gpio-count = <31>;
|
gpio-count = <31>;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/dts-v1/;
|
/dts-v1/;
|
||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
|
|
||||||
@@ -8,6 +9,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "Generic ESP32 S3";
|
model = "Generic ESP32 S3";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
gpio0 {
|
gpio0 {
|
||||||
compatible = "espressif,esp32-gpio";
|
compatible = "espressif,esp32-gpio";
|
||||||
gpio-count = <49>;
|
gpio-count = <49>;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/dts-v1/;
|
/dts-v1/;
|
||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@@ -12,6 +13,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "Guition JC2432W328C";
|
model = "Guition JC2432W328C";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
gpio0 {
|
gpio0 {
|
||||||
compatible = "espressif,esp32-gpio";
|
compatible = "espressif,esp32-gpio";
|
||||||
gpio-count = <40>;
|
gpio-count = <40>;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_i2s.h>
|
#include <tactility/bindings/esp32_i2s.h>
|
||||||
@@ -14,6 +15,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "Guition JC3248W535C";
|
model = "Guition JC3248W535C";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_i2s.h>
|
#include <tactility/bindings/esp32_i2s.h>
|
||||||
@@ -13,6 +14,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "Guition JC8048W550C";
|
model = "Guition JC8048W550C";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
|
|
||||||
@@ -9,6 +10,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "Heltec WiFi LoRa 32 V3";
|
model = "Heltec WiFi LoRa 32 V3";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c_master.h>
|
#include <tactility/bindings/esp32_i2c_master.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@@ -14,6 +15,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "LilyGO T-Deck Max";
|
model = "LilyGO T-Deck Max";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
#include "devices/KeyboardBacklight.h"
|
#include "devices/KeyboardBacklight.h"
|
||||||
#include "devices/TrackballDevice.h"
|
#include "devices/TrackballDevice.h"
|
||||||
|
|
||||||
|
#include <Tactility/SystemEvents.h>
|
||||||
|
#include <Tactility/LogMessages.h>
|
||||||
#include <Tactility/hal/gps/GpsConfiguration.h>
|
#include <Tactility/hal/gps/GpsConfiguration.h>
|
||||||
#include <Tactility/kernel/Kernel.h>
|
#include <Tactility/kernel/Kernel.h>
|
||||||
#include <Tactility/kernel/SystemEvents.h>
|
|
||||||
#include <Tactility/LogMessages.h>
|
|
||||||
#include <Tactility/service/gps/GpsService.h>
|
#include <Tactility/service/gps/GpsService.h>
|
||||||
#include <tactility/log.h>
|
#include <tactility/log.h>
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_grove.h>
|
#include <tactility/bindings/esp32_grove.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
@@ -16,6 +17,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "LilyGO T-Deck";
|
model = "LilyGO T-Deck";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#include "devices/Display.h"
|
#include "devices/Display.h"
|
||||||
|
|
||||||
#include "PwmBacklight.h"
|
#include "PwmBacklight.h"
|
||||||
#include <Tactility/kernel/SystemEvents.h>
|
#include <Tactility/SystemEvents.h>
|
||||||
#include <Tactility/TactilityCore.h>
|
#include <Tactility/TactilityCore.h>
|
||||||
#include <tactility/log.h>
|
#include <tactility/log.h>
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,18 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
|
|
||||||
/ {
|
/ {
|
||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "LilyGO T-Display S3";
|
model = "LilyGO T-Display S3";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/dts-v1/;
|
/dts-v1/;
|
||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@@ -10,6 +11,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "LilyGO T-Display";
|
model = "LilyGO T-Display";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
gpio0 {
|
gpio0 {
|
||||||
compatible = "espressif,esp32-gpio";
|
compatible = "espressif,esp32-gpio";
|
||||||
gpio-count = <49>;
|
gpio-count = <49>;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_sdmmc.h>
|
#include <tactility/bindings/esp32_sdmmc.h>
|
||||||
@@ -13,6 +14,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "LilyGO T-Dongle S3";
|
model = "LilyGO T-Dongle S3";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#include "devices/Display.h"
|
#include "devices/Display.h"
|
||||||
|
|
||||||
#include "PwmBacklight.h"
|
#include "PwmBacklight.h"
|
||||||
#include <Tactility/kernel/SystemEvents.h>
|
#include <Tactility/SystemEvents.h>
|
||||||
#include <tactility/log.h>
|
#include <tactility/log.h>
|
||||||
#include <Tactility/TactilityCore.h>
|
#include <Tactility/TactilityCore.h>
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_sdmmc.h>
|
#include <tactility/bindings/esp32_sdmmc.h>
|
||||||
@@ -13,6 +14,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "LilyGO T-HMI";
|
model = "LilyGO T-HMI";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include <Bq27220.h>
|
#include <Bq27220.h>
|
||||||
#include <Tactility/LogMessages.h>
|
#include <Tactility/LogMessages.h>
|
||||||
#include <Tactility/kernel/SystemEvents.h>
|
#include <Tactility/SystemEvents.h>
|
||||||
#include <Tactility/service/gps/GpsService.h>
|
#include <Tactility/service/gps/GpsService.h>
|
||||||
#include <Tactility/hal/gps/GpsConfiguration.h>
|
#include <Tactility/hal/gps/GpsConfiguration.h>
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <bindings/tlora_pager.h>
|
#include <bindings/tlora_pager.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_i2s.h>
|
#include <tactility/bindings/esp32_i2s.h>
|
||||||
@@ -15,6 +16,11 @@
|
|||||||
compatible = "lilygo,tlora-pager";
|
compatible = "lilygo,tlora-pager";
|
||||||
model = "LilyGO T-Lora Pager";
|
model = "LilyGO T-Lora Pager";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_grove.h>
|
#include <tactility/bindings/esp32_grove.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
@@ -17,6 +18,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "M5Stack Cardputer Adv";
|
model = "M5Stack Cardputer Adv";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_grove.h>
|
#include <tactility/bindings/esp32_grove.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
@@ -16,6 +17,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "M5Stack Cardputer";
|
model = "M5Stack Cardputer";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/dts-v1/;
|
/dts-v1/;
|
||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_grove.h>
|
#include <tactility/bindings/esp32_grove.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
@@ -17,6 +18,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "M5Stack Core2";
|
model = "M5Stack Core2";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
gpio0 {
|
gpio0 {
|
||||||
compatible = "espressif,esp32-gpio";
|
compatible = "espressif,esp32-gpio";
|
||||||
gpio-count = <40>;
|
gpio-count = <40>;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_grove.h>
|
#include <tactility/bindings/esp32_grove.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
@@ -18,6 +19,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "M5Stack CoreS3";
|
model = "M5Stack CoreS3";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@@ -13,6 +14,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "M5Stack PaperS3";
|
model = "M5Stack PaperS3";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_grove.h>
|
#include <tactility/bindings/esp32_grove.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
@@ -20,6 +21,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "M5Stack StackChan";
|
model = "M5Stack StackChan";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/dts-v1/;
|
/dts-v1/;
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@@ -12,6 +13,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "M5Stack StickC Plus2";
|
model = "M5Stack StickC Plus2";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
gpio0 {
|
gpio0 {
|
||||||
compatible = "espressif,esp32-gpio";
|
compatible = "espressif,esp32-gpio";
|
||||||
gpio-count = <40>;
|
gpio-count = <40>;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/dts-v1/;
|
/dts-v1/;
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_i2s.h>
|
#include <tactility/bindings/esp32_i2s.h>
|
||||||
@@ -15,6 +16,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "M5Stack StickS3";
|
model = "M5Stack StickS3";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@@ -13,6 +14,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "unPhone";
|
model = "unPhone";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_sdmmc.h>
|
#include <tactility/bindings/esp32_sdmmc.h>
|
||||||
@@ -13,6 +14,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "Waveshare ESP32-S3-Geek";
|
model = "Waveshare ESP32-S3-Geek";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@@ -14,6 +15,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "Waveshare S3 LCD 1.3";
|
model = "Waveshare S3 LCD 1.3";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@@ -14,6 +15,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "Waveshare S3 Touch LCD 1.28";
|
model = "Waveshare S3 Touch LCD 1.28";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@@ -13,6 +14,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "Waveshare S3 Touch LCD 1.47";
|
model = "Waveshare S3 Touch LCD 1.47";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@@ -12,6 +13,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "Waveshare ESP32-S3-Touch-LCD-4.3";
|
model = "Waveshare ESP32-S3-Touch-LCD-4.3";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@@ -11,6 +12,11 @@
|
|||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "Wireless-Tag WT32-SC01 Plus";
|
model = "Wireless-Tag WT32-SC01 Plus";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
ble0 {
|
ble0 {
|
||||||
compatible = "espressif,esp32-ble";
|
compatible = "espressif,esp32-ble";
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ idf_component_register(
|
|||||||
SRCS ${SOURCES}
|
SRCS ${SOURCES}
|
||||||
INCLUDE_DIRS "include/"
|
INCLUDE_DIRS "include/"
|
||||||
PRIV_INCLUDE_DIRS "private/"
|
PRIV_INCLUDE_DIRS "private/"
|
||||||
REQUIRES TactilityKernel driver esp_driver_i2c vfs fatfs
|
REQUIRES TactilityKernel driver esp_driver_i2c vfs fatfs esp_wifi esp_netif esp_event
|
||||||
)
|
)
|
||||||
|
|
||||||
idf_component_optional_requires(PRIVATE bt usb espressif__usb_host_hid espressif__usb_host_msc)
|
idf_component_optional_requires(PRIVATE bt usb espressif__usb_host_hid espressif__usb_host_msc)
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
description: ESP32 WiFi driver wrapper that marshals state-changing calls onto the WiFi task's CPU core
|
||||||
|
|
||||||
|
compatible: "espressif,esp32-wifi-pinned"
|
||||||
|
|
||||||
|
properties:
|
||||||
|
_unused:
|
||||||
|
type: int
|
||||||
|
default: 0
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
description: ESP32 WiFi driver
|
||||||
|
|
||||||
|
compatible: "espressif,esp32-wifi"
|
||||||
|
|
||||||
|
properties:
|
||||||
|
_unused:
|
||||||
|
type: int
|
||||||
|
default: 0
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <tactility/bindings/bindings.h>
|
||||||
|
#include <tactility/drivers/esp32_wifi.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DEFINE_DEVICETREE(esp32_wifi, struct Esp32WifiConfig)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <tactility/bindings/bindings.h>
|
||||||
|
#include <tactility/drivers/esp32_wifi_pinned.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DEFINE_DEVICETREE(esp32_wifi_pinned, struct Esp32WifiPinnedConfig)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** No device-tree configuration required for the ESP32 WiFi driver. */
|
||||||
|
struct Esp32WifiConfig {
|
||||||
|
int _unused; /**< Placeholder — driver reads all config from Kconfig. */
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** No device-tree configuration required for the ESP32 pinned WiFi driver. */
|
||||||
|
struct Esp32WifiPinnedConfig {
|
||||||
|
int _unused; /**< Placeholder — driver has no configurable properties. */
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,567 @@
|
|||||||
|
#ifdef ESP_PLATFORM
|
||||||
|
#include <sdkconfig.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED)
|
||||||
|
|
||||||
|
#include <esp_event.h>
|
||||||
|
#include <esp_netif.h>
|
||||||
|
#include <esp_wifi.h>
|
||||||
|
#include <esp_wifi_default.h>
|
||||||
|
|
||||||
|
#include <tactility/concurrent/mutex.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
#include <tactility/driver.h>
|
||||||
|
#include <tactility/drivers/esp32_wifi.h>
|
||||||
|
#include <tactility/drivers/wifi.h>
|
||||||
|
#include <tactility/error_esp32.h>
|
||||||
|
#include <tactility/log.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#define TAG "esp32_wifi"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr size_t WIFI_MAX_CALLBACKS = 4;
|
||||||
|
constexpr uint16_t WIFI_SCAN_RECORD_LIMIT = 32;
|
||||||
|
|
||||||
|
struct WifiCallbackEntry {
|
||||||
|
WifiEventCallback fn = nullptr;
|
||||||
|
void* ctx = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Esp32WifiCtx {
|
||||||
|
Device* device = nullptr;
|
||||||
|
|
||||||
|
Mutex mutex{};
|
||||||
|
WifiRadioState radioState = WIFI_RADIO_STATE_OFF;
|
||||||
|
WifiStationState stationState = WIFI_STATION_STATE_DISCONNECTED;
|
||||||
|
bool scanning = false;
|
||||||
|
char targetSsid[33] = {};
|
||||||
|
esp_netif_ip_info_t ipInfo{};
|
||||||
|
wifi_ap_record_t scanResults[WIFI_SCAN_RECORD_LIMIT] = {};
|
||||||
|
uint16_t scanResultCount = 0;
|
||||||
|
|
||||||
|
esp_netif_t* netif = nullptr;
|
||||||
|
esp_event_handler_instance_t wifiEventHandler = nullptr;
|
||||||
|
esp_event_handler_instance_t ipEventHandler = nullptr;
|
||||||
|
|
||||||
|
Mutex callbackMutex{};
|
||||||
|
WifiCallbackEntry callbacks[WIFI_MAX_CALLBACKS] = {};
|
||||||
|
size_t callbackCount = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define GET_CTX(device) (static_cast<Esp32WifiCtx*>(device_get_driver_data(device)))
|
||||||
|
|
||||||
|
WifiAuthenticationType to_wifi_authentication_type(wifi_auth_mode_t mode) {
|
||||||
|
switch (mode) {
|
||||||
|
case WIFI_AUTH_OPEN: return WIFI_AUTHENTICATION_TYPE_OPEN;
|
||||||
|
case WIFI_AUTH_WEP: return WIFI_AUTHENTICATION_TYPE_WEP;
|
||||||
|
case WIFI_AUTH_WPA_PSK: return WIFI_AUTHENTICATION_TYPE_WPA_PSK;
|
||||||
|
case WIFI_AUTH_WPA2_PSK: return WIFI_AUTHENTICATION_TYPE_WPA2_PSK;
|
||||||
|
case WIFI_AUTH_WPA_WPA2_PSK: return WIFI_AUTHENTICATION_TYPE_WPA_WPA2_PSK;
|
||||||
|
case WIFI_AUTH_WPA2_ENTERPRISE: return WIFI_AUTHENTICATION_TYPE_WPA2_ENTERPRISE;
|
||||||
|
case WIFI_AUTH_WPA3_PSK: return WIFI_AUTHENTICATION_TYPE_WPA3_PSK;
|
||||||
|
case WIFI_AUTH_WPA2_WPA3_PSK: return WIFI_AUTHENTICATION_TYPE_WPA2_WPA3_PSK;
|
||||||
|
case WIFI_AUTH_WAPI_PSK: return WIFI_AUTHENTICATION_TYPE_WAPI_PSK;
|
||||||
|
case WIFI_AUTH_OWE: return WIFI_AUTHENTICATION_TYPE_OWE;
|
||||||
|
case WIFI_AUTH_WPA3_ENT_192: return WIFI_AUTHENTICATION_TYPE_WPA3_ENT_192;
|
||||||
|
case WIFI_AUTH_WPA3_EXT_PSK: return WIFI_AUTHENTICATION_TYPE_WPA3_EXT_PSK;
|
||||||
|
case WIFI_AUTH_WPA3_EXT_PSK_MIXED_MODE: return WIFI_AUTHENTICATION_TYPE_WPA3_EXT_PSK_MIXED_MODE;
|
||||||
|
default: return WIFI_AUTHENTICATION_TYPE_OPEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fire_event(Esp32WifiCtx* ctx, WifiEvent event) {
|
||||||
|
WifiCallbackEntry local[WIFI_MAX_CALLBACKS];
|
||||||
|
size_t count;
|
||||||
|
mutex_lock(&ctx->callbackMutex);
|
||||||
|
count = ctx->callbackCount;
|
||||||
|
memcpy(local, ctx->callbacks, count * sizeof(WifiCallbackEntry));
|
||||||
|
mutex_unlock(&ctx->callbackMutex);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
local[i].fn(ctx->device, local[i].ctx, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- ESP-IDF event handling (runs on the esp_event task) ----
|
||||||
|
|
||||||
|
void on_wifi_or_ip_event(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
|
||||||
|
auto* ctx = static_cast<Esp32WifiCtx*>(arg);
|
||||||
|
|
||||||
|
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
bool was_pending = ctx->stationState == WIFI_STATION_STATE_CONNECTION_PENDING;
|
||||||
|
ctx->stationState = WIFI_STATION_STATE_DISCONNECTED;
|
||||||
|
memset(&ctx->ipInfo, 0, sizeof(ctx->ipInfo));
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
|
||||||
|
WifiEvent state_event = {};
|
||||||
|
state_event.type = WIFI_EVENT_TYPE_STATION_STATE_CHANGED;
|
||||||
|
state_event.station_state = WIFI_STATION_STATE_DISCONNECTED;
|
||||||
|
fire_event(ctx, state_event);
|
||||||
|
|
||||||
|
if (was_pending) {
|
||||||
|
WifiEvent result_event = {};
|
||||||
|
result_event.type = WIFI_EVENT_TYPE_STATION_CONNECTION_RESULT;
|
||||||
|
result_event.connection_error = WIFI_STATION_CONNECTION_ERROR_TARGET_NOT_FOUND;
|
||||||
|
fire_event(ctx, result_event);
|
||||||
|
}
|
||||||
|
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||||
|
auto* got_ip = static_cast<ip_event_got_ip_t*>(event_data);
|
||||||
|
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
ctx->ipInfo = got_ip->ip_info;
|
||||||
|
ctx->stationState = WIFI_STATION_STATE_CONNECTED;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
|
||||||
|
WifiEvent state_event = {};
|
||||||
|
state_event.type = WIFI_EVENT_TYPE_STATION_STATE_CHANGED;
|
||||||
|
state_event.station_state = WIFI_STATION_STATE_CONNECTED;
|
||||||
|
fire_event(ctx, state_event);
|
||||||
|
|
||||||
|
WifiEvent result_event = {};
|
||||||
|
result_event.type = WIFI_EVENT_TYPE_STATION_CONNECTION_RESULT;
|
||||||
|
result_event.connection_error = WIFI_STATION_CONNECTION_ERROR_NONE;
|
||||||
|
fire_event(ctx, result_event);
|
||||||
|
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_SCAN_DONE) {
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
ctx->scanning = false;
|
||||||
|
uint16_t count = WIFI_SCAN_RECORD_LIMIT;
|
||||||
|
esp_err_t err = esp_wifi_scan_get_ap_records(&count, ctx->scanResults);
|
||||||
|
ctx->scanResultCount = (err == ESP_OK) ? count : 0;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
|
||||||
|
WifiEvent event = {};
|
||||||
|
event.type = WIFI_EVENT_TYPE_SCAN_FINISHED;
|
||||||
|
fire_event(ctx, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Work, always run inline on the caller (see note at the top) ----
|
||||||
|
|
||||||
|
error_t bring_up_wifi(Esp32WifiCtx* ctx) {
|
||||||
|
ctx->netif = esp_netif_create_default_wifi_sta();
|
||||||
|
if (ctx->netif == nullptr) {
|
||||||
|
LOG_E(TAG, "Failed to create default STA netif");
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warning: this is the memory-intensive operation. It uses over 100kB of
|
||||||
|
// RAM with default settings.
|
||||||
|
wifi_init_config_t init_config = WIFI_INIT_CONFIG_DEFAULT();
|
||||||
|
esp_err_t err = esp_wifi_init(&init_config);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
LOG_E(TAG, "esp_wifi_init failed: %s", esp_err_to_name(err));
|
||||||
|
esp_netif_destroy(ctx->netif);
|
||||||
|
ctx->netif = nullptr;
|
||||||
|
return esp_err_to_error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_wifi_set_storage(WIFI_STORAGE_RAM);
|
||||||
|
|
||||||
|
err = esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &on_wifi_or_ip_event, ctx, &ctx->wifiEventHandler);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
LOG_E(TAG, "Failed to register WIFI_EVENT handler: %s", esp_err_to_name(err));
|
||||||
|
esp_wifi_deinit();
|
||||||
|
esp_netif_destroy(ctx->netif);
|
||||||
|
ctx->netif = nullptr;
|
||||||
|
return esp_err_to_error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &on_wifi_or_ip_event, ctx, &ctx->ipEventHandler);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
LOG_E(TAG, "Failed to register IP_EVENT handler: %s", esp_err_to_name(err));
|
||||||
|
esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, ctx->wifiEventHandler);
|
||||||
|
ctx->wifiEventHandler = nullptr;
|
||||||
|
esp_wifi_deinit();
|
||||||
|
esp_netif_destroy(ctx->netif);
|
||||||
|
ctx->netif = nullptr;
|
||||||
|
return esp_err_to_error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = esp_wifi_set_mode(WIFI_MODE_STA);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
LOG_E(TAG, "esp_wifi_set_mode failed: %s", esp_err_to_name(err));
|
||||||
|
esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, ctx->ipEventHandler);
|
||||||
|
esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, ctx->wifiEventHandler);
|
||||||
|
ctx->ipEventHandler = nullptr;
|
||||||
|
ctx->wifiEventHandler = nullptr;
|
||||||
|
esp_wifi_deinit();
|
||||||
|
esp_netif_destroy(ctx->netif);
|
||||||
|
ctx->netif = nullptr;
|
||||||
|
return esp_err_to_error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = esp_wifi_start();
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
LOG_E(TAG, "esp_wifi_start failed: %s", esp_err_to_name(err));
|
||||||
|
esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, ctx->ipEventHandler);
|
||||||
|
esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, ctx->wifiEventHandler);
|
||||||
|
ctx->ipEventHandler = nullptr;
|
||||||
|
ctx->wifiEventHandler = nullptr;
|
||||||
|
esp_wifi_set_mode(WIFI_MODE_NULL);
|
||||||
|
esp_wifi_deinit();
|
||||||
|
esp_netif_destroy(ctx->netif);
|
||||||
|
ctx->netif = nullptr;
|
||||||
|
return esp_err_to_error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
ctx->radioState = WIFI_RADIO_STATE_ON;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
|
||||||
|
LOG_I(TAG, "WiFi radio on");
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bring_down_wifi(Esp32WifiCtx* ctx) {
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
bool was_connected = ctx->stationState != WIFI_STATION_STATE_DISCONNECTED;
|
||||||
|
bool was_scanning = ctx->scanning;
|
||||||
|
ctx->stationState = WIFI_STATION_STATE_DISCONNECTED;
|
||||||
|
ctx->scanning = false;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
|
||||||
|
if (was_scanning) {
|
||||||
|
esp_wifi_scan_stop();
|
||||||
|
}
|
||||||
|
if (was_connected) {
|
||||||
|
esp_wifi_disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detach netif from the internal WiFi event handlers before stopping,
|
||||||
|
// otherwise esp_netif_destroy() can race with esp_wifi_stop()'s own
|
||||||
|
// netif teardown (see esp32_ble/WifiEsp.cpp for the same issue).
|
||||||
|
if (ctx->netif != nullptr) {
|
||||||
|
esp_wifi_clear_default_wifi_driver_and_handlers(ctx->netif);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_wifi_stop();
|
||||||
|
esp_wifi_set_mode(WIFI_MODE_NULL);
|
||||||
|
|
||||||
|
if (ctx->wifiEventHandler != nullptr) {
|
||||||
|
esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, ctx->wifiEventHandler);
|
||||||
|
ctx->wifiEventHandler = nullptr;
|
||||||
|
}
|
||||||
|
if (ctx->ipEventHandler != nullptr) {
|
||||||
|
esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, ctx->ipEventHandler);
|
||||||
|
ctx->ipEventHandler = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_wifi_deinit();
|
||||||
|
|
||||||
|
if (ctx->netif != nullptr) {
|
||||||
|
esp_netif_destroy(ctx->netif);
|
||||||
|
ctx->netif = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
ctx->radioState = WIFI_RADIO_STATE_OFF;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
|
||||||
|
LOG_I(TAG, "WiFi radio off");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- WifiApi ----
|
||||||
|
|
||||||
|
error_t api_get_radio_state(Device* device, WifiRadioState* state) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || state == nullptr) return ERROR_INVALID_ARGUMENT;
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
*state = ctx->radioState;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t api_get_station_state(Device* device, WifiStationState* state) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || state == nullptr) return ERROR_INVALID_ARGUMENT;
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
*state = ctx->stationState;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t api_get_access_point_state(Device* device, WifiAccessPointState* state) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || state == nullptr) return ERROR_INVALID_ARGUMENT;
|
||||||
|
// Access point mode isn't implemented by this driver.
|
||||||
|
*state = WIFI_ACCESS_POINT_STATE_STOPPED;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool api_is_scanning(Device* device) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr) return false;
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
bool scanning = ctx->scanning;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
return scanning;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t api_scan(Device* device) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr) return ERROR_INVALID_STATE;
|
||||||
|
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
if (ctx->radioState != WIFI_RADIO_STATE_ON || ctx->scanning) {
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
return ERROR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
|
||||||
|
esp_err_t err = esp_wifi_scan_start(nullptr, false);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
return esp_err_to_error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
ctx->scanning = true;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
|
||||||
|
WifiEvent event = {};
|
||||||
|
event.type = WIFI_EVENT_TYPE_SCAN_STARTED;
|
||||||
|
fire_event(ctx, event);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t api_get_scan_results(Device* device, WifiApRecord* results, size_t* num_results) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || results == nullptr || num_results == nullptr) return ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
size_t count = std::min<size_t>(*num_results, ctx->scanResultCount);
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
const wifi_ap_record_t& src = ctx->scanResults[i];
|
||||||
|
WifiApRecord& dst = results[i];
|
||||||
|
memset(dst.ssid, 0, sizeof(dst.ssid));
|
||||||
|
memcpy(dst.ssid, src.ssid, std::min(sizeof(dst.ssid) - 1, sizeof(src.ssid)));
|
||||||
|
dst.rssi = src.rssi;
|
||||||
|
dst.channel = src.primary;
|
||||||
|
dst.authentication_type = to_wifi_authentication_type(src.authmode);
|
||||||
|
}
|
||||||
|
*num_results = count;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t api_station_get_ipv4_address(Device* device, char* ipv4) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || ipv4 == nullptr) return ERROR_INVALID_ARGUMENT;
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
esp_ip4addr_ntoa(&ctx->ipInfo.ip, ipv4, 16);
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t api_station_get_target_ssid(Device* device, char* ssid) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || ssid == nullptr) return ERROR_INVALID_ARGUMENT;
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
constexpr size_t ssid_buffer_size = sizeof(ctx->targetSsid);
|
||||||
|
strncpy(ssid, ctx->targetSsid, ssid_buffer_size);
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t api_station_connect(Device* device, const char* ssid, const char* password, int32_t channel) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || ssid == nullptr) return ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
bool radio_on = ctx->radioState == WIFI_RADIO_STATE_ON;
|
||||||
|
bool was_connected = ctx->stationState != WIFI_STATION_STATE_DISCONNECTED;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
|
||||||
|
if (!radio_on) {
|
||||||
|
return ERROR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (was_connected) {
|
||||||
|
esp_wifi_disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
wifi_config_t config {};
|
||||||
|
config.sta.channel = static_cast<uint8_t>(channel);
|
||||||
|
config.sta.scan_method = WIFI_FAST_SCAN;
|
||||||
|
config.sta.sort_method = WIFI_CONNECT_AP_BY_SIGNAL;
|
||||||
|
config.sta.threshold.rssi = -127;
|
||||||
|
config.sta.pmf_cfg.capable = true;
|
||||||
|
strncpy(reinterpret_cast<char*>(config.sta.ssid), ssid, sizeof(config.sta.ssid) - 1);
|
||||||
|
if (password != nullptr && password[0] != '\0') {
|
||||||
|
strncpy(reinterpret_cast<char*>(config.sta.password), password, sizeof(config.sta.password) - 1);
|
||||||
|
config.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t err = esp_wifi_set_config(WIFI_IF_STA, &config);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
return esp_err_to_error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
strncpy(ctx->targetSsid, ssid, sizeof(ctx->targetSsid) - 1);
|
||||||
|
ctx->targetSsid[sizeof(ctx->targetSsid) - 1] = '\0';
|
||||||
|
ctx->stationState = WIFI_STATION_STATE_CONNECTION_PENDING;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
|
||||||
|
err = esp_wifi_connect();
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
ctx->stationState = WIFI_STATION_STATE_DISCONNECTED;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
return esp_err_to_error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
WifiEvent event = {};
|
||||||
|
event.type = WIFI_EVENT_TYPE_STATION_STATE_CHANGED;
|
||||||
|
event.station_state = WIFI_STATION_STATE_CONNECTION_PENDING;
|
||||||
|
fire_event(ctx, event);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t api_station_disconnect(Device* device) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr) return ERROR_INVALID_STATE;
|
||||||
|
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
bool was_connected = ctx->stationState != WIFI_STATION_STATE_DISCONNECTED;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
|
||||||
|
if (!was_connected) {
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The DISCONNECTED state change is published by the WIFI_EVENT handler
|
||||||
|
// once ESP-IDF confirms the disconnect, so we don't fire it here.
|
||||||
|
esp_err_t err = esp_wifi_disconnect();
|
||||||
|
return err == ESP_OK ? ERROR_NONE : esp_err_to_error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t api_station_get_rssi(Device* device, int32_t* rssi) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || rssi == nullptr) return ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
int native_rssi = 0;
|
||||||
|
esp_err_t err = esp_wifi_sta_get_rssi(&native_rssi);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
return esp_err_to_error(err);
|
||||||
|
}
|
||||||
|
*rssi = native_rssi;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t api_add_event_callback(Device* device, void* callback_context, WifiEventCallback callback) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || callback == nullptr) return ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
mutex_lock(&ctx->callbackMutex);
|
||||||
|
if (ctx->callbackCount >= WIFI_MAX_CALLBACKS) {
|
||||||
|
mutex_unlock(&ctx->callbackMutex);
|
||||||
|
return ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
ctx->callbacks[ctx->callbackCount] = { .fn = callback, .ctx = callback_context };
|
||||||
|
ctx->callbackCount++;
|
||||||
|
mutex_unlock(&ctx->callbackMutex);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t api_remove_event_callback(Device* device, WifiEventCallback callback) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || callback == nullptr) return ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
mutex_lock(&ctx->callbackMutex);
|
||||||
|
for (size_t i = 0; i < ctx->callbackCount; i++) {
|
||||||
|
if (ctx->callbacks[i].fn == callback) {
|
||||||
|
for (size_t j = i; j + 1 < ctx->callbackCount; j++) {
|
||||||
|
ctx->callbacks[j] = ctx->callbacks[j + 1];
|
||||||
|
}
|
||||||
|
ctx->callbackCount--;
|
||||||
|
mutex_unlock(&ctx->callbackMutex);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mutex_unlock(&ctx->callbackMutex);
|
||||||
|
return ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
const WifiApi esp32_wifi_api = {
|
||||||
|
.get_radio_state = api_get_radio_state,
|
||||||
|
.get_station_state = api_get_station_state,
|
||||||
|
.get_access_point_state = api_get_access_point_state,
|
||||||
|
.is_scanning = api_is_scanning,
|
||||||
|
.scan = api_scan,
|
||||||
|
.get_scan_results = api_get_scan_results,
|
||||||
|
.station_get_ipv4_address = api_station_get_ipv4_address,
|
||||||
|
.station_get_target_ssid = api_station_get_target_ssid,
|
||||||
|
.station_connect = api_station_connect,
|
||||||
|
.station_disconnect = api_station_disconnect,
|
||||||
|
.station_get_rssi = api_station_get_rssi,
|
||||||
|
.add_event_callback = api_add_event_callback,
|
||||||
|
.remove_event_callback = api_remove_event_callback
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---- Driver lifecycle ----
|
||||||
|
// The ESP-IDF WiFi stack isn't touched until the device is actually started:
|
||||||
|
// registering this driver (module start()) only makes it available for
|
||||||
|
// binding, it doesn't spin up any resources.
|
||||||
|
|
||||||
|
error_t start_device(Device* device) {
|
||||||
|
auto* ctx = new(std::nothrow) Esp32WifiCtx();
|
||||||
|
if (ctx == nullptr) return ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
ctx->device = device;
|
||||||
|
mutex_construct(&ctx->mutex);
|
||||||
|
mutex_construct(&ctx->callbackMutex);
|
||||||
|
device_set_driver_data(device, ctx);
|
||||||
|
|
||||||
|
error_t result = bring_up_wifi(ctx);
|
||||||
|
if (result != ERROR_NONE) {
|
||||||
|
device_set_driver_data(device, nullptr);
|
||||||
|
mutex_destruct(&ctx->callbackMutex);
|
||||||
|
mutex_destruct(&ctx->mutex);
|
||||||
|
delete ctx;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t stop_device(Device* device) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr) return ERROR_NONE;
|
||||||
|
|
||||||
|
bring_down_wifi(ctx);
|
||||||
|
|
||||||
|
device_set_driver_data(device, nullptr);
|
||||||
|
mutex_destruct(&ctx->callbackMutex);
|
||||||
|
mutex_destruct(&ctx->mutex);
|
||||||
|
delete ctx;
|
||||||
|
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
extern Module platform_esp32_module;
|
||||||
|
|
||||||
|
Driver esp32_wifi_driver = {
|
||||||
|
.name = "esp32_wifi",
|
||||||
|
.compatible = (const char*[]) { "espressif,esp32-wifi", nullptr },
|
||||||
|
.start_device = start_device,
|
||||||
|
.stop_device = stop_device,
|
||||||
|
.api = (const void*)&esp32_wifi_api,
|
||||||
|
.device_type = &WIFI_TYPE,
|
||||||
|
.owner = &platform_esp32_module,
|
||||||
|
.internal = nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
|
||||||
|
#endif // CONFIG_SOC_WIFI_SUPPORTED or CONFIG_SLAVE_SOC_WIFI_SUPPORTED
|
||||||
@@ -0,0 +1,336 @@
|
|||||||
|
#ifdef ESP_PLATFORM
|
||||||
|
#include <sdkconfig.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED)
|
||||||
|
|
||||||
|
#include <esp_wifi.h> // for WIFI_TASK_CORE_ID
|
||||||
|
|
||||||
|
#include <tactility/concurrent/dispatcher.h>
|
||||||
|
#include <tactility/concurrent/event_group.h>
|
||||||
|
#include <tactility/concurrent/thread.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
#include <tactility/driver.h>
|
||||||
|
#include <tactility/drivers/esp32_wifi_pinned.h>
|
||||||
|
#include <tactility/drivers/wifi.h>
|
||||||
|
#include <tactility/log.h>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <functional>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#define TAG "esp32_wifi_pinned"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr uint32_t CALL_DONE_FLAG = 1U;
|
||||||
|
constexpr configSTACK_DEPTH_TYPE PINNED_THREAD_STACK_SIZE = 4096;
|
||||||
|
|
||||||
|
// This driver wraps "espressif,esp32-wifi" (created as a child device) and
|
||||||
|
// marshals every call that mutates WiFi state onto a dedicated task pinned to
|
||||||
|
// WIFI_TASK_CORE_ID. ESP-IDF's WiFi driver misbehaves (hangs waiting on its
|
||||||
|
// internal task semaphore, tripping the watchdog) when those calls originate
|
||||||
|
// from an arbitrary caller task/core, so this driver guarantees the correct
|
||||||
|
// core regardless of who calls the WifiApi.
|
||||||
|
struct Esp32WifiPinnedCtx {
|
||||||
|
Device* device = nullptr;
|
||||||
|
Device* child = nullptr;
|
||||||
|
Thread* thread = nullptr;
|
||||||
|
DispatcherHandle_t dispatcher = nullptr;
|
||||||
|
volatile bool running = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define GET_CTX(device) (static_cast<Esp32WifiPinnedCtx*>(device_get_driver_data(device)))
|
||||||
|
|
||||||
|
struct MarshalledCall {
|
||||||
|
const std::function<void()>* work;
|
||||||
|
EventGroupHandle_t done;
|
||||||
|
};
|
||||||
|
|
||||||
|
void marshal_trampoline(void* context) {
|
||||||
|
auto* call = static_cast<MarshalledCall*>(context);
|
||||||
|
(*call->work)();
|
||||||
|
event_group_set(call->done, CALL_DONE_FLAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Runs `work` synchronously on the pinned WiFi task, blocking the caller until it completes. */
|
||||||
|
error_t run_on_pinned_thread(Esp32WifiPinnedCtx* ctx, const std::function<void()>& work) {
|
||||||
|
if (ctx == nullptr || ctx->thread == nullptr) {
|
||||||
|
return ERROR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid deadlocking when already running on the pinned thread (e.g. during device_start()).
|
||||||
|
if (thread_get_current() == ctx->thread) {
|
||||||
|
work();
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
MarshalledCall call = { .work = &work, .done = nullptr };
|
||||||
|
event_group_construct(&call.done);
|
||||||
|
|
||||||
|
error_t err = dispatcher_dispatch(ctx->dispatcher, &call, marshal_trampoline);
|
||||||
|
if (err != ERROR_NONE) {
|
||||||
|
event_group_destruct(&call.done);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
event_group_wait(call.done, CALL_DONE_FLAG, false, true, nullptr, portMAX_DELAY);
|
||||||
|
event_group_destruct(&call.done);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void request_stop(void* context) {
|
||||||
|
static_cast<Esp32WifiPinnedCtx*>(context)->running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t pinned_thread_main(void* context) {
|
||||||
|
auto* ctx = static_cast<Esp32WifiPinnedCtx*>(context);
|
||||||
|
while (ctx->running) {
|
||||||
|
dispatcher_consume(ctx->dispatcher);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Work that must run on the pinned thread (see start_device/stop_device) ----
|
||||||
|
|
||||||
|
error_t start_child_work(Esp32WifiPinnedCtx* ctx) {
|
||||||
|
ctx->child = new(std::nothrow) Device();
|
||||||
|
if (ctx->child == nullptr) {
|
||||||
|
return ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
std::memset(ctx->child, 0, sizeof(Device));
|
||||||
|
ctx->child->parent = ctx->device;
|
||||||
|
ctx->child->name = ctx->device->name;
|
||||||
|
|
||||||
|
error_t err = device_construct_add_start(ctx->child, "espressif,esp32-wifi");
|
||||||
|
if (err != ERROR_NONE) {
|
||||||
|
LOG_E(TAG, "%s: failed to start child wifi device: %s", ctx->device->name, error_to_string(err));
|
||||||
|
delete ctx->child;
|
||||||
|
ctx->child = nullptr;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop_child_work(Esp32WifiPinnedCtx* ctx) {
|
||||||
|
if (ctx->child == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (device_is_ready(ctx->child)) {
|
||||||
|
device_stop(ctx->child);
|
||||||
|
}
|
||||||
|
if (device_is_added(ctx->child)) {
|
||||||
|
device_remove(ctx->child);
|
||||||
|
}
|
||||||
|
device_destruct(ctx->child);
|
||||||
|
delete ctx->child;
|
||||||
|
ctx->child = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- WifiApi: read-only calls forward straight to the child, no core affinity needed ----
|
||||||
|
|
||||||
|
error_t api_get_radio_state(Device* device, WifiRadioState* state) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || ctx->child == nullptr) return ERROR_INVALID_STATE;
|
||||||
|
return wifi_get_radio_state(ctx->child, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t api_get_station_state(Device* device, WifiStationState* state) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || ctx->child == nullptr) return ERROR_INVALID_STATE;
|
||||||
|
return wifi_get_station_state(ctx->child, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t api_get_access_point_state(Device* device, WifiAccessPointState* state) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || ctx->child == nullptr) return ERROR_INVALID_STATE;
|
||||||
|
return wifi_get_access_point_state(ctx->child, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool api_is_scanning(Device* device) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || ctx->child == nullptr) return false;
|
||||||
|
return wifi_is_scanning(ctx->child);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t api_get_scan_results(Device* device, WifiApRecord* results, size_t* num_results) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || ctx->child == nullptr) return ERROR_INVALID_STATE;
|
||||||
|
return wifi_get_scan_results(ctx->child, results, num_results);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t api_station_get_ipv4_address(Device* device, char* ipv4) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || ctx->child == nullptr) return ERROR_INVALID_STATE;
|
||||||
|
return wifi_station_get_ipv4_address(ctx->child, ipv4);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t api_station_get_target_ssid(Device* device, char* ssid) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || ctx->child == nullptr) return ERROR_INVALID_STATE;
|
||||||
|
return wifi_station_get_target_ssid(ctx->child, ssid);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t api_station_get_rssi(Device* device, int32_t* rssi) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || ctx->child == nullptr) return ERROR_INVALID_STATE;
|
||||||
|
return wifi_station_get_rssi(ctx->child, rssi);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t api_add_event_callback(Device* device, void* callback_context, WifiEventCallback callback) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || ctx->child == nullptr) return ERROR_INVALID_STATE;
|
||||||
|
return wifi_add_event_callback(ctx->child, callback_context, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t api_remove_event_callback(Device* device, WifiEventCallback callback) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || ctx->child == nullptr) return ERROR_INVALID_STATE;
|
||||||
|
return wifi_remove_event_callback(ctx->child, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- WifiApi: state-changing calls are marshalled onto the pinned WiFi task ----
|
||||||
|
|
||||||
|
error_t api_scan(Device* device) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || ctx->child == nullptr) return ERROR_INVALID_STATE;
|
||||||
|
|
||||||
|
error_t result = ERROR_NONE;
|
||||||
|
Device* child = ctx->child;
|
||||||
|
error_t err = run_on_pinned_thread(ctx, [child, &result]() {
|
||||||
|
result = wifi_scan(child);
|
||||||
|
});
|
||||||
|
return err != ERROR_NONE ? err : result;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t api_station_connect(Device* device, const char* ssid, const char* password, int32_t channel) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || ctx->child == nullptr) return ERROR_INVALID_STATE;
|
||||||
|
|
||||||
|
error_t result = ERROR_NONE;
|
||||||
|
Device* child = ctx->child;
|
||||||
|
error_t err = run_on_pinned_thread(ctx, [child, ssid, password, channel, &result]() {
|
||||||
|
result = wifi_station_connect(child, ssid, password, channel);
|
||||||
|
});
|
||||||
|
return err != ERROR_NONE ? err : result;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t api_station_disconnect(Device* device) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || ctx->child == nullptr) return ERROR_INVALID_STATE;
|
||||||
|
|
||||||
|
error_t result = ERROR_NONE;
|
||||||
|
Device* child = ctx->child;
|
||||||
|
error_t err = run_on_pinned_thread(ctx, [child, &result]() {
|
||||||
|
result = wifi_station_disconnect(child);
|
||||||
|
});
|
||||||
|
return err != ERROR_NONE ? err : result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const WifiApi esp32_wifi_pinned_api = {
|
||||||
|
.get_radio_state = api_get_radio_state,
|
||||||
|
.get_station_state = api_get_station_state,
|
||||||
|
.get_access_point_state = api_get_access_point_state,
|
||||||
|
.is_scanning = api_is_scanning,
|
||||||
|
.scan = api_scan,
|
||||||
|
.get_scan_results = api_get_scan_results,
|
||||||
|
.station_get_ipv4_address = api_station_get_ipv4_address,
|
||||||
|
.station_get_target_ssid = api_station_get_target_ssid,
|
||||||
|
.station_connect = api_station_connect,
|
||||||
|
.station_disconnect = api_station_disconnect,
|
||||||
|
.station_get_rssi = api_station_get_rssi,
|
||||||
|
.add_event_callback = api_add_event_callback,
|
||||||
|
.remove_event_callback = api_remove_event_callback
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---- Driver lifecycle ----
|
||||||
|
// Starting/stopping the child (which brings the ESP-IDF WiFi stack up/down)
|
||||||
|
// also happens on the pinned thread, since esp_wifi_init/start/stop/deinit
|
||||||
|
// are subject to the same core-affinity requirement as the state-changing
|
||||||
|
// WifiApi calls above.
|
||||||
|
|
||||||
|
error_t start_device(Device* device) {
|
||||||
|
auto* ctx = new(std::nothrow) Esp32WifiPinnedCtx();
|
||||||
|
if (ctx == nullptr) return ERROR_OUT_OF_MEMORY;
|
||||||
|
ctx->device = device;
|
||||||
|
device_set_driver_data(device, ctx);
|
||||||
|
|
||||||
|
ctx->dispatcher = dispatcher_alloc();
|
||||||
|
ctx->running = true;
|
||||||
|
ctx->thread = thread_alloc_full(
|
||||||
|
"esp32_wifi_pinned",
|
||||||
|
PINNED_THREAD_STACK_SIZE,
|
||||||
|
pinned_thread_main,
|
||||||
|
ctx,
|
||||||
|
WIFI_TASK_CORE_ID
|
||||||
|
);
|
||||||
|
if (ctx->thread == nullptr || thread_start(ctx->thread) != ERROR_NONE) {
|
||||||
|
LOG_E(TAG, "%s: failed to start pinned wifi task", device->name);
|
||||||
|
if (ctx->thread != nullptr) thread_free(ctx->thread);
|
||||||
|
dispatcher_free(ctx->dispatcher);
|
||||||
|
device_set_driver_data(device, nullptr);
|
||||||
|
delete ctx;
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t result = ERROR_NONE;
|
||||||
|
error_t err = run_on_pinned_thread(ctx, [ctx, &result]() {
|
||||||
|
result = start_child_work(ctx);
|
||||||
|
});
|
||||||
|
if (err == ERROR_NONE) {
|
||||||
|
err = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err != ERROR_NONE) {
|
||||||
|
dispatcher_dispatch(ctx->dispatcher, ctx, request_stop);
|
||||||
|
thread_join(ctx->thread, portMAX_DELAY, 10);
|
||||||
|
thread_free(ctx->thread);
|
||||||
|
dispatcher_free(ctx->dispatcher);
|
||||||
|
device_set_driver_data(device, nullptr);
|
||||||
|
delete ctx;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t stop_device(Device* device) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr) return ERROR_NONE;
|
||||||
|
|
||||||
|
error_t err = run_on_pinned_thread(ctx, [ctx]() {
|
||||||
|
stop_child_work(ctx);
|
||||||
|
});
|
||||||
|
if (err != ERROR_NONE) {
|
||||||
|
LOG_E(TAG, "%s: failed to stop child wifi device on pinned task: %s", device->name, error_to_string(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatcher_dispatch(ctx->dispatcher, ctx, request_stop);
|
||||||
|
thread_join(ctx->thread, portMAX_DELAY, 10);
|
||||||
|
thread_free(ctx->thread);
|
||||||
|
dispatcher_free(ctx->dispatcher);
|
||||||
|
|
||||||
|
device_set_driver_data(device, nullptr);
|
||||||
|
delete ctx;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
extern Module platform_esp32_module;
|
||||||
|
|
||||||
|
Driver esp32_wifi_pinned_driver = {
|
||||||
|
.name = "esp32_wifi_pinned",
|
||||||
|
.compatible = (const char*[]) { "espressif,esp32-wifi-pinned", nullptr },
|
||||||
|
.start_device = start_device,
|
||||||
|
.stop_device = stop_device,
|
||||||
|
.api = (const void*)&esp32_wifi_pinned_api,
|
||||||
|
.device_type = &WIFI_TYPE,
|
||||||
|
.owner = &platform_esp32_module,
|
||||||
|
.internal = nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
|
||||||
|
#endif // CONFIG_SOC_WIFI_SUPPORTED or CONFIG_SLAVE_SOC_WIFI_SUPPORTED
|
||||||
@@ -22,6 +22,10 @@ extern Driver esp32_sdspi_driver;
|
|||||||
extern Driver esp32_spi_driver;
|
extern Driver esp32_spi_driver;
|
||||||
extern Driver esp32_uart_driver;
|
extern Driver esp32_uart_driver;
|
||||||
extern Driver esp32_grove_driver;
|
extern Driver esp32_grove_driver;
|
||||||
|
#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED)
|
||||||
|
extern Driver esp32_wifi_driver;
|
||||||
|
extern Driver esp32_wifi_pinned_driver;
|
||||||
|
#endif
|
||||||
#if defined(CONFIG_BT_NIMBLE_ENABLED)
|
#if defined(CONFIG_BT_NIMBLE_ENABLED)
|
||||||
extern Driver esp32_bluetooth_driver;
|
extern Driver esp32_bluetooth_driver;
|
||||||
extern Driver esp32_ble_serial_driver;
|
extern Driver esp32_ble_serial_driver;
|
||||||
@@ -49,6 +53,10 @@ static error_t start() {
|
|||||||
check(driver_construct_add(&esp32_spi_driver) == ERROR_NONE);
|
check(driver_construct_add(&esp32_spi_driver) == ERROR_NONE);
|
||||||
check(driver_construct_add(&esp32_uart_driver) == ERROR_NONE);
|
check(driver_construct_add(&esp32_uart_driver) == ERROR_NONE);
|
||||||
check(driver_construct_add(&esp32_grove_driver) == ERROR_NONE);
|
check(driver_construct_add(&esp32_grove_driver) == ERROR_NONE);
|
||||||
|
#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED)
|
||||||
|
check(driver_construct_add(&esp32_wifi_driver) == ERROR_NONE);
|
||||||
|
check(driver_construct_add(&esp32_wifi_pinned_driver) == ERROR_NONE);
|
||||||
|
#endif
|
||||||
#if defined(CONFIG_BT_NIMBLE_ENABLED)
|
#if defined(CONFIG_BT_NIMBLE_ENABLED)
|
||||||
check(driver_construct_add(&esp32_bluetooth_driver) == ERROR_NONE);
|
check(driver_construct_add(&esp32_bluetooth_driver) == ERROR_NONE);
|
||||||
check(driver_construct_add(&esp32_ble_serial_driver) == ERROR_NONE);
|
check(driver_construct_add(&esp32_ble_serial_driver) == ERROR_NONE);
|
||||||
@@ -67,6 +75,10 @@ static error_t start() {
|
|||||||
static error_t stop() {
|
static error_t stop() {
|
||||||
/* We crash when destruct fails, because if a single driver fails to destruct,
|
/* We crash when destruct fails, because if a single driver fails to destruct,
|
||||||
* there is no guarantee that the previously destroyed drivers can be recovered */
|
* there is no guarantee that the previously destroyed drivers can be recovered */
|
||||||
|
#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED)
|
||||||
|
check(driver_remove_destruct(&esp32_wifi_pinned_driver) == ERROR_NONE);
|
||||||
|
check(driver_remove_destruct(&esp32_wifi_driver) == ERROR_NONE);
|
||||||
|
#endif
|
||||||
#if SOC_USB_OTG_SUPPORTED
|
#if SOC_USB_OTG_SUPPORTED
|
||||||
check(driver_remove_destruct(&esp32_usbhost_msc_driver) == ERROR_NONE);
|
check(driver_remove_destruct(&esp32_usbhost_msc_driver) == ERROR_NONE);
|
||||||
check(driver_remove_destruct(&esp32_usbhost_midi_driver) == ERROR_NONE);
|
check(driver_remove_destruct(&esp32_usbhost_midi_driver) == ERROR_NONE);
|
||||||
|
|||||||
@@ -0,0 +1,349 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Mock WiFi driver for the simulator: fakes a radio with a fixed list of
|
||||||
|
// access points instead of talking to real hardware. Behaviour is modeled
|
||||||
|
// after Tactility/Source/service/wifi/WifiMock.cpp (the old HAL's equivalent
|
||||||
|
// mock) - actions succeed instantly, there's no real scan or connect delay.
|
||||||
|
|
||||||
|
#include <tactility/concurrent/mutex.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
#include <tactility/driver.h>
|
||||||
|
#include <tactility/drivers/wifi.h>
|
||||||
|
#include <tactility/log.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#define TAG "mock_wifi"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr size_t WIFI_MAX_CALLBACKS = 4;
|
||||||
|
|
||||||
|
struct MockApRecord {
|
||||||
|
const char* ssid;
|
||||||
|
int8_t rssi;
|
||||||
|
WifiAuthenticationType authentication_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Same fixture data as the old WifiMock.cpp, so simulator UI testing sees
|
||||||
|
// familiar results.
|
||||||
|
constexpr MockApRecord MOCK_SCAN_RESULTS[] = {
|
||||||
|
{ "Home Wifi", -30, WIFI_AUTHENTICATION_TYPE_WPA2_PSK },
|
||||||
|
{ "No place like 127.0.0.1", -67, WIFI_AUTHENTICATION_TYPE_WPA2_PSK },
|
||||||
|
{ "Pretty fly for a Wi-Fi", -70, WIFI_AUTHENTICATION_TYPE_WPA2_PSK },
|
||||||
|
{ "An AP with a really, really long name", -80, WIFI_AUTHENTICATION_TYPE_WPA2_PSK },
|
||||||
|
{ "Bad Reception", -90, WIFI_AUTHENTICATION_TYPE_OPEN },
|
||||||
|
};
|
||||||
|
constexpr size_t MOCK_SCAN_RESULT_COUNT = sizeof(MOCK_SCAN_RESULTS) / sizeof(MOCK_SCAN_RESULTS[0]);
|
||||||
|
constexpr int8_t MOCK_CONNECTED_RSSI = -30;
|
||||||
|
constexpr const char* MOCK_IPV4_ADDRESS = "192.168.1.2";
|
||||||
|
|
||||||
|
struct WifiCallbackEntry {
|
||||||
|
WifiEventCallback fn = nullptr;
|
||||||
|
void* ctx = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PosixWifiCtx {
|
||||||
|
Device* device = nullptr;
|
||||||
|
|
||||||
|
Mutex mutex {};
|
||||||
|
WifiRadioState radioState = WIFI_RADIO_STATE_OFF;
|
||||||
|
WifiStationState stationState = WIFI_STATION_STATE_DISCONNECTED;
|
||||||
|
bool scanning = false;
|
||||||
|
char targetSsid[33] = {};
|
||||||
|
|
||||||
|
Mutex callbackMutex {};
|
||||||
|
WifiCallbackEntry callbacks[WIFI_MAX_CALLBACKS] = {};
|
||||||
|
size_t callbackCount = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define GET_CTX(device) (static_cast<PosixWifiCtx*>(device_get_driver_data(device)))
|
||||||
|
|
||||||
|
void fireEvent(PosixWifiCtx* ctx, WifiEvent event) {
|
||||||
|
WifiCallbackEntry local[WIFI_MAX_CALLBACKS];
|
||||||
|
size_t count;
|
||||||
|
mutex_lock(&ctx->callbackMutex);
|
||||||
|
count = ctx->callbackCount;
|
||||||
|
memcpy(local, ctx->callbacks, count * sizeof(WifiCallbackEntry));
|
||||||
|
mutex_unlock(&ctx->callbackMutex);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
local[i].fn(ctx->device, local[i].ctx, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- WifiApi ----
|
||||||
|
|
||||||
|
error_t apiGetRadioState(Device* device, WifiRadioState* state) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || state == nullptr) return ERROR_INVALID_ARGUMENT;
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
*state = ctx->radioState;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t apiGetStationState(Device* device, WifiStationState* state) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || state == nullptr) return ERROR_INVALID_ARGUMENT;
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
*state = ctx->stationState;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t apiGetAccessPointState(Device* device, WifiAccessPointState* state) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || state == nullptr) return ERROR_INVALID_ARGUMENT;
|
||||||
|
// Access point mode isn't implemented by this mock.
|
||||||
|
*state = WIFI_ACCESS_POINT_STATE_STOPPED;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool apiIsScanning(Device* device) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr) return false;
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
bool scanning = ctx->scanning;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
return scanning;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t apiScan(Device* device) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr) return ERROR_INVALID_STATE;
|
||||||
|
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
if (ctx->radioState != WIFI_RADIO_STATE_ON || ctx->scanning) {
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
return ERROR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
ctx->scanning = true;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
|
||||||
|
WifiEvent started_event = {};
|
||||||
|
started_event.type = WIFI_EVENT_TYPE_SCAN_STARTED;
|
||||||
|
fireEvent(ctx, started_event);
|
||||||
|
|
||||||
|
// No real radio, so the "scan" completes instantly.
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
ctx->scanning = false;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
|
||||||
|
WifiEvent finished_event = {};
|
||||||
|
finished_event.type = WIFI_EVENT_TYPE_SCAN_FINISHED;
|
||||||
|
fireEvent(ctx, finished_event);
|
||||||
|
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t apiGetScanResults(Device* device, WifiApRecord* results, size_t* num_results) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || results == nullptr || num_results == nullptr) return ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
size_t count = std::min(*num_results, MOCK_SCAN_RESULT_COUNT);
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
const MockApRecord& src = MOCK_SCAN_RESULTS[i];
|
||||||
|
WifiApRecord& dst = results[i];
|
||||||
|
memset(dst.ssid, 0, sizeof(dst.ssid));
|
||||||
|
strncpy(dst.ssid, src.ssid, sizeof(dst.ssid) - 1);
|
||||||
|
dst.rssi = src.rssi;
|
||||||
|
dst.channel = 1;
|
||||||
|
dst.authentication_type = src.authentication_type;
|
||||||
|
}
|
||||||
|
*num_results = count;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t apiStationGetIpv4Address(Device* device, char* ipv4) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || ipv4 == nullptr) return ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
bool connected = ctx->stationState == WIFI_STATION_STATE_CONNECTED;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
|
||||||
|
strncpy(ipv4, connected ? MOCK_IPV4_ADDRESS : "0.0.0.0", 16);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t apiStationGetTargetSsid(Device* device, char* ssid) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || ssid == nullptr) return ERROR_INVALID_ARGUMENT;
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
strncpy(ssid, ctx->targetSsid, sizeof(ctx->targetSsid));
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t apiStationConnect(Device* device, const char* ssid, const char* password, int32_t channel) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || ssid == nullptr) return ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
if (ctx->radioState != WIFI_RADIO_STATE_ON) {
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
return ERROR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
strncpy(ctx->targetSsid, ssid, sizeof(ctx->targetSsid) - 1);
|
||||||
|
ctx->targetSsid[sizeof(ctx->targetSsid) - 1] = '\0';
|
||||||
|
ctx->stationState = WIFI_STATION_STATE_CONNECTION_PENDING;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
|
||||||
|
WifiEvent pending_event = {};
|
||||||
|
pending_event.type = WIFI_EVENT_TYPE_STATION_STATE_CHANGED;
|
||||||
|
pending_event.station_state = WIFI_STATION_STATE_CONNECTION_PENDING;
|
||||||
|
fireEvent(ctx, pending_event);
|
||||||
|
|
||||||
|
// No real radio to negotiate with, so the mock always succeeds instantly.
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
ctx->stationState = WIFI_STATION_STATE_CONNECTED;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
|
||||||
|
WifiEvent connected_event = {};
|
||||||
|
connected_event.type = WIFI_EVENT_TYPE_STATION_STATE_CHANGED;
|
||||||
|
connected_event.station_state = WIFI_STATION_STATE_CONNECTED;
|
||||||
|
fireEvent(ctx, connected_event);
|
||||||
|
|
||||||
|
WifiEvent result_event = {};
|
||||||
|
result_event.type = WIFI_EVENT_TYPE_STATION_CONNECTION_RESULT;
|
||||||
|
result_event.connection_error = WIFI_STATION_CONNECTION_ERROR_NONE;
|
||||||
|
fireEvent(ctx, result_event);
|
||||||
|
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t apiStationDisconnect(Device* device) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr) return ERROR_INVALID_STATE;
|
||||||
|
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
bool was_connected = ctx->stationState != WIFI_STATION_STATE_DISCONNECTED;
|
||||||
|
ctx->stationState = WIFI_STATION_STATE_DISCONNECTED;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
|
||||||
|
if (was_connected) {
|
||||||
|
WifiEvent event = {};
|
||||||
|
event.type = WIFI_EVENT_TYPE_STATION_STATE_CHANGED;
|
||||||
|
event.station_state = WIFI_STATION_STATE_DISCONNECTED;
|
||||||
|
fireEvent(ctx, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t apiStationGetRssi(Device* device, int32_t* rssi) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || rssi == nullptr) return ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
mutex_lock(&ctx->mutex);
|
||||||
|
bool connected = ctx->stationState == WIFI_STATION_STATE_CONNECTED;
|
||||||
|
mutex_unlock(&ctx->mutex);
|
||||||
|
|
||||||
|
if (!connected) return ERROR_INVALID_STATE;
|
||||||
|
*rssi = MOCK_CONNECTED_RSSI;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t apiAddEventCallback(Device* device, void* callback_context, WifiEventCallback callback) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || callback == nullptr) return ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
mutex_lock(&ctx->callbackMutex);
|
||||||
|
if (ctx->callbackCount >= WIFI_MAX_CALLBACKS) {
|
||||||
|
mutex_unlock(&ctx->callbackMutex);
|
||||||
|
return ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
ctx->callbacks[ctx->callbackCount] = { .fn = callback, .ctx = callback_context };
|
||||||
|
ctx->callbackCount++;
|
||||||
|
mutex_unlock(&ctx->callbackMutex);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t apiRemoveEventCallback(Device* device, WifiEventCallback callback) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr || callback == nullptr) return ERROR_INVALID_ARGUMENT;
|
||||||
|
|
||||||
|
mutex_lock(&ctx->callbackMutex);
|
||||||
|
for (size_t i = 0; i < ctx->callbackCount; i++) {
|
||||||
|
if (ctx->callbacks[i].fn == callback) {
|
||||||
|
for (size_t j = i; j + 1 < ctx->callbackCount; j++) {
|
||||||
|
ctx->callbacks[j] = ctx->callbacks[j + 1];
|
||||||
|
}
|
||||||
|
ctx->callbackCount--;
|
||||||
|
mutex_unlock(&ctx->callbackMutex);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mutex_unlock(&ctx->callbackMutex);
|
||||||
|
return ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
const WifiApi posix_wifi_api = {
|
||||||
|
.get_radio_state = apiGetRadioState,
|
||||||
|
.get_station_state = apiGetStationState,
|
||||||
|
.get_access_point_state = apiGetAccessPointState,
|
||||||
|
.is_scanning = apiIsScanning,
|
||||||
|
.scan = apiScan,
|
||||||
|
.get_scan_results = apiGetScanResults,
|
||||||
|
.station_get_ipv4_address = apiStationGetIpv4Address,
|
||||||
|
.station_get_target_ssid = apiStationGetTargetSsid,
|
||||||
|
.station_connect = apiStationConnect,
|
||||||
|
.station_disconnect = apiStationDisconnect,
|
||||||
|
.station_get_rssi = apiStationGetRssi,
|
||||||
|
.add_event_callback = apiAddEventCallback,
|
||||||
|
.remove_event_callback = apiRemoveEventCallback
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---- Driver lifecycle ----
|
||||||
|
// Unlike the real esp32 driver, there's no hardware to bring up: the radio
|
||||||
|
// simply reports itself as ON as soon as the device is started.
|
||||||
|
|
||||||
|
error_t startDevice(Device* device) {
|
||||||
|
auto* ctx = new(std::nothrow) PosixWifiCtx();
|
||||||
|
if (ctx == nullptr) return ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
ctx->device = device;
|
||||||
|
mutex_construct(&ctx->mutex);
|
||||||
|
mutex_construct(&ctx->callbackMutex);
|
||||||
|
ctx->radioState = WIFI_RADIO_STATE_ON;
|
||||||
|
|
||||||
|
device_set_driver_data(device, ctx);
|
||||||
|
|
||||||
|
LOG_I(TAG, "WiFi radio on (mock)");
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t stopDevice(Device* device) {
|
||||||
|
auto* ctx = GET_CTX(device);
|
||||||
|
if (ctx == nullptr) return ERROR_NONE;
|
||||||
|
|
||||||
|
device_set_driver_data(device, nullptr);
|
||||||
|
mutex_destruct(&ctx->callbackMutex);
|
||||||
|
mutex_destruct(&ctx->mutex);
|
||||||
|
delete ctx;
|
||||||
|
|
||||||
|
LOG_I(TAG, "WiFi radio off (mock)");
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
extern Module platform_posix_module;
|
||||||
|
|
||||||
|
Driver posix_wifi_driver = {
|
||||||
|
.name = "mock_wifi",
|
||||||
|
.compatible = (const char*[]) { "posix,mock-wifi", nullptr },
|
||||||
|
.start_device = startDevice,
|
||||||
|
.stop_device = stopDevice,
|
||||||
|
.api = (const void*)&posix_wifi_api,
|
||||||
|
.device_type = &WIFI_TYPE,
|
||||||
|
.owner = &platform_posix_module,
|
||||||
|
.internal = nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
@@ -1,15 +1,19 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/driver.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
|
extern Driver posix_wifi_driver;
|
||||||
|
|
||||||
static error_t start() {
|
static error_t start() {
|
||||||
/* NO-OP for now */
|
check(driver_construct_add(&posix_wifi_driver) == ERROR_NONE);
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static error_t stop() {
|
static error_t stop() {
|
||||||
/* NO-OP for now */
|
check(driver_remove_destruct(&posix_wifi_driver) == ERROR_NONE);
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,45 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "tactility/concurrent/dispatcher.h"
|
||||||
#include "tactility/device.h"
|
#include "tactility/device.h"
|
||||||
#include "tactility/module.h"
|
#include "tactility/module.h"
|
||||||
#include <Tactility/Dispatcher.h>
|
|
||||||
#include <Tactility/app/AppManifest.h>
|
#include <Tactility/app/AppManifest.h>
|
||||||
#include <Tactility/hal/Configuration.h>
|
#include <Tactility/hal/Configuration.h>
|
||||||
#include <Tactility/service/ServiceManifest.h>
|
#include <Tactility/service/ServiceManifest.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
struct DtsDevice;
|
struct DtsDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace tt {
|
namespace tt {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A thin C++ wrapper around the TactilityKernel dispatcher, allowing
|
||||||
|
* std::function (and therefore capturing lambdas) to be dispatched.
|
||||||
|
*/
|
||||||
|
class MainDispatcher final {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
using Function = std::function<void()>;
|
||||||
|
|
||||||
|
explicit MainDispatcher(DispatcherHandle_t handle) : handle(handle) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queue a function to be consumed on the main task.
|
||||||
|
* @param[in] function the function to execute elsewhere
|
||||||
|
* @param[in] timeout lock acquisition timeout
|
||||||
|
* @return true if dispatching was successful (timeout not reached)
|
||||||
|
*/
|
||||||
|
bool dispatch(Function function, TickType_t timeout = portMAX_DELAY) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
DispatcherHandle_t handle;
|
||||||
|
};
|
||||||
|
|
||||||
/** @brief The configuration for the operating system
|
/** @brief The configuration for the operating system
|
||||||
* It contains the hardware configuration, apps and services
|
* It contains the hardware configuration, apps and services
|
||||||
*/
|
*/
|
||||||
@@ -39,7 +66,7 @@ const Configuration* getConfiguration();
|
|||||||
* @warning This dispatcher is used for WiFi and might block for some time during WiFi connection.
|
* @warning This dispatcher is used for WiFi and might block for some time during WiFi connection.
|
||||||
* @return the dispatcher
|
* @return the dispatcher
|
||||||
*/
|
*/
|
||||||
Dispatcher& getMainDispatcher();
|
MainDispatcher getMainDispatcher();
|
||||||
|
|
||||||
namespace hal {
|
namespace hal {
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <tactility/drivers/spi_controller.h>
|
|
||||||
#include <tactility/device.h>
|
|
||||||
|
|
||||||
#include <Tactility/Lock.h>
|
|
||||||
|
|
||||||
namespace tt {
|
|
||||||
|
|
||||||
class SpiDeviceLock : public Lock {
|
|
||||||
::Device* device;
|
|
||||||
public:
|
|
||||||
explicit SpiDeviceLock(::Device* device) : device(device) { }
|
|
||||||
|
|
||||||
bool lock(TickType_t timeout) const override {
|
|
||||||
return spi_controller_try_lock(device, timeout) == ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void unlock() const override {
|
|
||||||
spi_controller_unlock(device);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_PLATFORM
|
||||||
|
|
||||||
#include <esp_http_server.h>
|
|
||||||
#include <Tactility/RecursiveMutex.h>
|
#include <Tactility/RecursiveMutex.h>
|
||||||
#include <Tactility/kernel/SystemEvents.h>
|
#include <esp_http_server.h>
|
||||||
|
|
||||||
namespace tt::network {
|
namespace tt::network {
|
||||||
|
|
||||||
|
|||||||
@@ -6,52 +6,16 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "WifiApSettings.h"
|
#include <tactility/drivers/wifi.h>
|
||||||
|
|
||||||
#ifdef ESP_PLATFORM
|
#include "WifiApSettings.h"
|
||||||
#include <esp_wifi.h>
|
|
||||||
#else
|
|
||||||
#include <cstdint>
|
|
||||||
// From esp_wifi_types.h in ESP-IDF 5.2
|
|
||||||
typedef enum {
|
|
||||||
WIFI_AUTH_OPEN = 0, /**< authenticate mode : open */
|
|
||||||
WIFI_AUTH_WEP, /**< authenticate mode : WEP */
|
|
||||||
WIFI_AUTH_WPA_PSK, /**< authenticate mode : WPA_PSK */
|
|
||||||
WIFI_AUTH_WPA2_PSK, /**< authenticate mode : WPA2_PSK */
|
|
||||||
WIFI_AUTH_WPA_WPA2_PSK, /**< authenticate mode : WPA_WPA2_PSK */
|
|
||||||
WIFI_AUTH_ENTERPRISE, /**< authenticate mode : WiFi EAP security */
|
|
||||||
WIFI_AUTH_WPA2_ENTERPRISE = WIFI_AUTH_ENTERPRISE, /**< authenticate mode : WiFi EAP security */
|
|
||||||
WIFI_AUTH_WPA3_PSK, /**< authenticate mode : WPA3_PSK */
|
|
||||||
WIFI_AUTH_WPA2_WPA3_PSK, /**< authenticate mode : WPA2_WPA3_PSK */
|
|
||||||
WIFI_AUTH_WAPI_PSK, /**< authenticate mode : WAPI_PSK */
|
|
||||||
WIFI_AUTH_OWE, /**< authenticate mode : OWE */
|
|
||||||
WIFI_AUTH_WPA3_ENT_192, /**< authenticate mode : WPA3_ENT_SUITE_B_192_BIT */
|
|
||||||
WIFI_AUTH_WPA3_EXT_PSK, /**< authenticate mode : WPA3_PSK_EXT_KEY */
|
|
||||||
WIFI_AUTH_WPA3_EXT_PSK_MIXED_MODE, /**< authenticate mode: WPA3_PSK + WPA3_PSK_EXT_KEY */
|
|
||||||
WIFI_AUTH_MAX
|
|
||||||
} wifi_auth_mode_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace tt::service::wifi {
|
namespace tt::service::wifi {
|
||||||
|
|
||||||
enum class WifiEvent {
|
/** The kernel wifi driver's event type: a WifiEventType tag plus a union
|
||||||
/** Radio was turned on */
|
* payload (radio_state/station_state/access_point_state/connection_error
|
||||||
RadioStateOn,
|
* depending on the tag). See tactility/drivers/wifi.h. */
|
||||||
/** Radio is turning on. */
|
using WifiEvent = ::WifiEvent;
|
||||||
RadioStateOnPending,
|
|
||||||
/** Radio is turned off */
|
|
||||||
RadioStateOff,
|
|
||||||
/** Radio is turning off */
|
|
||||||
RadioStateOffPending,
|
|
||||||
/** Started scanning for access points */
|
|
||||||
ScanStarted,
|
|
||||||
/** Finished scanning for access points */ // TODO: 1 second validity
|
|
||||||
ScanFinished,
|
|
||||||
Disconnected,
|
|
||||||
ConnectionPending,
|
|
||||||
ConnectionSuccess,
|
|
||||||
ConnectionFailed
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class RadioState {
|
enum class RadioState {
|
||||||
OnPending,
|
OnPending,
|
||||||
@@ -62,13 +26,6 @@ enum class RadioState {
|
|||||||
Off,
|
Off,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ApRecord {
|
|
||||||
std::string ssid;
|
|
||||||
int8_t rssi;
|
|
||||||
int32_t channel;
|
|
||||||
wifi_auth_mode_t auth_mode;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get wifi pubsub that broadcasts Event objects
|
* @brief Get wifi pubsub that broadcasts Event objects
|
||||||
* @return PubSub
|
* @return PubSub
|
||||||
@@ -93,7 +50,7 @@ bool isScanning();
|
|||||||
std::string getConnectionTarget();
|
std::string getConnectionTarget();
|
||||||
|
|
||||||
/** @return the access points from the last scan (if any). It only contains public APs. */
|
/** @return the access points from the last scan (if any). It only contains public APs. */
|
||||||
std::vector<ApRecord> getScanResults();
|
std::vector<WifiApRecord> getScanResults();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Overrides the default scan result size of 16.
|
* @brief Overrides the default scan result size of 16.
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class State final {
|
|||||||
bool scanning = false;
|
bool scanning = false;
|
||||||
bool scannedAfterRadioOn = false;
|
bool scannedAfterRadioOn = false;
|
||||||
service::wifi::RadioState radioState;
|
service::wifi::RadioState radioState;
|
||||||
std::vector<service::wifi::ApRecord> apRecords;
|
std::vector<WifiApRecord> apRecords;
|
||||||
std::string connectSsid;
|
std::string connectSsid;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -30,14 +30,14 @@ public:
|
|||||||
|
|
||||||
void updateApRecords();
|
void updateApRecords();
|
||||||
|
|
||||||
template <std::invocable<const std::vector<service::wifi::ApRecord>&> Func>
|
template <std::invocable<const std::vector<WifiApRecord>&> Func>
|
||||||
void withApRecords(Func&& onApRecords) const {
|
void withApRecords(Func&& onApRecords) const {
|
||||||
mutex.withLock([&] {
|
mutex.withLock([&] {
|
||||||
std::invoke(std::forward<Func>(onApRecords), apRecords);
|
std::invoke(std::forward<Func>(onApRecords), apRecords);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<service::wifi::ApRecord> getApRecords() const {
|
std::vector<WifiApRecord> getApRecords() const {
|
||||||
auto lock = mutex.asScopedLock();
|
auto lock = mutex.asScopedLock();
|
||||||
lock.lock();
|
lock.lock();
|
||||||
return apRecords;
|
return apRecords;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class View final {
|
|||||||
void updateScanning();
|
void updateScanning();
|
||||||
void updateNetworkList();
|
void updateNetworkList();
|
||||||
void updateConnectToHidden();
|
void updateConnectToHidden();
|
||||||
void createSsidListItem(const service::wifi::ApRecord& record, bool isConnecting, size_t index);
|
void createSsidListItem(const WifiApRecord& record, bool isConnecting, size_t index);
|
||||||
|
|
||||||
static void showDetails(lv_event_t* event);
|
static void showDetails(lv_event_t* event);
|
||||||
static void connect(lv_event_t* event);
|
static void connect(lv_event_t* event);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include <Tactility/kernel/critical/Critical.h>
|
#include <Tactility/Critical.h>
|
||||||
|
|
||||||
#include <Tactility/freertoscompat/Task.h>
|
#include <Tactility/freertoscompat/Task.h>
|
||||||
#include <Tactility/kernel/Kernel.h>
|
#include <Tactility/kernel/Kernel.h>
|
||||||
@@ -86,7 +86,7 @@ const CrashData& getRtcCrashData() { return crashData; }
|
|||||||
// Stub implementation for RISC-V and other architectures
|
// Stub implementation for RISC-V and other architectures
|
||||||
// TODO: Implement crash data collection for RISC-V using frame pointer or EH frame
|
// TODO: Implement crash data collection for RISC-V using frame pointer or EH frame
|
||||||
|
|
||||||
#include <Tactility/kernel/PanicHandler.h>
|
#include <Tactility/PanicHandler.h>
|
||||||
|
|
||||||
static CrashData emptyCrashData = {};
|
static CrashData emptyCrashData = {};
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "Tactility/kernel/Platform.h"
|
#include "../Include/Tactility/Platform.h"
|
||||||
|
|
||||||
namespace tt::kernel {
|
namespace tt::kernel {
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include <Tactility/kernel/SystemEvents.h>
|
#include <Tactility/SystemEvents.h>
|
||||||
|
|
||||||
#include <Tactility/Mutex.h>
|
#include <Tactility/Mutex.h>
|
||||||
#include <tactility/check.h>
|
#include <tactility/check.h>
|
||||||
@@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
#include <Tactility/LogMessages.h>
|
#include <Tactility/LogMessages.h>
|
||||||
#include <Tactility/CpuAffinity.h>
|
#include <Tactility/CpuAffinity.h>
|
||||||
#include <Tactility/DispatcherThread.h>
|
|
||||||
#include <Tactility/MountPoints.h>
|
#include <Tactility/MountPoints.h>
|
||||||
#include <Tactility/app/AppManifestParsing.h>
|
#include <Tactility/app/AppManifestParsing.h>
|
||||||
#include <Tactility/app/AppRegistration.h>
|
#include <Tactility/app/AppRegistration.h>
|
||||||
@@ -46,7 +45,26 @@ namespace tt {
|
|||||||
constexpr auto* TAG = "Tactility";
|
constexpr auto* TAG = "Tactility";
|
||||||
|
|
||||||
static const Configuration* config_instance = nullptr;
|
static const Configuration* config_instance = nullptr;
|
||||||
static Dispatcher mainDispatcher;
|
static DispatcherHandle_t mainDispatcherHandle = dispatcher_alloc();
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void mainDispatcherTrampoline(void* context) {
|
||||||
|
auto* function = static_cast<MainDispatcher::Function*>(context);
|
||||||
|
(*function)();
|
||||||
|
delete function;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool MainDispatcher::dispatch(Function function, TickType_t timeout) const {
|
||||||
|
auto* boxed = new Function(std::move(function));
|
||||||
|
if (dispatcher_dispatch_timed(handle, boxed, mainDispatcherTrampoline, timeout) != ERROR_NONE) {
|
||||||
|
delete boxed;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// region Default services
|
// region Default services
|
||||||
namespace service {
|
namespace service {
|
||||||
@@ -376,7 +394,7 @@ void run(const Configuration& config, Module* dtsModules[], DtsDevice dtsDevices
|
|||||||
|
|
||||||
LOG_I(TAG, "Main dispatcher ready");
|
LOG_I(TAG, "Main dispatcher ready");
|
||||||
while (true) {
|
while (true) {
|
||||||
mainDispatcher.consume();
|
dispatcher_consume(mainDispatcherHandle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -385,8 +403,8 @@ const Configuration* getConfiguration() {
|
|||||||
return config_instance;
|
return config_instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dispatcher& getMainDispatcher() {
|
MainDispatcher getMainDispatcher() {
|
||||||
return mainDispatcher;
|
return MainDispatcher(mainDispatcherHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
#include "Tactility/lvgl/Lvgl.h"
|
#include "Tactility/lvgl/Lvgl.h"
|
||||||
|
|
||||||
#include <Tactility/TactilityCore.h>
|
#include <Tactility/SystemEvents.h>
|
||||||
|
#include <Tactility/CpuAffinity.h>
|
||||||
|
#include <Tactility/Paths.h>
|
||||||
#include <Tactility/TactilityPrivate.h>
|
#include <Tactility/TactilityPrivate.h>
|
||||||
#include <Tactility/app/alertdialog/AlertDialog.h>
|
|
||||||
#include <Tactility/app/AppContext.h>
|
#include <Tactility/app/AppContext.h>
|
||||||
#include <Tactility/app/AppPaths.h>
|
#include <Tactility/app/AppPaths.h>
|
||||||
#include <Tactility/CpuAffinity.h>
|
#include <Tactility/app/alertdialog/AlertDialog.h>
|
||||||
#include <Tactility/hal/display/DisplayDevice.h>
|
#include <Tactility/hal/display/DisplayDevice.h>
|
||||||
#include <Tactility/hal/usb/Usb.h>
|
#include <Tactility/hal/usb/Usb.h>
|
||||||
#include <Tactility/kernel/SystemEvents.h>
|
|
||||||
#include <Tactility/lvgl/Style.h>
|
#include <Tactility/lvgl/Style.h>
|
||||||
#include <Tactility/Paths.h>
|
|
||||||
#include <Tactility/service/loader/Loader.h>
|
#include <Tactility/service/loader/Loader.h>
|
||||||
#include <Tactility/settings/BootSettings.h>
|
#include <Tactility/settings/BootSettings.h>
|
||||||
#include <Tactility/settings/DisplaySettings.h>
|
#include <Tactility/settings/DisplaySettings.h>
|
||||||
@@ -21,8 +20,8 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_PLATFORM
|
||||||
#include "Tactility/app/crashdiagnostics/CrashDiagnostics.h"
|
#include <Tactility/app/crashdiagnostics/CrashDiagnostics.h>
|
||||||
#include <Tactility/kernel/PanicHandler.h>
|
#include <Tactility/PanicHandler.h>
|
||||||
#include <esp_system.h>
|
#include <esp_system.h>
|
||||||
#include <sdkconfig.h>
|
#include <sdkconfig.h>
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_PLATFORM
|
||||||
|
|
||||||
#include <Tactility/app/crashdiagnostics/QrUrl.h>
|
#include <Tactility/app/crashdiagnostics/QrUrl.h>
|
||||||
#include <Tactility/kernel/PanicHandler.h>
|
#include <Tactility/PanicHandler.h>
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
#include <Tactility/app/files/State.h>
|
#include <Tactility/app/files/State.h>
|
||||||
|
|
||||||
#include <Tactility/LogMessages.h>
|
#include <Tactility/Platform.h>
|
||||||
#include <Tactility/MountPoints.h>
|
#include <Tactility/MountPoints.h>
|
||||||
#include <Tactility/file/File.h>
|
#include <Tactility/file/File.h>
|
||||||
#include <Tactility/file/FileLock.h>
|
#include <Tactility/file/FileLock.h>
|
||||||
#include <Tactility/kernel/Platform.h>
|
|
||||||
#include <tactility/log.h>
|
#include <tactility/log.h>
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
#include <Tactility/app/files/SupportedFiles.h>
|
#include <Tactility/app/files/SupportedFiles.h>
|
||||||
#include <Tactility/app/files/View.h>
|
#include <Tactility/app/files/View.h>
|
||||||
|
|
||||||
#include <Tactility/LogMessages.h>
|
#include <Tactility/Platform.h>
|
||||||
#include <Tactility/StringUtils.h>
|
#include <Tactility/StringUtils.h>
|
||||||
#include <Tactility/Tactility.h>
|
#include <Tactility/Tactility.h>
|
||||||
#include <Tactility/app/ElfApp.h>
|
|
||||||
#include <Tactility/app/alertdialog/AlertDialog.h>
|
#include <Tactility/app/alertdialog/AlertDialog.h>
|
||||||
#include <Tactility/app/imageviewer/ImageViewer.h>
|
#include <Tactility/app/imageviewer/ImageViewer.h>
|
||||||
#include <Tactility/app/inputdialog/InputDialog.h>
|
#include <Tactility/app/inputdialog/InputDialog.h>
|
||||||
#include <Tactility/app/notes/Notes.h>
|
#include <Tactility/app/notes/Notes.h>
|
||||||
#include <Tactility/file/File.h>
|
#include <Tactility/file/File.h>
|
||||||
#include <Tactility/kernel/Platform.h>
|
|
||||||
#include <Tactility/lvgl/LvglSync.h>
|
#include <Tactility/lvgl/LvglSync.h>
|
||||||
#include <Tactility/lvgl/Toolbar.h>
|
#include <Tactility/lvgl/Toolbar.h>
|
||||||
#include <tactility/check.h>
|
#include <tactility/check.h>
|
||||||
|
|||||||
@@ -2,12 +2,11 @@
|
|||||||
|
|
||||||
#include <Tactility/file/File.h>
|
#include <Tactility/file/File.h>
|
||||||
#include <Tactility/MountPoints.h>
|
#include <Tactility/MountPoints.h>
|
||||||
#include <Tactility/kernel/Platform.h>
|
#include <Tactility/Platform.h>
|
||||||
|
|
||||||
#include <Tactility/LogMessages.h>
|
|
||||||
#include <cstring>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <tactility/log.h>
|
#include <tactility/log.h>
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#include <Tactility/Tactility.h>
|
#include <Tactility/Tactility.h>
|
||||||
#include <Tactility/app/alertdialog/AlertDialog.h>
|
#include <Tactility/app/alertdialog/AlertDialog.h>
|
||||||
#include <Tactility/file/File.h>
|
#include <Tactility/file/File.h>
|
||||||
#include <Tactility/kernel/Platform.h>
|
#include <Tactility/Platform.h>
|
||||||
#include <Tactility/lvgl/LvglSync.h>
|
#include <Tactility/lvgl/LvglSync.h>
|
||||||
#include <Tactility/lvgl/Toolbar.h>
|
#include <Tactility/lvgl/Toolbar.h>
|
||||||
#include <tactility/check.h>
|
#include <tactility/check.h>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
#if TT_FEATURE_SCREENSHOT_ENABLED
|
#if TT_FEATURE_SCREENSHOT_ENABLED
|
||||||
|
|
||||||
|
#include <Tactility/Platform.h>
|
||||||
#include <Tactility/app/App.h>
|
#include <Tactility/app/App.h>
|
||||||
#include <Tactility/app/AppManifest.h>
|
#include <Tactility/app/AppManifest.h>
|
||||||
#include <Tactility/kernel/Platform.h>
|
|
||||||
#include <Tactility/lvgl/Lvgl.h>
|
#include <Tactility/lvgl/Lvgl.h>
|
||||||
#include <Tactility/lvgl/LvglSync.h>
|
#include <Tactility/lvgl/LvglSync.h>
|
||||||
#include <Tactility/lvgl/Toolbar.h>
|
#include <Tactility/lvgl/Toolbar.h>
|
||||||
|
|||||||
@@ -25,22 +25,19 @@ static void onConnect(const service::wifi::settings::WifiApSettings& ap_settings
|
|||||||
|
|
||||||
void WifiConnect::onWifiEvent(service::wifi::WifiEvent event) {
|
void WifiConnect::onWifiEvent(service::wifi::WifiEvent event) {
|
||||||
State& state = getState();
|
State& state = getState();
|
||||||
switch (event) {
|
if (event.type == WIFI_EVENT_TYPE_STATION_CONNECTION_RESULT) {
|
||||||
case service::wifi::WifiEvent::ConnectionFailed:
|
if (event.connection_error == WIFI_STATION_CONNECTION_ERROR_NONE) {
|
||||||
|
if (state.isConnecting()) {
|
||||||
|
state.setConnecting(false);
|
||||||
|
stop(manifest.appId);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (state.isConnecting()) {
|
if (state.isConnecting()) {
|
||||||
state.setConnecting(false);
|
state.setConnecting(false);
|
||||||
state.setConnectionError(true);
|
state.setConnectionError(true);
|
||||||
requestViewUpdate();
|
requestViewUpdate();
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
case service::wifi::WifiEvent::ConnectionSuccess:
|
|
||||||
if (getState().isConnecting()) {
|
|
||||||
state.setConnecting(false);
|
|
||||||
stop(manifest.appId);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
requestViewUpdate();
|
requestViewUpdate();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ void View::connect(lv_event_t* event) {
|
|||||||
|
|
||||||
if (index < ap_records.size()) {
|
if (index < ap_records.size()) {
|
||||||
LOG_I(TAG, "Clicked %zu/%zu", index, ap_records.size() - 1);
|
LOG_I(TAG, "Clicked %zu/%zu", index, ap_records.size() - 1);
|
||||||
auto& ssid = ap_records[index].ssid;
|
std::string ssid = ap_records[index].ssid;
|
||||||
LOG_I(TAG, "Clicked AP: %s", ssid.c_str());
|
LOG_I(TAG, "Clicked AP: %s", ssid.c_str());
|
||||||
std::string connection_target = service::wifi::getConnectionTarget();
|
std::string connection_target = service::wifi::getConnectionTarget();
|
||||||
if (connection_target == ssid) {
|
if (connection_target == ssid) {
|
||||||
@@ -97,7 +97,7 @@ void View::showDetails(lv_event_t* event) {
|
|||||||
auto ap_records = self->state->getApRecords();
|
auto ap_records = self->state->getApRecords();
|
||||||
|
|
||||||
if (index < ap_records.size()) {
|
if (index < ap_records.size()) {
|
||||||
auto& ssid = ap_records[index].ssid;
|
std::string ssid = ap_records[index].ssid;
|
||||||
LOG_I(TAG, "Clicked AP: %s", ssid.c_str());
|
LOG_I(TAG, "Clicked AP: %s", ssid.c_str());
|
||||||
self->bindings->onShowApSettings(ssid);
|
self->bindings->onShowApSettings(ssid);
|
||||||
} else {
|
} else {
|
||||||
@@ -105,14 +105,14 @@ void View::showDetails(lv_event_t* event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void View::createSsidListItem(const service::wifi::ApRecord& record, bool isConnecting, size_t index) {
|
void View::createSsidListItem(const WifiApRecord& record, bool isConnecting, size_t index) {
|
||||||
if (isConnecting) {
|
if (isConnecting) {
|
||||||
auto* button = lv_list_add_button(networks_list, LV_SYMBOL_WIFI, record.ssid.c_str());
|
auto* button = lv_list_add_button(networks_list, LV_SYMBOL_WIFI, record.ssid);
|
||||||
lv_obj_add_event_cb(button, showDetails, LV_EVENT_SHORT_CLICKED, this);
|
lv_obj_add_event_cb(button, showDetails, LV_EVENT_SHORT_CLICKED, this);
|
||||||
} else {
|
} else {
|
||||||
const std::string auth_info = (record.auth_mode == WIFI_AUTH_OPEN) ? "(open) " : " ";
|
const std::string auth_info = (record.authentication_type == WIFI_AUTHENTICATION_TYPE_OPEN) ? "(open) " : " ";
|
||||||
const auto percentage = mapRssiToPercentage(record.rssi);
|
const auto percentage = mapRssiToPercentage(record.rssi);
|
||||||
const auto label = std::format("{} {}{}%", record.ssid, auth_info, percentage);
|
const auto label = std::format("{} {}{}%", std::string(record.ssid), auth_info, percentage);
|
||||||
auto* button = lv_list_add_button(networks_list, nullptr, label.c_str());
|
auto* button = lv_list_add_button(networks_list, nullptr, label.c_str());
|
||||||
lv_obj_set_user_data(button, reinterpret_cast<void*>(index));
|
lv_obj_set_user_data(button, reinterpret_cast<void*>(index));
|
||||||
if (service::wifi::settings::contains(record.ssid)) {
|
if (service::wifi::settings::contains(record.ssid)) {
|
||||||
|
|||||||
@@ -79,17 +79,16 @@ void WifiManage::onWifiEvent(service::wifi::WifiEvent event) {
|
|||||||
auto radio_state = service::wifi::getRadioState();
|
auto radio_state = service::wifi::getRadioState();
|
||||||
LOG_I(TAG, "Update with state %s", service::wifi::radioStateToString(radio_state));
|
LOG_I(TAG, "Update with state %s", service::wifi::radioStateToString(radio_state));
|
||||||
getState().setRadioState(radio_state);
|
getState().setRadioState(radio_state);
|
||||||
switch (event) {
|
switch (event.type) {
|
||||||
using enum service::wifi::WifiEvent;
|
case WIFI_EVENT_TYPE_SCAN_STARTED:
|
||||||
case ScanStarted:
|
|
||||||
getState().setScanning(true);
|
getState().setScanning(true);
|
||||||
break;
|
break;
|
||||||
case ScanFinished:
|
case WIFI_EVENT_TYPE_SCAN_FINISHED:
|
||||||
getState().setScanning(false);
|
getState().setScanning(false);
|
||||||
getState().updateApRecords();
|
getState().updateApRecords();
|
||||||
break;
|
break;
|
||||||
case RadioStateOn:
|
case WIFI_EVENT_TYPE_RADIO_STATE_CHANGED:
|
||||||
if (!service::wifi::isScanning()) {
|
if (event.radio_state == WIFI_RADIO_STATE_ON && !service::wifi::isScanning()) {
|
||||||
service::wifi::scan();
|
service::wifi::scan();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
#include <Tactility/SystemEvents.h>
|
||||||
#include <Tactility/Tactility.h>
|
#include <Tactility/Tactility.h>
|
||||||
#include <Tactility/hal/Configuration.h>
|
#include <Tactility/hal/Configuration.h>
|
||||||
#include <Tactility/hal/display/DisplayDevice.h>
|
|
||||||
#include <Tactility/hal/SdCard.h>
|
#include <Tactility/hal/SdCard.h>
|
||||||
|
#include <Tactility/hal/display/DisplayDevice.h>
|
||||||
#include <Tactility/hal/touch/TouchDevice.h>
|
#include <Tactility/hal/touch/TouchDevice.h>
|
||||||
#include <Tactility/kernel/SystemEvents.h>
|
|
||||||
|
|
||||||
#include <tactility/check.h>
|
#include <tactility/check.h>
|
||||||
#include <tactility/hal/Device.h>
|
#include <tactility/hal/Device.h>
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
#define LV_USE_PRIVATE_API 1 // For actual lv_obj_t declaration
|
#define LV_USE_PRIVATE_API 1 // For actual lv_obj_t declaration
|
||||||
|
|
||||||
#include <Tactility/LogMessages.h>
|
#include <Tactility/SystemEvents.h>
|
||||||
#include <Tactility/PubSub.h>
|
#include <Tactility/PubSub.h>
|
||||||
#include <Tactility/RecursiveMutex.h>
|
#include <Tactility/RecursiveMutex.h>
|
||||||
#include <Tactility/Tactility.h>
|
#include <Tactility/Tactility.h>
|
||||||
#include <Tactility/Timer.h>
|
#include <Tactility/Timer.h>
|
||||||
#include <Tactility/kernel/SystemEvents.h>
|
|
||||||
#include <Tactility/lvgl/LvglSync.h>
|
#include <Tactility/lvgl/LvglSync.h>
|
||||||
#include <Tactility/lvgl/Statusbar.h>
|
#include <Tactility/lvgl/Statusbar.h>
|
||||||
#include <Tactility/lvgl/Style.h>
|
#include <Tactility/lvgl/Style.h>
|
||||||
@@ -17,6 +16,7 @@
|
|||||||
#include <tactility/lvgl_module.h>
|
#include <tactility/lvgl_module.h>
|
||||||
|
|
||||||
#include <lvgl.h>
|
#include <lvgl.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace tt::lvgl {
|
namespace tt::lvgl {
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_PLATFORM
|
||||||
#include <Tactility/kernel/SystemEvents.h>
|
#include <Tactility/SystemEvents.h>
|
||||||
#include <Tactility/TactilityCore.h>
|
#include <Tactility/TactilityCore.h>
|
||||||
#include <esp_netif_sntp.h>
|
#include <esp_netif_sntp.h>
|
||||||
#include <esp_sntp.h>
|
#include <esp_sntp.h>
|
||||||
|
|||||||
@@ -1,12 +1,30 @@
|
|||||||
#include <Tactility/service/wifi/Wifi.h>
|
#include <Tactility/service/wifi/Wifi.h>
|
||||||
|
|
||||||
#include <Tactility/CoreDefines.h>
|
#include <Tactility/CoreDefines.h>
|
||||||
#include <tactility/check.h>
|
#include <Tactility/LogMessages.h>
|
||||||
|
#include <Tactility/RecursiveMutex.h>
|
||||||
|
#include <Tactility/SystemEvents.h>
|
||||||
|
#include <Tactility/Tactility.h>
|
||||||
|
#include <Tactility/Timer.h>
|
||||||
|
#include <Tactility/service/Service.h>
|
||||||
#include <Tactility/service/ServiceManifest.h>
|
#include <Tactility/service/ServiceManifest.h>
|
||||||
#include <Tactility/service/ServiceRegistration.h>
|
#include <Tactility/service/ServiceRegistration.h>
|
||||||
|
#include <Tactility/service/wifi/WifiBootSplashInit.h>
|
||||||
|
#include <Tactility/service/wifi/WifiGlobals.h>
|
||||||
|
#include <Tactility/service/wifi/WifiSettings.h>
|
||||||
|
|
||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
#include <tactility/drivers/wifi.h>
|
||||||
|
#include <tactility/log.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace tt::service::wifi {
|
namespace tt::service::wifi {
|
||||||
|
|
||||||
|
constexpr auto* TAG = "WifiService";
|
||||||
|
constexpr auto AUTO_SCAN_INTERVAL = 10000; // ms
|
||||||
|
|
||||||
const char* radioStateToString(RadioState state) {
|
const char* radioStateToString(RadioState state) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
using enum RadioState;
|
using enum RadioState;
|
||||||
@@ -32,4 +50,479 @@ std::shared_ptr<ServiceContext> findServiceContext() {
|
|||||||
return findServiceContextById(manifest.id);
|
return findServiceContextById(manifest.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Everything below wraps a TactilityKernel WIFI_TYPE device: the driver owns
|
||||||
|
// the radio state, station state and scan results, this file only tracks the
|
||||||
|
// bits the kernel driver doesn't (in-flight connection target/credentials,
|
||||||
|
// auto-connect bookkeeping).
|
||||||
|
|
||||||
|
/** State lives for the entire process; only ever (re)initialized by onStart(). */
|
||||||
|
struct WifiServiceState {
|
||||||
|
Device* device = nullptr;
|
||||||
|
std::shared_ptr<PubSub<WifiEvent>> pubsub = std::make_shared<PubSub<WifiEvent>>();
|
||||||
|
RecursiveMutex mutex;
|
||||||
|
bool secureConnection = false;
|
||||||
|
bool pauseAutoConnect = false;
|
||||||
|
bool connectionTargetRemember = false;
|
||||||
|
settings::WifiApSettings connectionTarget;
|
||||||
|
uint16_t scanRecordLimit = TT_WIFI_SCAN_RECORD_LIMIT;
|
||||||
|
TickType_t lastScanTime = kernel::MAX_TICKS;
|
||||||
|
std::unique_ptr<Timer> autoConnectTimer;
|
||||||
|
kernel::SystemEventSubscription bootEventSubscription = kernel::NoSystemEventSubscription;
|
||||||
|
};
|
||||||
|
|
||||||
|
WifiServiceState state;
|
||||||
|
bool started = false;
|
||||||
|
|
||||||
|
void onWifiDeviceEvent(Device* device, void* context, ::WifiEvent event);
|
||||||
|
|
||||||
|
// ---- Helpers ----
|
||||||
|
|
||||||
|
void publish(WifiEvent event) {
|
||||||
|
state.pubsub->publish(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void publishRadioState(WifiRadioState radio_state) {
|
||||||
|
WifiEvent event = {};
|
||||||
|
event.type = WIFI_EVENT_TYPE_RADIO_STATE_CHANGED;
|
||||||
|
event.radio_state = radio_state;
|
||||||
|
publish(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
RadioState combineRadioState(WifiRadioState radio, WifiStationState station) {
|
||||||
|
switch (radio) {
|
||||||
|
case WIFI_RADIO_STATE_OFF: return RadioState::Off;
|
||||||
|
case WIFI_RADIO_STATE_ON_PENDING: return RadioState::OnPending;
|
||||||
|
case WIFI_RADIO_STATE_OFF_PENDING: return RadioState::OffPending;
|
||||||
|
case WIFI_RADIO_STATE_ON:
|
||||||
|
switch (station) {
|
||||||
|
case WIFI_STATION_STATE_CONNECTION_PENDING: return RadioState::ConnectionPending;
|
||||||
|
case WIFI_STATION_STATE_CONNECTED: return RadioState::ConnectionActive;
|
||||||
|
case WIFI_STATION_STATE_DISCONNECTED: default: return RadioState::On;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return RadioState::Off;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Dispatched work (runs on the main task) ----
|
||||||
|
|
||||||
|
void dispatchSetEnabled(bool enabled) {
|
||||||
|
LOG_I(TAG, "dispatchSetEnabled(%d)", (int)enabled);
|
||||||
|
if (!started || state.device == nullptr) return;
|
||||||
|
|
||||||
|
bool ready = device_is_ready(state.device);
|
||||||
|
if (enabled == ready) {
|
||||||
|
LOG_W(TAG, "Can't enable/disable from current state");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enabled) {
|
||||||
|
publishRadioState(WIFI_RADIO_STATE_ON_PENDING);
|
||||||
|
|
||||||
|
if (device_start(state.device) != ERROR_NONE) {
|
||||||
|
LOG_E(TAG, "Failed to start WiFi device");
|
||||||
|
publishRadioState(WIFI_RADIO_STATE_OFF);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wifi_add_event_callback(state.device, nullptr, onWifiDeviceEvent) != ERROR_NONE) {
|
||||||
|
LOG_E(TAG, "Failed to register WiFi event callback");
|
||||||
|
device_stop(state.device);
|
||||||
|
publishRadioState(WIFI_RADIO_STATE_OFF);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.pauseAutoConnect = false;
|
||||||
|
state.lastScanTime = 0;
|
||||||
|
publishRadioState(WIFI_RADIO_STATE_ON);
|
||||||
|
} else {
|
||||||
|
publishRadioState(WIFI_RADIO_STATE_OFF_PENDING);
|
||||||
|
|
||||||
|
if (device_stop(state.device) != ERROR_NONE) {
|
||||||
|
LOG_E(TAG, "Failed to stop WiFi device");
|
||||||
|
publishRadioState(WIFI_RADIO_STATE_ON);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wifi_remove_event_callback(state.device, onWifiDeviceEvent);
|
||||||
|
|
||||||
|
state.secureConnection = false;
|
||||||
|
publishRadioState(WIFI_RADIO_STATE_OFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispatchScan() {
|
||||||
|
LOG_I(TAG, "dispatchScan()");
|
||||||
|
if (!started || state.device == nullptr || !device_is_ready(state.device)) return;
|
||||||
|
|
||||||
|
state.lastScanTime = kernel::getTicks();
|
||||||
|
|
||||||
|
error_t result = wifi_scan(state.device);
|
||||||
|
if (result != ERROR_NONE) {
|
||||||
|
LOG_I(TAG, "Can't start scan (%s)", error_to_string(result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispatchConnect() {
|
||||||
|
LOG_I(TAG, "dispatchConnect()");
|
||||||
|
if (!started || state.device == nullptr) return;
|
||||||
|
|
||||||
|
settings::WifiApSettings target;
|
||||||
|
{
|
||||||
|
auto lock = state.mutex.asScopedLock();
|
||||||
|
if (!lock.lock(50 / portTICK_PERIOD_MS)) {
|
||||||
|
LOG_E(TAG, LOG_MESSAGE_MUTEX_LOCK_FAILED_FMT, "dispatchConnect()");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
target = state.connectionTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_I(TAG, "Connecting to %s", target.ssid.c_str());
|
||||||
|
|
||||||
|
error_t result = wifi_station_connect(state.device, target.ssid.c_str(), target.password.c_str(), target.channel);
|
||||||
|
if (result != ERROR_NONE) {
|
||||||
|
LOG_E(TAG, "Failed to connect to %s (%s)", target.ssid.c_str(), error_to_string(result));
|
||||||
|
WifiEvent event = {};
|
||||||
|
event.type = WIFI_EVENT_TYPE_STATION_CONNECTION_RESULT;
|
||||||
|
// The driver couldn't even initiate the connection attempt; there's no
|
||||||
|
// more specific WifiStationConnectionError for that.
|
||||||
|
event.connection_error = WIFI_STATION_CONNECTION_ERROR_TIMEOUT;
|
||||||
|
publish(event);
|
||||||
|
}
|
||||||
|
// On success, WIFI_EVENT_TYPE_STATION_STATE_CHANGED / _CONNECTION_RESULT arrive
|
||||||
|
// asynchronously via onWifiDeviceEvent().
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispatchDisconnect() {
|
||||||
|
LOG_I(TAG, "dispatchDisconnect()");
|
||||||
|
if (!started || state.device == nullptr) return;
|
||||||
|
|
||||||
|
error_t result = wifi_station_disconnect(state.device);
|
||||||
|
if (result != ERROR_NONE) {
|
||||||
|
LOG_E(TAG, "Failed to disconnect (%s)", error_to_string(result));
|
||||||
|
}
|
||||||
|
// The Disconnected event arrives asynchronously via onWifiDeviceEvent().
|
||||||
|
}
|
||||||
|
|
||||||
|
bool findAutoConnectAp(settings::WifiApSettings& out) {
|
||||||
|
for (const auto& record : getScanResults()) {
|
||||||
|
if (settings::contains(record.ssid)) {
|
||||||
|
settings::WifiApSettings loaded;
|
||||||
|
if (settings::load(record.ssid, loaded)) {
|
||||||
|
if (loaded.autoConnect) {
|
||||||
|
out = loaded;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_E(TAG, "Failed to load credentials for ssid %s", record.ssid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispatchAutoConnect() {
|
||||||
|
LOG_I(TAG, "dispatchAutoConnect()");
|
||||||
|
if (state.pauseAutoConnect) {
|
||||||
|
// A manual disconnect() or an in-progress manual connect() has paused
|
||||||
|
// auto-connect. This is called on every SCAN_FINISHED, not just the
|
||||||
|
// auto-connect timer's own scans (e.g. WifiManage re-scans on show),
|
||||||
|
// so it must honor the pause instead of reconnecting unconditionally.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
RadioState radio_state = getRadioState();
|
||||||
|
if (radio_state == RadioState::ConnectionActive || radio_state == RadioState::ConnectionPending) {
|
||||||
|
// Already connected (or connecting): reconnecting to the same AP would just
|
||||||
|
// force a pointless disconnect/reconnect blip, e.g. when WifiManage's
|
||||||
|
// on-show scan finishes while we're already on the saved auto-connect AP.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
settings::WifiApSettings target;
|
||||||
|
if (findAutoConnectAp(target)) {
|
||||||
|
LOG_I(TAG, "Auto-connecting to %s", target.ssid.c_str());
|
||||||
|
connect(target, false);
|
||||||
|
// connect() pauses auto-connect (it assumes a manual/user call); undo that
|
||||||
|
// since this call was automatic.
|
||||||
|
state.pauseAutoConnect = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool shouldScanForAutoConnect() {
|
||||||
|
bool radio_scannable = getRadioState() == RadioState::On && !isScanning() && !state.pauseAutoConnect;
|
||||||
|
if (!radio_scannable) return false;
|
||||||
|
|
||||||
|
TickType_t current_time = kernel::getTicks();
|
||||||
|
bool scan_time_has_looped = current_time < state.lastScanTime;
|
||||||
|
bool no_recent_scan = (current_time - state.lastScanTime) > (AUTO_SCAN_INTERVAL / portTICK_PERIOD_MS);
|
||||||
|
return scan_time_has_looped || no_recent_scan;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onAutoConnectTimer() {
|
||||||
|
if (!started || state.device == nullptr) return;
|
||||||
|
if (shouldScanForAutoConnect()) {
|
||||||
|
getMainDispatcher().dispatch([] { dispatchScan(); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Kernel driver event bridge ----
|
||||||
|
|
||||||
|
void onWifiDeviceEvent(Device* /*device*/, void* /*context*/, ::WifiEvent event) {
|
||||||
|
switch (event.type) {
|
||||||
|
case WIFI_EVENT_TYPE_SCAN_FINISHED:
|
||||||
|
getMainDispatcher().dispatch([] { dispatchAutoConnect(); });
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WIFI_EVENT_TYPE_STATION_STATE_CHANGED:
|
||||||
|
if (event.station_state == WIFI_STATION_STATE_DISCONNECTED) {
|
||||||
|
// Don't touch pauseAutoConnect here: a deliberate disconnect() sets it
|
||||||
|
// and relies on it staying set until a new connection is established.
|
||||||
|
// Resetting it on every disconnect (including deliberate ones) would
|
||||||
|
// let auto-connect immediately reconnect the user. Attempts that fail
|
||||||
|
// while pending are unpaused via WIFI_EVENT_TYPE_STATION_CONNECTION_RESULT below.
|
||||||
|
kernel::publishSystemEvent(kernel::SystemEvent::NetworkDisconnected);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WIFI_EVENT_TYPE_STATION_CONNECTION_RESULT:
|
||||||
|
if (event.connection_error == WIFI_STATION_CONNECTION_ERROR_NONE) {
|
||||||
|
settings::WifiApSettings target;
|
||||||
|
bool remember;
|
||||||
|
{
|
||||||
|
auto lock = state.mutex.asScopedLock();
|
||||||
|
if (lock.lock(50 / portTICK_PERIOD_MS)) {
|
||||||
|
target = state.connectionTarget;
|
||||||
|
remember = state.connectionTargetRemember;
|
||||||
|
state.secureConnection = !target.password.empty();
|
||||||
|
} else {
|
||||||
|
remember = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto lock = state.mutex.asScopedLock();
|
||||||
|
if (lock.lock(50 / portTICK_PERIOD_MS)) {
|
||||||
|
state.pauseAutoConnect = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG_I(TAG, "Connected to %s", target.ssid.c_str());
|
||||||
|
if (remember && !settings::save(target)) {
|
||||||
|
LOG_E(TAG, "Failed to store credentials");
|
||||||
|
}
|
||||||
|
kernel::publishSystemEvent(kernel::SystemEvent::NetworkConnected);
|
||||||
|
} else {
|
||||||
|
// The pending connection attempt (which paused auto-connect via connect())
|
||||||
|
// failed; unpause so auto-connect can try other saved APs.
|
||||||
|
auto lock = state.mutex.asScopedLock();
|
||||||
|
if (lock.lock(50 / portTICK_PERIOD_MS)) {
|
||||||
|
state.pauseAutoConnect = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward the event as-is: subscribers inspect event.type and the
|
||||||
|
// relevant union field directly, same as this function does.
|
||||||
|
publish(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// region Public functions
|
||||||
|
|
||||||
|
std::shared_ptr<PubSub<WifiEvent>> getPubsub() {
|
||||||
|
return state.pubsub;
|
||||||
|
}
|
||||||
|
|
||||||
|
RadioState getRadioState() {
|
||||||
|
if (!started || state.device == nullptr || !device_is_ready(state.device)) {
|
||||||
|
return RadioState::Off;
|
||||||
|
}
|
||||||
|
|
||||||
|
WifiRadioState radio = WIFI_RADIO_STATE_OFF;
|
||||||
|
WifiStationState station = WIFI_STATION_STATE_DISCONNECTED;
|
||||||
|
wifi_get_radio_state(state.device, &radio);
|
||||||
|
wifi_get_station_state(state.device, &station);
|
||||||
|
return combineRadioState(radio, station);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getConnectionTarget() {
|
||||||
|
RadioState radio_state = getRadioState();
|
||||||
|
if (radio_state != RadioState::ConnectionPending && radio_state != RadioState::ConnectionActive) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
char ssid[33] = {};
|
||||||
|
if (wifi_station_get_target_ssid(state.device, ssid) != ERROR_NONE) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return { ssid };
|
||||||
|
}
|
||||||
|
|
||||||
|
void scan() {
|
||||||
|
LOG_I(TAG, "scan()");
|
||||||
|
if (!started || state.device == nullptr) return;
|
||||||
|
getMainDispatcher().dispatch([] { dispatchScan(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isScanning() {
|
||||||
|
if (!started || state.device == nullptr) return false;
|
||||||
|
return wifi_is_scanning(state.device);
|
||||||
|
}
|
||||||
|
|
||||||
|
void connect(const settings::WifiApSettings& ap, bool remember) {
|
||||||
|
LOG_I(TAG, "connect(%s, %d)", ap.ssid.c_str(), (int)remember);
|
||||||
|
if (!started || state.device == nullptr) return;
|
||||||
|
|
||||||
|
bool radio_off;
|
||||||
|
{
|
||||||
|
auto lock = state.mutex.asScopedLock();
|
||||||
|
if (!lock.lock(10 / portTICK_PERIOD_MS)) {
|
||||||
|
LOG_E(TAG, LOG_MESSAGE_MUTEX_LOCK_FAILED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Stop auto-connecting until the connection is established.
|
||||||
|
state.pauseAutoConnect = true;
|
||||||
|
state.connectionTarget = ap;
|
||||||
|
state.connectionTargetRemember = remember;
|
||||||
|
radio_off = !device_is_ready(state.device);
|
||||||
|
}
|
||||||
|
|
||||||
|
getMainDispatcher().dispatch([radio_off] {
|
||||||
|
if (radio_off) {
|
||||||
|
dispatchSetEnabled(true);
|
||||||
|
}
|
||||||
|
dispatchConnect();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void disconnect() {
|
||||||
|
LOG_I(TAG, "disconnect()");
|
||||||
|
if (!started || state.device == nullptr) return;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto lock = state.mutex.asScopedLock();
|
||||||
|
if (!lock.lock(10 / portTICK_PERIOD_MS)) {
|
||||||
|
LOG_E(TAG, LOG_MESSAGE_MUTEX_LOCK_FAILED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state.connectionTarget = settings::WifiApSettings("", "");
|
||||||
|
// Manual disconnect (e.g. via app) should stop auto-connecting until a new connection is established.
|
||||||
|
state.pauseAutoConnect = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
getMainDispatcher().dispatch([] { dispatchDisconnect(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void setScanRecords(uint16_t records) {
|
||||||
|
LOG_I(TAG, "setScanRecords(%u)", records);
|
||||||
|
if (!started) return;
|
||||||
|
auto lock = state.mutex.asScopedLock();
|
||||||
|
if (lock.lock(10 / portTICK_PERIOD_MS)) {
|
||||||
|
state.scanRecordLimit = records;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<WifiApRecord> getScanResults() {
|
||||||
|
std::vector<WifiApRecord> records;
|
||||||
|
if (!started || state.device == nullptr) return records;
|
||||||
|
|
||||||
|
records.resize(state.scanRecordLimit);
|
||||||
|
size_t count = records.size();
|
||||||
|
if (wifi_get_scan_results(state.device, records.data(), &count) != ERROR_NONE) {
|
||||||
|
records.clear();
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
|
||||||
|
records.resize(count);
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setEnabled(bool enabled) {
|
||||||
|
LOG_I(TAG, "setEnabled(%d)", (int)enabled);
|
||||||
|
if (!started || state.device == nullptr) return;
|
||||||
|
getMainDispatcher().dispatch([enabled] { dispatchSetEnabled(enabled); });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isConnectionSecure() {
|
||||||
|
return state.secureConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getRssi() {
|
||||||
|
if (!started || state.device == nullptr) return 1;
|
||||||
|
int32_t rssi = 0;
|
||||||
|
if (wifi_station_get_rssi(state.device, &rssi) == ERROR_NONE) {
|
||||||
|
return rssi;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getIp() {
|
||||||
|
if (!started || state.device == nullptr) return "";
|
||||||
|
char ipv4[16] = {};
|
||||||
|
if (wifi_station_get_ipv4_address(state.device, ipv4) != ERROR_NONE) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return { ipv4 };
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion Public functions
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class WifiService final : public Service {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
bool onStart(ServiceContext& /*service*/) override {
|
||||||
|
check(!started);
|
||||||
|
|
||||||
|
state.device = wifi_find_first_registered_device();
|
||||||
|
if (state.device == nullptr) {
|
||||||
|
LOG_W(TAG, "No WiFi device found");
|
||||||
|
}
|
||||||
|
|
||||||
|
state.bootEventSubscription = kernel::subscribeSystemEvent(kernel::SystemEvent::BootSplash, [](auto) {
|
||||||
|
bootSplashInit();
|
||||||
|
});
|
||||||
|
|
||||||
|
auto timer_interval = std::min(2000, AUTO_SCAN_INTERVAL);
|
||||||
|
state.autoConnectTimer = std::make_unique<Timer>(Timer::Type::Periodic, timer_interval, [] { onAutoConnectTimer(); });
|
||||||
|
// We want to try and scan more often in case of startup or scan lock failure.
|
||||||
|
state.autoConnectTimer->start();
|
||||||
|
|
||||||
|
started = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onStop(ServiceContext& /*service*/) override {
|
||||||
|
check(started);
|
||||||
|
started = false;
|
||||||
|
|
||||||
|
state.autoConnectTimer->stop();
|
||||||
|
state.autoConnectTimer = nullptr; // Must release as it holds a reference via its callback.
|
||||||
|
|
||||||
|
kernel::unsubscribeSystemEvent(state.bootEventSubscription);
|
||||||
|
state.bootEventSubscription = kernel::NoSystemEventSubscription;
|
||||||
|
|
||||||
|
if (state.device != nullptr && device_is_ready(state.device)) {
|
||||||
|
wifi_remove_event_callback(state.device, onWifiDeviceEvent);
|
||||||
|
device_stop(state.device);
|
||||||
|
}
|
||||||
|
|
||||||
|
state.secureConnection = false;
|
||||||
|
state.pauseAutoConnect = false;
|
||||||
|
state.device = nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
extern const ServiceManifest manifest = {
|
||||||
|
.id = "wifi",
|
||||||
|
.createService = create<WifiService>
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace tt::service::wifi
|
||||||
|
|||||||
@@ -1,967 +0,0 @@
|
|||||||
#ifdef ESP_PLATFORM
|
|
||||||
#include <sdkconfig.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED)
|
|
||||||
|
|
||||||
#include <Tactility/service/wifi/Wifi.h>
|
|
||||||
|
|
||||||
#include <Tactility/LogMessages.h>
|
|
||||||
#include <Tactility/EventGroup.h>
|
|
||||||
#include <Tactility/RecursiveMutex.h>
|
|
||||||
#include <Tactility/Tactility.h>
|
|
||||||
#include <Tactility/Timer.h>
|
|
||||||
#include <Tactility/kernel/SystemEvents.h>
|
|
||||||
#include <Tactility/service/ServiceContext.h>
|
|
||||||
#include <Tactility/service/wifi/WifiBootSplashInit.h>
|
|
||||||
#include <Tactility/service/wifi/WifiGlobals.h>
|
|
||||||
#include <Tactility/service/wifi/WifiSettings.h>
|
|
||||||
|
|
||||||
#include <tactility/check.h>
|
|
||||||
#include <tactility/log.h>
|
|
||||||
|
|
||||||
#include <esp_wifi_default.h>
|
|
||||||
#include <lwip/esp_netif_net_stack.h>
|
|
||||||
#include <freertos/FreeRTOS.h>
|
|
||||||
#include <atomic>
|
|
||||||
#include <cstring>
|
|
||||||
#include <sys/cdefs.h>
|
|
||||||
|
|
||||||
namespace tt::service::wifi {
|
|
||||||
|
|
||||||
constexpr auto* TAG = "WifiService";
|
|
||||||
|
|
||||||
constexpr auto WIFI_CONNECTED_BIT = BIT0;
|
|
||||||
constexpr auto WIFI_FAIL_BIT = BIT1;
|
|
||||||
constexpr auto AUTO_SCAN_INTERVAL = 10000; // ms
|
|
||||||
|
|
||||||
// Forward declarations
|
|
||||||
class Wifi;
|
|
||||||
static void scan_list_free_safely(std::shared_ptr<Wifi> wifi);
|
|
||||||
// Methods for main thread dispatcher
|
|
||||||
static void dispatchAutoConnect(std::shared_ptr<Wifi> wifi);
|
|
||||||
static void dispatchEnable(std::shared_ptr<Wifi> wifi);
|
|
||||||
static void dispatchDisable(std::shared_ptr<Wifi> wifi);
|
|
||||||
static void dispatchScan(std::shared_ptr<Wifi> wifi);
|
|
||||||
static void dispatchConnect(std::shared_ptr<Wifi> wifi);
|
|
||||||
static void dispatchDisconnectButKeepActive(std::shared_ptr<Wifi> wifi);
|
|
||||||
|
|
||||||
class Wifi {
|
|
||||||
|
|
||||||
std::atomic<RadioState> radio_state = RadioState::Off;
|
|
||||||
std::atomic<bool> scan_active = false;
|
|
||||||
std::atomic<bool> secure_connection = false;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/** @brief Locking mechanism for modifying the Wifi instance */
|
|
||||||
RecursiveMutex radioMutex;
|
|
||||||
RecursiveMutex dataMutex;
|
|
||||||
std::unique_ptr<Timer> autoConnectTimer;
|
|
||||||
/** @brief The public event bus */
|
|
||||||
std::shared_ptr<PubSub<WifiEvent>> pubsub = std::make_shared<PubSub<WifiEvent>>();
|
|
||||||
// TODO: Deal with messages that come in while an action is ongoing
|
|
||||||
// for example: when scanning and you turn off the radio, the scan should probably stop or turning off
|
|
||||||
// the radio should disable the on/off button in the app as it is pending.
|
|
||||||
/** @brief The network interface when wifi is started */
|
|
||||||
esp_netif_t* netif = nullptr;
|
|
||||||
/** @brief Scanning results */
|
|
||||||
wifi_ap_record_t* scan_list = nullptr;
|
|
||||||
/** @brief The current item count in scan_list (-1 when scan_list is NULL) */
|
|
||||||
uint16_t scan_list_count = 0;
|
|
||||||
/** @brief Maximum amount of records to scan (value > 0) */
|
|
||||||
uint16_t scan_list_limit = TT_WIFI_SCAN_RECORD_LIMIT;
|
|
||||||
/** @brief when we last requested a scan. Loops around every 50 days. */
|
|
||||||
TickType_t last_scan_time = kernel::MAX_TICKS;
|
|
||||||
esp_event_handler_instance_t event_handler_any_id = nullptr;
|
|
||||||
esp_event_handler_instance_t event_handler_got_ip = nullptr;
|
|
||||||
EventGroup connection_wait_flags;
|
|
||||||
settings::WifiApSettings connection_target;
|
|
||||||
bool pause_auto_connect = false; // Pause when manually disconnecting until manually connecting again
|
|
||||||
bool connection_target_remember = false; // Whether to store the connection_target on successful connection or not
|
|
||||||
esp_netif_ip_info_t ip_info;
|
|
||||||
kernel::SystemEventSubscription bootEventSubscription = kernel::NoSystemEventSubscription;
|
|
||||||
|
|
||||||
RadioState getRadioState() const {
|
|
||||||
return radio_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setRadioState(RadioState newState) {
|
|
||||||
radio_state = newState;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isScanning() const {
|
|
||||||
return scan_active;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setScanning(bool newState) {
|
|
||||||
scan_active = newState;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isScanActive() const {
|
|
||||||
return scan_active;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setScanActive(bool newState) {
|
|
||||||
scan_active = newState;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isSecureConnection() const {
|
|
||||||
return secure_connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSecureConnection(bool newState) {
|
|
||||||
secure_connection = newState;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::shared_ptr<Wifi> wifi_singleton;
|
|
||||||
|
|
||||||
|
|
||||||
// region Public functions
|
|
||||||
|
|
||||||
std::shared_ptr<PubSub<WifiEvent>> getPubsub() {
|
|
||||||
auto wifi = wifi_singleton;
|
|
||||||
if (wifi == nullptr) {
|
|
||||||
check(false, "Service not running");
|
|
||||||
}
|
|
||||||
|
|
||||||
return wifi->pubsub;
|
|
||||||
}
|
|
||||||
|
|
||||||
RadioState getRadioState() {
|
|
||||||
auto wifi = wifi_singleton;
|
|
||||||
if (wifi != nullptr) {
|
|
||||||
return wifi->getRadioState();
|
|
||||||
} else {
|
|
||||||
return RadioState::Off;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getConnectionTarget() {
|
|
||||||
auto wifi = wifi_singleton;
|
|
||||||
if (wifi == nullptr) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
RadioState state = wifi->getRadioState();
|
|
||||||
if (
|
|
||||||
state != RadioState::ConnectionPending &&
|
|
||||||
state != RadioState::ConnectionActive
|
|
||||||
) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
return wifi->connection_target.ssid;
|
|
||||||
}
|
|
||||||
|
|
||||||
void scan() {
|
|
||||||
LOG_I(TAG, "scan()");
|
|
||||||
auto wifi = wifi_singleton;
|
|
||||||
if (wifi == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
getMainDispatcher().dispatch([wifi]() { dispatchScan(wifi); });
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isScanning() {
|
|
||||||
auto wifi = wifi_singleton;
|
|
||||||
if (wifi == nullptr) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return wifi->isScanActive();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void connect(const settings::WifiApSettings& ap, bool remember) {
|
|
||||||
LOG_I(TAG, "connect(%s, %d)", ap.ssid.c_str(), (int)remember);
|
|
||||||
auto wifi = wifi_singleton;
|
|
||||||
if (wifi == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto lock = wifi->dataMutex.asScopedLock();
|
|
||||||
if (!lock.lock(10 / portTICK_PERIOD_MS)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop auto-connecting until the connection is established
|
|
||||||
wifi->pause_auto_connect = true;
|
|
||||||
wifi->connection_target = ap;
|
|
||||||
wifi->connection_target_remember = remember;
|
|
||||||
|
|
||||||
if (wifi->getRadioState() == RadioState::Off) {
|
|
||||||
getMainDispatcher().dispatch([wifi] { dispatchEnable(wifi); });
|
|
||||||
}
|
|
||||||
|
|
||||||
getMainDispatcher().dispatch([wifi] { dispatchConnect(wifi); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void disconnect() {
|
|
||||||
LOG_I(TAG, "disconnect()");
|
|
||||||
auto wifi = wifi_singleton;
|
|
||||||
if (wifi == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto lock = wifi->dataMutex.asScopedLock();
|
|
||||||
if (!lock.lock(10 / portTICK_PERIOD_MS)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wifi->connection_target = settings::WifiApSettings("", "");
|
|
||||||
// Manual disconnect (e.g. via app) should stop auto-connecting until a new connection is established
|
|
||||||
wifi->pause_auto_connect = true;
|
|
||||||
getMainDispatcher().dispatch([wifi]() { dispatchDisconnectButKeepActive(wifi); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearIp() {
|
|
||||||
auto wifi = wifi_singleton;
|
|
||||||
if (wifi == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto lock = wifi->dataMutex.asScopedLock();
|
|
||||||
if (!lock.lock(10 / portTICK_PERIOD_MS)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&wifi->ip_info, 0, sizeof(esp_netif_ip_info_t));
|
|
||||||
}
|
|
||||||
void setScanRecords(uint16_t records) {
|
|
||||||
LOG_I(TAG, "setScanRecords(%u)", records);
|
|
||||||
auto wifi = wifi_singleton;
|
|
||||||
if (wifi == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto lock = wifi->dataMutex.asScopedLock();
|
|
||||||
if (!lock.lock(10 / portTICK_PERIOD_MS)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (records != wifi->scan_list_limit) {
|
|
||||||
scan_list_free_safely(wifi);
|
|
||||||
wifi->scan_list_limit = records;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<ApRecord> getScanResults() {
|
|
||||||
LOG_I(TAG, "getScanResults()");
|
|
||||||
auto wifi = wifi_singleton;
|
|
||||||
|
|
||||||
std::vector<ApRecord> records;
|
|
||||||
|
|
||||||
if (wifi == nullptr) {
|
|
||||||
return records;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto lock = wifi->dataMutex.asScopedLock();
|
|
||||||
if (!lock.lock(10 / portTICK_PERIOD_MS)) {
|
|
||||||
return records;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wifi->scan_list_count > 0) {
|
|
||||||
uint16_t i = 0;
|
|
||||||
for (; i < wifi->scan_list_count; ++i) {
|
|
||||||
const auto& scanned_item = wifi->scan_list[i];
|
|
||||||
records.push_back((ApRecord) {
|
|
||||||
.ssid = reinterpret_cast<const char*>(scanned_item.ssid),
|
|
||||||
.rssi = scanned_item.rssi,
|
|
||||||
.channel = scanned_item.primary,
|
|
||||||
.auth_mode = scanned_item.authmode
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return records;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setEnabled(bool enabled) {
|
|
||||||
LOG_I(TAG, "setEnabled(%d)", (int)enabled);
|
|
||||||
auto wifi = wifi_singleton;
|
|
||||||
if (wifi == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto lock = wifi->dataMutex.asScopedLock();
|
|
||||||
if (!lock.lock(10 / portTICK_PERIOD_MS)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enabled) {
|
|
||||||
getMainDispatcher().dispatch([wifi] { dispatchEnable(wifi); });
|
|
||||||
} else {
|
|
||||||
getMainDispatcher().dispatch([wifi] { dispatchDisable(wifi); });
|
|
||||||
}
|
|
||||||
|
|
||||||
wifi->pause_auto_connect = false;
|
|
||||||
wifi->last_scan_time = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isConnectionSecure() {
|
|
||||||
auto wifi = wifi_singleton;
|
|
||||||
if (wifi == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return wifi->isSecureConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
int getRssi() {
|
|
||||||
assert(wifi_singleton);
|
|
||||||
static int rssi = 0;
|
|
||||||
if (esp_wifi_sta_get_rssi(&rssi) == ESP_OK) {
|
|
||||||
return rssi;
|
|
||||||
} else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion Public functions
|
|
||||||
|
|
||||||
static void scan_list_alloc(std::shared_ptr<Wifi> wifi) {
|
|
||||||
auto lock = wifi->dataMutex.asScopedLock();
|
|
||||||
if (lock.lock()) {
|
|
||||||
assert(wifi->scan_list == nullptr);
|
|
||||||
wifi->scan_list = static_cast<wifi_ap_record_t*>(malloc(sizeof(wifi_ap_record_t) * wifi->scan_list_limit));
|
|
||||||
wifi->scan_list_count = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void scan_list_alloc_safely(std::shared_ptr<Wifi> wifi) {
|
|
||||||
auto lock = wifi->dataMutex.asScopedLock();
|
|
||||||
if (lock.lock()) {
|
|
||||||
if (wifi->scan_list == nullptr) {
|
|
||||||
scan_list_alloc(wifi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void scan_list_free(std::shared_ptr<Wifi> wifi) {
|
|
||||||
auto lock = wifi->dataMutex.asScopedLock();
|
|
||||||
if (lock.lock()) {
|
|
||||||
assert(wifi->scan_list != nullptr);
|
|
||||||
free(wifi->scan_list);
|
|
||||||
wifi->scan_list = nullptr;
|
|
||||||
wifi->scan_list_count = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void scan_list_free_safely(std::shared_ptr<Wifi> wifi) {
|
|
||||||
auto lock = wifi->dataMutex.asScopedLock();
|
|
||||||
if (lock.lock()) {
|
|
||||||
if (wifi->scan_list != nullptr) {
|
|
||||||
scan_list_free(wifi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void publish_event(std::shared_ptr<Wifi> wifi, WifiEvent event) {
|
|
||||||
auto lock = wifi->dataMutex.asScopedLock();
|
|
||||||
if (lock.lock()) {
|
|
||||||
wifi->pubsub->publish(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool copy_scan_list(std::shared_ptr<Wifi> wifi) {
|
|
||||||
auto state = wifi->getRadioState();
|
|
||||||
bool can_fetch_results = (state == RadioState::On || state == RadioState::ConnectionActive) &&
|
|
||||||
wifi->isScanActive();
|
|
||||||
|
|
||||||
if (!can_fetch_results) {
|
|
||||||
LOG_I(TAG, "Skip scan result fetching");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto lock = wifi->dataMutex.asScopedLock();
|
|
||||||
if (!lock.lock()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create scan list if it does not exist
|
|
||||||
scan_list_alloc_safely(wifi);
|
|
||||||
wifi->scan_list_count = 0;
|
|
||||||
uint16_t record_count = wifi->scan_list_limit;
|
|
||||||
esp_err_t scan_result = esp_wifi_scan_get_ap_records(&record_count, wifi->scan_list);
|
|
||||||
if (scan_result == ESP_OK) {
|
|
||||||
uint16_t safe_record_count = std::min(wifi->scan_list_limit, record_count);
|
|
||||||
wifi->scan_list_count = safe_record_count;
|
|
||||||
LOG_I(TAG, "Scanned %u APs. Showing %u:", record_count, safe_record_count);
|
|
||||||
for (uint16_t i = 0; i < safe_record_count; i++) {
|
|
||||||
wifi_ap_record_t* record = &wifi->scan_list[i];
|
|
||||||
if (record->ssid[0] != 0 && record->primary != 0) {
|
|
||||||
LOG_I(TAG, " - SSID %s, RSSI %d, channel %u, BSSID %02x:%02x:%02x:%02x:%02x:%02x",
|
|
||||||
reinterpret_cast<const char*>(record->ssid),
|
|
||||||
record->rssi,
|
|
||||||
record->primary,
|
|
||||||
record->bssid[0],
|
|
||||||
record->bssid[1],
|
|
||||||
record->bssid[2],
|
|
||||||
record->bssid[3],
|
|
||||||
record->bssid[4],
|
|
||||||
record->bssid[5]
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
LOG_I(TAG, " - (missing channel info)"); // Behaviour on on P4 with C6
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
LOG_I(TAG, "Failed to get scanned records: %s", esp_err_to_name(scan_result));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool find_auto_connect_ap(std::shared_ptr<Wifi> wifi, settings::WifiApSettings& settings) {
|
|
||||||
LOG_I(TAG, "find_auto_connect_ap()");
|
|
||||||
auto lock = wifi->dataMutex.asScopedLock();
|
|
||||||
if (lock.lock(10 / portTICK_PERIOD_MS)) {
|
|
||||||
for (int i = 0; i < wifi->scan_list_count; ++i) {
|
|
||||||
auto ssid = reinterpret_cast<const char*>(wifi->scan_list[i].ssid);
|
|
||||||
if (settings::contains(ssid)) {
|
|
||||||
static_assert(sizeof(wifi->scan_list[i].ssid) == (TT_WIFI_SSID_LIMIT + 1), "SSID size mismatch");
|
|
||||||
if (settings::load(ssid, settings)) {
|
|
||||||
if (settings.autoConnect) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOG_E(TAG, "Failed to load credentials for ssid %s", ssid);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dispatchAutoConnect(std::shared_ptr<Wifi> wifi) {
|
|
||||||
LOG_I(TAG, "dispatchAutoConnect()");
|
|
||||||
|
|
||||||
settings::WifiApSettings settings;
|
|
||||||
if (find_auto_connect_ap(wifi, settings)) {
|
|
||||||
LOG_I(TAG, "Auto-connecting to %s", settings.ssid.c_str());
|
|
||||||
connect(settings, false);
|
|
||||||
// TODO: We currently have to manually reset it because connect() sets it.
|
|
||||||
// connect() assumes it's only being called by the user and not internally, so it disables auto-connect
|
|
||||||
wifi->pause_auto_connect = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void eventHandler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
|
|
||||||
auto wifi = wifi_singleton;
|
|
||||||
if (wifi == nullptr) {
|
|
||||||
LOG_E(TAG, "eventHandler: no wifi instance");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event_base == WIFI_EVENT) {
|
|
||||||
LOG_I(TAG, "eventHandler: WIFI_EVENT %d", (int)event_id);
|
|
||||||
} else if (event_base == IP_EVENT) {
|
|
||||||
LOG_I(TAG, "eventHandler: IP_EVENT %d", (int)event_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
|
||||||
LOG_I(TAG, "eventHandler: STA_START");
|
|
||||||
if (wifi->getRadioState() == RadioState::ConnectionPending) {
|
|
||||||
esp_wifi_connect();
|
|
||||||
}
|
|
||||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
|
||||||
LOG_I(TAG, "eventHandler: STA_DISCONNECTED");
|
|
||||||
clearIp();
|
|
||||||
switch (wifi->getRadioState()) {
|
|
||||||
case RadioState::ConnectionPending:
|
|
||||||
wifi->connection_wait_flags.set(WIFI_FAIL_BIT);
|
|
||||||
break;
|
|
||||||
case RadioState::On:
|
|
||||||
// Ensure we can reconnect again
|
|
||||||
wifi->pause_auto_connect = false;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
wifi->setRadioState(RadioState::On);
|
|
||||||
publish_event(wifi, WifiEvent::Disconnected);
|
|
||||||
kernel::publishSystemEvent(kernel::SystemEvent::NetworkDisconnected);
|
|
||||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
|
||||||
auto* event = static_cast<ip_event_got_ip_t*>(event_data);
|
|
||||||
memcpy(&wifi->ip_info, &event->ip_info, sizeof(esp_netif_ip_info_t));
|
|
||||||
LOG_I(TAG, "eventHandler: got ip: %d.%d.%d.%d", IP2STR(&event->ip_info.ip));
|
|
||||||
if (wifi->getRadioState() == RadioState::ConnectionPending) {
|
|
||||||
wifi->connection_wait_flags.set(WIFI_CONNECTED_BIT);
|
|
||||||
// We resume auto-connecting only when there was an explicit request by the user for the connection
|
|
||||||
// TODO: Make thread-safe
|
|
||||||
wifi->pause_auto_connect = false; // Resume auto-connection
|
|
||||||
}
|
|
||||||
kernel::publishSystemEvent(kernel::SystemEvent::NetworkConnected);
|
|
||||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_SCAN_DONE) {
|
|
||||||
auto* event = static_cast<wifi_event_sta_scan_done_t*>(event_data);
|
|
||||||
LOG_I(TAG, "eventHandler: wifi scanning done (scan id %u)", event->scan_id);
|
|
||||||
bool copied_list = copy_scan_list(wifi);
|
|
||||||
|
|
||||||
auto state = wifi->getRadioState();
|
|
||||||
if (
|
|
||||||
state != RadioState::Off &&
|
|
||||||
state != RadioState::OffPending
|
|
||||||
) {
|
|
||||||
wifi->setScanActive(false);
|
|
||||||
esp_wifi_scan_stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
publish_event(wifi_singleton, WifiEvent::ScanFinished);
|
|
||||||
LOG_I(TAG, "eventHandler: Finished scan");
|
|
||||||
|
|
||||||
if (copied_list && wifi_singleton->getRadioState() == RadioState::On && !wifi->pause_auto_connect) {
|
|
||||||
getMainDispatcher().dispatch([wifi]() { dispatchAutoConnect(wifi); });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dispatchEnable(std::shared_ptr<Wifi> wifi) {
|
|
||||||
LOG_I(TAG, "dispatchEnable()");
|
|
||||||
|
|
||||||
RadioState state = wifi->getRadioState();
|
|
||||||
if (
|
|
||||||
state == RadioState::On ||
|
|
||||||
state == RadioState::OnPending ||
|
|
||||||
state == RadioState::OffPending
|
|
||||||
) {
|
|
||||||
LOG_W(TAG, "Can't enable from current state");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto lock = wifi->radioMutex.asScopedLock();
|
|
||||||
if (lock.lock(50 / portTICK_PERIOD_MS)) {
|
|
||||||
LOG_I(TAG, "Enabling");
|
|
||||||
wifi->setRadioState(RadioState::OnPending);
|
|
||||||
publish_event(wifi, WifiEvent::RadioStateOnPending);
|
|
||||||
|
|
||||||
if (wifi->netif != nullptr) {
|
|
||||||
esp_wifi_clear_default_wifi_driver_and_handlers(wifi->netif);
|
|
||||||
esp_netif_destroy(wifi->netif);
|
|
||||||
}
|
|
||||||
wifi->netif = esp_netif_create_default_wifi_sta();
|
|
||||||
|
|
||||||
// Warning: this is the memory-intensive operation
|
|
||||||
// It uses over 117kB of RAM with default settings for S3 on IDF v5.1.2
|
|
||||||
wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT();
|
|
||||||
esp_err_t init_result = esp_wifi_init(&config);
|
|
||||||
if (init_result != ESP_OK) {
|
|
||||||
LOG_E(TAG, "Wifi init failed");
|
|
||||||
if (init_result == ESP_ERR_NO_MEM) {
|
|
||||||
LOG_E(TAG, "Insufficient memory");
|
|
||||||
}
|
|
||||||
wifi->setRadioState(RadioState::Off);
|
|
||||||
publish_event(wifi, WifiEvent::RadioStateOff);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_wifi_set_storage(WIFI_STORAGE_RAM);
|
|
||||||
|
|
||||||
// TODO: don't crash on check failure
|
|
||||||
ESP_ERROR_CHECK(esp_event_handler_instance_register(
|
|
||||||
WIFI_EVENT,
|
|
||||||
ESP_EVENT_ANY_ID,
|
|
||||||
&eventHandler,
|
|
||||||
nullptr,
|
|
||||||
&wifi->event_handler_any_id
|
|
||||||
));
|
|
||||||
|
|
||||||
// TODO: don't crash on check failure
|
|
||||||
ESP_ERROR_CHECK(esp_event_handler_instance_register(
|
|
||||||
IP_EVENT,
|
|
||||||
IP_EVENT_STA_GOT_IP,
|
|
||||||
&eventHandler,
|
|
||||||
nullptr,
|
|
||||||
&wifi->event_handler_got_ip
|
|
||||||
));
|
|
||||||
|
|
||||||
if (esp_wifi_set_mode(WIFI_MODE_STA) != ESP_OK) {
|
|
||||||
LOG_E(TAG, "Wifi mode setting failed");
|
|
||||||
wifi->setRadioState(RadioState::Off);
|
|
||||||
esp_wifi_deinit();
|
|
||||||
publish_event(wifi, WifiEvent::RadioStateOff);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t start_result = esp_wifi_start();
|
|
||||||
if (start_result != ESP_OK) {
|
|
||||||
LOG_E(TAG, "Wifi start failed");
|
|
||||||
if (start_result == ESP_ERR_NO_MEM) {
|
|
||||||
LOG_E(TAG, "Insufficient memory");
|
|
||||||
}
|
|
||||||
wifi->setRadioState(RadioState::Off);
|
|
||||||
esp_wifi_set_mode(WIFI_MODE_NULL);
|
|
||||||
esp_wifi_deinit();
|
|
||||||
publish_event(wifi, WifiEvent::RadioStateOff);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wifi->setRadioState(RadioState::On);
|
|
||||||
publish_event(wifi, WifiEvent::RadioStateOn);
|
|
||||||
|
|
||||||
wifi->pause_auto_connect = false;
|
|
||||||
|
|
||||||
LOG_I(TAG, "Enabled");
|
|
||||||
} else {
|
|
||||||
LOG_E(TAG, LOG_MESSAGE_MUTEX_LOCK_FAILED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dispatchDisable(std::shared_ptr<Wifi> wifi) {
|
|
||||||
LOG_I(TAG, "dispatchDisable()");
|
|
||||||
auto lock = wifi->radioMutex.asScopedLock();
|
|
||||||
|
|
||||||
if (!lock.lock(50 / portTICK_PERIOD_MS)) {
|
|
||||||
LOG_E(TAG, LOG_MESSAGE_MUTEX_LOCK_FAILED_FMT, "disable()");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
RadioState state = wifi->getRadioState();
|
|
||||||
if (
|
|
||||||
state == RadioState::Off ||
|
|
||||||
state == RadioState::OffPending ||
|
|
||||||
state == RadioState::OnPending
|
|
||||||
) {
|
|
||||||
LOG_W(TAG, "Can't disable from current state");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_I(TAG, "Disabling");
|
|
||||||
wifi->setRadioState(RadioState::OffPending);
|
|
||||||
publish_event(wifi, WifiEvent::RadioStateOffPending);
|
|
||||||
|
|
||||||
// Free up scan list memory
|
|
||||||
scan_list_free_safely(wifi_singleton);
|
|
||||||
|
|
||||||
// Detach netif from the internal WiFi event handlers before stopping.
|
|
||||||
// Those handlers call esp_netif_action_stop on WIFI_EVENT_STA_STOP, which
|
|
||||||
// queues esp_netif_stop_api to the lwIP thread. esp_netif_destroy later
|
|
||||||
// queues a second one; the first zeroes lwip_netif, and the second then
|
|
||||||
// crashes in netif_ip6_addr_set_parts (null pointer + 0x263 offset).
|
|
||||||
if (wifi->netif != nullptr) {
|
|
||||||
esp_wifi_clear_default_wifi_driver_and_handlers(wifi->netif);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: handlers are already detached above, so we cannot safely return to
|
|
||||||
// RadioState::On from here — the netif would be missing its default WiFi
|
|
||||||
// event handlers and subsequent disable attempts would behave incorrectly.
|
|
||||||
// If stop fails, continue the teardown anyway so we end in a clean Off state.
|
|
||||||
if (esp_wifi_stop() != ESP_OK) {
|
|
||||||
LOG_E(TAG, "Failed to stop radio - continuing teardown");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (esp_wifi_set_mode(WIFI_MODE_NULL) != ESP_OK) {
|
|
||||||
LOG_E(TAG, "Failed to unset mode");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (esp_event_handler_instance_unregister(
|
|
||||||
WIFI_EVENT,
|
|
||||||
ESP_EVENT_ANY_ID,
|
|
||||||
wifi->event_handler_any_id
|
|
||||||
) != ESP_OK) {
|
|
||||||
LOG_E(TAG, "Failed to unregister id event handler");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (esp_event_handler_instance_unregister(
|
|
||||||
IP_EVENT,
|
|
||||||
IP_EVENT_STA_GOT_IP,
|
|
||||||
wifi->event_handler_got_ip
|
|
||||||
) != ESP_OK) {
|
|
||||||
LOG_E(TAG, "Failed to unregister ip event handler");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (esp_wifi_deinit() != ESP_OK) {
|
|
||||||
LOG_E(TAG, "Failed to deinit");
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(wifi->netif != nullptr);
|
|
||||||
esp_netif_destroy(wifi->netif);
|
|
||||||
wifi->netif = nullptr;
|
|
||||||
wifi->setScanActive(false);
|
|
||||||
wifi->setRadioState(RadioState::Off);
|
|
||||||
publish_event(wifi, WifiEvent::RadioStateOff);
|
|
||||||
LOG_I(TAG, "Disabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dispatchScan(std::shared_ptr<Wifi> wifi) {
|
|
||||||
LOG_I(TAG, "dispatchScan()");
|
|
||||||
auto lock = wifi->radioMutex.asScopedLock();
|
|
||||||
|
|
||||||
if (!lock.lock(10 / portTICK_PERIOD_MS)) {
|
|
||||||
LOG_E(TAG, LOG_MESSAGE_MUTEX_LOCK_FAILED);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
RadioState state = wifi->getRadioState();
|
|
||||||
if (state != RadioState::On && state != RadioState::ConnectionActive && state != RadioState::ConnectionPending) {
|
|
||||||
LOG_W(TAG, "Scan unavailable: wifi not enabled");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wifi->isScanActive()) {
|
|
||||||
LOG_W(TAG, "Scan already pending");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Thread safety
|
|
||||||
wifi->last_scan_time = tt::kernel::getTicks();
|
|
||||||
|
|
||||||
if (esp_wifi_scan_start(nullptr, false) != ESP_OK) {
|
|
||||||
LOG_I(TAG, "Can't start scan");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_I(TAG, "Starting scan");
|
|
||||||
wifi->setScanActive(true);
|
|
||||||
publish_event(wifi, WifiEvent::ScanStarted);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dispatchConnect(std::shared_ptr<Wifi> wifi) {
|
|
||||||
LOG_I(TAG, "dispatchConnect()");
|
|
||||||
auto lock = wifi->radioMutex.asScopedLock();
|
|
||||||
|
|
||||||
if (!lock.lock(50 / portTICK_PERIOD_MS)) {
|
|
||||||
LOG_E(TAG, LOG_MESSAGE_MUTEX_LOCK_FAILED_FMT, "dispatchConnect()");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_I(TAG, "Connecting to %s", wifi->connection_target.ssid.c_str());
|
|
||||||
|
|
||||||
// Stop radio first, if needed
|
|
||||||
RadioState radio_state = wifi->getRadioState();
|
|
||||||
if (
|
|
||||||
radio_state == RadioState::On ||
|
|
||||||
radio_state == RadioState::ConnectionActive ||
|
|
||||||
radio_state == RadioState::ConnectionPending
|
|
||||||
) {
|
|
||||||
LOG_I(TAG, "Connecting: Stopping radio first");
|
|
||||||
esp_err_t stop_result = esp_wifi_stop();
|
|
||||||
wifi->setScanActive(false);
|
|
||||||
if (stop_result != ESP_OK) {
|
|
||||||
LOG_E(TAG, "Connecting: Failed to disconnect (%s)", esp_err_to_name(stop_result));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wifi->setScanActive(false);
|
|
||||||
|
|
||||||
wifi->setRadioState(RadioState::ConnectionPending);
|
|
||||||
|
|
||||||
publish_event(wifi, WifiEvent::ConnectionPending);
|
|
||||||
|
|
||||||
wifi_config_t config;
|
|
||||||
memset(&config, 0, sizeof(wifi_config_t));
|
|
||||||
config.sta.channel = wifi_singleton->connection_target.channel;
|
|
||||||
config.sta.scan_method = WIFI_FAST_SCAN;
|
|
||||||
config.sta.sort_method = WIFI_CONNECT_AP_BY_SIGNAL;
|
|
||||||
config.sta.threshold.rssi = -127;
|
|
||||||
config.sta.pmf_cfg.capable = true;
|
|
||||||
|
|
||||||
memcpy(config.sta.ssid, wifi_singleton->connection_target.ssid.c_str(), wifi_singleton->connection_target.ssid.size());
|
|
||||||
|
|
||||||
if (wifi_singleton->connection_target.password[0] != 0x00) {
|
|
||||||
memcpy(config.sta.password, wifi_singleton->connection_target.password.c_str(), wifi_singleton->connection_target.password.size());
|
|
||||||
config.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_I(TAG, "esp_wifi_set_config()");
|
|
||||||
esp_err_t set_config_result = esp_wifi_set_config(WIFI_IF_STA, &config);
|
|
||||||
if (set_config_result != ESP_OK) {
|
|
||||||
wifi->setRadioState(RadioState::On);
|
|
||||||
LOG_E(TAG, "Failed to set wifi config (%s)", esp_err_to_name(set_config_result));
|
|
||||||
publish_event(wifi, WifiEvent::ConnectionFailed);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_I(TAG, "esp_wifi_start()");
|
|
||||||
esp_err_t wifi_start_result = esp_wifi_start();
|
|
||||||
if (wifi_start_result != ESP_OK) {
|
|
||||||
wifi->setRadioState(RadioState::On);
|
|
||||||
LOG_E(TAG, "Failed to start wifi to begin connecting (%s)", esp_err_to_name(wifi_start_result));
|
|
||||||
publish_event(wifi, WifiEvent::ConnectionFailed);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Waiting until either the connection is established (WIFI_CONNECTED_BIT)
|
|
||||||
* or connection failed for the maximum number of re-tries (WIFI_FAIL_BIT).
|
|
||||||
* The bits are set by wifi_event_handler() */
|
|
||||||
uint32_t flags;
|
|
||||||
if (wifi_singleton->connection_wait_flags.wait(WIFI_FAIL_BIT | WIFI_CONNECTED_BIT, false, true, &flags, kernel::MAX_TICKS)) {
|
|
||||||
LOG_I(TAG, "Waiting for EventGroup by event_handler()");
|
|
||||||
|
|
||||||
if (flags & WIFI_CONNECTED_BIT) {
|
|
||||||
wifi->setSecureConnection(config.sta.password[0] != 0x00U);
|
|
||||||
wifi->setRadioState(RadioState::ConnectionActive);
|
|
||||||
publish_event(wifi, WifiEvent::ConnectionSuccess);
|
|
||||||
LOG_I(TAG, "Connected to %s", wifi->connection_target.ssid.c_str());
|
|
||||||
if (wifi->connection_target_remember) {
|
|
||||||
if (!settings::save(wifi->connection_target)) {
|
|
||||||
LOG_E(TAG, "Failed to store credentials");
|
|
||||||
} else {
|
|
||||||
LOG_I(TAG, "Stored credentials");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (flags & WIFI_FAIL_BIT) {
|
|
||||||
wifi->setRadioState(RadioState::On);
|
|
||||||
publish_event(wifi, WifiEvent::ConnectionFailed);
|
|
||||||
LOG_I(TAG, "Failed to connect to %s", wifi->connection_target.ssid.c_str());
|
|
||||||
} else {
|
|
||||||
wifi->setRadioState(RadioState::On);
|
|
||||||
publish_event(wifi, WifiEvent::ConnectionFailed);
|
|
||||||
LOG_E(TAG, "UNEXPECTED EVENT");
|
|
||||||
}
|
|
||||||
|
|
||||||
wifi_singleton->connection_wait_flags.clear(WIFI_FAIL_BIT | WIFI_CONNECTED_BIT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dispatchDisconnectButKeepActive(std::shared_ptr<Wifi> wifi) {
|
|
||||||
LOG_I(TAG, "dispatchDisconnectButKeepActive()");
|
|
||||||
auto lock = wifi->radioMutex.asScopedLock();
|
|
||||||
|
|
||||||
if (!lock.lock(50 / portTICK_PERIOD_MS)) {
|
|
||||||
LOG_E(TAG, LOG_MESSAGE_MUTEX_LOCK_FAILED);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t stop_result = esp_wifi_stop();
|
|
||||||
if (stop_result != ESP_OK) {
|
|
||||||
LOG_E(TAG, "Failed to disconnect (%s)", esp_err_to_name(stop_result));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wifi_config_t config;
|
|
||||||
memset(&config, 0, sizeof(wifi_config_t));
|
|
||||||
config.sta.channel = wifi_singleton->connection_target.channel;
|
|
||||||
config.sta.scan_method = WIFI_ALL_CHANNEL_SCAN;
|
|
||||||
config.sta.sort_method = WIFI_CONNECT_AP_BY_SIGNAL;
|
|
||||||
config.sta.threshold.rssi = -127;
|
|
||||||
config.sta.pmf_cfg.capable = true;
|
|
||||||
|
|
||||||
esp_err_t set_config_result = esp_wifi_set_config(WIFI_IF_STA, &config);
|
|
||||||
if (set_config_result != ESP_OK) {
|
|
||||||
// TODO: disable radio, because radio state is in limbo between off and on
|
|
||||||
wifi->setRadioState(RadioState::Off);
|
|
||||||
LOG_E(TAG, "failed to set wifi config (%s)", esp_err_to_name(set_config_result));
|
|
||||||
publish_event(wifi, WifiEvent::RadioStateOff);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t wifi_start_result = esp_wifi_start();
|
|
||||||
if (wifi_start_result != ESP_OK) {
|
|
||||||
// TODO: disable radio, because radio state is in limbo between off and on
|
|
||||||
wifi->setRadioState(RadioState::Off);
|
|
||||||
LOG_E(TAG, "failed to start wifi to begin connecting (%s)", esp_err_to_name(wifi_start_result));
|
|
||||||
publish_event(wifi, WifiEvent::RadioStateOff);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wifi->setRadioState(RadioState::On);
|
|
||||||
publish_event(wifi, WifiEvent::Disconnected);
|
|
||||||
LOG_I(TAG, "Disconnected");
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool shouldScanForAutoConnect(std::shared_ptr<Wifi> wifi) {
|
|
||||||
auto lock = wifi->dataMutex.asScopedLock();
|
|
||||||
if (!lock.lock(100 / portTICK_PERIOD_MS)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_radio_in_scannable_state = wifi->getRadioState() == RadioState::On &&
|
|
||||||
!wifi->isScanActive() &&
|
|
||||||
!wifi->pause_auto_connect;
|
|
||||||
|
|
||||||
if (!is_radio_in_scannable_state) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
TickType_t current_time = kernel::getTicks();
|
|
||||||
bool scan_time_has_looped = (current_time < wifi->last_scan_time);
|
|
||||||
bool no_recent_scan = (current_time - wifi->last_scan_time) > (AUTO_SCAN_INTERVAL / portTICK_PERIOD_MS);
|
|
||||||
|
|
||||||
if (!scan_time_has_looped && !no_recent_scan) {
|
|
||||||
}
|
|
||||||
|
|
||||||
return scan_time_has_looped || no_recent_scan;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onAutoConnectTimer() {
|
|
||||||
auto wifi = std::static_pointer_cast<Wifi>(wifi_singleton);
|
|
||||||
// Automatic scanning is done so we can automatically connect to access points
|
|
||||||
bool should_auto_scan = shouldScanForAutoConnect(wifi);
|
|
||||||
if (should_auto_scan) {
|
|
||||||
getMainDispatcher().dispatch([wifi]() { dispatchScan(wifi); });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getIp() {
|
|
||||||
auto wifi = std::static_pointer_cast<Wifi>(wifi_singleton);
|
|
||||||
|
|
||||||
if (wifi == nullptr) return "127.0.0.1";
|
|
||||||
|
|
||||||
auto lock = wifi->dataMutex.asScopedLock();
|
|
||||||
if (!lock.lock(100 / portTICK_PERIOD_MS)) {
|
|
||||||
return "127.0.0.1";
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::format("{}.{}.{}.{}", IP2STR(&wifi->ip_info.ip));
|
|
||||||
}
|
|
||||||
|
|
||||||
class WifiService final : public Service {
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
bool onStart(ServiceContext& service) override {
|
|
||||||
assert(wifi_singleton == nullptr);
|
|
||||||
wifi_singleton = std::make_shared<Wifi>();
|
|
||||||
|
|
||||||
wifi_singleton->bootEventSubscription = kernel::subscribeSystemEvent(kernel::SystemEvent::BootSplash, [](auto) {
|
|
||||||
bootSplashInit();
|
|
||||||
});
|
|
||||||
|
|
||||||
auto timer_interval = std::min(2000, AUTO_SCAN_INTERVAL);
|
|
||||||
wifi_singleton->autoConnectTimer = std::make_unique<Timer>(Timer::Type::Periodic, timer_interval, [] { onAutoConnectTimer(); });
|
|
||||||
// We want to try and scan more often in case of startup or scan lock failure
|
|
||||||
wifi_singleton->autoConnectTimer->start();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onStop(ServiceContext& service) override {
|
|
||||||
auto wifi = wifi_singleton;
|
|
||||||
assert(wifi != nullptr);
|
|
||||||
|
|
||||||
RadioState state = wifi->getRadioState();
|
|
||||||
if (state != RadioState::Off) {
|
|
||||||
dispatchDisable(wifi);
|
|
||||||
}
|
|
||||||
|
|
||||||
wifi->autoConnectTimer->stop();
|
|
||||||
wifi->autoConnectTimer = nullptr; // Must release as it holds a reference to this Wifi instance
|
|
||||||
|
|
||||||
// Acquire all mutexes
|
|
||||||
wifi->dataMutex.lock();
|
|
||||||
wifi->radioMutex.lock();
|
|
||||||
|
|
||||||
// Detach
|
|
||||||
wifi_singleton = nullptr;
|
|
||||||
|
|
||||||
// Release mutexes
|
|
||||||
wifi->dataMutex.unlock();
|
|
||||||
wifi->radioMutex.unlock();
|
|
||||||
|
|
||||||
// Release (hopefully) last Wifi instance by scope
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
extern const ServiceManifest manifest = {
|
|
||||||
.id = "wifi",
|
|
||||||
.createService = create<WifiService>
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
#endif // CONFIG_SOC_WIFI_SUPPORTED or CONFIG_SLAVE_SOC_WIFI_SUPPORTED
|
|
||||||
@@ -1,168 +0,0 @@
|
|||||||
#ifdef ESP_PLATFORM
|
|
||||||
#include <sdkconfig.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if not defined(CONFIG_SOC_WIFI_SUPPORTED) && not defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED)
|
|
||||||
|
|
||||||
#include <Tactility/service/wifi/Wifi.h>
|
|
||||||
|
|
||||||
#include <Tactility/PubSub.h>
|
|
||||||
#include <Tactility/RecursiveMutex.h>
|
|
||||||
#include <tactility/check.h>
|
|
||||||
#include <Tactility/service/Service.h>
|
|
||||||
#include <Tactility/service/ServiceManifest.h>
|
|
||||||
|
|
||||||
namespace tt::service::wifi {
|
|
||||||
|
|
||||||
struct Wifi {
|
|
||||||
/** @brief Locking mechanism for modifying the Wifi instance */
|
|
||||||
RecursiveMutex mutex;
|
|
||||||
/** @brief The public event bus */
|
|
||||||
std::shared_ptr<PubSub<WifiEvent>> pubsub = std::make_shared<PubSub<WifiEvent>>();
|
|
||||||
/** @brief The internal message queue */
|
|
||||||
bool scan_active = false;
|
|
||||||
bool secure_connection = false;
|
|
||||||
RadioState radio_state = RadioState::ConnectionActive;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static Wifi* wifi = nullptr;
|
|
||||||
|
|
||||||
// region Static
|
|
||||||
|
|
||||||
static void publish_event(WifiEvent event) {
|
|
||||||
wifi->pubsub->publish(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion Static
|
|
||||||
|
|
||||||
// region Public functions
|
|
||||||
|
|
||||||
std::shared_ptr<PubSub<WifiEvent>> getPubsub() {
|
|
||||||
assert(wifi);
|
|
||||||
return wifi->pubsub;
|
|
||||||
}
|
|
||||||
|
|
||||||
RadioState getRadioState() {
|
|
||||||
return wifi->radio_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getConnectionTarget() {
|
|
||||||
return "Home Wifi";
|
|
||||||
}
|
|
||||||
|
|
||||||
void scan() {
|
|
||||||
assert(wifi);
|
|
||||||
wifi->scan_active = false; // TODO: enable and then later disable automatically
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isScanning() {
|
|
||||||
assert(wifi);
|
|
||||||
return wifi->scan_active;
|
|
||||||
}
|
|
||||||
|
|
||||||
void connect(const settings::WifiApSettings& ap, bool remember) {
|
|
||||||
assert(wifi);
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
void disconnect() {
|
|
||||||
assert(wifi);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setScanRecords(uint16_t records) {
|
|
||||||
assert(wifi);
|
|
||||||
// TODO: implement
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<ApRecord> getScanResults() {
|
|
||||||
check(wifi);
|
|
||||||
|
|
||||||
std::vector<ApRecord> records;
|
|
||||||
records.push_back((ApRecord) {
|
|
||||||
.ssid = "Home Wifi",
|
|
||||||
.rssi = -30,
|
|
||||||
.channel = 0,
|
|
||||||
.auth_mode = WIFI_AUTH_WPA2_PSK
|
|
||||||
});
|
|
||||||
records.push_back((ApRecord) {
|
|
||||||
.ssid = "No place like 127.0.0.1",
|
|
||||||
.rssi = -67,
|
|
||||||
.channel = 0,
|
|
||||||
.auth_mode = WIFI_AUTH_WPA2_PSK
|
|
||||||
});
|
|
||||||
records.push_back((ApRecord) {
|
|
||||||
.ssid = "Pretty fly for a Wi-Fi",
|
|
||||||
.rssi = -70,
|
|
||||||
.channel = 0,
|
|
||||||
.auth_mode = WIFI_AUTH_WPA2_PSK
|
|
||||||
});
|
|
||||||
records.push_back((ApRecord) {
|
|
||||||
.ssid = "An AP with a really, really long name",
|
|
||||||
.rssi = -80,
|
|
||||||
.channel = 0,
|
|
||||||
.auth_mode = WIFI_AUTH_WPA2_PSK
|
|
||||||
});
|
|
||||||
records.push_back((ApRecord) {
|
|
||||||
.ssid = "Bad Reception",
|
|
||||||
.rssi = -90,
|
|
||||||
.channel = 0,
|
|
||||||
.auth_mode = WIFI_AUTH_OPEN
|
|
||||||
});
|
|
||||||
|
|
||||||
return records;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setEnabled(bool enabled) {
|
|
||||||
assert(wifi != nullptr);
|
|
||||||
if (enabled) {
|
|
||||||
wifi->radio_state = RadioState::On;
|
|
||||||
wifi->secure_connection = true;
|
|
||||||
} else {
|
|
||||||
wifi->radio_state = RadioState::Off;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isConnectionSecure() {
|
|
||||||
return wifi->secure_connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getRssi() {
|
|
||||||
if (wifi->radio_state == RadioState::ConnectionActive) {
|
|
||||||
return -30;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getIp() {
|
|
||||||
return "192.168.1.2";
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion Public functions
|
|
||||||
|
|
||||||
class WifiService final : public Service {
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
bool onStart(ServiceContext& service) override {
|
|
||||||
check(wifi == nullptr);
|
|
||||||
wifi = new Wifi();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onStop(ServiceContext& service) override {
|
|
||||||
check(wifi != nullptr);
|
|
||||||
delete wifi;
|
|
||||||
wifi = nullptr;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
extern const ServiceManifest manifest = {
|
|
||||||
.id = "wifi",
|
|
||||||
.createService = create<WifiService>
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
#endif // ESP_PLATFORM
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#include <Tactility/settings/Time.h>
|
#include <Tactility/settings/Time.h>
|
||||||
|
|
||||||
#include <Tactility/kernel/SystemEvents.h>
|
#include <Tactility/SystemEvents.h>
|
||||||
#include <Tactility/Preferences.h>
|
#include <Tactility/Preferences.h>
|
||||||
#include <Tactility/settings/SystemSettings.h>
|
#include <Tactility/settings/SystemSettings.h>
|
||||||
|
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define TT_WIFI_SSID_LIMIT 32 // 32 characters/octets, according to IEEE 802.11-2020 spec
|
|
||||||
#define TT_WIFI_CREDENTIALS_PASSWORD_LIMIT 64 // 64 characters/octets, according to IEEE 802.11-2020 spec
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** Important: These values must map to tt::service::wifi::RadioState values exactly */
|
|
||||||
typedef enum {
|
|
||||||
WifiRadioStateOnPending,
|
|
||||||
WifiRadioStateOn,
|
|
||||||
WifiRadioStateConnectionPending,
|
|
||||||
WifiRadioStateConnectionActive,
|
|
||||||
WifiRadioStateOffPending,
|
|
||||||
WifiRadioStateOff,
|
|
||||||
} WifiRadioState;
|
|
||||||
|
|
||||||
/** @return the state of the WiFi radio */
|
|
||||||
WifiRadioState tt_wifi_get_radio_state();
|
|
||||||
|
|
||||||
/** @return a textual representation of the WiFi radio state */
|
|
||||||
const char* tt_wifi_radio_state_to_string(WifiRadioState state);
|
|
||||||
|
|
||||||
/** Start scanning */
|
|
||||||
void tt_wifi_scan();
|
|
||||||
|
|
||||||
/** @return true if a scan is active/pending */
|
|
||||||
bool tt_wifi_is_scanning();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the WiFi SSID that the system tries to connect to, or is connected to.
|
|
||||||
* @param[out] buffer an allocated string buffer. Its size must be (WIFI_SSID_LIMIT + 1).
|
|
||||||
*/
|
|
||||||
void tt_wifi_get_connection_target(char* buffer);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Enable/disable the radio. Ignores input if desired state matches current state.
|
|
||||||
* @param[in] enabled
|
|
||||||
*/
|
|
||||||
void tt_wifi_set_enabled(bool enabled);
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param ssid The access point identifier - maximal 32 characters/octets
|
|
||||||
* @param password the password - maximum 64 characters/octets
|
|
||||||
* @param channel 0 means "any"
|
|
||||||
* @param autoConnect whether we want to automatically reconnect if a disconnect occurs
|
|
||||||
* @param remember whether the record should be stored permanently on the device (it is only stored if this connection attempt succeeds)
|
|
||||||
*/
|
|
||||||
void tt_wifi_connect(const char* ssid, const char* password, int32_t channel, bool autoConnect, bool remember);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If WiFi is connected, this disconnects it.
|
|
||||||
*/
|
|
||||||
void tt_wifi_disconnect();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if WiFi is active and encrypted
|
|
||||||
*/
|
|
||||||
bool tt_wifi_is_connnection_secure();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the current radio connection link quality
|
|
||||||
*/
|
|
||||||
int tt_wifi_get_rssi();
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -16,7 +16,6 @@
|
|||||||
#include "tt_lvgl_toolbar.h"
|
#include "tt_lvgl_toolbar.h"
|
||||||
#include "tt_preferences.h"
|
#include "tt_preferences.h"
|
||||||
#include "tt_time.h"
|
#include "tt_time.h"
|
||||||
#include "tt_wifi.h"
|
|
||||||
|
|
||||||
#include "symbols/cplusplus.h"
|
#include "symbols/cplusplus.h"
|
||||||
#include "symbols/esp_event.h"
|
#include "symbols/esp_event.h"
|
||||||
@@ -360,16 +359,6 @@ const esp_elfsym main_symbols[] {
|
|||||||
ESP_ELFSYM_EXPORT(tt_timezone_get_code),
|
ESP_ELFSYM_EXPORT(tt_timezone_get_code),
|
||||||
ESP_ELFSYM_EXPORT(tt_timezone_is_format_24_hour),
|
ESP_ELFSYM_EXPORT(tt_timezone_is_format_24_hour),
|
||||||
ESP_ELFSYM_EXPORT(tt_timezone_set_format_24_hour),
|
ESP_ELFSYM_EXPORT(tt_timezone_set_format_24_hour),
|
||||||
ESP_ELFSYM_EXPORT(tt_wifi_get_radio_state),
|
|
||||||
ESP_ELFSYM_EXPORT(tt_wifi_radio_state_to_string),
|
|
||||||
ESP_ELFSYM_EXPORT(tt_wifi_scan),
|
|
||||||
ESP_ELFSYM_EXPORT(tt_wifi_is_scanning),
|
|
||||||
ESP_ELFSYM_EXPORT(tt_wifi_get_connection_target),
|
|
||||||
ESP_ELFSYM_EXPORT(tt_wifi_set_enabled),
|
|
||||||
ESP_ELFSYM_EXPORT(tt_wifi_connect),
|
|
||||||
ESP_ELFSYM_EXPORT(tt_wifi_disconnect),
|
|
||||||
ESP_ELFSYM_EXPORT(tt_wifi_is_connnection_secure),
|
|
||||||
ESP_ELFSYM_EXPORT(tt_wifi_get_rssi),
|
|
||||||
// tt::lvgl
|
// tt::lvgl
|
||||||
ESP_ELFSYM_EXPORT(tt_lvgl_spinner_create),
|
ESP_ELFSYM_EXPORT(tt_lvgl_spinner_create),
|
||||||
|
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
#include "tt_wifi.h"
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <Tactility/service/wifi/Wifi.h>
|
|
||||||
#include <Tactility/service/wifi/WifiSettings.h>
|
|
||||||
|
|
||||||
using namespace tt::service;
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
WifiRadioState tt_wifi_get_radio_state() {
|
|
||||||
return static_cast<WifiRadioState>(wifi::getRadioState());
|
|
||||||
}
|
|
||||||
const char* tt_wifi_radio_state_to_string(WifiRadioState state) {
|
|
||||||
return wifi::radioStateToString(static_cast<wifi::RadioState>(state));
|
|
||||||
}
|
|
||||||
|
|
||||||
void tt_wifi_scan() {
|
|
||||||
wifi::scan();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool tt_wifi_is_scanning() {
|
|
||||||
return wifi::isScanning();
|
|
||||||
}
|
|
||||||
|
|
||||||
void tt_wifi_get_connection_target(char* buffer) {
|
|
||||||
auto target = wifi::getConnectionTarget();
|
|
||||||
strcpy(buffer, target.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void tt_wifi_set_enabled(bool enabled) {
|
|
||||||
wifi::setEnabled(enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tt_wifi_connect(const char* ssid, const char* password, int32_t channel, bool autoConnect, bool remember) {
|
|
||||||
wifi::settings::WifiApSettings settings;
|
|
||||||
settings.ssid = ssid;
|
|
||||||
settings.password = password;
|
|
||||||
settings.channel = channel;
|
|
||||||
settings.autoConnect = autoConnect;
|
|
||||||
wifi::connect(settings, remember);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tt_wifi_disconnect() {
|
|
||||||
wifi::disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool tt_wifi_is_connnection_secure() {
|
|
||||||
return wifi::isConnectionSecure();
|
|
||||||
}
|
|
||||||
|
|
||||||
int tt_wifi_get_rssi() {
|
|
||||||
return wifi::getRssi();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -18,7 +18,8 @@ namespace tt {
|
|||||||
|
|
||||||
class Thread final {
|
class Thread final {
|
||||||
|
|
||||||
static constexpr size_t LOCAL_STORAGE_SELF_POINTER_INDEX = 0;
|
// Slot 0 is reserved by ESP-IDF's pthread API (see esp_wifi/lwip use of pthread_getspecific).
|
||||||
|
static constexpr size_t LOCAL_STORAGE_SELF_POINTER_INDEX = 1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -70,7 +71,7 @@ private:
|
|||||||
ESP_LOGI(TAG, "Stopped %s", thread->name.c_str());
|
ESP_LOGI(TAG, "Stopped %s", thread->name.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
vTaskSetThreadLocalStoragePointer(nullptr, 0, nullptr);
|
vTaskSetThreadLocalStoragePointer(nullptr, LOCAL_STORAGE_SELF_POINTER_INDEX, nullptr);
|
||||||
thread->taskHandle = nullptr;
|
thread->taskHandle = nullptr;
|
||||||
|
|
||||||
vTaskDelete(nullptr);
|
vTaskDelete(nullptr);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user