Skip to content

Commit d626566

Browse files
committed
shared/tinyusb,extmod/machine_usb_device: Add NCM USB networking support.
This commit adds Network Control Model (NCM) USB class support to the USB device configurability framework, enabling USB-based networking functionality. Key features: - NCM class flag (USB_BUILTIN_FLAG_NCM, value 0x04) for bitfield operations - BUILTIN_NCM constant for user-level enable/disable control - Dynamic NCM descriptor generation based on enabled state - Automatic interface/endpoint/string counting for NCM (2 interfaces, 3 endpoints) - Runtime NCM cleanup on disable (calls usbnet_deinit()) - Guarded by MICROPY_HW_NETWORK_USBNET compile flag NCM support integrates with the existing CDC/MSC infrastructure, following the same enable/disable patterns and descriptor generation logic. Signed-off-by: Andrew Leech <[email protected]>
1 parent c812ca3 commit d626566

File tree

3 files changed

+82
-1
lines changed

3 files changed

+82
-1
lines changed

extmod/machine_usb_device.c

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
#include "device/usbd_pvt.h"
4444
#endif
4545

46-
#define HAS_BUILTIN_DRIVERS (MICROPY_HW_USB_CDC || MICROPY_HW_USB_MSC)
46+
#define HAS_BUILTIN_DRIVERS (MICROPY_HW_USB_CDC || MICROPY_HW_USB_MSC || MICROPY_HW_USB_NCM)
4747

4848
// USB class flags are defined in mp_usbd.h
4949

