8000 Merge pull request #5537 from microDev1/monitor-mode · adafruit/circuitpython@c117766 · GitHub
[go: up one dir, main page]

Skip to content

Commit c117766

Browse files
authored
Merge pull request #5537 from microDev1/monitor-mode
Add Monitor Mode
2 parents adac5ee + a62675a commit c117766

File tree

16 files changed

+638
-72
lines changed

16 files changed

+638
-72
lines changed

locale/circuitpython.pot

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ msgstr ""
148148
msgid "%q must be power of 2"
149149
msgstr ""
150150

151+
#: shared-bindings/wifi/Monitor.c
152+
msgid "%q out of bounds"
153+
msgstr ""
154+
151155
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
152156
#: shared-bindings/canio/Match.c
153157
msgid "%q out of range"
@@ -3570,6 +3574,10 @@ msgstr ""
35703574
msgid "module not found"
35713575
msgstr ""
35723576

3577+
#: ports/espressif/common-hal/wifi/Monitor.c
3578+
msgid "monitor init failed"
3579+
msgstr ""
3580+
35733581
#: extmod/ulab/code/numpy/poly.c
35743582
msgid "more degrees of freedom than data points"
35753583
msgstr ""
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2021 microDev
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 6D40 +
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include <string.h>
28+
29+
#include "py/mpstate.h"
30+
#include "py/runtime.h"
31+
32+
#include "shared-bindings/wifi/Monitor.h"
33+
#include "shared-bindings/wifi/Packet.h"
34+
35+
#include "esp_log.h"
36+
37+
#define MONITOR_PAYLOAD_FCS_LEN (4)
38+
#define MONITOR_QUEUE_TIMEOUT_TICK (0)
39+
40+
typedef struct {
41+
void *payload;
42+
unsigned channel;
43+
uint32_t length;
44+
signed rssi;
45+
} monitor_packet_t;
46+
47+
static const char *TAG = "monitor";
48+
49+
static void wifi_monitor_cb(void *recv_buf, wifi_promiscuous_pkt_type_t type) {
50+
wifi_promiscuous_pkt_t *pkt = (wifi_promiscuous_pkt_t *)recv_buf;
51+
52+
// prepare packet
53+
monitor_packet_t packet = {
54+
.channel = pkt->rx_ctrl.channel,
55+
.length = pkt->rx_ctrl.sig_len,
56+
.rssi = pkt->rx_ctrl.rssi,
57+
};
58+
59+
// for now, the monitor only dumps the length of the MISC type frame
60+
if (type != WIFI_PKT_MISC && !pkt->rx_ctrl.rx_state) {
61+
packet.length -= MONITOR_PAYLOAD_FCS_LEN;
62+
packet.payload = malloc(packet.length);
63+
if (packet.payload) {
64+
memcpy(packet.payload, pkt->payload, packet.length);
65+
wifi_monitor_obj_t *self = MP_STATE_VM(wifi_monitor_singleton);
66+
if (self->queue) {
67+
// send packet
68+
if (xQueueSendFromISR(self->queue, &packet, NULL) != pdTRUE) {
69+
self->lost++;
70+
free(packet.payload);
71+
ESP_LOGE(TAG, "packet queue full");
72+
}
73+
}
74+
} else {
75+
ESP_LOGE(TAG, "not enough memory for packet");
76+
}
77+
}
78+
}
79+
80+
void common_hal_wifi_monitor_construct(wifi_monitor_obj_t *self, uint8_t channel, size_t queue) {
81+
const compressed_string_t *monitor_mode_init_error = translate("monitor init failed");
82+
83+
self->queue = xQueueCreate(queue, sizeof(monitor_packet_t));
84+
if (!self->queue) {
85+
mp_raise_RuntimeError(monitor_mode_init_error);
86+
}
87+
88+
// start wifi promicuous mode
89+
wifi_promiscuous_filter_t wifi_filter = {
90+
.filter_mask = WIFI_PROMIS_FILTER_MASK_MGMT,
91+
};
92+
esp_wifi_set_promiscuous_filter(&wifi_filter);
93+
esp_wifi_set_promiscuous_rx_cb(wifi_monitor_cb);
94+
if (esp_wifi_set_promiscuous(true) != ESP_OK) {
95+
mp_raise_RuntimeError(monitor_mode_init_error);
96+
}
97+
esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
98+
99+
self->channel = channel;
100+
self->queue_length = queue;
101+
}
102+
103+
bool common_hal_wifi_monitor_deinited(void) {
104+
bool enabled;
105+
return (esp_wifi_get_promiscuous(&enabled) == ESP_ERR_WIFI_NOT_INIT) ? true : !enabled;
106+
}
107+
108+
void common_hal_wifi_monitor_deinit(wifi_monitor_obj_t *self) {
109+
if (common_hal_wifi_monitor_deinited()) {
110+
return;
111+
}
112+
113+
// disable wifi promiscuous mode
114+
esp_wifi_set_promiscuous(false);
115+
116+
// make sure to free all resources in the left items
117+
UBaseType_t left_items = uxQueueMessagesWaiting(self->queue);
118+
monitor_packet_t packet;
119+
while (left_items--) {
120+
xQueueReceive(self->queue, &packet, MONITOR_QUEUE_TIMEOUT_TICK);
121+
free(packet.payload);
122+
}
123+
vQueueDelete(self->queue);
124+
self->queue = NULL;
125+
}
126+
127+
void common_hal_wifi_monitor_set_channel(wifi_monitor_obj_t *self, uint8_t channel) {
128+
self->channel = channel;
129+
esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
130+
}
131+
132+
mp_obj_t common_hal_wifi_monitor_get_channel(wifi_monitor_obj_t *self) {
133+
return MP_OBJ_NEW_SMALL_INT(self->channel);
134+
}
135+
136+
mp_obj_t common_hal_wifi_monitor_get_queue(wifi_monitor_obj_t *self) {
137+
return mp_obj_new_int_from_uint(self->queue_length);
138+
}
139+
140+
mp_obj_t common_hal_wifi_monitor_get_lost(wifi_monitor_obj_t *self) {
141+
size_t lost = self->lost;
142+
self->lost = 0;
143+
return mp_obj_new_int_from_uint(lost);
144+
}
F987 145+
146+
mp_obj_t common_hal_wifi_monitor_get_queued(wifi_monitor_obj_t *self) {
147+
return mp_obj_new_int_from_uint(uxQueueMessagesWaiting(self->queue));
148+
}
149+
150+
mp_obj_t common_hal_wifi_monitor_get_packet(wifi_monitor_obj_t *self) {
151+
monitor_packet_t packet;
152+
153+
if (xQueueReceive(self->queue, &packet, MONITOR_QUEUE_TIMEOUT_TICK) != pdTRUE) {
154+
return (mp_obj_t)&mp_const_empty_dict_obj;
155+
}
156+
157+
mp_obj_dict_t *dict = MP_OBJ_TO_PTR(mp_obj_new_dict(4));
158+
159+
mp_obj_dict_store(dict, cp_enum_find(&wifi_packet_type, PACKET_CH), MP_OBJ_NEW_SMALL_INT(packet.channel));
160+
161+
mp_obj_dict_store(dict, cp_enum_find(&wifi_packet_type, PACKET_LEN), MP_OBJ_NEW_SMALL_INT(packet.length));
162+
163+
mp_obj_dict_store(dict, cp_enum_find(&wifi_packet_type, PACKET_RAW), mp_obj_new_bytes(packet.payload, packet.length));
164+
free(packet.payload);
165+
166+
mp_obj_dict_store(dict, cp_enum_find(&wifi_packet_type, PACKET_RSSI), MP_OBJ_NEW_SMALL_INT(packet.rssi));
167+
168+
return MP_OBJ_FROM_PTR(dict);
169+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2021 microDev
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#ifndef MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_WIFI_MONITOR_H
28+
#define MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_WIFI_MONITOR_H
29+
30+
#include "py/obj.h"
31+
#include "components/esp_wifi/include/esp_wifi.h"
32+
33+
typedef struct {
34+
mp_obj_base_t base;
35+
uint8_t channel;
36+
size_t lost;
37+
size_t queue_length;
38+
QueueHandle_t queue;
39+
} wifi_monitor_obj_t;
40+
41+
#endif // MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_WIFI_MONITOR_H

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

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,19 @@ void common_hal_wifi_radio_set_enabled(wifi_radio_obj_t *self, bool enabled) {
101101
}
102102
}
103103

