Skip to content

Commit 95172cf

Browse files
microdev1anecdata
andcommitted
add monitor class
Co-authored-by: anecdata <[email protected]>
1 parent e2652f8 commit 95172cf

File tree

9 files changed

+446
-12
lines changed

9 files changed

+446
-12
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"
@@ -3553,6 +3557,10 @@ msgstr ""
35533557
msgid "module not found"
35543558
msgstr ""
35553559

3560+
#: ports/espressif/common-hal/wifi/Monitor.c
3561+
msgid "monitor init failed"
3562+
msgstr ""
3563+
35563564
#: extmod/ulab/code/numpy/poly.c
35573565
msgid "more degrees of freedom than data points"
35583566
msgstr ""
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
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+
#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->loss++;
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+
esp_wifi_get_promiscuous(&enabled);
106+
return !enabled;
107+
}
108+
109+
void common_hal_wifi_monitor_deinit(wifi_monitor_obj_t *self) {
110+
if (common_hal_wifi_monitor_deinited()) {
111+
return;
112+
}
113+
114+
// disable wifi promiscuous mode
115+
esp_wifi_set_promiscuous(false);
116+
117+
// make sure to free all resources in the left items
118+
UBaseType_t left_items = uxQueueMessagesWaiting(self->queue);
119+
monitor_packet_t packet;
120+
while (left_items--) {
121+
xQueueReceive(self->queue, &packet, MONITOR_QUEUE_TIMEOUT_TICK);
122+
free(packet.payload);
123+
}
124+
vQueueDelete(self->queue);
125+
self->queue = NULL;
126+
}
127+
128+
void common_hal_wifi_monitor_set_channel(wifi_monitor_obj_t *self, uint8_t channel) {
129+
self->channel = channel;
130+
esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
131+
}
132+
133+
mp_obj_t common_hal_wifi_monitor_get_channel(wifi_monitor_obj_t *self) {
134+
return MP_OBJ_NEW_SMALL_INT(self->channel);
135+
}
136+
137+
mp_obj_t common_hal_wifi_monitor_get_queue(wifi_monitor_obj_t *self) {
138+
return mp_obj_new_int_from_uint(self->queue_length);
139+
}
140+
141+
mp_obj_t common_hal_wifi_monitor_get_loss(wifi_monitor_obj_t *self) {
142+
size_t loss = self->loss;
143+
self->loss = 0;
144+
return mp_obj_new_int_from_uint(loss);
145+
}
146+
147+
mp_obj_t common_hal_wifi_monitor_get_packet(wifi_monitor_obj_t *self) {
148+
monitor_packet_t packet;
149+
150+
if (xQueueReceive(self->queue, &packet, MONITOR_QUEUE_TIMEOUT_TICK) != pdTRUE) {
151+
return (mp_obj_t)&mp_const_empty_dict_obj;
152+
}
153+
154+
mp_obj_dict_t *dict = MP_OBJ_TO_PTR(mp_obj_new_dict(4));
155+
156+
mp_obj_dict_store(dict, cp_enum_find(&wifi_packet_type, PACKET_CH), MP_OBJ_NEW_SMALL_INT(packet.channel));
157+
158+
mp_obj_dict_store(dict, cp_enum_find(&wifi_packet_type, PACKET_LEN), MP_OBJ_NEW_SMALL_INT(packet.length));
159+
160+
mp_obj_dict_store(dict, cp_enum_find(&wifi_packet_type, PACKET_RAW), mp_obj_new_bytes(packet.payload, packet.length));
161+
free(packet.payload);
162+
163+
mp_obj_dict_store(dict, cp_enum_find(&wifi_packet_type, PACKET_RSSI), MP_OBJ_NEW_SMALL_INT(packet.rssi));
164+
165+
return MP_OBJ_FROM_PTR(dict);
166+
}
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 loss;
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/__init__.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@
2727
#include "common-hal/wifi/__init__.h"
2828

2929
#include "shared-bindings/ipaddress/IPv4Address.h"
30+
#include "shared-bindings/wifi/Monitor.h"
3031
#include "shared-bindings/wifi/Radio.h"
3132

33+
#include "py/mpstate.h"
3234
#include "py/runtime.h"
3335

3436
#include "components/esp_wifi/include/esp_wifi.h"
@@ -158,6 +160,7 @@ void wifi_reset(void) {
158160
if (!wifi_inited) {
159161
return;
160162
}
163+
common_hal_wifi_monitor_deinit(MP_STATE_VM(wifi_monitor_singleton));
161164
wifi_radio_obj_t *radio = &common_hal_wifi_radio_obj;
162165
common_hal_wifi_radio_set_enabled(radio, false);
163166
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT,

py/circuitpy_mpconfig.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,12 @@ extern const struct _mp_obj_module_t nvm_module;
319319
#endif
320320
#endif
321321

322+
#if CIRCUITPY_WIFI
323+
#define WIFI_MONITOR_ROOT_POINTERS mp_obj_t wifi_monitor_singleton;
324+
#else
325+
#define WIFI_MONITOR_ROOT_POINTERS
326+
#endif
327+
322328
// Define certain native modules with weak links so they can be replaced with Python
323329
// implementations. This list may grow over time.
324330

@@ -442,6 +448,7 @@ struct _supervisor_allocation_node;
442448
KEYPAD_ROOT_POINTERS \
443449
GAMEPAD_ROOT_POINTERS \
444450
BOARD_UART_ROOT_POINTER \
451+
WIFI_MONITOR_ROOT_POINTERS \
445452
MEMORYMONITOR_ROOT_POINTERS \
446453
vstr_t *repl_line; \
447454
mp_obj_t pew_singleton; \

0 commit comments

Comments
 (0)