Skip to content

Commit 1a6f4e0

Browse files
committed
Scanning WIP. Need to sort out supervisor memory
1 parent c5b8401 commit 1a6f4e0

17 files changed

Lines changed: 511 additions & 30 deletions

File tree

ports/esp32s2/Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ menuconfig: $(BUILD)/esp-idf/config
248248
$(HEADER_BUILD)/qstr.i.last: | $(BUILD)/esp-idf/config/sdkconfig.h
249249

250250
# Order here matters
251-
ESP_IDF_COMPONENTS_LINK = freertos log esp_system esp32s2 bootloader_support pthread esp_timer vfs spi_flash app_update esp_common esp32s2 heap newlib driver xtensa soc esp_ringbuf esp_wifi esp_event wpa_supplicant mbedtls efuse nvs_flash
251+
ESP_IDF_COMPONENTS_LINK = freertos log esp_system esp32s2 bootloader_support pthread esp_timer vfs spi_flash app_update esp_common esp32s2 heap newlib driver xtensa soc esp_ringbuf esp_wifi esp_event wpa_supplicant mbedtls efuse nvs_flash esp_netif lwip
252252

253253
ESP_IDF_COMPONENTS_INCLUDE = driver freertos log soc
254254

@@ -278,8 +278,10 @@ esp-idf-stamp: $(BUILD)/esp-idf/config/sdkconfig.h
278278
esp-idf/bootloader_support/libbootloader_support.a \
279279
esp-idf/esp32s2/ld/esp32s2.project.ld \
280280
esp-idf/esp_event/libesp_event.a \
281+
esp-idf/esp_netif/libesp_netif.a \
281282
esp-idf/esp_system/libesp_system.a \
282283
esp-idf/esp_wifi/libesp_wifi.a \
284+
esp-idf/lwip/liblwip.a \
283285
esp-idf/nvs_flash/libnvs_flash.a \
284286
esp-idf/wpa_supplicant/libwpa_supplicant.a \
285287
esp-idf/mbedtls/libmbedtls.a \

ports/esp32s2/common-hal/wifi/Network.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,11 @@
2929

3030
#include "py/obj.h"
3131

32+
#include "esp-idf/components/esp_wifi/include/esp_wifi_types.h"
33+
3234
typedef struct {
3335
mp_obj_base_t base;
34-
// Stores no state currently.
36+
wifi_ap_record_t record;
3537
} wifi_network_obj_t;
3638

3739
#endif // MICROPY_INCLUDED_ESP32S2_COMMON_HAL_WIFI_NETWORK_H

ports/esp32s2/common-hal/wifi/Radio.c

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,28 +26,62 @@
2626

2727
#include "shared-bindings/wifi/Radio.h"
2828

29+
#include "py/runtime.h"
30+
#include "shared-bindings/wifi/ScannedNetworks.h"
31+
32+
#include "esp-idf/components/esp_wifi/include/esp_wifi.h"
33+
2934
bool common_hal_wifi_radio_get_enabled(wifi_radio_obj_t *self) {
30-
return true;
35+
return self->started;
3136
}
3237

3338
void common_hal_wifi_radio_set_enabled(wifi_radio_obj_t *self, bool enabled) {
34-
39+
if (self->started && !enabled) {
40+
esp_wifi_stop();
41+
self->started = false;
42+
return;
43+
}
44+
if (!self->started && enabled) {
45+
esp_wifi_start();
46+
self->started = true;
47+
return;
48+
}
3549
}
3650

3751
mp_obj_t common_hal_wifi_radio_get_mac_address(wifi_radio_obj_t *self) {
52+
uint8_t mac[6];
53+
esp_wifi_get_mac(ESP_IF_WIFI_STA, mac);
3854
return mp_const_none;
3955
}
4056

4157
mp_obj_t common_hal_wifi_radio_start_scanning_networks(wifi_radio_obj_t *self) {
42-
return mp_const_none;
58+
if (self->current_scan != NULL) {
59+
mp_raise_RuntimeError(translate("Already scanning for wifi networks"));
60+
}
61+
// check enabled
62+
63+
wifi_scannednetworks_obj_t *scan = m_new_obj(wifi_scannednetworks_obj_t);
64+
self->current_scan = scan;
65+
scan->base.type = &wifi_scannednetworks_type;
66+
scan->start_channel = 1;
67+
scan->end_channel = 11;
68+
scan->radio_event_group = self->event_group_handle;
69+
wifi_scannednetworks_scan_next_channel(scan);
70+
return scan;
4371
}
4472

4573
void common_hal_wifi_radio_stop_scanning_networks(wifi_radio_obj_t *self) {
46-
74+
// Free the memory used to store the found aps.
75+
wifi_scannednetworks_deinit(self->current_scan);
76+
self->current_scan = NULL;
4777
}
4878

