diff --git a/arduino/libretuya/api/Events.cpp b/arduino/libretuya/api/Events.cpp new file mode 100644 index 0000000..3f6d44c --- /dev/null +++ b/arduino/libretuya/api/Events.cpp @@ -0,0 +1,5 @@ +/* Copyright (c) Kuba Szczodrzyński 2022-05-17. */ + +#include "Events.h" + +uint16_t EventHandler_s::lastId = 1; diff --git a/arduino/libretuya/api/Events.h b/arduino/libretuya/api/Events.h new file mode 100644 index 0000000..1197d87 --- /dev/null +++ b/arduino/libretuya/api/Events.h @@ -0,0 +1,117 @@ +/* + ESP8266WiFiGeneric.h - esp8266 Wifi support. + Based on WiFi.h from Ardiono WiFi shield library. + Copyright (c) 2011-2014 Arduino. All right reserved. + Modified by Ivan Grokhotkov, December 2014 + Reworked by Markus Sattler, December 2015 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include + +#include "WiFiEvents.h" + +typedef enum { + ARDUINO_EVENT_WIFI_READY = 0, /**< ESP32 WiFi ready */ + ARDUINO_EVENT_WIFI_SCAN_DONE, /**< ESP32 finish scanning AP */ + ARDUINO_EVENT_WIFI_STA_START, /**< ESP32 station start */ + ARDUINO_EVENT_WIFI_STA_STOP, /**< ESP32 station stop */ + ARDUINO_EVENT_WIFI_STA_CONNECTED, /**< ESP32 station connected to AP */ + ARDUINO_EVENT_WIFI_STA_DISCONNECTED, /**< ESP32 station disconnected from AP */ + ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE, /**< the auth mode of AP connected by ESP32 station changed */ + ARDUINO_EVENT_WIFI_STA_GOT_IP, + ARDUINO_EVENT_WIFI_STA_GOT_IP6, + ARDUINO_EVENT_WIFI_STA_LOST_IP, + ARDUINO_EVENT_WIFI_AP_START, /**< ESP32 soft-AP start */ + ARDUINO_EVENT_WIFI_AP_STOP, /**< ESP32 soft-AP stop */ + ARDUINO_EVENT_WIFI_AP_STACONNECTED, /**< a station connected to ESP32 soft-AP */ + ARDUINO_EVENT_WIFI_AP_STADISCONNECTED, /**< a station disconnected from ESP32 soft-AP */ + ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED, + ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED, /**< Receive probe request packet in soft-AP interface */ + ARDUINO_EVENT_WIFI_AP_GOT_IP6, + ARDUINO_EVENT_WIFI_FTM_REPORT, /**< Receive report of FTM procedure */ + ARDUINO_EVENT_ETH_START, + ARDUINO_EVENT_ETH_STOP, + ARDUINO_EVENT_ETH_CONNECTED, + ARDUINO_EVENT_ETH_DISCONNECTED, + ARDUINO_EVENT_ETH_GOT_IP, + ARDUINO_EVENT_ETH_GOT_IP6, + ARDUINO_EVENT_WPS_ER_SUCCESS, /**< ESP32 station wps succeeds in enrollee mode */ + ARDUINO_EVENT_WPS_ER_FAILED, /**< ESP32 station wps fails in enrollee mode */ + ARDUINO_EVENT_WPS_ER_TIMEOUT, /**< ESP32 station wps timeout in enrollee mode */ + ARDUINO_EVENT_WPS_ER_PIN, /**< ESP32 station wps pin code in enrollee mode */ + ARDUINO_EVENT_WPS_ER_PBC_OVERLAP, /**< ESP32 station wps overlap in enrollee mode */ + ARDUINO_EVENT_SC_SCAN_DONE, + ARDUINO_EVENT_SC_FOUND_CHANNEL, + ARDUINO_EVENT_SC_GOT_SSID_PSWD, + ARDUINO_EVENT_SC_SEND_ACK_DONE, + ARDUINO_EVENT_PROV_INIT, + ARDUINO_EVENT_PROV_DEINIT, + ARDUINO_EVENT_PROV_START, + ARDUINO_EVENT_PROV_END, + ARDUINO_EVENT_PROV_CRED_RECV, + ARDUINO_EVENT_PROV_CRED_FAIL, + ARDUINO_EVENT_PROV_CRED_SUCCESS, + ARDUINO_EVENT_MAX +} arduino_event_id_t; + +typedef union { + wifi_event_sta_scan_done_t wifi_scan_done; + wifi_event_sta_authmode_change_t wifi_sta_authmode_change; + wifi_event_sta_connected_t wifi_sta_connected; + wifi_event_sta_disconnected_t wifi_sta_disconnected; + wifi_event_sta_wps_er_pin_t wps_er_pin; + wifi_event_sta_wps_fail_reason_t wps_fail_reason; + wifi_event_ap_probe_req_rx_t wifi_ap_probereqrecved; + wifi_event_ap_staconnected_t wifi_ap_staconnected; + wifi_event_ap_stadisconnected_t wifi_ap_stadisconnected; + wifi_event_ftm_report_t wifi_ftm_report; + ip_event_ap_staipassigned_t wifi_ap_staipassigned; + ip_event_got_ip_t got_ip; + ip_event_got_ip6_t got_ip6; + // smartconfig_event_got_ssid_pswd_t sc_got_ssid_pswd; + // esp_eth_handle_t eth_connected; + // wifi_sta_config_t prov_cred_recv; + // wifi_prov_sta_fail_reason_t prov_fail_reason; +} arduino_event_info_t; + +typedef struct { + arduino_event_id_t event_id; + arduino_event_info_t event_info; +} arduino_event_t; + +#define EventId arduino_event_id_t +#define EventId_t arduino_event_id_t +#define EventInfo arduino_event_info_t +#define EventInfo_t arduino_event_info_t +#define Event_t arduino_event_t + +typedef void (*EventCb)(EventId event); +typedef std::function EventFuncCb; +typedef void (*EventSysCb)(Event_t *event); + +typedef struct EventHandler_s { + static uint16_t lastId; + uint16_t id; + EventCb cb; + EventFuncCb fcb; + EventSysCb scb; + EventId eventId; + + EventHandler_s() : id(lastId++), cb(NULL), fcb(NULL), scb(NULL) {} +} EventHandler; diff --git a/arduino/libretuya/api/WiFi.cpp b/arduino/libretuya/api/WiFi.cpp new file mode 100644 index 0000000..73514db --- /dev/null +++ b/arduino/libretuya/api/WiFi.cpp @@ -0,0 +1,84 @@ +/* Copyright (c) Kuba Szczodrzyński 2022-05-17. */ + +#include "WiFi.h" + +std::vector IWiFiGenericClass::handlers; + +uint16_t IWiFiGenericClass::onEvent(EventCb callback, EventId eventId) { + if (!callback) + return 0; + EventHandler handler; + handler.cb = callback; + handler.eventId = eventId; + handlers.push_back(handler); + return handler.id; +} + +uint16_t IWiFiGenericClass::onEvent(EventFuncCb callback, EventId eventId) { + if (!callback) + return 0; + EventHandler handler; + handler.fcb = callback; + handler.eventId = eventId; + handlers.push_back(handler); + return handler.id; +} + +uint16_t IWiFiGenericClass::onEvent(EventSysCb callback, EventId eventId) { + if (!callback) + return 0; + EventHandler handler; + handler.scb = callback; + handler.eventId = eventId; + handlers.push_back(handler); + return handler.id; +} + +void IWiFiGenericClass::removeEvent(EventCb callback, EventId eventId) { + if (!callback) + return; + for (uint16_t i = 0; i < handlers.size(); i++) { + EventHandler handler = handlers[i]; + if (handler.cb == callback && handler.eventId == eventId) { + handlers.erase(handlers.begin() + i); + } + } +} + +void IWiFiGenericClass::removeEvent(EventSysCb callback, EventId eventId) { + if (!callback) + return; + for (uint16_t i = 0; i < handlers.size(); i++) { + EventHandler handler = handlers[i]; + if (handler.scb == callback && handler.eventId == eventId) { + handlers.erase(handlers.begin() + i); + } + } +} + +void IWiFiGenericClass::removeEvent(uint16_t id) { + for (uint16_t i = 0; i < handlers.size(); i++) { + EventHandler handler = handlers[i]; + if (handler.id == id) { + handlers.erase(handlers.begin() + i); + } + } +} + +void IWiFiGenericClass::postEvent(EventId eventId, EventInfo eventInfo) { + for (auto handler : handlers) { + if (handler.eventId != ARDUINO_EVENT_MAX && handler.eventId != eventId) + continue; + if (handler.cb) { + handler.cb(eventId); + } else if (handler.fcb) { + handler.fcb(eventId, eventInfo); + } else if (handler.scb) { + Event_t event = { + .event_id = eventId, + .event_info = eventInfo, + }; + handler.scb(&event); + } + } +} diff --git a/arduino/libretuya/api/WiFi.h b/arduino/libretuya/api/WiFi.h index a350175..c76636c 100644 --- a/arduino/libretuya/api/WiFi.h +++ b/arduino/libretuya/api/WiFi.h @@ -26,11 +26,11 @@ #include #include #include +#include +#include "Events.h" #include "WiFiType.h" -// TODO wifi events - class IWiFiClass { public: virtual void printDiag(Print &dest) = 0; @@ -63,6 +63,20 @@ class IWiFiGenericClass { static IPAddress calculateBroadcast(IPAddress ip, IPAddress subnet); static uint8_t calculateSubnetCIDR(IPAddress subnetMask); static String macToString(uint8_t *mac); + + protected: + static std::vector handlers; + + public: + uint16_t onEvent(EventCb callback, EventId eventId = ARDUINO_EVENT_MAX); + uint16_t onEvent(EventFuncCb callback, EventId eventId = ARDUINO_EVENT_MAX); + uint16_t onEvent(EventSysCb callback, EventId eventId = ARDUINO_EVENT_MAX); + void removeEvent(EventCb callback, EventId eventId); + void removeEvent(EventSysCb callback, EventId eventId); + void removeEvent(uint16_t id); + + protected: + static void postEvent(EventId eventId, EventInfo eventInfo); }; class IWiFiSTAClass { diff --git a/arduino/libretuya/api/WiFiEvents.h b/arduino/libretuya/api/WiFiEvents.h new file mode 100644 index 0000000..c728360 --- /dev/null +++ b/arduino/libretuya/api/WiFiEvents.h @@ -0,0 +1,173 @@ +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "WiFiType.h" + +/** Argument structure for WIFI_EVENT_SCAN_DONE event */ +typedef struct { + uint32_t status; /**< status of scanning APs: 0 - success, 1 - failure */ + uint8_t number; /**< number of scan results */ + uint8_t scan_id; /**< scan sequence number, used for block scan */ +} wifi_event_sta_scan_done_t; + +/** Argument structure for WIFI_EVENT_STA_CONNECTED event */ +typedef struct { + uint8_t ssid[32]; /**< SSID of connected AP */ + uint8_t ssid_len; /**< SSID length of connected AP */ + uint8_t bssid[6]; /**< BSSID of connected AP*/ + uint8_t channel; /**< channel of connected AP*/ + wifi_auth_mode_t authmode; /**< authentication mode used by AP*/ +} wifi_event_sta_connected_t; + +/** Argument structure for WIFI_EVENT_STA_DISCONNECTED event */ +typedef struct { + uint8_t ssid[32]; /**< SSID of disconnected AP */ + uint8_t ssid_len; /**< SSID length of disconnected AP */ + uint8_t bssid[6]; /**< BSSID of disconnected AP */ + uint8_t reason; /**< reason of disconnection */ +} wifi_event_sta_disconnected_t; + +/** Argument structure for WIFI_EVENT_STA_AUTHMODE_CHANGE event */ +typedef struct { + wifi_auth_mode_t old_mode; /**< the old auth mode of AP */ + wifi_auth_mode_t new_mode; /**< the new auth mode of AP */ +} wifi_event_sta_authmode_change_t; + +/** Argument structure for WIFI_EVENT_STA_WPS_ER_PIN event */ +typedef struct { + uint8_t pin_code[8]; /**< PIN code of station in enrollee mode */ +} wifi_event_sta_wps_er_pin_t; + +/** Argument structure for WIFI_EVENT_STA_WPS_ER_FAILED event */ +typedef enum { + WPS_FAIL_REASON_NORMAL = 0, /**< ESP32 WPS normal fail reason */ + WPS_FAIL_REASON_RECV_M2D, /**< ESP32 WPS receive M2D frame */ + WPS_FAIL_REASON_MAX +} wifi_event_sta_wps_fail_reason_t; + +#define MAX_SSID_LEN 32 +#define MAX_PASSPHRASE_LEN 64 +#define MAX_WPS_AP_CRED 3 + +/** Argument structure for WIFI_EVENT_STA_WPS_ER_SUCCESS event */ +typedef struct { + uint8_t ap_cred_cnt; /**< Number of AP credentials received */ + + struct { + uint8_t ssid[MAX_SSID_LEN]; /**< SSID of AP */ + uint8_t passphrase[MAX_PASSPHRASE_LEN]; /**< Passphrase for the AP */ + } ap_cred[MAX_WPS_AP_CRED]; /**< All AP credentials received from WPS handshake */ +} wifi_event_sta_wps_er_success_t; + +/** Argument structure for WIFI_EVENT_AP_STACONNECTED event */ +typedef struct { + uint8_t mac[6]; /**< MAC address of the station connected to ESP32 soft-AP */ + uint8_t aid; /**< the aid that ESP32 soft-AP gives to the station connected to */ + bool is_mesh_child; /**< flag to identify mesh child */ +} wifi_event_ap_staconnected_t; + +/** Argument structure for WIFI_EVENT_AP_STADISCONNECTED event */ +typedef struct { + uint8_t mac[6]; /**< MAC address of the station disconnects to ESP32 soft-AP */ + uint8_t aid; /**< the aid that ESP32 soft-AP gave to the station disconnects to */ + bool is_mesh_child; /**< flag to identify mesh child */ +} wifi_event_ap_stadisconnected_t; + +/** Argument structure for WIFI_EVENT_AP_PROBEREQRECVED event */ +typedef struct { + int rssi; /**< Received probe request signal strength */ + uint8_t mac[6]; /**< MAC address of the station which send probe request */ +} wifi_event_ap_probe_req_rx_t; + +/** + * @brief FTM operation status types + * + */ +typedef enum { + FTM_STATUS_SUCCESS = 0, /**< FTM exchange is successful */ + FTM_STATUS_UNSUPPORTED, /**< Peer does not support FTM */ + FTM_STATUS_CONF_REJECTED, /**< Peer rejected FTM configuration in FTM Request */ + FTM_STATUS_NO_RESPONSE, /**< Peer did not respond to FTM Requests */ + FTM_STATUS_FAIL, /**< Unknown error during FTM exchange */ +} wifi_ftm_status_t; + +/** Argument structure for */ +typedef struct { + uint8_t dlog_token; /**< Dialog Token of the FTM frame */ + int8_t rssi; /**< RSSI of the FTM frame received */ + uint32_t rtt; /**< Round Trip Time in pSec with a peer */ + uint64_t t1; /**< Time of departure of FTM frame from FTM Responder in pSec */ + uint64_t t2; /**< Time of arrival of FTM frame at FTM Initiator in pSec */ + uint64_t t3; /**< Time of departure of ACK from FTM Initiator in pSec */ + uint64_t t4; /**< Time of arrival of ACK at FTM Responder in pSec */ +} wifi_ftm_report_entry_t; + +/** Argument structure for WIFI_EVENT_FTM_REPORT event */ +typedef struct { + uint8_t peer_mac[6]; /**< MAC address of the FTM Peer */ + wifi_ftm_status_t status; /**< Status of the FTM operation */ + uint32_t rtt_raw; /**< Raw average Round-Trip-Time with peer in Nano-Seconds */ + uint32_t rtt_est; /**< Estimated Round-Trip-Time with peer in Nano-Seconds */ + uint32_t dist_est; /**< Estimated one-way distance in Centi-Meters */ + wifi_ftm_report_entry_t + *ftm_report_data; /**< Pointer to FTM Report with multiple entries, should be freed after use */ + uint8_t ftm_report_num_entries; /**< Number of entries in the FTM Report data */ +} wifi_event_ftm_report_t; + +#define WIFI_STATIS_BUFFER (1 << 0) +#define WIFI_STATIS_RXTX (1 << 1) +#define WIFI_STATIS_HW (1 << 2) +#define WIFI_STATIS_DIAG (1 << 3) +#define WIFI_STATIS_PS (1 << 4) +#define WIFI_STATIS_ALL (-1) + +/** Argument structure for WIFI_EVENT_ACTION_TX_STATUS event */ +typedef struct { + int ifx; /**< WiFi interface to send request to */ + uint32_t context; /**< Context to identify the request */ + uint8_t da[6]; /**< Destination MAC address */ + uint8_t status; /**< Status of the operation */ +} wifi_event_action_tx_status_t; + +/** Argument structure for WIFI_EVENT_ROC_DONE event */ +typedef struct { + uint32_t context; /**< Context to identify the request */ +} wifi_event_roc_done_t; + +/** Event structure for IP_EVENT_STA_GOT_IP, IP_EVENT_ETH_GOT_IP events */ +typedef struct { + esp_ip4_addr_t ip; /**< Interface IPV4 address */ + esp_ip4_addr_t netmask; /**< Interface IPV4 netmask */ + esp_ip4_addr_t gw; /**< Interface IPV4 gateway address */ +} esp_netif_ip_info_t; + +/** @brief IPV6 IP address information + */ +typedef struct { + esp_ip6_addr_t ip; /**< Interface IPV6 address */ +} esp_netif_ip6_info_t; + +typedef struct { + int if_index; /*!< Interface index for which the event is received (left for legacy compilation) */ + void *esp_netif; /*!< Pointer to corresponding esp-netif object */ + esp_netif_ip_info_t ip_info; /*!< IP address, netmask, gatway IP address */ + bool ip_changed; /*!< Whether the assigned IP has changed or not */ +} ip_event_got_ip_t; + +/** Event structure for IP_EVENT_GOT_IP6 event */ +typedef struct { + int if_index; /*!< Interface index for which the event is received (left for legacy compilation) */ + void *esp_netif; /*!< Pointer to corresponding esp-netif object */ + esp_netif_ip6_info_t ip6_info; /*!< IPv6 address of the interface */ + int ip_index; /*!< IPv6 address index */ +} ip_event_got_ip6_t; + +/** Event structure for IP_EVENT_AP_STAIPASSIGNED event */ +typedef struct { + esp_ip4_addr_t ip; /*!< IP address which was assigned to the station */ +} ip_event_ap_staipassigned_t; diff --git a/arduino/libretuya/api/WiFiType.h b/arduino/libretuya/api/WiFiType.h index 0f7fea3..2f40a9c 100644 --- a/arduino/libretuya/api/WiFiType.h +++ b/arduino/libretuya/api/WiFiType.h @@ -34,12 +34,28 @@ #define WIFI_AP WIFI_MODE_AP #define WIFI_AP_STA WIFI_MODE_APSTA +#define WiFiEvent_t arduino_event_id_t +#define WiFiEventInfo_t arduino_event_info_t +#define WiFiEventId_t uint16_t + +struct esp_ip6_addr { + uint32_t addr[4]; + uint8_t zone; +}; + +struct esp_ip4_addr { + uint32_t addr; +}; + +typedef struct esp_ip4_addr esp_ip4_addr_t; +typedef struct esp_ip6_addr esp_ip6_addr_t; + typedef enum { - WIFI_MODE_NULL = 0, - WIFI_MODE_STA, - WIFI_MODE_AP, - WIFI_MODE_APSTA, - WIFI_MODE_MAX, + WIFI_MODE_NULL = 0, /**< null mode */ + WIFI_MODE_STA, /**< WiFi station mode */ + WIFI_MODE_AP, /**< WiFi soft-AP mode */ + WIFI_MODE_APSTA, /**< WiFi station + soft-AP mode */ + WIFI_MODE_MAX } wifi_mode_t; typedef enum { @@ -54,13 +70,54 @@ typedef enum { } wl_status_t; typedef enum { - WIFI_AUTH_INVALID = 255, - WIFI_AUTH_AUTO = 200, - WIFI_AUTH_OPEN = 0, - WIFI_AUTH_WEP = 1, - WIFI_AUTH_WPA = 5, - WIFI_AUTH_WPA2 = 6, - WIFI_AUTH_WPA_PSK = 2, - WIFI_AUTH_WPA2_PSK = 3, - WIFI_AUTH_WPA_WPA2_PSK = 4, + 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_WPA2_ENTERPRISE, /**< authenticate mode : WPA2_ENTERPRISE */ + 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_WPA, + WIFI_AUTH_WPA2, + WIFI_AUTH_AUTO = 200, + WIFI_AUTH_INVALID = 255, + WIFI_AUTH_MAX } wifi_auth_mode_t; + +typedef enum { + WIFI_REASON_UNSPECIFIED = 1, + WIFI_REASON_AUTH_EXPIRE = 2, + WIFI_REASON_AUTH_LEAVE = 3, + WIFI_REASON_ASSOC_EXPIRE = 4, + WIFI_REASON_ASSOC_TOOMANY = 5, + WIFI_REASON_NOT_AUTHED = 6, + WIFI_REASON_NOT_ASSOCED = 7, + WIFI_REASON_ASSOC_LEAVE = 8, + WIFI_REASON_ASSOC_NOT_AUTHED = 9, + WIFI_REASON_DISASSOC_PWRCAP_BAD = 10, + WIFI_REASON_DISASSOC_SUPCHAN_BAD = 11, + WIFI_REASON_BSS_TRANSITION_DISASSOC = 12, + WIFI_REASON_IE_INVALID = 13, + WIFI_REASON_MIC_FAILURE = 14, + WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT = 15, + WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT = 16, + WIFI_REASON_IE_IN_4WAY_DIFFERS = 17, + WIFI_REASON_GROUP_CIPHER_INVALID = 18, + WIFI_REASON_PAIRWISE_CIPHER_INVALID = 19, + WIFI_REASON_AKMP_INVALID = 20, + WIFI_REASON_UNSUPP_RSN_IE_VERSION = 21, + WIFI_REASON_INVALID_RSN_IE_CAP = 22, + WIFI_REASON_802_1X_AUTH_FAILED = 23, + WIFI_REASON_CIPHER_SUITE_REJECTED = 24, + WIFI_REASON_INVALID_PMKID = 53, + WIFI_REASON_BEACON_TIMEOUT = 200, + WIFI_REASON_NO_AP_FOUND = 201, + WIFI_REASON_AUTH_FAIL = 202, + WIFI_REASON_ASSOC_FAIL = 203, + WIFI_REASON_HANDSHAKE_TIMEOUT = 204, + WIFI_REASON_CONNECTION_FAIL = 205, + WIFI_REASON_AP_TSF_RESET = 206, + WIFI_REASON_ROAMING = 207, +} wifi_err_reason_t; diff --git a/arduino/libretuya/core/LibreTuyaConfig.h b/arduino/libretuya/core/LibreTuyaConfig.h index 8bb7e43..32d6637 100644 --- a/arduino/libretuya/core/LibreTuyaConfig.h +++ b/arduino/libretuya/core/LibreTuyaConfig.h @@ -44,6 +44,11 @@ #define LT_LOGLEVEL LT_LEVEL_INFO #endif +// Free heap size debugging +#ifndef LT_LOG_HEAP +#define LT_LOG_HEAP 0 +#endif + // Per-module debugging #ifndef LT_DEBUG_WIFI #define LT_DEBUG_WIFI 0 diff --git a/arduino/libretuya/core/lt_logger.h b/arduino/libretuya/core/lt_logger.h index 2f5c03d..3199da1 100644 --- a/arduino/libretuya/core/lt_logger.h +++ b/arduino/libretuya/core/lt_logger.h @@ -51,6 +51,12 @@ void lt_log(const uint8_t level, const char *format, ...); #define LT_F(...) #endif +#if LT_LOG_HEAP +#define LT_HEAP_I() LT_I("Free heap: %u", LT_HEAP_FUNC()); +#else +#define LT_HEAP_I() +#endif + // ESP32 compat #define log_printf(...) LT_I(__VA_ARGS__) #define log_v(...) LT_V(__VA_ARGS__) diff --git a/arduino/realtek-ambz/cores/arduino/sdk_mem.h b/arduino/realtek-ambz/cores/arduino/sdk_mem.h index 2f0e9e2..a242d4a 100644 --- a/arduino/realtek-ambz/cores/arduino/sdk_mem.h +++ b/arduino/realtek-ambz/cores/arduino/sdk_mem.h @@ -17,3 +17,5 @@ extern void vPortFree(void *pv); #define calloc pvPortCalloc #define realloc pvPortReAlloc #define free vPortFree + +#define LT_HEAP_FUNC xPortGetFreeHeapSize diff --git a/arduino/realtek-ambz/cores/arduino/wiring.c b/arduino/realtek-ambz/cores/arduino/wiring.c index d5b12f8..ebe7bd1 100644 --- a/arduino/realtek-ambz/cores/arduino/wiring.c +++ b/arduino/realtek-ambz/cores/arduino/wiring.c @@ -31,7 +31,7 @@ static __inline uint32_t __get_ipsr__(void) { return (__regIPSR); } -void init(void) { +__attribute__((weak)) void init(void) { // nop } diff --git a/arduino/realtek-ambz/libraries/WiFi/WiFi.h b/arduino/realtek-ambz/libraries/WiFi/WiFi.h index b77ecec..dcfede1 100644 --- a/arduino/realtek-ambz/libraries/WiFi/WiFi.h +++ b/arduino/realtek-ambz/libraries/WiFi/WiFi.h @@ -73,6 +73,8 @@ class WiFiClass : public IWiFiClass, static uint8_t calculateSubnetCIDR(IPAddress subnetMask); static String macToString(uint8_t *mac); + static void handleRtwEvent(uint16_t event, char *data, int len, int flags); + public: // IWiFiSTAClass WiFiStatus begin( diff --git a/arduino/realtek-ambz/libraries/WiFi/WiFiAP.cpp b/arduino/realtek-ambz/libraries/WiFi/WiFiAP.cpp index 8c82ec3..d055a8d 100644 --- a/arduino/realtek-ambz/libraries/WiFi/WiFiAP.cpp +++ b/arduino/realtek-ambz/libraries/WiFi/WiFiAP.cpp @@ -7,6 +7,8 @@ bool WiFiClass::softAP(const char *ssid, const char *passphrase, int channel, bo if (!enableAP(true)) return false; + LT_HEAP_I(); + vTaskDelay(20); if (!ssid || *ssid == 0x00 || strlen(ssid) > 32) { diff --git a/arduino/realtek-ambz/libraries/WiFi/WiFiEvents.cpp b/arduino/realtek-ambz/libraries/WiFi/WiFiEvents.cpp new file mode 100644 index 0000000..5c2dce3 --- /dev/null +++ b/arduino/realtek-ambz/libraries/WiFi/WiFiEvents.cpp @@ -0,0 +1,204 @@ +/* Copyright (c) Kuba Szczodrzyński 2022-05-16. */ + +#include "WiFi.h" +#include "WiFiPriv.h" + +#include + +#define WIFI_EVENT_MAX_ROW 3 + +static xQueueHandle wifiEventQueueHandle = NULL; +static xTaskHandle wifiEventTaskHandle = NULL; + +// C code to support SDK-defined events (in wifi_conf.c) +extern "C" { +// SDK events +static event_list_elem_t event_callback_list[WIFI_EVENT_MAX][WIFI_EVENT_MAX_ROW]; + +typedef struct { + rtw_event_indicate_t event; + char *buf; + int buf_len; + int flags; +} rtw_event_t; + +// reset callbacks +void init_event_callback_list() { + memset(event_callback_list, 0, sizeof(event_callback_list)); +} + +// dummy +int wifi_manager_init() { + return 0; +} + +void wifi_reg_event_handler(unsigned int event_cmds, rtw_event_handler_t handler_func, void *handler_user_data) { + int i = 0, j = 0; + if (event_cmds < WIFI_EVENT_MAX) { + for (i = 0; i < WIFI_EVENT_MAX_ROW; i++) { + if (event_callback_list[event_cmds][i].handler == NULL) { + for (j = 0; j < WIFI_EVENT_MAX_ROW; j++) { + if (event_callback_list[event_cmds][j].handler == handler_func) { + return; + } + } + event_callback_list[event_cmds][i].handler = handler_func; + event_callback_list[event_cmds][i].handler_user_data = handler_user_data; + return; + } + } + } +} + +void wifi_unreg_event_handler(unsigned int event_cmds, rtw_event_handler_t handler_func) { + int i; + if (event_cmds < WIFI_EVENT_MAX) { + for (i = 0; i < WIFI_EVENT_MAX_ROW; i++) { + if (event_callback_list[event_cmds][i].handler == handler_func) { + event_callback_list[event_cmds][i].handler = NULL; + event_callback_list[event_cmds][i].handler_user_data = NULL; + return; + } + } + } +} +} // extern "C" + +// function called by wext_wlan_indicate +void wifi_indication(rtw_event_indicate_t event, char *buf, int buf_len, int flags) { + LT_HEAP_I(); + if (event >= WIFI_EVENT_MAX) + return; + if (wifiEventQueueHandle && wifiEventTaskHandle) { + rtw_event_t *ev = (rtw_event_t *)malloc(sizeof(rtw_event_t)); + if (buf_len > 0) { + // copy data to allow freeing from calling scopes + char *bufCopy = (char *)malloc(buf_len); + memcpy(bufCopy, buf, buf_len); + ev->buf = bufCopy; + } else { + ev->buf = NULL; + } + ev->event = event; + ev->buf_len = buf_len; + ev->flags = flags; + xQueueSend(wifiEventQueueHandle, &ev, portMAX_DELAY); + } else { + WiFiClass::handleRtwEvent(event, buf, buf_len, flags); + } +} + +static void wifiEventTask(void *arg) { + rtw_event_t *data = NULL; + for (;;) { + if (xQueueReceive(wifiEventQueueHandle, &data, portMAX_DELAY) == pdTRUE) { + WiFiClass::handleRtwEvent(data->event, data->buf, data->buf_len, data->flags); + if (data->buf) { + // free memory allocated in wifi_indication + free(data->buf); + } + free(data); + } + } +} + +void startWifiTask() { + if (!wifiEventQueueHandle) { + LT_HEAP_I(); + wifiEventQueueHandle = xQueueCreate(32, sizeof(Event_t *)); + LT_HEAP_I(); + } + if (!wifiEventTaskHandle) { + LT_HEAP_I(); + xTaskCreate(wifiEventTask, "wifievent", 512, NULL, 4, &wifiEventTaskHandle); + LT_HEAP_I(); + } +} + +void WiFiClass::handleRtwEvent(uint16_t event, char *data, int len, int flags) { + if (flags == -2) { + // already an Arduino event, just pass it + EventId eventId = (EventId)len; + EventInfo *eventInfo = (EventInfo *)data; + postEvent(eventId, *eventInfo); + free(eventInfo); + return; + } + + // send to SDK listeners + for (uint8_t i = 0; i < WIFI_EVENT_MAX_ROW; i++) { + rtw_event_handler_t handler = event_callback_list[event][i].handler; + if (!handler) + continue; + handler(data, len, flags, event_callback_list[event][i].handler_user_data); + } + + EventId eventId; + EventInfo eventInfo; + String ssid; + + memset(&eventInfo, 0, sizeof(EventInfo)); + + switch (event) { + case WIFI_EVENT_CONNECT: + eventId = ARDUINO_EVENT_WIFI_STA_START; + break; + + case WIFI_EVENT_DISCONNECT: + case WIFI_EVENT_RECONNECTION_FAIL: + eventId = ARDUINO_EVENT_WIFI_STA_DISCONNECTED; + eventInfo.wifi_sta_disconnected.ssid_len = 0; + eventInfo.wifi_sta_disconnected.reason = WIFI_REASON_UNSPECIFIED; + if (event == WIFI_EVENT_RECONNECTION_FAIL) + eventInfo.wifi_sta_disconnected.reason = WIFI_REASON_CONNECTION_FAIL; + break; + + case WIFI_EVENT_FOURWAY_HANDSHAKE_DONE: + eventId = ARDUINO_EVENT_WIFI_STA_CONNECTED; + ssid = WiFi.SSID(); + eventInfo.wifi_sta_connected.ssid_len = ssid.length(); + eventInfo.wifi_sta_connected.channel = WiFi.channel(); + eventInfo.wifi_sta_connected.authmode = WiFi.getEncryption(); + memcpy(eventInfo.wifi_sta_connected.ssid, ssid.c_str(), eventInfo.wifi_sta_connected.ssid_len + 1); + memcpy(eventInfo.wifi_sta_connected.bssid, WiFi.BSSID(), 6); + break; + + case WIFI_EVENT_SCAN_DONE: + eventId = ARDUINO_EVENT_WIFI_SCAN_DONE; + eventInfo.wifi_scan_done.status = 0; + eventInfo.wifi_scan_done.number = WiFi._netCount; + eventInfo.wifi_scan_done.scan_id = 0; + break; + + case WIFI_EVENT_STA_ASSOC: + // data(124) has MAC at 0x0A + if (len != 124) + return; + eventId = ARDUINO_EVENT_WIFI_AP_STACONNECTED; + memcpy(eventInfo.wifi_ap_staconnected.mac, (const char *)data[10], 6); + break; + + case WIFI_EVENT_STA_DISASSOC: + // data(6) is MAC + eventId = ARDUINO_EVENT_WIFI_AP_STADISCONNECTED; + memcpy(eventInfo.wifi_ap_stadisconnected.mac, (const char *)data, 6); + break; + + // case WIFI_EVENT_SCAN_RESULT_REPORT: + // case WIFI_EVENT_SEND_ACTION_DONE: + // case WIFI_EVENT_RX_MGNT: + // case WIFI_EVENT_STA_WPS_START: + // case WIFI_EVENT_WPS_FINISH: + // case WIFI_EVENT_EAPOL_START: + // case WIFI_EVENT_EAPOL_RECVD: + // case WIFI_EVENT_NO_NETWORK: + // case WIFI_EVENT_BEACON_AFTER_DHCP: + // case WIFI_EVENT_IP_CHANGED: + // case WIFI_EVENT_ICV_ERROR: + // case WIFI_EVENT_CHALLENGE_FAIL: + default: + return; + } + + postEvent(eventId, eventInfo); +} diff --git a/arduino/realtek-ambz/libraries/WiFi/WiFiGeneric.cpp b/arduino/realtek-ambz/libraries/WiFi/WiFiGeneric.cpp index cf8779c..d2a2732 100644 --- a/arduino/realtek-ambz/libraries/WiFi/WiFiGeneric.cpp +++ b/arduino/realtek-ambz/libraries/WiFi/WiFiGeneric.cpp @@ -9,20 +9,24 @@ int32_t WiFiClass::channel() { return channel; } +extern void startWifiTask(); + bool WiFiClass::mode(WiFiMode mode) { WiFiMode currentMode = getMode(); LT_D_WG("Mode changing %u -> %u", currentMode, mode); if (mode == currentMode) return true; + LT_HEAP_I(); + startWifiTask(); if (!currentMode && mode && !_initialized) { // initialize wifi first LT_I("Initializing LwIP"); LwIP_Init(); reset_wifi_struct(); - // wifi_manager_init(); // these are events! _initialized = true; } + LT_HEAP_I(); if (currentMode) { // stop wifi to change mode LT_D_WG("Stopping WiFi to change mode"); @@ -37,6 +41,7 @@ bool WiFiClass::mode(WiFiMode mode) { LT_E("Error while changing mode(%u)", mode); return false; } + LT_HEAP_I(); return true; } diff --git a/arduino/realtek-ambz/libraries/WiFi/WiFiSTA.cpp b/arduino/realtek-ambz/libraries/WiFi/WiFiSTA.cpp index 038eb04..fcd2c19 100644 --- a/arduino/realtek-ambz/libraries/WiFi/WiFiSTA.cpp +++ b/arduino/realtek-ambz/libraries/WiFi/WiFiSTA.cpp @@ -12,6 +12,8 @@ WiFiClass::begin(const char *ssid, const char *passphrase, int32_t channel, cons if (!enableSTA(true)) return WL_CONNECT_FAILED; + LT_HEAP_I(); + if (!ssid || *ssid == 0x00 || strlen(ssid) > 32) { LT_W("SSID not specified or too long"); return WL_CONNECT_FAILED; @@ -47,18 +49,26 @@ WiFiClass::begin(const char *ssid, const char *passphrase, int32_t channel, cons bool WiFiClass::config(IPAddress localIP, IPAddress gateway, IPAddress subnet, IPAddress dns1, IPAddress dns2) { if (!enableSTA(true)) return false; - struct netif *ifs = NETIF_RTW_STA; - struct ip_addr ipaddr, netmask, gw, d1, d2; - ipaddr.addr = localIP; - netmask.addr = subnet; - gw.addr = gateway; - d1.addr = dns1; - d2.addr = dns2; - netif_set_addr(ifs, &ipaddr, &netmask, &gw); + + struct ip_addr d1, d2; + d1.addr = dns1; + d2.addr = dns2; if (dns1[0]) dns_setserver(0, &d1); if (dns2[0]) dns_setserver(0, &d2); + + if (!localIP[0]) { + LwIP_DHCP(0, DHCP_START); + return true; + } + struct netif *ifs = NETIF_RTW_STA; + struct ip_addr ipaddr, netmask, gw; + ipaddr.addr = localIP; + netmask.addr = subnet; + gw.addr = gateway; + netif_set_addr(ifs, &ipaddr, &netmask, &gw); + LwIP_DHCP(0, DHCP_STOP); return true; } @@ -94,8 +104,21 @@ bool WiFiClass::reconnect(const uint8_t *bssid) { if (ret == RTW_SUCCESS) { dhcpRet = LwIP_DHCP(0, DHCP_START); - if (dhcpRet == DHCP_ADDRESS_ASSIGNED) + if (dhcpRet == DHCP_ADDRESS_ASSIGNED) { + LT_HEAP_I(); + EventInfo *eventInfo = (EventInfo *)zalloc(sizeof(EventInfo)); + eventInfo->got_ip.if_index = 0; + eventInfo->got_ip.esp_netif = NULL; + eventInfo->got_ip.ip_info.ip.addr = localIP(); + eventInfo->got_ip.ip_info.gw.addr = gatewayIP(); + eventInfo->got_ip.ip_info.netmask.addr = subnetMask(); + eventInfo->got_ip.ip_changed = true; + // pass the event through the queue + wifi_indication(WIFI_EVENT_CONNECT, (char *)eventInfo, ARDUINO_EVENT_WIFI_STA_GOT_IP, -2); + // free memory as wifi_indication creates a copy + free(eventInfo); return true; + } LT_E("DHCP failed; dhcpRet=%d", dhcpRet); wifi_disconnect(); return false; diff --git a/builder/frameworks/realtek-ambz-arduino.py b/builder/frameworks/realtek-ambz-arduino.py index bf2aa4c..dcbed40 100644 --- a/builder/frameworks/realtek-ambz-arduino.py +++ b/builder/frameworks/realtek-ambz-arduino.py @@ -6,7 +6,13 @@ from SCons.Script import DefaultEnvironment env = DefaultEnvironment() +# SDK options env.Replace(AMBZ_NO_POLARSSL=True) +env.Replace( + LIB_AMBZ_SDK_SKIP=[ + "component/common/api/wifi/wifi_ind.c", + ] +) env.SConscript("realtek-ambz-sdk.py", exports="env") env.SConscript("../arduino-common.py", exports="env") diff --git a/builder/utils.py b/builder/utils.py index 12f2e77..68e81e3 100644 --- a/builder/utils.py +++ b/builder/utils.py @@ -73,6 +73,13 @@ def env_add_library( expr = join(base_dir, src[2:-1]) sources.append(src[0] + "<" + expr + ">") + + # allow removing sources from parent builders + key = f"LIB_{name.upper()}_SKIP" + if key in env: + for expr in env[key]: + sources.append("-<" + expr + ">") + # queue library for further env clone and build env.Prepend(LIBQUEUE=[[join("$BUILD_DIR", name), base_dir, sources]]) diff --git a/platform/realtek-ambz/fixups/inc/FreeRTOSConfig.h b/platform/realtek-ambz/fixups/inc/FreeRTOSConfig.h index a92826e..d735e54 100644 --- a/platform/realtek-ambz/fixups/inc/FreeRTOSConfig.h +++ b/platform/realtek-ambz/fixups/inc/FreeRTOSConfig.h @@ -94,7 +94,7 @@ extern uint32_t SystemCoreClock; #define configSYSTICK_CLOCK_HZ 32768 #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 512 ) #ifdef CONFIG_WIFI_EN -#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 110 * 1024 ) ) +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 160 * 1024 ) ) #else #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 20 * 1024 ) ) #endif