1313#include "freertos/queue.h"
1414#include "freertos/ringbuf.h"
1515#include "usbh_rndis_protocol.h"
16- #include "usb/usb_host.h"
1716#include "usb/cdc_acm_host.h"
1817#include "esp_netif.h"
18+ #include "esp_mac.h"
19+ #include "esp_event.h"
20+ #include "usb_host_rndis.h"
1921
2022static const char * TAG = "usbh_rndis" ;
2123
@@ -31,6 +33,7 @@ static uint8_t g_rndis_rx_buffer[CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE];
3133static uint8_t g_rndis_tx_buffer [CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE ];
3234
3335typedef struct {
36+ esp_netif_t * netif ;
3437 cdc_acm_dev_hdl_t cdc_dev ;
3538 uint8_t minor ;
3639 uint32_t request_id ;
@@ -44,53 +47,19 @@ typedef struct {
4447 size_t rndis_msg_buf_len ;
4548 RingbufHandle_t in_ringbuf_handle ; /*!< in ringbuffer handle of corresponding interface */
4649 QueueHandle_t in_queue_handle ; /*!< in queue handle of corresponding interface */
50+ QueueHandle_t tx_queue_handle ; /*!< in queue handle of corresponding interface */
4751 size_t in_ringbuf_size ;
4852
4953 void * user_data ;
5054} usbh_rndis_t ;
5155
52- static usbh_rndis_t * rndis = NULL ;
53-
54- static void usb_lib_task (void * arg )
55- {
56- // Install USB Host driver. Should only be called once in entire application
57- const usb_host_config_t host_config = {
58- .skip_phy_setup = false,
59- .intr_flags = ESP_INTR_FLAG_LEVEL1 ,
60- };
61- ESP_ERROR_CHECK (usb_host_install (& host_config ));
62-
63- //Signalize the usbh_cdc_driver_install, the USB host library has been installed
64- xTaskNotifyGive (arg );
65-
66- bool has_clients = true;
67- bool has_devices = false;
68- while (has_clients ) {
69- uint32_t event_flags ;
70- ESP_ERROR_CHECK (usb_host_lib_handle_events (portMAX_DELAY , & event_flags ));
71- if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS ) {
72- ESP_LOGI (TAG , "Get FLAGS_NO_CLIENTS" );
73- if (ESP_OK == usb_host_device_free_all ()) {
74- ESP_LOGI (TAG , "All devices marked as free, no need to wait FLAGS_ALL_FREE event" );
75- has_clients = false;
76- } else {
77- ESP_LOGI (TAG , "Wait for the FLAGS_ALL_FREE" );
78- has_devices = true;
79- }
80- }
81- if (has_devices && event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE ) {
82- ESP_LOGI (TAG , "Get FLAGS_ALL_FREE" );
83- has_clients = false;
84- }
85- }
86- ESP_LOGI (TAG , "No more clients and devices, uninstall USB Host library" );
56+ // Structure for TX packets
57+ typedef struct {
58+ void * buffer ;
59+ uint32_t length ;
60+ } usb_ecm_tx_packet_t ;
8761
88- // Clean up USB Host
89- vTaskDelay (100 ); // Short delay to allow clients clean-up
90- usb_host_uninstall ();
91- ESP_LOGD (TAG , "USB Host library is uninstalled" );
92- vTaskDelete (NULL );
93- }
62+ static usbh_rndis_t * rndis = NULL ;
9463
9564/*--------------------------------- CDC Buffer Handle Code --------------------------------------*/
9665static size_t _get_ringbuf_len (RingbufHandle_t ringbuf_hdl )
@@ -157,13 +126,51 @@ static void _ring_buffer_flush(RingbufHandle_t ringbuf_hdl)
157126 }
158127}
159128
129+ static void got_ip_event_handler (void * arg , esp_event_base_t event_base ,
130+ int32_t event_id , void * event_data )
131+ {
132+ ip_event_got_ip_t * event = (ip_event_got_ip_t * ) event_data ;
133+ const esp_netif_ip_info_t * ip_info = & event -> ip_info ;
134+ // s_got_ip = true;
135+ ESP_LOGI (TAG , "Ethernet Got IP Address" );
136+ ESP_LOGI (TAG , "~~~~~~~~~~~" );
137+ ESP_LOGI (TAG , "ETHIP:" IPSTR , IP2STR (& ip_info -> ip ));
138+ ESP_LOGI (TAG , "ETHMASK:" IPSTR , IP2STR (& ip_info -> netmask ));
139+ ESP_LOGI (TAG , "ETHGW:" IPSTR , IP2STR (& ip_info -> gw ));
140+ ESP_LOGI (TAG , "~~~~~~~~~~~" );
141+ }
142+
143+ static void usb_rndis_free_rx_buffer (void * h , void * buffer )
144+ {
145+ if (buffer ) {
146+ free (buffer - 44 );
147+ }
148+ }
149+
160150#define USB_RNDIS_MSG_BUF_SIZE 512
161151#define USB_RNDIS_IN_RINGBUF_SIZE 2048*2
162152
163- esp_err_t usbh_rndis_init (void )
153+ esp_err_t usbh_rndis_init (const usb_host_rndis_config_t * config )
164154{
165- esp_err_t ret = ESP_OK ;
166- ESP_LOGI (TAG , "Installing USB Host" );
155+ ESP_RETURN_ON_FALSE (config != NULL , ESP_ERR_INVALID_ARG , TAG , "Invalid argument" );
156+
157+ // Init TCP/IP network interface (should be called only once in application)
158+ esp_err_t ret = esp_netif_init ();
159+ if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE ) { // Already initialized is OK
160+ ESP_LOGE (TAG , "Failed to initialize TCP/IP stack" );
161+ return ret ;
162+ }
163+
164+ // Create default event loop that runs in background if not already created
165+ ret = esp_event_loop_create_default ();
166+ if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE ) { // Already initialized is OK
167+ ESP_LOGE (TAG , "Failed to create event loop" );
168+ return ret ;
169+ }
170+
171+ // Register event handlers
172+ ESP_ERROR_CHECK (esp_event_handler_register (IP_EVENT , IP_EVENT_ETH_GOT_IP , & got_ip_event_handler , NULL ));
173+
167174 rndis = calloc (1 , sizeof (usbh_rndis_t ));
168175 ESP_RETURN_ON_FALSE (rndis != NULL , ESP_ERR_NO_MEM , TAG , "Failed to allocate memory for rndis" );
169176
@@ -177,20 +184,46 @@ esp_err_t usbh_rndis_init(void)
177184 rndis -> in_queue_handle = xQueueCreate (10 , sizeof (size_t ));
178185 ESP_RETURN_ON_FALSE (rndis -> in_queue_handle != NULL , ESP_ERR_NO_MEM , TAG , "Failed to create queue" );
179186
180- // Create a task that will handle USB library events
181- BaseType_t task_created = xTaskCreate (usb_lib_task , "usb_lib" , 4096 , xTaskGetCurrentTaskHandle (), 5 , NULL );
182- assert (task_created == pdTRUE ); // Task should always be created
187+ rndis -> tx_queue_handle = xQueueCreate (10 , sizeof (usb_ecm_tx_packet_t ));
188+ ESP_RETURN_ON_FALSE (rndis -> tx_queue_handle != NULL , ESP_ERR_NO_MEM , TAG , "Failed to create queue" );
183189
184- // Wait unit the USB host library is installed
185- uint32_t notify_value = ulTaskNotifyTake (false, pdMS_TO_TICKS (1000 ));
186- if (notify_value == 0 ) {
187- ESP_LOGE (TAG , "USB host library not installed" );
188- return ESP_FAIL ;
190+ // Create network interface for USB ECM with default config
191+ esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH ();
192+ rndis -> netif = esp_netif_new (& netif_cfg );
193+ if (!rndis -> netif ) {
194+ ESP_LOGE (TAG , "Failed to create netif" );
195+ return ESP_ERR_NO_MEM ;
196+ }
197+
198+ esp_netif_driver_ifconfig_t driver_cfg = {
199+ .handle = rndis -> netif , // not using an instance, USB-NCM is a static singleton (must be != NULL)
200+ .transmit = usbh_rndis_eth_output , // point to static Tx function
201+ .driver_free_rx_buffer = usb_rndis_free_rx_buffer , // point to Free Rx buffer function
202+ };
203+
204+ // Set the driver configuration for the netif
205+ ret = esp_netif_set_driver_config (rndis -> netif , & driver_cfg );
206+ if (ret != ESP_OK ) {
207+ esp_netif_destroy (rndis -> netif );
208+ rndis -> netif = NULL ;
209+ return ret ;
189210 }
190211
212+ // Generate a MAC address for the interface
213+ uint8_t mac_addr [6 ];
214+ // uint8_t mac_addr[6] = { 0x01, 0x01, 0x5E, 0x01, 0x01, 0x01 };
215+
216+ esp_read_mac (mac_addr , ESP_MAC_ETH );
217+ mac_addr [5 ] ^= 0x01 ; // Make it unique from the default Ethernet MAC
218+ ESP_ERROR_CHECK (esp_netif_set_mac (rndis -> netif , mac_addr ));
219+
220+ ESP_LOGI (TAG , "USB RNDIS MAC: %02x:%02x:%02x:%02x:%02x:%02x" ,
221+ mac_addr [0 ], mac_addr [1 ], mac_addr [2 ], mac_addr [3 ], mac_addr [4 ], mac_addr [5 ]);
222+
223+ ESP_LOGI (TAG , "USB RNDIS network interface initialized" );
191224 ESP_LOGI (TAG , "Installing CDC-ACM driver" );
192225 ESP_ERROR_CHECK (cdc_acm_host_install (NULL ));
193- return ret ;
226+ return ESP_OK ;
194227}
195228
196229/**
@@ -208,7 +241,6 @@ static bool handle_rx(const uint8_t *data, size_t data_len, void *arg)
208241 usbh_rndis_t * rndis = (usbh_rndis_t * )arg ;
209242 if (_ringbuf_push (rndis -> in_ringbuf_handle , data , data_len , pdMS_TO_TICKS (1000 )) == ESP_OK ) {
210243 xQueueSend (rndis -> in_queue_handle , & data_len , pdMS_TO_TICKS (1000 ));
211- printf ("!!!!Received %d bytes\n" , data_len );
212244 }
213245
214246 return true;
@@ -237,17 +269,45 @@ static void handle_event(const cdc_acm_host_dev_event_data_t *event, void *user_
237269 ESP_LOGI (TAG , "Serial state notif 0x%04X" , event -> data .serial_state .val );
238270 break ;
239271 case CDC_ACM_HOST_NETWORK_CONNECTION :
272+ break ;
240273 default :
241274 ESP_LOGW (TAG , "Unsupported CDC event: %i" , event -> type );
242275 break ;
243276 }
244277}
245278
279+ // USB ECM transmit task
280+ static void usb_rndis_tx_task (void * arg )
281+ {
282+ usb_ecm_tx_packet_t tx_packet ;
283+ printf ("usb_rndis_tx_task started\n" );
284+ while (1 ) {
285+ if (xQueueReceive (rndis -> tx_queue_handle , & tx_packet , portMAX_DELAY ) == pdTRUE ) {
286+ // if (!s_cdc_dev) {
287+ // // Device disconnected, free buffer and continue
288+ // free(tx_packet.buffer);
289+ // continue;
290+ // }
291+
292+ // Send packet through USB ECM interface
293+ ESP_LOGD (TAG , "Transmitting packet, len=%lu" , tx_packet .length );
294+ esp_err_t ret = cdc_acm_host_data_tx_blocking (rndis -> cdc_dev , tx_packet .buffer ,
295+ tx_packet .length , 1000 );
296+ if (ret != ESP_OK ) {
297+ ESP_LOGE (TAG , "Failed to transmit packet: %s" , esp_err_to_name (ret ));
298+ }
299+
300+ // Free the buffer after transmitting
301+ free (tx_packet .buffer );
302+ }
303+ }
304+ }
305+
246306esp_err_t usbh_rndis_create (void )
247307{
248308 const cdc_acm_host_device_config_t dev_config = {
249309 .connection_timeout_ms = 1000 ,
250- .out_buffer_size = 512 ,
310+ .out_buffer_size = 2048 ,
251311 // TODO: make this configurable
252312 .in_buffer_size = 2048 ,
253313 .event_cb = handle_event ,
@@ -267,6 +327,7 @@ esp_err_t usbh_rndis_create(void)
267327 break ;
268328 }
269329 cdc_acm_host_desc_print (rndis -> cdc_dev );
330+ xTaskCreate (usb_rndis_tx_task , "usb_rndis_tx_task" , 4096 , rndis , 10 , NULL );
270331 return ESP_OK ;
271332}
272333
@@ -507,6 +568,11 @@ esp_err_t usbh_rndis_open(void)
507568
508569 ESP_LOGI (TAG , "Register RNDIS success" );
509570 // usbh_rndis_run(rndis);
571+
572+ xTaskCreate (usbh_rndis_rx_thread , "usbh_rndis_rx_thread" , 4096 , rndis -> netif , 5 , NULL );
573+
574+ esp_netif_action_start (rndis -> netif , NULL , 0 , NULL );
575+ esp_netif_action_connected (rndis -> netif , NULL , 0 , NULL );
510576 return ret ;
511577query_errorout :
512578 ESP_LOGE (TAG , "rndis query iod:%08x error" , oid );
@@ -557,7 +623,7 @@ void usbh_rndis_rx_thread(void *arg)
557623 pmg_offset = 0 ;
558624 uint32_t total_len = rx_length ;
559625 while (rx_length > 0 ) {
560- ESP_LOGI (TAG , "rndis rx thread rx_length %d\r\n" , rx_length );
626+ ESP_LOGD (TAG , "rndis rx thread rx_length %d\r\n" , rx_length );
561627 size_t read_len = 0 ;
562628 // TODO: if can get read_len < sizeof(rndis_query_cmplt_t)
563629 ret = _ringbuf_pop (rndis -> in_ringbuf_handle , data_buffer , rx_length , & read_len , pdMS_TO_TICKS (1000 ));
@@ -617,24 +683,37 @@ esp_err_t usbh_rndis_eth_output(void *h, void *buffer, size_t buflen)
617683 return ESP_ERR_INVALID_STATE ;
618684 }
619685
620- hdr = (rndis_data_packet_t * )g_rndis_tx_buffer ;
621- memset (hdr , 0 , sizeof (rndis_data_packet_t ));
686+ hdr = (rndis_data_packet_t * )malloc (sizeof (rndis_data_packet_t ) + buflen );
687+ // (rndis_data_packet_t *)g_rndis_tx_buffer;
688+ // memset(hdr, 0, sizeof(rndis_data_packet_t));
622689
623690 hdr -> MessageType = REMOTE_NDIS_PACKET_MSG ;
624691 hdr -> MessageLength = sizeof (rndis_data_packet_t ) + buflen ;
625692 hdr -> DataOffset = sizeof (rndis_data_packet_t ) - sizeof (rndis_generic_msg_t );
626693 hdr -> DataLength = buflen ;
627694
628695 len = hdr -> MessageLength ;
629- ESP_LOGI (TAG , "rndis tx length %" PRIu32 "" , len );
630- memcpy (g_rndis_tx_buffer + sizeof (rndis_data_packet_t ), buffer , buflen );
696+ ESP_LOGD (TAG , "rndis tx length %" PRIu32 "" , len );
697+ memcpy (( uint8_t * ) hdr + sizeof (rndis_data_packet_t ), buffer , buflen );
631698 // ESP_LOG_BUFFER_HEX("rndis tx data", g_rndis_tx_buffer, len);
632- if (len > CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE ) {
633- ESP_LOGE (TAG , "rndis tx length %" PRIu32 " is too large" , len );
634- return ESP_ERR_INVALID_SIZE ;
635- }
699+ // if (len > CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE) {
700+ // ESP_LOGE(TAG, "rndis tx length %"PRIu32" is too large", len);
701+ // return ESP_ERR_INVALID_SIZE;
702+ // }
703+
704+ // Create packet structure
705+ usb_ecm_tx_packet_t tx_packet = {
706+ .buffer = hdr ,
707+ .length = len
708+ };
636709
637- cdc_acm_host_data_tx_blocking (rndis -> cdc_dev , g_rndis_tx_buffer , len , pdMS_TO_TICKS (1000 ));
710+ // Send packet to transmit queue
711+ if (xQueueSend (rndis -> tx_queue_handle , & tx_packet , pdMS_TO_TICKS (100 )) != pdTRUE ) {
712+ ESP_LOGE (TAG , "TX queue full, dropping packet" );
713+ free (hdr );
714+ return ESP_ERR_TIMEOUT ;
715+ }
716+ // cdc_acm_host_data_tx_blocking(rndis->cdc_dev, g_rndis_tx_buffer, len, pdMS_TO_TICKS(1000));
638717 return ESP_OK ;
639718}
640719
0 commit comments