@@ -58,9 +58,8 @@ STATIC const mp_obj_str_t pyb_usb_hid_mouse_desc_obj = {
5858};
5959const mp_obj_tuple_t pyb_usb_hid_mouse_obj = {
6060 {& mp_type_tuple },
61- 5 ,
61+ 4 ,
6262 {
63- MP_OBJ_NEW_SMALL_INT (USBD_PID_CDC_HID ),
6463 MP_OBJ_NEW_SMALL_INT (1 ), // subclass: boot
6564 MP_OBJ_NEW_SMALL_INT (2 ), // protocol: mouse
6665 MP_OBJ_NEW_SMALL_INT (USBD_HID_MOUSE_MAX_PACKET ),
@@ -77,9 +76,8 @@ STATIC const mp_obj_str_t pyb_usb_hid_keyboard_desc_obj = {
7776};
7877const mp_obj_tuple_t pyb_usb_hid_keyboard_obj = {
7978 {& mp_type_tuple },
80- 5 ,
79+ 4 ,
8180 {
82- MP_OBJ_NEW_SMALL_INT (USBD_PID_CDC_HID ),
8381 MP_OBJ_NEW_SMALL_INT (1 ), // subclass: boot
8482 MP_OBJ_NEW_SMALL_INT (1 ), // protocol: keyboard
8583 MP_OBJ_NEW_SMALL_INT (USBD_HID_KEYBOARD_MAX_PACKET ),
@@ -94,12 +92,14 @@ void pyb_usb_init0(void) {
9492 MP_STATE_PORT (pyb_hid_report_desc ) = MP_OBJ_NULL ;
9593}
9694
97- void pyb_usb_dev_init (uint16_t pid , usb_device_mode_t mode , USBD_HID_ModeInfoTypeDef * hid_info ) {
95+ bool pyb_usb_dev_init (uint16_t vid , uint16_t pid , usb_device_mode_t mode , USBD_HID_ModeInfoTypeDef * hid_info ) {
9896#ifdef USE_DEVICE_MODE
9997 if (!(pyb_usb_flags & PYB_USB_FLAG_DEV_ENABLED )) {
10098 // only init USB once in the device's power-lifetime
101- USBD_SetPID (pid );
102- USBD_SelectMode (mode , hid_info );
99+ USBD_SetVIDPIDRelease (vid , pid , 0x0200 );
100+ if (USBD_SelectMode (mode , hid_info ) != 0 ) {
101+ return false;
102+ }
103103 USBD_Init (& hUSBDDevice , (USBD_DescriptorsTypeDef * )& USBD_Descriptors , 0 );
104104 USBD_RegisterClass (& hUSBDDevice , & USBD_CDC_MSC_HID );
105105 USBD_CDC_RegisterInterface (& hUSBDDevice , (USBD_CDC_ItfTypeDef * )& USBD_CDC_fops );
@@ -117,6 +117,8 @@ void pyb_usb_dev_init(uint16_t pid, usb_device_mode_t mode, USBD_HID_ModeInfoTyp
117117 }
118118 pyb_usb_flags |= PYB_USB_FLAG_DEV_ENABLED ;
119119#endif
120+
121+ return true;
120122}
121123
122124void pyb_usb_dev_deinit (void ) {
@@ -169,75 +171,120 @@ void usb_vcp_send_strn_cooked(const char *str, int len) {
169171// Micro Python bindings for USB
170172
171173/*
172- TODO think about how to expose the USB device. Currently we have:
173- pyb.usb_mode(None) # disable USB
174- pyb.usb_mode('CDC+MSC')
175- pyb.usb_mode('CDC+HID') # defaults to mouse
176- pyb.usb_mode('CDC+HID', pyb.hid_mouse)
177- pyb.usb_mode('CDC+HID', pyb.hid_keyboard)
178- pyb.usb_mode('CDC+HID', (pid, subclass, protocol, max_packet_len, report_desc))
179- pyb.usb_mode('host', ...)
174+ Philosophy of USB driver and Python API: pyb.usb_mode(...) configures the USB
175+ on the board. The USB itself is not an entity, rather the interfaces are, and
176+ can be accessed by creating objects, such as pyb.USB_VCP() and pyb.USB_HID().
177+
178+ We have:
179+
180+ pyb.usb_mode(None) # disable USB
181+ pyb.usb_mode('VCP') # enable with VCP interface
182+ pyb.usb_mode('VCP+MSC') # enable with VCP and MSC interfaces
183+ pyb.usb_mode('VCP+HID') # enable with VCP and HID, defaulting to mouse protocol
184+ pyb.usb_mode('VCP+HID', vid=0xf055, pid=0x9800) # specify VID and PID
185+ pyb.usb_mode('VCP+HID', hid=pyb.hid_mouse)
186+ pyb.usb_mode('VCP+HID', hid=pyb.hid_keyboard)
187+ pyb.usb_mode('VCP+HID', pid=0x1234, hid=(subclass, protocol, max_packet_len, report_desc))
188+
180189 vcp = pyb.USB_VCP() # get the VCP device for read/write
181190 hid = pyb.USB_HID() # get the HID device for write/poll
182191
183- We could use a more class based approach, like UART and others:
184- usb = pyb.USB('CDC+MSC')
185- usb = pyb.USB('CDC+HID', pyb.USB.hid_mouse)
186- usb = pyb.USB('CDC+HID', pyb.USB.hid_keyboard)
187- usb = pyb.USB('CDC+HID', (pid, subclass, protocol, max_packet_len, report_desc))
188- usb = pyb.USB('host', ...)
189- usb = pyb.USB() # get currently configured object
190- vcp = usb.VCP() # get VCP device
191- hid = usb.HID() # get HID device
192+ Possible extensions:
193+ pyb.usb_mode('host', ...)
194+ pyb.usb_mode('OTG', ...)
195+ pyb.usb_mode(..., port=2) # for second USB port
192196*/
193197
194- STATIC mp_obj_t pyb_usb_mode (mp_uint_t n_args , const mp_obj_t * args ) {
198+ STATIC mp_obj_t pyb_usb_mode (mp_uint_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
199+ static const mp_arg_t allowed_args [] = {
200+ { MP_QSTR_mode , MP_ARG_REQUIRED | MP_ARG_OBJ , {.u_obj = mp_const_none } },
201+ { MP_QSTR_vid , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = USBD_VID } },
202+ { MP_QSTR_pid , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = -1 } },
203+ { MP_QSTR_hid , MP_ARG_KW_ONLY | MP_ARG_OBJ , {.u_obj = (mp_obj_t )& pyb_usb_hid_mouse_obj } },
204+ };
205+
206+ // parse args
207+ mp_arg_val_t args [MP_ARRAY_SIZE (allowed_args )];
208+ mp_arg_parse_all (n_args , pos_args , kw_args , MP_ARRAY_SIZE (allowed_args ), allowed_args , args );
209+
210+ // record the fact that the usb has been explicitly configured
195211 pyb_usb_flags |= PYB_USB_FLAG_USB_MODE_CALLED ;
196212
197- if (args [0 ] == mp_const_none ) {
213+ // check if user wants to disable the USB
214+ if (args [0 ].u_obj == mp_const_none ) {
198215 // disable usb
199216 #if defined(USE_DEVICE_MODE )
200217 pyb_usb_dev_deinit ();
201218 #endif
202219 return mp_const_none ;
203220 }
204221
205- const char * mode_str = mp_obj_str_get_str (args [0 ]);
222+ // get mode string
223+ const char * mode_str = mp_obj_str_get_str (args [0 ].u_obj );
224+
206225#if defined(USE_HOST_MODE )
207- // USB host
226+
227+ // hardware configured for USB host mode
228+
208229 if (strcmp (mode_str , "host" ) == 0 ) {
209230 pyb_usb_host_init ();
210231 } else {
211232 goto bad_mode ;
212233 }
234+
213235#elif defined(USE_DEVICE_MODE )
214- // USB device
215- if (strcmp (mode_str , "CDC+MSC" ) == 0 ) {
216- pyb_usb_dev_init (USBD_PID_CDC_MSC , USBD_MODE_CDC_MSC , NULL );
217- } else if (strcmp (mode_str , "CDC+HID" ) == 0 ) {
218- mp_obj_t hid_info_obj = (mp_obj_t )& pyb_usb_hid_mouse_obj ; // default is mouse mode
219- if (n_args == 2 ) {
220- hid_info_obj = args [1 ];
236+
237+ // hardware configured for USB device mode
238+
239+ // get the VID, PID and USB mode
240+ // note: PID=-1 means select PID based on mode
241+ // note: we support CDC as a synonym for VCP for backward compatibility
242+ uint16_t vid = args [1 ].u_int ;
243+ uint16_t pid = args [2 ].u_int ;
244+ usb_device_mode_t mode ;
245+ if (strcmp (mode_str , "CDC+MSC" ) == 0 || strcmp (mode_str , "VCP+MSC" ) == 0 ) {
246+ if (args [2 ].u_int == -1 ) {
247+ pid = USBD_PID_CDC_MSC ;
248+ }
249+ mode = USBD_MODE_CDC_MSC ;
250+ } else if (strcmp (mode_str , "CDC+HID" ) == 0 || strcmp (mode_str , "VCP+HID" ) == 0 ) {
251+ if (args [2 ].u_int == -1 ) {
252+ pid = USBD_PID_CDC_HID ;
221253 }
254+ mode = USBD_MODE_CDC_HID ;
255+ } else if (strcmp (mode_str , "CDC" ) == 0 || strcmp (mode_str , "VCP" ) == 0 ) {
256+ if (args [2 ].u_int == -1 ) {
257+ pid = USBD_PID_CDC ;
258+ }
259+ mode = USBD_MODE_CDC ;
260+ } else {
261+ goto bad_mode ;
262+ }
263+
264+ // get hid info if user selected such a mode
265+ USBD_HID_ModeInfoTypeDef hid_info ;
266+ if (mode & USBD_MODE_HID ) {
222267 mp_obj_t * items ;
223- mp_obj_get_array_fixed_n (hid_info_obj , 5 , & items );
224- USBD_HID_ModeInfoTypeDef hid_info ;
225- mp_int_t pid = mp_obj_get_int (items [0 ]);
226- hid_info .subclass = mp_obj_get_int (items [1 ]);
227- hid_info .protocol = mp_obj_get_int (items [2 ]);
228- hid_info .max_packet_len = mp_obj_get_int (items [3 ]);
229- MP_STATE_PORT (pyb_hid_report_desc ) = items [4 ]; // need to keep a copy of this so report_desc does not get GC'd
268+ mp_obj_get_array_fixed_n (args [3 ].u_obj , 4 , & items );
269+ hid_info .subclass = mp_obj_get_int (items [0 ]);
270+ hid_info .protocol = mp_obj_get_int (items [1 ]);
271+ hid_info .max_packet_len = mp_obj_get_int (items [2 ]);
230272 mp_buffer_info_t bufinfo ;
231- mp_get_buffer_raise (items [4 ], & bufinfo , MP_BUFFER_READ );
273+ mp_get_buffer_raise (items [3 ], & bufinfo , MP_BUFFER_READ );
232274 hid_info .report_desc = bufinfo .buf ;
233275 hid_info .report_desc_len = bufinfo .len ;
234- pyb_usb_dev_init (pid , USBD_MODE_CDC_HID , & hid_info );
235- } else if (strcmp (mode_str , "CDC" ) == 0 ) {
236- pyb_usb_dev_init (USBD_PID_CDC , USBD_MODE_CDC , NULL );
237- } else {
276+
277+ // need to keep a copy of this so report_desc does not get GC'd
278+ MP_STATE_PORT (pyb_hid_report_desc ) = items [3 ];
279+ }
280+
281+ // init the USB device
282+ if (!pyb_usb_dev_init (vid , pid , mode , & hid_info )) {
238283 goto bad_mode ;
239284 }
285+
240286#else
287+ // hardware not configured for USB
241288 goto bad_mode ;
242289#endif
243290
@@ -246,7 +293,7 @@ STATIC mp_obj_t pyb_usb_mode(mp_uint_t n_args, const mp_obj_t *args) {
246293bad_mode :
247294 nlr_raise (mp_obj_new_exception_msg (& mp_type_ValueError , "bad USB mode" ));
248295}
249- MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (pyb_usb_mode_obj , 1 , 2 , pyb_usb_mode );
296+ MP_DEFINE_CONST_FUN_OBJ_KW (pyb_usb_mode_obj , 1 , pyb_usb_mode );
250297
251298/******************************************************************************/
252299// Micro Python bindings for USB VCP
@@ -274,6 +321,8 @@ STATIC mp_obj_t pyb_usb_vcp_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint
274321 // check arguments
275322 mp_arg_check_num (n_args , n_kw , 0 , 0 , false);
276323
324+ // TODO raise exception if USB is not configured for VCP
325+
277326 // return the USB VCP object
278327 return (mp_obj_t )& pyb_usb_vcp_obj ;
279328}
@@ -463,6 +512,8 @@ STATIC mp_obj_t pyb_usb_hid_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint
463512 // check arguments
464513 mp_arg_check_num (n_args , n_kw , 0 , 0 , false);
465514
515+ // TODO raise exception if USB is not configured for HID
516+
466517 // return the USB HID object
467518 return (mp_obj_t )& pyb_usb_hid_obj ;
468519}
0 commit comments