Skip to content
This repository was archived by the owner on Sep 6, 2023. It is now read-only.

Wired ethernet implementation #187

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions ports/esp32/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ SRC_C = \
machine_uart.c \
modmachine.c \
modnetwork.c \
network_lan.c \
modsocket.c \
modesp.c \
moduhashlib.c \
Expand Down Expand Up @@ -267,6 +268,9 @@ ESPIDF_CXX_O = $(addprefix $(ESPCOMP)/cxx/,\
ESPIDF_ETHERNET_O = $(addprefix $(ESPCOMP)/ethernet/,\
emac_dev.o \
emac_main.o \
eth_phy/phy_tlk110.o \
eth_phy/phy_lan8720.o \
eth_phy/phy_common.o \
)

$(BUILD)/$(ESPCOMP)/expat/%.o: CFLAGS += -Wno-unused-function
Expand Down
44 changes: 29 additions & 15 deletions ports/esp32/modnetwork.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2016, 2017 Nick Moore @mnemote
* Copyright (c) 2017 "Eric Poulsen" <[email protected]>
*
* Based on esp8266/modnetwork.c which is Copyright (c) 2015 Paul Sokolovsky
* And the ESP IDF example code which is Public Domain / CC0
Expand Down Expand Up @@ -48,6 +49,8 @@
#include "lwip/dns.h"
#include "tcpip_adapter.h"

#include "modnetwork.h"

#define MODNETWORK_INCLUDE_CONSTANTS (1)

NORETURN void _esp_exceptions(esp_err_t e) {
Expand Down Expand Up @@ -122,7 +125,7 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) {
ESP_LOGI("wifi", "STA_START");
break;
case SYSTEM_EVENT_STA_GOT_IP:
ESP_LOGI("wifi", "GOT_IP");
ESP_LOGI("network", "GOT_IP");
break;
case SYSTEM_EVENT_STA_DISCONNECTED: {
// This is a workaround as ESP32 WiFi libs don't currently
Expand Down Expand Up @@ -161,7 +164,7 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) {
break;
}
default:
ESP_LOGI("wifi", "event %d", event->event_id);
ESP_LOGI("network", "event %d", event->event_id);
break;
}
return ESP_OK;
Expand All @@ -182,6 +185,19 @@ STATIC void require_if(mp_obj_t wlan_if, int if_no) {
}

STATIC mp_obj_t get_wlan(size_t n_args, const mp_obj_t *args) {
static int initialized = 0;
if (!initialized) {
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_LOGD("modnetwork", "Initializing WiFi");
ESP_EXCEPTIONS( esp_wifi_init(&cfg) );
ESP_EXCEPTIONS( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
ESP_LOGD("modnetwork", "Initialized");
ESP_EXCEPTIONS( esp_wifi_set_mode(0) );
ESP_EXCEPTIONS( esp_wifi_start() );
ESP_LOGD("modnetwork", "Started");
initialized = 1;
}

int idx = (n_args > 0) ? mp_obj_get_int(args[0]) : WIFI_IF_STA;
if (idx == WIFI_IF_STA) {
return MP_OBJ_FROM_PTR(&wlan_sta_obj);
Expand All @@ -201,14 +217,6 @@ STATIC mp_obj_t esp_initialize() {
ESP_LOGD("modnetwork", "Initializing Event Loop");
ESP_EXCEPTIONS( esp_event_loop_init(event_handler, NULL) );
ESP_LOGD("modnetwork", "esp_event_loop_init done");
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_LOGD("modnetwork", "Initializing WiFi");
ESP_EXCEPTIONS( esp_wifi_init(&cfg) );
ESP_EXCEPTIONS( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
ESP_LOGD("modnetwork", "Initialized");
ESP_EXCEPTIONS( esp_wifi_set_mode(0) );
ESP_EXCEPTIONS( esp_wifi_start() );
ESP_LOGD("modnetwork", "Started");
initialized = 1;
}
return mp_const_none;
Expand Down Expand Up @@ -358,11 +366,11 @@ STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) {
netutils_parse_ipv4_addr(items[2], (void*)&info.gw, NETUTILS_BIG);
netutils_parse_ipv4_addr(items[3], (void*)&dns_info.ip, NETUTILS_BIG);
// To set a static IP we have to disable DHCP first
if (self->if_id == WIFI_IF_STA) {
esp_err_t e = tcpip_adapter_dhcpc_stop(WIFI_IF_STA);
if (self->if_id == WIFI_IF_STA || self->if_id == ESP_IF_ETH) {
esp_err_t e = tcpip_adapter_dhcpc_stop(self->if_id);
if (e != ESP_OK && e != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) _esp_exceptions(e);
ESP_EXCEPTIONS(tcpip_adapter_set_ip_info(WIFI_IF_STA, &info));
ESP_EXCEPTIONS(tcpip_adapter_set_dns_info(WIFI_IF_STA, TCPIP_ADAPTER_DNS_MAIN, &dns_info));
ESP_EXCEPTIONS(tcpip_adapter_set_ip_info(self->if_id, &info));
ESP_EXCEPTIONS(tcpip_adapter_set_dns_info(self->if_id, TCPIP_ADAPTER_DNS_MAIN, &dns_info));
} else if (self->if_id == WIFI_IF_AP) {
esp_err_t e = tcpip_adapter_dhcps_stop(WIFI_IF_AP);
if (e != ESP_OK && e != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) _esp_exceptions(e);
Expand All @@ -374,7 +382,7 @@ STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) {
}
}

STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj, 1, 2, esp_ifconfig);
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj, 1, 2, esp_ifconfig);

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

#if MODNETWORK_INCLUDE_CONSTANTS
Expand Down Expand Up @@ -560,6 +569,11 @@ STATIC const mp_map_elem_t mp_module_network_globals_table[] = {
MP_OBJ_NEW_SMALL_INT(WIFI_AUTH_WPA_WPA2_PSK) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_AUTH_MAX),
MP_OBJ_NEW_SMALL_INT(WIFI_AUTH_MAX) },

{ MP_OBJ_NEW_QSTR(MP_QSTR_PHY_LAN8720),
MP_OBJ_NEW_SMALL_INT(PHY_LAN8720) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_PHY_TLK110),
MP_OBJ_NEW_SMALL_INT(PHY_TLK110) },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the constants be prefixed with something like ETH or LAN to emphasise that they are for wired and not wifi?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, the hardware in question is a PHY, thus the PHY prefix -- this should stay.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But it's specifically a wired LAN PHY, as opposed to a wireless/USB/etc PHY. So I was thinking something like ETH_PHY_LAN8720.

#endif
};

