Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / platform / ESP32 / ESP32Utils.cpp
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *    Copyright (c) 2018 Nest Labs, Inc.
5  *    All rights reserved.
6  *
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
10  *
11  *        http://www.apache.org/licenses/LICENSE-2.0
12  *
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.
18  */
19
20 /**
21  *    @file
22  *          General utility methods for the ESP32 platform.
23  */
24 /* this file behaves like a config.h, comes first */
25 #include <platform/internal/CHIPDeviceLayerInternal.h>
26
27 #include <platform/ESP32/ESP32Utils.h>
28 #include <support/CodeUtils.h>
29 #include <support/ErrorStr.h>
30 #include <support/logging/CHIPLogging.h>
31
32 #include "esp_event.h"
33 #include "esp_netif.h"
34 #include "esp_netif_net_stack.h"
35 #include "esp_wifi.h"
36
37 using namespace ::chip::DeviceLayer::Internal;
38 using chip::DeviceLayer::Internal::DeviceNetworkInfo;
39
40 CHIP_ERROR ESP32Utils::IsAPEnabled(bool & apEnabled)
41 {
42     CHIP_ERROR err;
43     wifi_mode_t curWiFiMode;
44
45     err = esp_wifi_get_mode(&curWiFiMode);
46     if (err != ESP_OK)
47     {
48         ChipLogError(DeviceLayer, "esp_wifi_get_mode() failed: %s", chip::ErrorStr(err));
49         return err;
50     }
51
52     apEnabled = (curWiFiMode == WIFI_MODE_AP || curWiFiMode == WIFI_MODE_APSTA);
53
54     return CHIP_NO_ERROR;
55 }
56
57 bool ESP32Utils::IsStationProvisioned(void)
58 {
59     wifi_config_t stationConfig;
60     return (esp_wifi_get_config(WIFI_IF_STA, &stationConfig) == ERR_OK && stationConfig.sta.ssid[0] != 0);
61 }
62
63 CHIP_ERROR ESP32Utils::IsStationConnected(bool & connected)
64 {
65     wifi_ap_record_t apInfo;
66     connected = (esp_wifi_sta_get_ap_info(&apInfo) == ESP_OK);
67     return CHIP_NO_ERROR;
68 }
69
70 CHIP_ERROR ESP32Utils::StartWiFiLayer(void)
71 {
72     CHIP_ERROR err;
73     int8_t ignored;
74     bool wifiStarted;
75
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);
80     switch (err)
81     {
82     case ESP_OK:
83         wifiStarted = true;
84         break;
85     case ESP_ERR_WIFI_NOT_STARTED:
86         wifiStarted = false;
87         err         = ESP_OK;
88         break;
89     default:
90         ExitNow();
91     }
92
93     if (!wifiStarted)
94     {
95         ChipLogProgress(DeviceLayer, "Starting ESP WiFi layer");
96
97         err = esp_wifi_start();
98         if (err != ESP_OK)
99         {
100             ChipLogError(DeviceLayer, "esp_wifi_start() failed: %s", chip::ErrorStr(err));
101         }
102     }
103
104 exit:
105     return err;
106 }
107
108 CHIP_ERROR ESP32Utils::EnableStationMode(void)
109 {
110     CHIP_ERROR err;
111     wifi_mode_t curWiFiMode;
112
113     // Get the current ESP WiFI mode.
114     err = esp_wifi_get_mode(&curWiFiMode);
115     if (err != ESP_OK)
116     {
117         ChipLogError(DeviceLayer, "esp_wifi_get_mode() failed: %s", chip::ErrorStr(err));
118     }
119     SuccessOrExit(err);
120
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)
124     {
125         ChipLogProgress(DeviceLayer, "Changing ESP WiFi mode: %s -> %s", WiFiModeToStr(WIFI_MODE_AP),
126                         WiFiModeToStr(WIFI_MODE_APSTA));
127
128         err = esp_wifi_set_mode(WIFI_MODE_APSTA);
129         if (err != ESP_OK)
130         {
131             ChipLogError(DeviceLayer, "esp_wifi_set_mode() failed: %s", chip::ErrorStr(err));
132         }
133         SuccessOrExit(err);
134     }
135
136 exit:
137     return err;
138 }
139
140 CHIP_ERROR ESP32Utils::SetAPMode(bool enabled)
141 {
142     CHIP_ERROR err;
143     wifi_mode_t curWiFiMode, targetWiFiMode;
144
145     targetWiFiMode = (enabled) ? WIFI_MODE_APSTA : WIFI_MODE_STA;
146
147     // Get the current ESP WiFI mode.
148     err = esp_wifi_get_mode(&curWiFiMode);
149     if (err != ESP_OK)
150     {
151         ChipLogError(DeviceLayer, "esp_wifi_get_mode() failed: %s", chip::ErrorStr(err));
152     }
153     SuccessOrExit(err);
154
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)
158     {
159         ChipLogProgress(DeviceLayer, "Changing ESP WiFi mode: %s -> %s", WiFiModeToStr(curWiFiMode), WiFiModeToStr(targetWiFiMode));
160
161         err = esp_wifi_set_mode(targetWiFiMode);
162         if (err != ESP_OK)
163         {
164             ChipLogError(DeviceLayer, "esp_wifi_set_mode() failed: %s", chip::ErrorStr(err));
165         }
166         SuccessOrExit(err);
167     }
168
169 exit:
170     return err;
171 }
172
173 int ESP32Utils::OrderScanResultsByRSSI(const void * _res1, const void * _res2)
174 {
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;
177
178     if (res1->rssi > res2->rssi)
179     {
180         return -1;
181     }
182     if (res1->rssi < res2->rssi)
183     {
184         return 1;
185     }
186     return 0;
187 }
188
189 const char * ESP32Utils::WiFiModeToStr(wifi_mode_t wifiMode)
190 {
191     switch (wifiMode)
192     {
193     case WIFI_MODE_NULL:
194         return "NULL";
195     case WIFI_MODE_STA:
196         return "STA";
197     case WIFI_MODE_AP:
198         return "AP";
199     case WIFI_MODE_APSTA:
200         return "STA+AP";
201     default:
202         return "(unknown)";
203     }
204 }
205
206 struct netif * ESP32Utils::GetStationNetif(void)
207 {
208     return GetNetif("WIFI_STA_DEF");
209 }
210
211 struct netif * ESP32Utils::GetNetif(const char * ifKey)
212 {
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);
217     return netif;
218 }
219
220 bool ESP32Utils::IsInterfaceUp(const char * ifKey)
221 {
222     struct netif * netif = GetNetif(ifKey);
223     return netif != NULL && netif_is_up(netif);
224 }
225
226 bool ESP32Utils::HasIPv6LinkLocalAddress(const char * ifKey)
227 {
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;
230 }
231
232 CHIP_ERROR ESP32Utils::GetWiFiStationProvision(Internal::DeviceNetworkInfo & netInfo, bool includeCredentials)
233 {
234     CHIP_ERROR err = CHIP_NO_ERROR;
235     wifi_config_t stationConfig;
236
237     err = esp_wifi_get_config(WIFI_IF_STA, &stationConfig);
238     SuccessOrExit(err);
239
240     VerifyOrExit(stationConfig.sta.ssid[0] != 0, err = CHIP_ERROR_INCORRECT_STATE);
241
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)));
246
247     // Enforce that netInfo wifiSSID is null terminated
248     netInfo.WiFiSSID[kMaxWiFiSSIDLength] = '\0';
249
250     if (includeCredentials)
251     {
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);
255     }
256
257 exit:
258     return err;
259 }
260
261 CHIP_ERROR ESP32Utils::SetWiFiStationProvision(const Internal::DeviceNetworkInfo & netInfo)
262 {
263     CHIP_ERROR err = CHIP_NO_ERROR;
264     wifi_config_t wifiConfig;
265
266     char wifiSSID[kMaxWiFiSSIDLength + 1];
267     size_t netInfoSSIDLen = strlen(netInfo.WiFiSSID);
268
269     // Ensure that ESP station mode is enabled.  This is required before esp_wifi_set_config(ESP_IF_WIFI_STA,...)
270     // can be called.
271     err = ESP32Utils::EnableStationMode();
272     SuccessOrExit(err);
273
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))
277     {
278         wifiSSID[netInfoSSIDLen] = '\0';
279     }
280     else
281     {
282         wifiSSID[kMaxWiFiSSIDLength] = '\0';
283     }
284
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;
291
292     // Configure the ESP WiFi interface.
293     err = esp_wifi_set_config(WIFI_IF_STA, &wifiConfig);
294     if (err != ESP_OK)
295     {
296         ChipLogError(DeviceLayer, "esp_wifi_set_config() failed: %s", chip::ErrorStr(err));
297     }
298     SuccessOrExit(err);
299
300     ChipLogProgress(DeviceLayer, "WiFi station provision set (SSID: %s)", netInfo.WiFiSSID);
301
302 exit:
303     return err;
304 }
305
306 CHIP_ERROR ESP32Utils::ClearWiFiStationProvision(void)
307 {
308     CHIP_ERROR err = CHIP_NO_ERROR;
309     wifi_config_t stationConfig;
310
311     // Clear the ESP WiFi station configuration.
312     memset(&stationConfig, 0, sizeof(stationConfig));
313     esp_wifi_set_config(WIFI_IF_STA, &stationConfig);
314
315     return err;
316 }