4979
bool common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t* ssid, size_t ssid_len, uint8_t* password, size_t password_len, mp_float_t timeout) {
50-
return false;
80+
// check enabled
81+
wifi_config_t config;
82+
esp_err_t result = esp_wifi_set_config(ESP_IF_WIFI_STA, &config);
83+
result = esp_wifi_connect();
84+
return result == ESP_OK;
5185
}
5286

5387
mp_obj_t common_hal_wifi_radio_get_ip_address(wifi_radio_obj_t *self) {

ports/esp32s2/common-hal/wifi/Radio.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,21 @@
2929

3030
#include "py/obj.h"
3131

32+
#include "esp-idf/components/esp_event/include/esp_event.h"
33+
34+
#include "shared-bindings/wifi/ScannedNetworks.h"
35+
36+
// Event bits for the Radio event group.
37+
#define WIFI_SCAN_DONE_BIT BIT0
38+
3239
typedef struct {
3340
mp_obj_base_t base;
34-
// Stores no state currently.
41+
esp_event_handler_instance_t handler_instance_all_wifi;
42+
esp_event_handler_instance_t handler_instance_got_ip;
43+
wifi_scannednetworks_obj_t *current_scan;
44+
StaticEventGroup_t event_group;
45+
EventGroupHandle_t event_group_handle;
46+
bool started;
3547
} wifi_radio_obj_t;
3648

3749
#endif // MICROPY_INCLUDED_ESP32S2_COMMON_HAL_WIFI_RADIO_H
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2019 Dan Halbert for Adafruit Industries
7+
* Copyright (c) 2018 Artur Pacholec
8+
* Copyright (c) 2017 Glenn Ruben Bakke
9+
*
10+
* Permission is hereby granted, free of charge, to any person obtaining a copy
11+
* of this software and associated documentation files (the "Software"), to deal
12+
* in the Software without restriction, including without limitation the rights
13+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14+
* copies of the Software, and to permit persons to whom the Software is
15+
* furnished to do so, subject to the following conditions:
16+
*
17+
* The above copyright notice and this permission notice shall be included in
18+
* all copies or substantial portions of the Software.
19+
*
20+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26+
* THE SOFTWARE.
27+
*/
28+
29+
#include <string.h>
30+
31+
#include "lib/utils/interrupt_char.h"
32+
#include "py/objstr.h"
33+
#include "py/runtime.h"
34+
#include "shared-bindings/wifi/__init__.h"
35+
#include "shared-bindings/wifi/Network.h"
36+
#include "shared-bindings/wifi/Radio.h"
37+
#include "shared-bindings/wifi/ScannedNetworks.h"
38+
39+
#include "esp-idf/components/esp_wifi/include/esp_wifi.h"
40+
41+
static void wifi_scannednetworks_done(wifi_scannednetworks_obj_t *self) {
42+
self->done = true;
43+
free(self->results);
44+
self->results = NULL;
45+
}
46+
47+
static bool wifi_scannednetworks_wait_for_scan(wifi_scannednetworks_obj_t *self) {
48+
EventBits_t bits = xEventGroupWaitBits(self->radio_event_group,
49+
WIFI_SCAN_DONE_BIT,
50+
pdTRUE,
51+
pdTRUE,
52+
0);
53+
while ((bits & WIFI_SCAN_DONE_BIT) == 0 && !mp_hal_is_interrupted()) {
54+
RUN_BACKGROUND_TASKS;
55+
bits = xEventGroupWaitBits(self->radio_event_group,
56+
WIFI_SCAN_DONE_BIT,
57+
pdTRUE,
58+
pdTRUE,
59+
0);
60+
}
61+
return !mp_hal_is_interrupted();
62+
}
63+
64+
mp_obj_t common_hal_wifi_scannednetworks_next(wifi_scannednetworks_obj_t *self) {
65+
if (self->done) {
66+
return mp_const_none;
67+
}
68+
// If we are scanning, wait and then load them.
69+
if (self->scanning) {
70+
// We may have to scan more than one channel to get a result.
71+
while (!self->done) {
72+
if (!wifi_scannednetworks_wait_for_scan(self)) {
73+
wifi_scannednetworks_done(self);
74+
return mp_const_none;
75+
}
76+
77+
esp_wifi_scan_get_ap_num(&self->total_results);
78+
if (self->total_results > 0) {
79+
break;
80+
}
81+
// If total_results is zero then we need to start a scan and wait again.
82+
wifi_scannednetworks_scan_next_channel(self);
83+
}
84+
// We not have found any more results so we're done.
85+
if (self->done) {
86+
return mp_const_none;
87+
}
88+
// If we need more space than we have, realloc.
89+
if (self->total_results > self->max_results) {
90+
wifi_ap_record_t* results = m_renew_maybe(wifi_ap_record_t,
91+
self->results,
92+
self->max_results,
93+
self->total_results,
94+
true /* allow move */);
95+
if (results != NULL) {
96+
self->results = results;
97+
self->max_results = self->total_results;
98+
} else {
99+
if (self->max_results == 0) {
100+
// No room for any results should error.
101+
mp_raise_msg(&mp_type_MemoryError, translate("Failed to allocate wifi scan memory"));
102+
}
103+
// Unable to allocate more results, so load what we can.
104+
self->total_results = self->max_results;
105+
}
106+
}
107+
esp_wifi_scan_get_ap_records(&self->total_results, self->results);
108+
self->scanning = false;
109+
}
110+
111+
wifi_network_obj_t *entry = m_new_obj(wifi_network_obj_t);
112+
entry->base.type = &wifi_network_type;
113+
memcpy(&entry->record, &self->results[self->current_result], sizeof(wifi_ap_record_t));
114+
self->current_result++;
115+
116+
// If we're returning our last network then start the next channel scan or
117+
// be done.
118+
if (self->current_result >= self->total_results) {
119+
wifi_scannednetworks_scan_next_channel(self);
120+
self->total_results = 0;
121+
self->current_result = 0;
122+
}
123+
124+
return MP_OBJ_FROM_PTR(entry);
125+
}
126+
127+
// We don't do a linear scan so that we look at a variety of spectrum up front.
128+
static uint8_t scan_pattern[] = {6, 1, 11, 3, 9, 13, 2, 4, 8, 12, 5, 7, 10, 14};
129+
130+
void wifi_scannednetworks_scan_next_channel(wifi_scannednetworks_obj_t *self) {
131+
wifi_scan_config_t config;
132+
uint8_t next_channel = sizeof(scan_pattern);
133+
while (self->current_channel_index < sizeof(scan_pattern)) {
134+
next_channel = scan_pattern[self->current_channel_index];
135+
self->current_channel_index++;
136+
if (self->start_channel <= next_channel && next_channel <= self->end_channel) {
137+
break;
138+
}
139+
}
140+
if (next_channel == sizeof(scan_pattern) ||
141+
esp_wifi_scan_start(&config, false) != ESP_OK) {
142+
wifi_scannednetworks_done(self);
143+
} else {
144+
self->scanning = true;
145+
}
146+
}
147+
148+
void wifi_scannednetworks_deinit(wifi_scannednetworks_obj_t* self) {
149+
// if a scan is active, make sure and clean up the idf's buffer of results.
150+
if (self->scanning) {
151+
esp_wifi_scan_stop();
152+
if (wifi_scannednetworks_wait_for_scan(self)) {
153+
uint16_t number = 0;
154+
esp_wifi_scan_get_ap_records(&number, NULL);
155+
self->scanning = false;
156+
}
157+
}
158+
wifi_scannednetworks_done(self);
159+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2019 Dan Halbert for Adafruit Industries
7+
* Copyright (c) 2018 Artur Pacholec
8+
*
9+
* Permission is hereby granted, free of charge, to any person obtaining a copy
10+
* of this software and associated documentation files (the "Software"), to deal
11+
* in the Software without restriction, including without limitation the rights
12+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
* copies of the Software, and to permit persons to whom the Software is
14+
* furnished to do so, subject to the following conditions:
15+
*
16+
* The above copyright notice and this permission notice shall be included in
17+
* all copies or substantial portions of the Software.
18+
*
19+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
* THE SOFTWARE.
26+
*/
27+
28+
#ifndef MICROPY_INCLUDED_ESP32S2_COMMON_HAL_WIFI_SCANNEDNETWORKS_H
29+
#define MICROPY_INCLUDED_ESP32S2_COMMON_HAL_WIFI_SCANNEDNETWORKS_H
30+
31+
#include <stdint.h>
32+
33+
#include "py/obj.h"
34+
35+
#include "FreeRTOS.h"
36+
#include "freertos/event_groups.h"
37+
38+
#include "esp-idf/components/esp_wifi/include/esp_wifi_types.h"
39+
40+
typedef struct {
41+
mp_obj_base_t base;
42+
uint8_t current_channel_index;
43+
EventGroupHandle_t radio_event_group;
44+
45+
// Results from the last channel scan
46+
wifi_ap_record_t* results;
47+
uint16_t current_result;
48+
uint16_t total_results;
49+
uint16_t max_results;
50+
51+
// Limits on what channels to scan.
52+
uint8_t start_channel;
53+
uint8_t end_channel; // Inclusive
54+
55+
bool done;
56+
bool scanning;
57+
} wifi_scannednetworks_obj_t;
58+
59+
void wifi_scannednetworks_scan_next_channel(wifi_scannednetworks_obj_t *self);
60+
void wifi_scannednetworks_deinit(wifi_scannednetworks_obj_t *self);
61+
62+
#endif // MICROPY_INCLUDED_ESP32S2_COMMON_HAL_WIFI_SCANNEDNETWORKS_H

0 commit comments

Comments
 (0)