Skip to content

Commit 29a3eac

Browse files
committed
feat(iot_eth): add iot eth components
1 parent 514f118 commit 29a3eac

File tree

21 files changed

+1354
-597
lines changed

21 files changed

+1354
-597
lines changed

components/iot_eth/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
idf_component_register(SRCS "iot_eth.c"
2+
INCLUDE_DIRS "include" "interface"
3+
REQUIRES esp_netif)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#pragma once
7+
8+
#include "esp_err.h"
9+
#include "iot_eth_interface.h"
10+
11+
#ifdef __cplusplus
12+
extern "C" {
13+
#endif
14+
15+
typedef void *iot_eth_handle_t;
16+
17+
typedef struct {
18+
iot_eth_driver_t *driver;
19+
esp_err_t (*on_lowlevel_init_done)(iot_eth_handle_t handle);
20+
esp_err_t (*on_lowlevel_deinit)(iot_eth_handle_t handle);
21+
esp_err_t (*stack_input)(iot_eth_handle_t handle, uint8_t *data, size_t len, void *user_data);
22+
void *user_data;
23+
} iot_eth_config_t;
24+
25+
esp_err_t iot_eth_install(iot_eth_config_t *config, iot_eth_handle_t *handle);
26+
27+
esp_err_t iot_eth_uninstall(iot_eth_handle_t handle);
28+
29+
esp_err_t iot_eth_start(iot_eth_handle_t handle);
30+
31+
esp_err_t iot_eth_stop(iot_eth_handle_t handle);
32+
33+
esp_err_t iot_eth_transmit(iot_eth_handle_t handle, uint8_t *data, size_t len);
34+
35+
esp_err_t iot_eth_get_addr(iot_eth_handle_t handle, uint8_t *mac);
36+
37+
#ifdef __cplusplus
38+
}
39+
#endif
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#pragma once
7+
8+
#ifdef __cplusplus
9+
extern "C" {
10+
#endif
11+
12+
/**
13+
* @brief Ethernet link status
14+
*
15+
*/
16+
typedef enum {
17+
IOT_ETH_LINK_UP, /*!< Ethernet link is up */
18+
IOT_ETH_LINK_DOWN /*!< Ethernet link is down */
19+
} iot_eth_link_t;
20+
21+
#ifdef __cplusplus
22+
}
23+
#endif
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#pragma once
7+
8+
#include "esp_err.h"
9+
10+
#ifdef __cplusplus
11+
extern "C" {
12+
#endif
13+
14+
typedef struct iot_eth_driver_s iot_eth_driver_t;
15+
typedef struct iot_eth_mediator_s iot_eth_mediator_t;
16+
17+
struct iot_eth_driver_s {
18+
const char *name;
19+
esp_err_t (*set_mediator)(iot_eth_driver_t *driver, iot_eth_mediator_t *eth);
20+
esp_err_t (*init)(iot_eth_driver_t *driver);
21+
esp_err_t (*deinit)(iot_eth_driver_t *driver);
22+
esp_err_t (*start)(iot_eth_driver_t *driver);
23+
esp_err_t (*stop)(iot_eth_driver_t *driver);
24+
esp_err_t (*transmit)(iot_eth_driver_t *driver, uint8_t *data, size_t len);
25+
/**
26+
* @brief Get MAC address
27+
*
28+
* @param driver
29+
* @param mac_address
30+
* @return esp_err_t
31+
*/
32+
esp_err_t (*get_addr)(iot_eth_driver_t *driver, uint8_t *mac_address);
33+
};
34+
35+
typedef enum {
36+
IOT_ETH_STAGE_LLINIT,
37+
IOT_ETH_STAGE_DEINIT,
38+
IOT_ETH_STAGE_GET_MAC,
39+
IOT_ETH_STAGE_LINK,
40+
IOT_ETH_STATE_PAUSE,
41+
} iot_eth_stage_t;
42+
43+
struct iot_eth_mediator_s {
44+
esp_err_t (*stack_input)(iot_eth_mediator_t *mediator, uint8_t *data, size_t len);
45+
// TODO: args 可能不需要,让 driver 层传递给 eth 层
46+
esp_err_t (*on_stage_changed)(iot_eth_mediator_t *mediator, iot_eth_stage_t stage, void *arg);
47+
};
48+
49+
#ifdef __cplusplus
50+
}
51+
#endif

