Skip to content

Commit 236297f

Browse files
MrSurlydpgeorge
authored andcommitted
esp32: Implement wired Ethernet via network.LAN().
Updates to Makefile, modnetwork.c, and addition of network_lan.c to implement `network.LAN()` object for wired PHY objects.
1 parent 54c6ebc commit 236297f

File tree

4 files changed

+270
-15
lines changed

4 files changed

+270
-15
lines changed

ports/esp32/Makefile

+4
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ SRC_C = \
136136
machine_uart.c \
137137
modmachine.c \
138138
modnetwork.c \
139+
network_lan.c \
139140
modsocket.c \
140141
modesp.c \
141142
moduhashlib.c \
@@ -267,6 +268,9 @@ ESPIDF_CXX_O = $(addprefix $(ESPCOMP)/cxx/,\
267268
ESPIDF_ETHERNET_O = $(addprefix $(ESPCOMP)/ethernet/,\
268269
emac_dev.o \
269270
emac_main.o \
271+
eth_phy/phy_tlk110.o \
272+
eth_phy/phy_lan8720.o \
273+
eth_phy/phy_common.o \
270274
)
271275

272276
$(BUILD)/$(ESPCOMP)/expat/%.o: CFLAGS += -Wno-unused-function

ports/esp32/modnetwork.c

+29-15
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* The MIT License (MIT)
88
*
99
* Copyright (c) 2016, 2017 Nick Moore @mnemote
10+
* Copyright (c) 2017 "Eric Poulsen" <[email protected]>
1011
*
1112
* Based on esp8266/modnetwork.c which is Copyright (c) 2015 Paul Sokolovsky
1213
* And the ESP IDF example code which is Public Domain / CC0
@@ -48,6 +49,8 @@
4849
#include "lwip/dns.h"
4950
#include "tcpip_adapter.h"
5051

52+
#include "modnetwork.h"
53+
5154
#define MODNETWORK_INCLUDE_CONSTANTS (1)
5255

5356
NORETURN void _esp_exceptions(esp_err_t e) {
@@ -122,7 +125,7 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) {
122125
ESP_LOGI("wifi", "STA_START");
123126
break;
124127
case SYSTEM_EVENT_STA_GOT_IP:
125-
ESP_LOGI("wifi", "GOT_IP");
128+
ESP_LOGI("network", "GOT_IP");
126129
break;
127130
case SYSTEM_EVENT_STA_DISCONNECTED: {
128131
// This is a workaround as ESP32 WiFi libs don't currently
@@ -161,7 +164,7 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) {
161164
break;
162165
}
163166
default:
164-
ESP_LOGI("wifi", "event %d", event->event_id);
167+
ESP_LOGI("network", "event %d", event->event_id);
165168
break;
166169
}
167170
return ESP_OK;
@@ -182,6 +185,19 @@ STATIC void require_if(mp_obj_t wlan_if, int if_no) {
182185
}
183186

184187
STATIC mp_obj_t get_wlan(size_t n_args, const mp_obj_t *args) {
188+
static int initialized = 0;
189+
if (!initialized) {
190+
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
191+
ESP_LOGD("modnetwork", "Initializing WiFi");
192+
ESP_EXCEPTIONS( esp_wifi_init(&cfg) );
193+
ESP_EXCEPTIONS( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
194+
ESP_LOGD("modnetwork", "Initialized");
195+
ESP_EXCEPTIONS( esp_wifi_set_mode(0) );
196+
ESP_EXCEPTIONS( esp_wifi_start() );
197+
ESP_LOGD("modnetwork", "Started");
198+
initialized = 1;
199+
}
200+
185201
int idx = (n_args > 0) ? mp_obj_get_int(args[0]) : WIFI_IF_STA;
186202
if (idx == WIFI_IF_STA) {
187203
return MP_OBJ_FROM_PTR(&wlan_sta_obj);
@@ -201,14 +217,6 @@ STATIC mp_obj_t esp_initialize() {
201217
ESP_LOGD("modnetwork", "Initializing Event Loop");
202218
ESP_EXCEPTIONS( esp_event_loop_init(event_handler, NULL) );
203219
ESP_LOGD("modnetwork", "esp_event_loop_init done");
204-
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
205-
ESP_LOGD("modnetwork", "Initializing WiFi");
206-
ESP_EXCEPTIONS( esp_wifi_init(&cfg) );
207-
ESP_EXCEPTIONS( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
208-
ESP_LOGD("modnetwork", "Initialized");
209-
ESP_EXCEPTIONS( esp_wifi_set_mode(0) );
210-
ESP_EXCEPTIONS( esp_wifi_start() );
211-
ESP_LOGD("modnetwork", "Started");
212220
initialized = 1;
213221
}
214222
return mp_const_none;
@@ -358,11 +366,11 @@ STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) {
358366
netutils_parse_ipv4_addr(items[2], (void*)&info.gw, NETUTILS_BIG);
359367
netutils_parse_ipv4_addr(items[3], (void*)&dns_info.ip, NETUTILS_BIG);
360368
// To set a static IP we have to disable DHCP first
361-
if (self->if_id == WIFI_IF_STA) {
362-
esp_err_t e = tcpip_adapter_dhcpc_stop(WIFI_IF_STA);
369+
if (self->if_id == WIFI_IF_STA || self->if_id == ESP_IF_ETH) {
370+
esp_err_t e = tcpip_adapter_dhcpc_stop(self->if_id);
363371
if (e != ESP_OK && e != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) _esp_exceptions(e);
364-
ESP_EXCEPTIONS(tcpip_adapter_set_ip_info(WIFI_IF_STA, &info));
365-
ESP_EXCEPTIONS(tcpip_adapter_set_dns_info(WIFI_IF_STA, TCPIP_ADAPTER_DNS_MAIN, &dns_info));
372+
ESP_EXCEPTIONS(tcpip_adapter_set_ip_info(self->if_id, &info));
373+
ESP_EXCEPTIONS(tcpip_adapter_set_dns_info(self->if_id, TCPIP_ADAPTER_DNS_MAIN, &dns_info));
366374
} else if (self->if_id == WIFI_IF_AP) {
367375
esp_err_t e = tcpip_adapter_dhcps_stop(WIFI_IF_AP);
368376
if (e != ESP_OK && e != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) _esp_exceptions(e);
@@ -374,7 +382,7 @@ STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) {
374382
}
375383
}
376384

377-
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj, 1, 2, esp_ifconfig);
385+
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj, 1, 2, esp_ifconfig);
378386

379387
STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
380388
if (n_args != 1 && kwargs->used != 0) {
@@ -533,6 +541,7 @@ STATIC const mp_map_elem_t mp_module_network_globals_table[] = {
533541
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_network) },
534542
{ MP_OBJ_NEW_QSTR(MP_QSTR___init__), (mp_obj_t)&esp_initialize_obj },
535543
{ MP_OBJ_NEW_QSTR(MP_QSTR_WLAN), (mp_obj_t)&get_wlan_obj },
544+
{ MP_OBJ_NEW_QSTR(MP_QSTR_LAN), (mp_obj_t)&get_lan_obj },
536545
{ MP_OBJ_NEW_QSTR(MP_QSTR_phy_mode), (mp_obj_t)&esp_phy_mode_obj },
537546

538547
#if MODNETWORK_INCLUDE_CONSTANTS
@@ -560,6 +569,11 @@ STATIC const mp_map_elem_t mp_module_network_globals_table[] = {
560569
MP_OBJ_NEW_SMALL_INT(WIFI_AUTH_WPA_WPA2_PSK) },
561570
{ MP_OBJ_NEW_QSTR(MP_QSTR_AUTH_MAX),
562571
MP_OBJ_NEW_SMALL_INT(WIFI_AUTH_MAX) },
572+
573+
{ MP_OBJ_NEW_QSTR(MP_QSTR_PHY_LAN8720),
574+
MP_OBJ_NEW_SMALL_INT(PHY_LAN8720) },
575+
{ MP_OBJ_NEW_QSTR(MP_QSTR_PHY_TLK110),
576+
MP_OBJ_NEW_SMALL_INT(PHY_TLK110) },
563577
#endif
564578
};
565579

ports/esp32/modnetwork.h

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2017 "Eric Poulsen" <[email protected]>
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+
#ifndef MICROPY_INCLUDED_ESP32_MODNETWORK_H
27+
#define MICROPY_INCLUDED_ESP32_MODNETWORK_H
28+
29+
enum { PHY_LAN8720, PHY_TLK110 };
30+
31+
MP_DECLARE_CONST_FUN_OBJ_KW(get_lan_obj);
32+
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj);
33+
34+
#endif

ports/esp32/network_lan.c

+203
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2017 "Eric Poulsen" <[email protected]>
7+
*
8+
* Based on the ESP IDF example code which is Public Domain / CC0
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 "py/runtime.h"
30+
#include "py/mphal.h"
31+
32+
#include "eth_phy/phy.h"
33+
#include "eth_phy/phy_tlk110.h"
34+
#include "eth_phy/phy_lan8720.h"
35+
#include "tcpip_adapter.h"
36+
37+
#include "modnetwork.h"
38+
39+
typedef struct _lan_if_obj_t {
40+
mp_obj_base_t base;
41+
int if_id; // MUST BE FIRST to match wlan_if_obj_t
42+
bool initialized;
43+
bool active;
44+
uint8_t mdc_pin;
45+
uint8_t mdio_pin;
46+
int8_t phy_power_pin;
47+
uint8_t phy_addr;
48+
uint8_t phy_type;
49+
eth_phy_check_link_func link_func;
50+
eth_phy_power_enable_func power_func;
51+
} lan_if_obj_t;
52+
53+
const mp_obj_type_t lan_if_type;
54+
STATIC lan_if_obj_t lan_obj = {{&lan_if_type}, ESP_IF_ETH, false, false};
55+
56+
STATIC void phy_power_enable(bool enable) {
57+
lan_if_obj_t* self = &lan_obj;
58+
59+
if (self->phy_power_pin != -1) {
60+
61+
if (!enable) {
62+
// Do the PHY-specific power_enable(false) function before powering down
63+
self->power_func(false);
64+
}
65+
66+
gpio_pad_select_gpio(self->phy_power_pin);
67+
gpio_set_direction(self->phy_power_pin, GPIO_MODE_OUTPUT);
68+
if (enable) {
69+
gpio_set_level(self->phy_power_pin, 1);
70+
} else {
71+
gpio_set_level(self->phy_power_pin, 0);
72+
}
73+
74+
// Allow the power up/down to take effect, min 300us
75+
vTaskDelay(1);
76+
77+
if (enable) {
78+
// Run the PHY-specific power on operations now the PHY has power
79+
self->power_func(true);
80+
}
81+
}
82+
}
83+
84+
STATIC void init_lan_rmii() {
85+
lan_if_obj_t* self = &lan_obj;
86+
phy_rmii_configure_data_interface_pins();
87+
phy_rmii_smi_configure_pins(self->mdc_pin, self->mdio_pin);
88+
}
89+
90+
STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
91+
lan_if_obj_t* self = &lan_obj;
92+
93+
if (self->initialized) {
94+
return MP_OBJ_FROM_PTR(&lan_obj);
95+
}
96+
97+
enum { ARG_id, ARG_mdc, ARG_mdio, ARG_power, ARG_phy_addr, ARG_phy_type };
98+
static const mp_arg_t allowed_args[] = {
99+
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = mp_const_none} },
100+
{ MP_QSTR_mdc, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
101+
{ MP_QSTR_mdio, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
102+
{ MP_QSTR_power, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
103+
{ MP_QSTR_phy_addr, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
104+
{ MP_QSTR_phy_type, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
105+
};
106+
107+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
108+
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
109+
110+
if (args[ARG_id].u_obj != mp_const_none) {
111+
if (mp_obj_get_int(args[ARG_id].u_obj) != 0) {
112+
mp_raise_ValueError("invalid LAN interface identifier");
113+
}
114+
}
115+
116+
self->mdc_pin = machine_pin_get_id(args[ARG_mdc].u_obj);
117+
self->mdio_pin = machine_pin_get_id(args[ARG_mdio].u_obj);
118+
self->phy_power_pin = args[ARG_power].u_obj == mp_const_none ? -1 : machine_pin_get_id(args[ARG_power].u_obj);
119+
120+
if (args[ARG_phy_addr].u_int < 0x00 || args[ARG_phy_addr].u_int > 0x1f) {
121+
mp_raise_ValueError("invalid phy address");
122+
}
123+
124+
if (args[ARG_phy_type].u_int != PHY_LAN8720 && args[ARG_phy_type].u_int != PHY_TLK110) {
125+
mp_raise_ValueError("invalid phy type");
126+
}
127+
128+
eth_config_t config;
129+
130+
switch (args[ARG_phy_type].u_int) {
131+
case PHY_TLK110:
132+
config = phy_tlk110_default_ethernet_config;
133+
break;
134+
case PHY_LAN8720:
135+
config = phy_lan8720_default_ethernet_config;
136+
break;
137+
}
138+
139+
self->link_func = config.phy_check_link;
140+
141+
// Replace default power func with our own
142+
self->power_func = config.phy_power_enable;
143+
config.phy_power_enable = phy_power_enable;
144+
145+
config.phy_addr = args[ARG_phy_addr].u_int;
146+
config.gpio_config = init_lan_rmii;
147+
config.tcpip_input = tcpip_adapter_eth_input;
148+
149+
if (esp_eth_init(&config) == ESP_OK) {
150+
self->active = false;
151+
self->initialized = true;
152+
} else {
153+
mp_raise_msg(&mp_type_OSError, "esp_eth_init() failed");
154+
}
155+
return MP_OBJ_FROM_PTR(&lan_obj);
156+
}
157+
MP_DEFINE_CONST_FUN_OBJ_KW(get_lan_obj, 0, get_lan);
158+
159+
STATIC mp_obj_t lan_active(size_t n_args, const mp_obj_t *args) {
160+
lan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
161+
162+
if (n_args > 1) {
163+
if (mp_obj_is_true(args[1])) {
164+
self->active = (esp_eth_enable() == ESP_OK);
165+
if (!self->active) {
166+
mp_raise_msg(&mp_type_OSError, "ethernet enable failed");
167+
}
168+
} else {
169+
self->active = !(esp_eth_disable() == ESP_OK);
170+
if (self->active) {
171+
mp_raise_msg(&mp_type_OSError, "ethernet disable failed");
172+
}
173+
}
174+
}
175+
return mp_obj_new_bool(self->active);
176+
}
177+
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lan_active_obj, 1, 2, lan_active);
178+
179+
STATIC mp_obj_t lan_status(mp_obj_t self_in) {
180+
return mp_const_none;
181+
}
182+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(lan_status_obj, lan_status);
183+
184+
STATIC mp_obj_t lan_isconnected(mp_obj_t self_in) {
185+
lan_if_obj_t *self = MP_OBJ_TO_PTR(self_in);
186+
return self->active ? mp_obj_new_bool(self->link_func()) : mp_const_false;
187+
}
188+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(lan_isconnected_obj, lan_isconnected);
189+
190+
STATIC const mp_rom_map_elem_t lan_if_locals_dict_table[] = {
191+
{ MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&lan_active_obj) },
192+
{ MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&lan_isconnected_obj) },
193+
{ MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&lan_status_obj) },
194+
{ MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) },
195+
};
196+
197+
STATIC MP_DEFINE_CONST_DICT(lan_if_locals_dict, lan_if_locals_dict_table);
198+
199+
const mp_obj_type_t lan_if_type = {
200+
{ &mp_type_type },
201+
.name = MP_QSTR_LAN,
202+
.locals_dict = (mp_obj_dict_t*)&lan_if_locals_dict,
203+
};

0 commit comments

Comments
 (0)