Skip to content

Commit 608c01a

Browse files
committed
stations_ap now returns None instead of throwing an exception if not in AP mode
return value is now a list of named tuples with three elements IP address is now None instead of 0.0.0.0 if there's no lease information
1 parent 294d563 commit 608c01a

File tree

5 files changed

+139
-0
lines changed

5 files changed

+139
-0
lines changed

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,47 @@ void common_hal_wifi_radio_stop_ap(wifi_radio_obj_t *self) {
250250
set_mode_ap(self, false);
251251
}
252252

253+
mp_obj_t common_hal_wifi_radio_get_stations_ap(wifi_radio_obj_t *self) {
254+
wifi_sta_list_t esp_sta_list;
255+
esp_netif_pair_mac_ip_t mac_ip_pair[ESP_WIFI_MAX_CONN_NUM];
256+
esp_err_t result;
257+
258+
result = esp_wifi_ap_get_sta_list(&esp_sta_list);
259+
if (result == ESP_OK) {
260+
for (int i = 0; i < esp_sta_list.num; i++) {
261+
memcpy(mac_ip_pair[i].mac, esp_sta_list.sta[i].mac, MAC_ADDRESS_LENGTH);
262+
mac_ip_pair[i].ip.addr = 0;
263+
}
264+
265+
result = esp_netif_dhcps_get_clients_by_mac(self->ap_netif, esp_sta_list.num, mac_ip_pair);
266+
}
267+
268+
if (!self->ap_mode || result != ESP_OK) {
269+
return mp_const_none;
270+
}
271+
272+
mp_obj_t mp_sta_list = mp_obj_new_list(0, NULL);
273+
for (int i = 0; i < esp_sta_list.num; i++) {
274+
mp_obj_t elems[3] = {
275+
mp_obj_new_bytes(esp_sta_list.sta[i].mac, MAC_ADDRESS_LENGTH),
276+
MP_OBJ_NEW_SMALL_INT(esp_sta_list.sta[i].rssi),
277+
mp_const_none
278+
};
279+
280+
if (mac_ip_pair[i].ip.addr) {
281+
elems[2] = common_hal_ipaddress_new_ipv4address(mac_ip_pair[i].ip.addr);
282+
}
283+
284+
mp_obj_list_append(mp_sta_list, namedtuple_make_new((const mp_obj_type_t *)&wifi_radio_station_type, 3, 0, elems));
285+
}
286+
287+
return mp_sta_list;
288+
}
289+
290+
mp_obj_t common_hal_wifi_radio_get_max_stations_ap(wifi_radio_obj_t *self) {
291+
return MP_OBJ_NEW_SMALL_INT(ESP_WIFI_MAX_CONN_NUM);
292+
}
293+
253294
wifi_radio_error_t common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t *ssid, size_t ssid_len, uint8_t *password, size_t password_len, uint8_t channel, mp_float_t timeout, uint8_t *bssid, size_t bssid_len) {
254295
if (!common_hal_wifi_radio_get_enabled(self)) {
255296
mp_raise_RuntimeError(MP_ERROR_TEXT("wifi is not enabled"));

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

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,59 @@ void common_hal_wifi_radio_stop_ap(wifi_radio_obj_t *self) {
244244
bindings_cyw43_wifi_enforce_pm();
245245
}
246246

247+
// There's no published API for the DHCP server to retrieve lease information
248+
// This code depends on undocumented internal structures and is likely to break in the future
249+
static uint32_t cyw43_dhcps_get_ip_addr(dhcp_server_t *dhcp_server, uint8_t *mac_address) {
250+
for (int i = 0; i < DHCPS_MAX_IP; i++) {
251+
if (memcmp(dhcp_server->lease[i].mac, mac_address, MAC_ADDRESS_LENGTH) == 0) {
252+
return (dhcp_server->ip.addr & 0x00FFFFFF) + ((DHCPS_BASE_IP + i) << 24);
253+
}
254+
}
255+
256+
return 0;
257+
}
258+
259+
mp_obj_t common_hal_wifi_radio_get_stations_ap(wifi_radio_obj_t *self) {
260+
int max_stas;
261+
int num_stas;
262+
263+
if (cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_AP) != CYW43_LINK_UP) {
264+
return mp_const_none;
265+
}
266+
267+
cyw43_wifi_ap_get_max_stas(&cyw43_state, &max_stas);
268+
269+
uint8_t macs[max_stas * MAC_ADDRESS_LENGTH];
270+
271+
cyw43_wifi_ap_get_stas(&cyw43_state, &num_stas, macs);
272+
273+
mp_obj_t mp_sta_list = mp_obj_new_list(0, NULL);
274+
for (int i = 0; i < num_stas; i++) {
275+
mp_obj_t elems[3] = {
276+
mp_obj_new_bytes(&macs[i * MAC_ADDRESS_LENGTH], MAC_ADDRESS_LENGTH),
277+
mp_const_none,
278+
mp_const_none
279+
};
280+
281+
uint32_t ipv4_addr = cyw43_dhcps_get_ip_addr(&cyw43_state.dhcp_server, &macs[i * MAC_ADDRESS_LENGTH]);
282+
if (ipv4_addr) {
283+
elems[2] = common_hal_ipaddress_new_ipv4address(ipv4_addr);
284+
}
285+
286+
mp_obj_list_append(mp_sta_list, namedtuple_make_new((const mp_obj_type_t *)&wifi_radio_station_type, 3, 0, elems));
287+
}
288+
289+
return mp_sta_list;
290+
}
291+
292+
mp_obj_t common_hal_wifi_radio_get_max_stations_ap(wifi_radio_obj_t *self) {
293+
int max_stas;
294+
295+
cyw43_wifi_ap_get_max_stas(&cyw43_state, &max_stas);
296+
297+
return MP_OBJ_NEW_SMALL_INT(max_stas);
298+
}
299+
247300
static bool connection_unchanged(wifi_radio_obj_t *self, const uint8_t *ssid, size_t ssid_len) {
248301
if (cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA) != CYW43_LINK_UP) {
249302
return false;

shared-bindings/wifi/Radio.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,34 @@ STATIC mp_obj_t wifi_radio_get_ap_info(mp_obj_t self) {
661661
}
662662
MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_ap_info_obj, wifi_radio_get_ap_info);
663663

664+
//| stations_ap: None
665+
//| """In AP mode, returns list of objects (read-only)
666+
//| mac: bytearray
667+
//| rssi: int
668+
//| ipv4_address: ipv4_address (0.0.0.0 if station connected but no address assigned yet or self-assigned address)
669+
//|
670+
//| .. note::
671+
//|
672+
//| The raspberrypi port (RP2040 CYW43) does not report rssi, so the value will be None"""
673+
STATIC mp_obj_t wifi_radio_get_stations_ap(mp_obj_t self) {
674+
return common_hal_wifi_radio_get_stations_ap(self);
675+
}
676+
677+
MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_stations_ap_obj, wifi_radio_get_stations_ap);
678+
679+
MP_PROPERTY_GETTER(wifi_radio_stations_ap_obj,
680+
(mp_obj_t)&wifi_radio_get_stations_ap_obj);
681+
682+
//| max_stations_ap: Optional[Network]
683+
//| """In AP mode, returns the maximum possible number of connected stations (read-only)"""
684+
STATIC mp_obj_t wifi_radio_get_max_stations_ap(mp_obj_t self) {
685+
return common_hal_wifi_radio_get_max_stations_ap(self);
686+
}
687+
MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_max_stations_ap_obj, wifi_radio_get_max_stations_ap);
688+
689+
MP_PROPERTY_GETTER(wifi_radio_max_stations_ap_obj,
690+
(mp_obj_t)&wifi_radio_get_max_stations_ap_obj);
691+
664692
//| def start_dhcp(self) -> None:
665693
//| """Starts the station DHCP client."""
666694
//| ...
@@ -750,6 +778,8 @@ STATIC const mp_rom_map_elem_t wifi_radio_locals_dict_table[] = {
750778
{ MP_ROM_QSTR(MP_QSTR_start_ap), MP_ROM_PTR(&wifi_radio_start_ap_obj) },
751779
{ MP_ROM_QSTR(MP_QSTR_stop_ap), MP_ROM_PTR(&wifi_radio_stop_ap_obj) },
752780
{ MP_ROM_QSTR(MP_QSTR_ap_active), MP_ROM_PTR(&wifi_radio_ap_active_obj) },
781+
{ MP_ROM_QSTR(MP_QSTR_stations_ap), MP_ROM_PTR(&wifi_radio_stations_ap_obj) },
782+
{ MP_ROM_QSTR(MP_QSTR_max_stations_ap), MP_ROM_PTR(&wifi_radio_max_stations_ap_obj) },
753783

754784
{ MP_ROM_QSTR(MP_QSTR_start_dhcp), MP_ROM_PTR(&wifi_radio_start_dhcp_client_obj) },
755785
{ MP_ROM_QSTR(MP_QSTR_stop_dhcp), MP_ROM_PTR(&wifi_radio_stop_dhcp_client_obj) },
@@ -783,3 +813,13 @@ MP_DEFINE_CONST_OBJ_TYPE(
783813
MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS,
784814
locals_dict, &wifi_radio_locals_dict
785815
);
816+
817+
const mp_obj_namedtuple_type_t wifi_radio_station_type = {
818+
NAMEDTUPLE_TYPE_BASE_AND_SLOTS(MP_QSTR_WifiRadioStation),
819+
.n_fields = 3,
820+
.fields = {
821+
MP_QSTR_mac_address,
822+
MP_QSTR_rssi,
823+
MP_QSTR_ipv4_address,
824+
},
825+
};

shared-bindings/wifi/Radio.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@
3232
#include "common-hal/wifi/Radio.h"
3333

3434
#include "py/objstr.h"
35+
#include "py/objnamedtuple.h"
3536

3637
extern const mp_obj_type_t wifi_radio_type;
38+
extern const mp_obj_namedtuple_type_t wifi_radio_station_type;
3739

3840
typedef enum {
3941
// 0 is circuitpython-specific; 1-53 are IEEE; 200+ are Espressif
@@ -96,6 +98,8 @@ extern void common_hal_wifi_radio_stop_station(wifi_radio_obj_t *self);
9698
extern void common_hal_wifi_radio_start_ap(wifi_radio_obj_t *self, uint8_t *ssid, size_t ssid_len, uint8_t *password, size_t password_len, uint8_t channel, uint32_t authmode, uint8_t max_connections);
9799
extern void common_hal_wifi_radio_stop_ap(wifi_radio_obj_t *self);
98100
extern bool common_hal_wifi_radio_get_ap_active(wifi_radio_obj_t *self);
101+
extern mp_obj_t common_hal_wifi_radio_get_stations_ap(wifi_radio_obj_t *self);
102+
extern mp_obj_t common_hal_wifi_radio_get_max_stations_ap(wifi_radio_obj_t *self);
99103

100104
extern void common_hal_wifi_radio_start_dhcp_client(wifi_radio_obj_t *self);
101105
extern void common_hal_wifi_radio_stop_dhcp_client(wifi_radio_obj_t *self);

shared-bindings/wifi/__init__.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ STATIC const mp_rom_map_elem_t wifi_module_globals_table[] = {
5959
{ MP_ROM_QSTR(MP_QSTR_Network), MP_ROM_PTR(&wifi_network_type) },
6060
{ MP_ROM_QSTR(MP_QSTR_Packet), MP_ROM_PTR(&wifi_packet_type) },
6161
{ MP_ROM_QSTR(MP_QSTR_Radio), MP_ROM_PTR(&wifi_radio_type) },
62+
{ MP_ROM_QSTR(MP_QSTR_Station), MP_ROM_PTR(&wifi_radio_station_type) },
6263

6364
// Properties
6465
{ MP_ROM_QSTR(MP_QSTR_radio), MP_ROM_PTR(&common_hal_wifi_radio_obj) },

0 commit comments

Comments
 (0)