3 * Copyright (c) 2020 Project CHIP Authors
4 * Copyright (c) 2018 Nest Labs, Inc.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
22 * General utility methods for the ESP32 platform.
24 /* this file behaves like a config.h, comes first */
25 #include <platform/internal/CHIPDeviceLayerInternal.h>
27 #include <platform/ESP32/ESP32Utils.h>
28 #include <support/CodeUtils.h>
29 #include <support/ErrorStr.h>
30 #include <support/logging/CHIPLogging.h>
32 #include "esp_event.h"
33 #include "esp_netif.h"
34 #include "esp_netif_net_stack.h"
37 using namespace ::chip::DeviceLayer::Internal;
38 using chip::DeviceLayer::Internal::DeviceNetworkInfo;
40 CHIP_ERROR ESP32Utils::IsAPEnabled(bool & apEnabled)
43 wifi_mode_t curWiFiMode;
45 err = esp_wifi_get_mode(&curWiFiMode);
48 ChipLogError(DeviceLayer, "esp_wifi_get_mode() failed: %s", chip::ErrorStr(err));
52 apEnabled = (curWiFiMode == WIFI_MODE_AP || curWiFiMode == WIFI_MODE_APSTA);
57 bool ESP32Utils::IsStationProvisioned(void)
59 wifi_config_t stationConfig;
60 return (esp_wifi_get_config(WIFI_IF_STA, &stationConfig) == ERR_OK && stationConfig.sta.ssid[0] != 0);
63 CHIP_ERROR ESP32Utils::IsStationConnected(bool & connected)
65 wifi_ap_record_t apInfo;
66 connected = (esp_wifi_sta_get_ap_info(&apInfo) == ESP_OK);
70 CHIP_ERROR ESP32Utils::StartWiFiLayer(void)
76 // There appears to be no direct way to ask the ESP WiFi layer if esp_wifi_start()
77 // has been called. So use the ESP_ERR_WIFI_NOT_STARTED error returned by
78 // esp_wifi_get_max_tx_power() to detect this.
79 err = esp_wifi_get_max_tx_power(&ignored);
85 case ESP_ERR_WIFI_NOT_STARTED:
95 ChipLogProgress(DeviceLayer, "Starting ESP WiFi layer");
97 err = esp_wifi_start();
100 ChipLogError(DeviceLayer, "esp_wifi_start() failed: %s", chip::ErrorStr(err));
108 CHIP_ERROR ESP32Utils::EnableStationMode(void)
111 wifi_mode_t curWiFiMode;
113 // Get the current ESP WiFI mode.
114 err = esp_wifi_get_mode(&curWiFiMode);
117 ChipLogError(DeviceLayer, "esp_wifi_get_mode() failed: %s", chip::ErrorStr(err));
121 // If station mode is not already enabled (implying the current mode is WIFI_MODE_AP), change
122 // the mode to WIFI_MODE_APSTA.
123 if (curWiFiMode == WIFI_MODE_AP)
125 ChipLogProgress(DeviceLayer, "Changing ESP WiFi mode: %s -> %s", WiFiModeToStr(WIFI_MODE_AP),
126 WiFiModeToStr(WIFI_MODE_APSTA));
128 err = esp_wifi_set_mode(WIFI_MODE_APSTA);
131 ChipLogError(DeviceLayer, "esp_wifi_set_mode() failed: %s", chip::ErrorStr(err));
140 CHIP_ERROR ESP32Utils::SetAPMode(bool enabled)
143 wifi_mode_t curWiFiMode, targetWiFiMode;
145 targetWiFiMode = (enabled) ? WIFI_MODE_APSTA : WIFI_MODE_STA;
147 // Get the current ESP WiFI mode.
148 err = esp_wifi_get_mode(&curWiFiMode);
151 ChipLogError(DeviceLayer, "esp_wifi_get_mode() failed: %s", chip::ErrorStr(err));
155 // If station mode is not already enabled (implying the current mode is WIFI_MODE_AP), change
156 // the mode to WIFI_MODE_APSTA.
157 if (curWiFiMode != targetWiFiMode)
159 ChipLogProgress(DeviceLayer, "Changing ESP WiFi mode: %s -> %s", WiFiModeToStr(curWiFiMode), WiFiModeToStr(targetWiFiMode));
161 err = esp_wifi_set_mode(targetWiFiMode);
164 ChipLogError(DeviceLayer, "esp_wifi_set_mode() failed: %s", chip::ErrorStr(err));
173 int ESP32Utils::OrderScanResultsByRSSI(const void * _res1, const void * _res2)
175 const wifi_ap_record_t * res1 = (const wifi_ap_record_t *) _res1;
176 const wifi_ap_record_t * res2 = (const wifi_ap_record_t *) _res2;
178 if (res1->rssi > res2->rssi)
182 if (res1->rssi < res2->rssi)
189 const char * ESP32Utils::WiFiModeToStr(wifi_mode_t wifiMode)
199 case WIFI_MODE_APSTA:
206 struct netif * ESP32Utils::GetStationNetif(void)
208 return GetNetif("WIFI_STA_DEF");
211 struct netif * ESP32Utils::GetNetif(const char * ifKey)
213 struct netif * netif = NULL;
214 esp_netif_t * netif_handle = NULL;
215 netif_handle = esp_netif_get_handle_from_ifkey(ifKey);
216 netif = (struct netif *) esp_netif_get_netif_impl(netif_handle);
220 bool ESP32Utils::IsInterfaceUp(const char * ifKey)
222 struct netif * netif = GetNetif(ifKey);
223 return netif != NULL && netif_is_up(netif);
226 bool ESP32Utils::HasIPv6LinkLocalAddress(const char * ifKey)
228 struct esp_ip6_addr if_ip6_unused;
229 return esp_netif_get_ip6_linklocal(esp_netif_get_handle_from_ifkey(ifKey), &if_ip6_unused) == ESP_OK;
232 CHIP_ERROR ESP32Utils::GetWiFiStationProvision(Internal::DeviceNetworkInfo & netInfo, bool includeCredentials)
234 CHIP_ERROR err = CHIP_NO_ERROR;
235 wifi_config_t stationConfig;
237 err = esp_wifi_get_config(WIFI_IF_STA, &stationConfig);
240 VerifyOrExit(stationConfig.sta.ssid[0] != 0, err = CHIP_ERROR_INCORRECT_STATE);
242 netInfo.NetworkId = kWiFiStationNetworkId;
243 netInfo.FieldPresent.NetworkId = true;
244 memcpy(netInfo.WiFiSSID, stationConfig.sta.ssid,
245 min(strlen(reinterpret_cast<char *>(stationConfig.sta.ssid)) + 1, sizeof(netInfo.WiFiSSID)));
247 // Enforce that netInfo wifiSSID is null terminated
248 netInfo.WiFiSSID[kMaxWiFiSSIDLength] = '\0';
250 if (includeCredentials)
252 static_assert(sizeof(netInfo.WiFiKey) < 255, "Our min might not fit in netInfo.WiFiKeyLen");
253 netInfo.WiFiKeyLen = static_cast<uint8_t>(min(strlen((char *) stationConfig.sta.password), sizeof(netInfo.WiFiKey)));
254 memcpy(netInfo.WiFiKey, stationConfig.sta.password, netInfo.WiFiKeyLen);
261 CHIP_ERROR ESP32Utils::SetWiFiStationProvision(const Internal::DeviceNetworkInfo & netInfo)
263 CHIP_ERROR err = CHIP_NO_ERROR;
264 wifi_config_t wifiConfig;
266 char wifiSSID[kMaxWiFiSSIDLength + 1];
267 size_t netInfoSSIDLen = strlen(netInfo.WiFiSSID);
269 // Ensure that ESP station mode is enabled. This is required before esp_wifi_set_config(ESP_IF_WIFI_STA,...)
271 err = ESP32Utils::EnableStationMode();
274 // Enforce that wifiSSID is null terminated before copying it
275 memcpy(wifiSSID, netInfo.WiFiSSID, min(netInfoSSIDLen + 1, sizeof(wifiSSID)));
276 if (netInfoSSIDLen + 1 < sizeof(wifiSSID))
278 wifiSSID[netInfoSSIDLen] = '\0';
282 wifiSSID[kMaxWiFiSSIDLength] = '\0';
285 // Initialize an ESP wifi_config_t structure based on the new provision information.
286 memset(&wifiConfig, 0, sizeof(wifiConfig));
287 memcpy(wifiConfig.sta.ssid, wifiSSID, min(strlen(wifiSSID) + 1, sizeof(wifiConfig.sta.ssid)));
288 memcpy(wifiConfig.sta.password, netInfo.WiFiKey, min((size_t) netInfo.WiFiKeyLen, sizeof(wifiConfig.sta.password)));
289 wifiConfig.sta.scan_method = WIFI_ALL_CHANNEL_SCAN;
290 wifiConfig.sta.sort_method = WIFI_CONNECT_AP_BY_SIGNAL;
292 // Configure the ESP WiFi interface.
293 err = esp_wifi_set_config(WIFI_IF_STA, &wifiConfig);
296 ChipLogError(DeviceLayer, "esp_wifi_set_config() failed: %s", chip::ErrorStr(err));
300 ChipLogProgress(DeviceLayer, "WiFi station provision set (SSID: %s)", netInfo.WiFiSSID);
306 CHIP_ERROR ESP32Utils::ClearWiFiStationProvision(void)
308 CHIP_ERROR err = CHIP_NO_ERROR;
309 wifi_config_t stationConfig;
311 // Clear the ESP WiFi station configuration.
312 memset(&stationConfig, 0, sizeof(stationConfig));
313 esp_wifi_set_config(WIFI_IF_STA, &stationConfig);