@@ -92,6 +92,11 @@ static mp_obj_t usb_device_make_new(const mp_obj_type_t *type, size_t n_args, si
9292
if (mp_usbd_class_state.msc_enabled) {
9393
flags |= USB_BUILTIN_FLAG_MSC;
9494
}
95+
#if MICROPY_HW_NETWORK_USBNET
96+
if (mp_usbd_class_state.ncm_enabled) {
97+
flags |= USB_BUILTIN_FLAG_NCM;
98+
}
99+
#endif
95100

96101
// Create appropriate builtin object based on current state
97102
if (flags == USB_BUILTIN_FLAG_NONE) {
@@ -381,6 +386,11 @@ static uint8_t mp_usbd_get_itf_max(uint8_t flags) {
381386
if ((flags & USB_BUILTIN_FLAG_MSC) && MICROPY_HW_USB_MSC) {
382387
count += 1;
383388
}
389+
#if MICROPY_HW_NETWORK_USBNET
390+
if ((flags & USB_BUILTIN_FLAG_NCM) && MICROPY_HW_NETWORK_USBNET) {
391+
count += 2; // NCM uses 2 interfaces (control + data)
392+
}
393+
#endif
384394
return count;
385395
}
386396

@@ -392,6 +402,11 @@ static uint8_t mp_usbd_get_ep_max(uint8_t flags) {
392402
if ((flags & USB_BUILTIN_FLAG_MSC) && MICROPY_HW_USB_MSC) {
393403
ep_max = (ep_max > 2) ? ep_max : 2; // MSC uses endpoints 1, 2
394404
}
405+
#if MICROPY_HW_NETWORK_USBNET
406+
if ((flags & USB_BUILTIN_FLAG_NCM) && MICROPY_HW_NETWORK_USBNET) {
407+
ep_max = (ep_max > 3) ? ep_max : 3; // NCM uses endpoints 1, 2, 3
408+
}
409+
#endif
395410
return ep_max;
396411
}
397412

@@ -403,6 +418,11 @@ static uint8_t mp_usbd_get_str_max(uint8_t flags) {
403418
if ((flags & USB_BUILTIN_FLAG_MSC) && MICROPY_HW_USB_MSC) {
404419
str_max = (str_max > 2) ? str_max : 2; // MSC uses strings 1, 2
405420
}
421+
#if MICROPY_HW_NETWORK_USBNET
422+
if ((flags & USB_BUILTIN_FLAG_NCM) && MICROPY_HW_NETWORK_USBNET) {
423+
str_max = (str_max > 3) ? str_max : 3; // NCM uses strings 1, 2, 3
424+
}
425+
#endif
406426
return str_max;
407427
}
408428

@@ -481,6 +501,12 @@ static const mp_obj_usb_builtin_t builtin_msc_obj = {
481501
{&mp_type_usb_builtin}, USB_BUILTIN_FLAG_MSC
482502
};
483503

504+
#if MICROPY_HW_NETWORK_USBNET
505+
static const mp_obj_usb_builtin_t builtin_ncm_obj = {
506+
{&mp_type_usb_builtin}, USB_BUILTIN_FLAG_NCM
507+
};
508+
#endif
509+
484510
// Create default combination based on compile-time configuration
485511
#if MICROPY_HW_USB_CDC && MICROPY_HW_USB_MSC
486512
static const mp_obj_usb_builtin_t builtin_default_obj = {
@@ -524,6 +550,10 @@ static const mp_rom_map_elem_t usb_device_locals_dict_table[] = {
524550
{ MP_ROM_QSTR(MP_QSTR_BUILTIN_CDC), MP_ROM_PTR(&builtin_cdc_obj) },
525551
{ MP_ROM_QSTR(MP_QSTR_BUILTIN_MSC), MP_ROM_PTR(&builtin_msc_obj) },
526552

553+
#if MICROPY_HW_NETWORK_USBNET
554+
{ MP_ROM_QSTR(MP_QSTR_BUILTIN_NCM), MP_ROM_PTR(&builtin_ncm_obj) },
555+
#endif
556+
527557
// Legacy combination constant for backward compatibility
528558
#if MICROPY_HW_USB_CDC && MICROPY_HW_USB_MSC
529559
{ MP_ROM_QSTR(MP_QSTR_BUILTIN_CDC_MSC), MP_ROM_PTR(&builtin_cdc_msc_obj) },
@@ -542,6 +572,10 @@ static const mp_rom_map_elem_t usb_device_locals_dict_table[] = {
542572
{ MP_ROM_QSTR(MP_QSTR_BUILTIN_CDC), MP_ROM_PTR(&builtin_cdc_obj) },
543573
{ MP_ROM_QSTR(MP_QSTR_BUILTIN_MSC), MP_ROM_PTR(&builtin_msc_obj) },
544574

575+
#if MICROPY_HW_NETWORK_USBNET
576+
{ MP_ROM_QSTR(MP_QSTR_BUILTIN_NCM), MP_ROM_PTR(&builtin_ncm_obj) },
577+
#endif
578+
545579
// Legacy combination constant for backward compatibility
546580
#if MICROPY_HW_USB_CDC && MICROPY_HW_USB_MSC
547581
{ MP_ROM_QSTR(MP_QSTR_BUILTIN_CDC_MSC), MP_ROM_PTR(&builtin_cdc_msc_obj) },
@@ -594,6 +628,10 @@ static void usb_device_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
594628
flags = USB_BUILTIN_FLAG_CDC;
595629
} else if (dest[1] == MP_OBJ_FROM_PTR(&builtin_msc_obj)) {
596630
flags = USB_BUILTIN_FLAG_MSC;
631+
#if MICROPY_HW_NETWORK_USBNET
632+
} else if (dest[1] == MP_OBJ_FROM_PTR(&builtin_ncm_obj)) {
633+
flags = USB_BUILTIN_FLAG_NCM;
634+
#endif
597635
#if MICROPY_HW_USB_CDC && MICROPY_HW_USB_MSC
598636
} else if (dest[1] == MP_OBJ_FROM_PTR(&builtin_cdc_msc_obj)) {
599637
flags = USB_BUILTIN_FLAG_CDC | USB_BUILTIN_FLAG_MSC;

shared/tinyusb/mp_usbd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ void mp_usbd_hex_str(char *out_str, const uint8_t *bytes, size_t bytes_len);
6060
typedef struct {
6161
bool cdc_enabled;
6262
bool msc_enabled;
63+
bool ncm_enabled;
6364
} mp_usbd_class_state_t;
6465

6566
// Global class enable state

shared/tinyusb/mp_usbd_descriptor.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,17 +64,32 @@ void mp_usbd_init_class_state(void) {
6464
// In runtime mode, only CDC enabled by default
6565
mp_usbd_class_state.cdc_enabled = (CFG_TUD_CDC == 1);
6666
mp_usbd_class_state.msc_enabled = false;
67+
mp_usbd_class_state.ncm_enabled = false;
6768
#else
6869
// In static mode, enable all compiled classes
6970
mp_usbd_class_state.cdc_enabled = (CFG_TUD_CDC == 1);
7071
mp_usbd_class_state.msc_enabled = (CFG_TUD_MSC == 1);
72+
mp_usbd_class_state.ncm_enabled = (CFG_TUD_NCM == 1);
7173
#endif
7274
}
7375

7476
// Update class state based on bitfield flags
7577
void mp_usbd_update_class_state(uint8_t flags) {
78+
#if MICROPY_HW_NETWORK_USBNET
79+
bool prev_ncm_enabled = mp_usbd_class_state.ncm_enabled;
80+
#endif
81+
7682
mp_usbd_class_state.cdc_enabled = (flags & USB_BUILTIN_FLAG_CDC) && (CFG_TUD_CDC == 1);
7783
mp_usbd_class_state.msc_enabled = (flags & USB_BUILTIN_FLAG_MSC) && (CFG_TUD_MSC == 1);
84+
mp_usbd_class_state.ncm_enabled = (flags & USB_BUILTIN_FLAG_NCM) && (CFG_TUD_NCM == 1);
85+
86+
// If NCM is being disabled and it was active, clean it up
87+
#if MICROPY_HW_NETWORK_USBNET
88+
if (prev_ncm_enabled && !mp_usbd_class_state.ncm_enabled) {
89+
extern void usbnet_deinit(void);
90+
usbnet_deinit();
91+
}
92+
#endif
7893
}
7994

8095
// Functions to generate descriptors from flags (for new bitfield-based system)
@@ -87,6 +102,9 @@ size_t mp_usbd_get_descriptor_cfg_len_from_flags(uint8_t flags) {
87102
if ((flags & USB_BUILTIN_FLAG_MSC) && CFG_TUD_MSC) {
88103
len += TUD_MSC_DESC_LEN;
89104
}
105+
if ((flags & USB_BUILTIN_FLAG_NCM) && CFG_TUD_NCM) {
106+
len += TUD_CDC_NCM_DESC_LEN;
107+
}
90108

91109
return len;
92110
}
@@ -100,6 +118,9 @@ static uint8_t mp_usbd_get_interface_count_from_flags(uint8_t flags) {
100118
if ((flags & USB_BUILTIN_FLAG_MSC) && CFG_TUD_MSC) {
101119
count += 1;
102120
}
121+
if ((flags & USB_BUILTIN_FLAG_NCM) && CFG_TUD_NCM) {
122+
count += 2; // NCM uses 2 interfaces (control + data)
123+
}
103124

104125
return count;
105126
}
@@ -148,6 +169,17 @@ static const uint8_t *mp_usbd_generate_desc_cfg_unified(uint8_t flags, uint8_t *
148169
}
149170
#endif
150171

172+
#if CFG_TUD_NCM
173+
if (flags & USB_BUILTIN_FLAG_NCM) {
174+
const uint8_t ncm_desc[] = {
175+
TUD_CDC_NCM_DESCRIPTOR(itf_num, USBD_STR_NET, USBD_STR_NET_MAC, USBD_NET_EP_CMD, 64, USBD_NET_EP_OUT, USBD_NET_EP_IN, USBD_NET_IN_OUT_MAX_SIZE, CFG_TUD_NET_MTU)
176+
};
177+
memcpy(desc, ncm_desc, sizeof(ncm_desc));
178+
desc += sizeof(ncm_desc);
179+
itf_num += 2; // NCM uses 2 interfaces (control + data)
180+
}
181+
#endif
182+
151183
return buffer;
152184
}
153185

@@ -170,6 +202,9 @@ size_t mp_usbd_get_descriptor_cfg_len(void) {
170202
if (mp_usbd_class_state.msc_enabled && CFG_TUD_MSC) {
171203
len += TUD_MSC_DESC_LEN;
172204
}
205+
if (mp_usbd_class_state.ncm_enabled && CFG_TUD_NCM) {
206+
len += TUD_CDC_NCM_DESC_LEN;
207+
}
173208

174209
return len;
175210
}
@@ -188,6 +223,10 @@ static const uint8_t mp_usbd_builtin_desc_cfg_max[MP_USBD_BUILTIN_DESC_CFG_LEN]
188223
#if CFG_TUD_MSC
189224
TUD_MSC_DESCRIPTOR(USBD_ITF_MSC, USBD_STR_MSC, USBD_MSC_EP_OUT, USBD_MSC_EP_IN, USBD_MSC_IN_OUT_MAX_SIZE),
190225
#endif
226+
#if CFG_TUD_NCM
227+
// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
228+
TUD_CDC_NCM_DESCRIPTOR(USBD_ITF_NET, USBD_STR_NET, USBD_STR_NET_MAC, USBD_NET_EP_CMD, 64, USBD_NET_EP_OUT, USBD_NET_EP_IN, USBD_NET_IN_OUT_MAX_SIZE, CFG_TUD_NET_MTU),
229+
#endif
191230
};
192231
#endif
193232

@@ -204,6 +243,9 @@ static uint8_t mp_usbd_class_state_to_flags(void) {
204243
if (mp_usbd_class_state.msc_enabled) {
205244
flags |= USB_BUILTIN_FLAG_MSC;
206245
}
246+
if (mp_usbd_class_state.ncm_enabled) {
247+
flags |= USB_BUILTIN_FLAG_NCM;
248+
}
207249
return flags;
208250
}
209251

0 commit comments

Comments
 (0)