Expand Down
36 changes: 36 additions & 0 deletions ports/esp32/modnetwork.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 "Eric Poulsen" <[email protected]>
*
* Based on the ESP IDF example code which is Public Domain / CC0
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#ifndef MICROPY_INCLUDED_ESP32_MODNETWORK_H
#define MICROPY_INCLUDED_ESP32_MODNETWORK_H

enum { PHY_LAN8720, PHY_TLK110 };
MP_DECLARE_CONST_FUN_OBJ_KW(get_lan_obj);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj);

#endif
206 changes: 206 additions & 0 deletions ports/esp32/network_lan.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 "Eric Poulsen" <[email protected]>
*
* Based on the ESP IDF example code which is Public Domain / CC0
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include "py/runtime.h"
#include "py/mphal.h"

#include "eth_phy/phy.h"
#include "eth_phy/phy_tlk110.h"
#include "eth_phy/phy_lan8720.h"
#include "tcpip_adapter.h"

#include "modnetwork.h"

typedef struct _lan_if_obj_t {
mp_obj_base_t base;
int if_id; // MUST BE FIRST to match wlan_if_obj_t
bool initialized;
bool active;
uint8_t mdc_pin;
uint8_t mdio_pin;
int8_t phy_power_pin;
uint8_t phy_addr;
uint8_t phy_type;
eth_phy_check_link_func link_func;
eth_phy_power_enable_func power_func;
} lan_if_obj_t;

const mp_obj_type_t lan_if_type;
STATIC lan_if_obj_t lan_obj = {{&lan_if_type}, ESP_IF_ETH, false, false};

STATIC void phy_power_enable(bool enable) {
lan_if_obj_t* self = &lan_obj;

if (self->phy_power_pin != -1) {

if (!enable) {
// Do the PHY-specific power_enable(false) function before powering down
self->power_func(false);
}

gpio_pad_select_gpio(self->phy_power_pin);
gpio_set_direction(self->phy_power_pin, GPIO_MODE_OUTPUT);
if (enable) {
gpio_set_level(self->phy_power_pin, 1);
} else {
gpio_set_level(self->phy_power_pin, 0);
}

// Allow the power up/down to take effect, min 300us
vTaskDelay(1);

if (enable) {
// Run the PHY-specific power on operations now the PHY has power
self->power_func(true);
}
}
}