components/iot_eth/iot_eth.c

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <stdatomic.h>
8+
#include "esp_err.h"
9+
#include "esp_log.h"
10+
#include "esp_check.h"
11+
#include "esp_netif.h"
12+
#include "esp_event.h"
13+
#include "iot_eth.h"
14+
#include "iot_eth_types.h"
15+
16+
static const char *TAG = "iot_eth";
17+
18+
typedef struct {
19+
iot_eth_driver_t *driver;
20+
iot_eth_mediator_t mediator;
21+
esp_netif_t *netif;
22+
_Atomic iot_eth_link_t link;
23+
uint8_t mac[6];
24+
void *user_data;
25+
esp_err_t (*stack_input)(iot_eth_handle_t handle, uint8_t *data, size_t len, void *user_data);
26+
esp_err_t (*on_lowlevel_init_done)(iot_eth_handle_t handle);
27+
esp_err_t (*on_lowlevel_deinit)(iot_eth_handle_t handle);
28+
} iot_eth_t;
29+
30+
static esp_err_t iot_eth_stack_input_default(iot_eth_handle_t handle, uint8_t *data, size_t len, void *user_data)
31+
{
32+
iot_eth_t *eth = (iot_eth_t *)handle;
33+
return esp_netif_receive(eth->netif, data, len, NULL);
34+
}
35+
36+
esp_err_t iot_eth_stack_input(iot_eth_mediator_t *mediator, uint8_t *data, size_t len)
37+
{
38+
iot_eth_t *eth = __containerof(mediator, iot_eth_t, mediator);
39+
if (eth->stack_input != NULL) {
40+
return eth->stack_input(eth, data, len, eth->user_data);
41+
}
42+
// if no stack input, free the data
43+
free(data);
44+
return ESP_OK;
45+
}
46+
47+
static esp_err_t iot_eth_transmit_default(void *handle, void *data, size_t len)
48+
{
49+
return iot_eth_transmit(handle, data, len);
50+
}
51+
52+
esp_err_t iot_eth_transmit(iot_eth_handle_t handle, uint8_t *data, size_t len)
53+
{
54+
ESP_RETURN_ON_FALSE(handle != NULL, ESP_ERR_INVALID_ARG, TAG, "handle is NULL");
55+
ESP_RETURN_ON_FALSE(data != NULL, ESP_ERR_INVALID_ARG, TAG, "buf can't be NULL");
56+
ESP_RETURN_ON_FALSE(len > 0, ESP_ERR_INVALID_ARG, TAG, "buf len can't be zero");
57+
iot_eth_t *eth = (iot_eth_t *)handle;
58+
esp_err_t ret = ESP_OK;
59+
if (atomic_load(&eth->link) != IOT_ETH_LINK_UP) {
60+
ret = ESP_ERR_INVALID_STATE;
61+
goto err;
62+
}
63+
ret = eth->driver->transmit(eth->driver, data, len);
64+
err:
65+
return ret;
66+
}
67+
68+
static void iot_eth_free_rx_buffer(void *h, void *buffer)
69+
{
70+
if (buffer) {
71+
free(buffer);
72+
}
73+
}
74+
75+
static void iot_eth_got_ip_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
76+
{
77+
ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
78+
const esp_netif_ip_info_t *ip_info = &event->ip_info;
79+
ESP_LOGI(TAG, "Ethernet Got IP Address");
80+
ESP_LOGI(TAG, "~~~~~~~~~~~");
81+
ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip));
82+
ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask));
83+
ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw));
84+
ESP_LOGI(TAG, "~~~~~~~~~~~");
85+
}
86+
87+
esp_err_t iot_eth_on_stage_changed(iot_eth_mediator_t *mediator, iot_eth_stage_t stage, void *arg)
88+
{
89+
iot_eth_t *eth = __containerof(mediator, iot_eth_t, mediator);
90+
switch (stage) {
91+
case IOT_ETH_STAGE_LLINIT:
92+
if (eth->on_lowlevel_init_done != NULL) {
93+
return eth->on_lowlevel_init_done(eth);
94+
}
95+
break;
96+
case IOT_ETH_STAGE_DEINIT:
97+
if (eth->on_lowlevel_deinit != NULL) {
98+
return eth->on_lowlevel_deinit(eth);
99+
}
100+
break;
101+
case IOT_ETH_STAGE_GET_MAC:
102+
eth->driver->get_addr(eth->driver, eth->mac);
103+
ESP_LOGI(TAG, "%s: MAC address: %02X:%02X:%02X:%02X:%02X:%02X", eth->driver->name, eth->mac[0], eth->mac[1], eth->mac[2], eth->mac[3], eth->mac[4], eth->mac[5]);
104+
if (eth->netif) {
105+
esp_netif_set_mac(eth->netif, eth->mac);
106+
}
107+
break;
108+
case IOT_ETH_STAGE_LINK:
109+
iot_eth_link_t *link = (iot_eth_link_t *)arg;
110+
atomic_store(&eth->link, *link);
111+
if (*link == IOT_ETH_LINK_UP) {
112+
if (eth->netif) {
113+
esp_netif_action_start(eth->netif, NULL, 0, NULL);
114+
esp_netif_action_connected(eth->netif, NULL, 0, NULL);
115+
ESP_LOGI(TAG, "%s: Link up", eth->driver->name);
116+
}
117+
} else {
118+
if (eth->netif) {
119+
esp_netif_action_disconnected(eth->netif, NULL, 0, NULL);
120+
esp_netif_action_stop(eth->netif, NULL, 0, NULL);
121+
ESP_LOGI(TAG, "%s: Link down", eth->driver->name);
122+
}
123+
}
124+
break;
125+
case IOT_ETH_STATE_PAUSE:
126+
break;
127+
}
128+
return ESP_OK;
129+
}
130+
131+
esp_err_t iot_eth_install(iot_eth_config_t *config, iot_eth_handle_t *handle)
132+
{
133+
ESP_RETURN_ON_FALSE(config != NULL, ESP_ERR_INVALID_ARG, TAG, "config is NULL");
134+
ESP_RETURN_ON_FALSE(handle != NULL, ESP_ERR_INVALID_ARG, TAG, "handle is NULL");
135+
136+
// Init TCP/IP network interface (should be called only once in application)
137+
esp_err_t ret = esp_netif_init();
138+
if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) { // Already initialized is OK
139+
ESP_LOGE(TAG, "Failed to initialize TCP/IP stack");
140+
return ret;
141+
}
142+
143+
// Create default event loop that runs in background if not already created
144+
ret = esp_event_loop_create_default();
145+
if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) { // Already initialized is OK
146+
ESP_LOGE(TAG, "Failed to create event loop");
147+
return ret;
148+
}
149+
150+
iot_eth_t *eth = calloc(1, sizeof(iot_eth_t));
151+
ESP_RETURN_ON_FALSE(eth != NULL, ESP_ERR_NO_MEM, TAG, "Failed to allocate memory for iot_eth_t");
152+
eth->driver = config->driver;
153+
// default stack input to esp_netif_receive(TCP/IP stack)
154+
if (config->stack_input == NULL) {
155+
// TODO: 如果不创建 netif 是否还需要这个?
156+
ret = esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &iot_eth_got_ip_event_handler, NULL);
157+
ESP_GOTO_ON_FALSE(ret == ESP_OK, ESP_FAIL, err, TAG, "Failed to register event handler");
158+
159+
printf("555\n");
160+
161+
eth->stack_input = iot_eth_stack_input_default;
162+
// Prepare network interface for the driver
163+
esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH();
164+
eth->netif = esp_netif_new(&netif_cfg);
165+
printf("666\n");
166+
ESP_RETURN_ON_FALSE(eth->netif != NULL, ESP_ERR_NO_MEM, TAG, "Failed to create netif");
167+
esp_netif_driver_ifconfig_t driver_ifconfig = {
168+
.handle = eth,
169+
.transmit = iot_eth_transmit_default,
170+
.driver_free_rx_buffer = iot_eth_free_rx_buffer,
171+
};
172+
printf("777\n");
173+
174+
ret = esp_netif_set_driver_config(eth->netif, &driver_ifconfig);
175+
ESP_GOTO_ON_FALSE(ret == ESP_OK, ESP_FAIL, err, TAG, "Failed to set driver config");
176+
printf("888\n");
177+
esp_netif_set_hostname(eth->netif, eth->driver->name);
178+
} else {
179+
eth->stack_input = config->stack_input;
180+
}
181+
eth->on_lowlevel_init_done = config->on_lowlevel_init_done;
182+
eth->on_lowlevel_deinit = config->on_lowlevel_deinit;
183+
eth->mediator.stack_input = iot_eth_stack_input;
184+
eth->mediator.on_stage_changed = iot_eth_on_stage_changed;
185+
eth->driver->set_mediator(eth->driver, &eth->mediator);
186+
ret = eth->driver->init(eth->driver);
187+
ESP_GOTO_ON_FALSE(ret == ESP_OK, ESP_FAIL, err, TAG, "Failed to init driver");
188+
*handle = (iot_eth_handle_t)eth;
189+
return ESP_OK;
190+
err:
191+
if (eth->netif != NULL) {
192+
esp_event_handler_unregister(IP_EVENT, IP_EVENT_ETH_GOT_IP, &iot_eth_got_ip_event_handler);
193+
esp_netif_destroy(eth->netif);
194+
eth->netif = NULL;
195+
}
196+
free(eth);
197+
return ret;
198+
}
199+
200+
esp_err_t iot_eth_uninstall(iot_eth_handle_t handle)
201+
{
202+
ESP_RETURN_ON_FALSE(handle != NULL, ESP_ERR_INVALID_ARG, TAG, "handle is NULL");
203+
iot_eth_t *eth = (iot_eth_t *)handle;
204+
esp_err_t ret = eth->driver->deinit(eth->driver);
205+
ESP_GOTO_ON_FALSE(ret == ESP_OK, ESP_FAIL, err, TAG, "Failed to deinit driver");
206+
207+
if (eth->netif != NULL) {
208+
esp_event_handler_unregister(IP_EVENT, IP_EVENT_ETH_GOT_IP, &iot_eth_got_ip_event_handler);
209+
esp_netif_destroy(eth->netif);
210+
eth->netif = NULL;
211+
}
212+
free(eth);
213+
return ESP_OK;
214+
err:
215+
return ret;
216+
}
217+
218+
esp_err_t iot_eth_start(iot_eth_handle_t handle)
219+
{
220+
ESP_RETURN_ON_FALSE(handle != NULL, ESP_ERR_INVALID_ARG, TAG, "handle is NULL");
221+
iot_eth_t *eth = (iot_eth_t *)handle;
222+
return eth->driver->start(eth->driver);
223+
}
224+
225+
esp_err_t iot_eth_stop(iot_eth_handle_t handle)
226+
{
227+
ESP_RETURN_ON_FALSE(handle != NULL, ESP_ERR_INVALID_ARG, TAG, "handle is NULL");
228+
iot_eth_t *eth = (iot_eth_t *)handle;
229+
return eth->driver->stop(eth->driver);
230+
}
231+
232+
esp_err_t iot_eth_get_addr(iot_eth_handle_t handle, uint8_t *mac)
233+
{
234+
ESP_RETURN_ON_FALSE(handle != NULL, ESP_ERR_INVALID_ARG, TAG, "handle is NULL");
235+
iot_eth_t *eth = (iot_eth_t *)handle;
236+
return eth->driver->get_addr(eth->driver, mac);
237+
}

components/usb/iot_usbh_cdc/Kconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ menu "IoT USB Host CDC"
1313
help
1414
usb task base priority
1515

16+
config CONTROL_TRANSFER_BUFFER_SIZE
17+
int "usbh control transfer size"
18+
default 512
19+
help
20+
usb host control transfer size
21+
1622
config IN_TRANSFER_BUFFER_SIZE
1723
int "usbh IN transfer buffer size"
1824
default 512

0 commit comments

Comments
 (0)