104+
mp_obj_t common_hal_wifi_radio_get_hostname(wifi_radio_obj_t *self) {
105+
const char *hostname = NULL;
106+
esp_netif_get_hostname(self->netif, &hostname);
107+
if (hostname == NULL) {
108+
return mp_const_none;
109+
}
110+
return mp_obj_new_str(hostname, strlen(hostname));
111+
}
112+
113+
void common_hal_wifi_radio_set_hostname(wifi_radio_obj_t *self, const char *hostname) {
114+
esp_netif_set_hostname(self->netif, hostname);
115+
}
116+
104117
mp_obj_t common_hal_wifi_radio_get_mac_address(wifi_radio_obj_t *self) {
105118
uint8_t mac[MAC_ADDRESS_LENGTH];
106119
esp_wifi_get_mac(ESP_IF_WIFI_STA, mac);
@@ -142,19 +155,6 @@ void common_hal_wifi_radio_stop_scanning_networks(wifi_radio_obj_t *self) {
142155
self->current_scan = NULL;
143156
}
144157

145-
mp_obj_t common_hal_wifi_radio_get_hostname(wifi_radio_obj_t *self) {
146-
const char *hostname = NULL;
147-
esp_netif_get_hostname(self->netif, &hostname);
148-
if (hostname == NULL) {
149-
return mp_const_none;
150-
}
151-
return mp_obj_new_str(hostname, strlen(hostname));
152-
}
153-
154-
void common_hal_wifi_radio_set_hostname(wifi_radio_obj_t *self, const char *hostname) {
155-
esp_netif_set_hostname(self->netif, hostname);
156-
}
157-
158158
void common_hal_wifi_radio_start_station(wifi_radio_obj_t *self) {
159159
set_mode_station(self, true);
160160
}

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ typedef struct {
5757
uint8_t retries_left;
5858
uint8_t starting_retries;
5959
uint8_t last_disconnect_reason;
60-
6160
wifi_config_t ap_config;
6261
esp_netif_ip_info_t ap_ip_info;
6362
esp_netif_t *ap_netif;

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@
2828#include "shared-bindings/wifi/__init__.h"
2929

3030
#include "shared-bindings/ipaddress/IPv4Address.h"
31+
#include "shared-bindings/wifi/Monitor.h"
3132
#include "shared-bindings/wifi/Radio.h"
3233

34+
#include "py/mpstate.h"
3335
#include "py/runtime.h"
3436

3537
#include "components/esp_wifi/include/esp_wifi.h"
@@ -159,6 +161,7 @@ void wifi_reset(void) {
159161
if (!wifi_inited) {
160162
return;
161163
}
164+
common_hal_wifi_monitor_deinit(MP_STATE_VM(wifi_monitor_singleton));
162165
wifi_radio_obj_t *radio = &common_hal_wifi_radio_obj;
163166
common_hal_wifi_radio_set_enabled(radio, false);
164167
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT,
@@ -172,6 +175,7 @@ void wifi_reset(void) {
172175
radio->netif = NULL;
173176
esp_netif_destroy(radio->ap_netif);
174177
radio->ap_netif = NULL;
178+
wifi_inited = false;
175179
}
176180

177181
void ipaddress_ipaddress_to_esp_idf(mp_obj_t ip_address, ip_addr_t *esp_ip_address) {

py/circuitpy_defns.mk

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ SRC_COMMON_HAL_ALL = \
436436
watchdog/WatchDogMode.c \
437437
watchdog/WatchDogTimer.c \
438438
watchdog/__init__.c \
439+
wifi/Monitor.c \
439440
wifi/Network.c \
440441
wifi/Radio.c \
441442
wifi/ScannedNetworks.c \
@@ -480,6 +481,7 @@ $(filter $(SRC_PATTERNS), \
480481
paralleldisplay/ParallelBus.c \
481482
supervisor/RunReason.c \
482483
wifi/AuthMode.c \
484+
wifi/Packet.c \
483485
)
484486

485487
SRC_BINDINGS_ENUMS += \

py/circuitpy_mpconfig.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,12 @@ extern const struct _mp_obj_module_t nvm_module;
328328
#endif
329329
#endif
330330

331+
#if CIRCUITPY_WIFI
332+
#define WIFI_MONITOR_ROOT_POINTERS mp_obj_t wifi_monitor_singleton;
333+
#else
334+
#define WIFI_MONITOR_ROOT_POINTERS
335+
#endif
336+
331337
// Define certain native modules with weak links so they can be replaced with Python
332338
// implementations. This list may grow over time.
333339

@@ -451,6 +457,7 @@ struct _supervisor_allocation_node;
451457
KEYPAD_ROOT_POINTERS \
452458
GAMEPAD_ROOT_POINTERS \
453459
BOARD_UART_ROOT_POINTER \
460+
WIFI_MONITOR_ROOT_POINTERS \
454461
MEMORYMONITOR_ROOT_POINTERS \
455462
vstr_t *repl_line; \
456463
mp_obj_t pew_singleton; \

0 commit comments

Comments
 (0)
0