STATIC void init_lan_rmii() {
lan_if_obj_t* self = &lan_obj;
phy_rmii_configure_data_interface_pins();
phy_rmii_smi_configure_pins(self->mdc_pin, self->mdio_pin);
}

STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
lan_if_obj_t* self = &lan_obj;

if (self->initialized) {
return MP_OBJ_FROM_PTR(&lan_obj);
}

enum { ARG_id, ARG_mdc, ARG_mdio, ARG_power, ARG_phy_addr, ARG_phy_type };


static const mp_arg_t allowed_args[] = {
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_mdc, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_mdio, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_power, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_phy_addr, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_phy_type, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
};

mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);

if (args[ARG_id].u_obj != mp_const_none) {
if (mp_obj_get_int(args[ARG_id].u_obj) != 0) {
mp_raise_ValueError("invalid LAN interface identifier");
}
}

self->mdc_pin = machine_pin_get_id(args[ARG_mdc].u_obj);
self->mdio_pin = machine_pin_get_id(args[ARG_mdio].u_obj);
self->phy_power_pin = args[ARG_power].u_obj == mp_const_none ? -1 : machine_pin_get_id(args[ARG_power].u_obj);

if (args[ARG_phy_addr].u_int < 0x00 || args[ARG_phy_addr].u_int > 0x1f) {
mp_raise_ValueError("invalid phy address");
}

if (args[ARG_phy_type].u_int != PHY_LAN8720 && args[ARG_phy_type].u_int != PHY_TLK110) {
mp_raise_ValueError("invalid phy type");
}


eth_config_t config;

switch (args[ARG_phy_type].u_int) {
case PHY_TLK110:
config = phy_tlk110_default_ethernet_config;
break;
case PHY_LAN8720:
config = phy_lan8720_default_ethernet_config;
break;
}

self->link_func = config.phy_check_link;

// Replace default power func with our own
self->power_func = config.phy_power_enable;
config.phy_power_enable = phy_power_enable;

config.phy_addr = args[ARG_phy_addr].u_int;
config.gpio_config = init_lan_rmii;
config.tcpip_input = tcpip_adapter_eth_input;

if (esp_eth_init(&config) == ESP_OK) {
self->active = false;
self->initialized = true;
} else {
mp_raise_msg(&mp_type_OSError, "esp_eth_init() failed");
}
return MP_OBJ_FROM_PTR(&lan_obj);
}
MP_DEFINE_CONST_FUN_OBJ_KW(get_lan_obj, 0, get_lan);

STATIC mp_obj_t lan_active(size_t n_args, const mp_obj_t *args) {
lan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);

if (n_args > 1) {
if (mp_obj_is_true(args[1])) {
self->active = (esp_eth_enable() == ESP_OK);
if (!self->active) {
mp_raise_msg(&mp_type_OSError, "ethernet enable failed");
}
} else {
self->active = !(esp_eth_disable() == ESP_OK);
if (self->active) {
mp_raise_msg(&mp_type_OSError, "ethernet disable failed");
}
}
}
return mp_obj_new_bool(self->active);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lan_active_obj, 1, 2, lan_active);

STATIC mp_obj_t lan_status(mp_obj_t self_in) {
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(lan_status_obj, lan_status);

STATIC mp_obj_t lan_isconnected(mp_obj_t self_in) {
lan_if_obj_t *self = MP_OBJ_TO_PTR(self_in);
return self->active ? mp_obj_new_bool(self->link_func()) : mp_const_false;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(lan_isconnected_obj, lan_isconnected);

STATIC const mp_map_elem_t lan_if_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_active), (mp_obj_t)&lan_active_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_isconnected), (mp_obj_t)&lan_isconnected_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_status), (mp_obj_t)&lan_status_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ifconfig), (mp_obj_t)&esp_ifconfig_obj },
};

STATIC MP_DEFINE_CONST_DICT(lan_if_locals_dict, lan_if_locals_dict_table);

const mp_obj_type_t lan_if_type = {
{ &mp_type_type },
.name = MP_QSTR_LAN,
.locals_dict = (mp_obj_dict_t*)&lan_if_locals_dict,
};