Skip to content

Commit 55d6218

Browse files
committed
stmhal: Properly define pyb.usb_mode() semantics.
1 parent 65af7eb commit 55d6218

File tree

8 files changed

+127
-60
lines changed

8 files changed

+127
-60
lines changed

stmhal/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ int main(void) {
473473
#if defined(USE_DEVICE_MODE)
474474
// init USB device to default setting if it was not already configured
475475
if (!(pyb_usb_flags & PYB_USB_FLAG_USB_MODE_CALLED)) {
476-
pyb_usb_dev_init(USBD_PID_CDC_MSC, USBD_MODE_CDC_MSC, NULL);
476+
pyb_usb_dev_init(USBD_VID, USBD_PID_CDC_MSC, USBD_MODE_CDC_MSC, NULL);
477477
}
478478
#endif
479479

stmhal/qstrdefsport.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,6 @@ Q(enable_irq)
4141
Q(stop)
4242
Q(standby)
4343
Q(main)
44-
Q(usb_mode)
45-
Q(hid_mouse)
46-
Q(hid_keyboard)
4744
Q(sync)
4845
Q(gc)
4946
Q(repl_info)
@@ -56,7 +53,6 @@ Q(readall)
5653
Q(readline)
5754
Q(write)
5855
Q(repl_uart)
59-
Q(hid)
6056
Q(time)
6157
Q(rng)
6258
Q(SD)
@@ -96,6 +92,15 @@ Q(hashlib)
9692
Q(seek)
9793
Q(tell)
9894

95+
// for USB configuration
96+
Q(usb_mode)
97+
Q(mode)
98+
Q(vid)
99+
Q(pid)
100+
Q(hid)
101+
Q(hid_mouse)
102+
Q(hid_keyboard)
103+
99104
// for USB VCP class
100105
Q(USB_VCP)
101106
Q(setinterrupt)

stmhal/usb.c

Lines changed: 99 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,8 @@ STATIC const mp_obj_str_t pyb_usb_hid_mouse_desc_obj = {
5858
};
5959
const 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
};
7877
const 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

122124
void 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) {
246293
bad_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
}

stmhal/usb.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#define PYB_USB_FLAG_USB_MODE_CALLED (0x0002)
3131

3232
// Windows needs a different PID to distinguish different device configurations
33+
#define USBD_VID (0xf055)
3334
#define USBD_PID_CDC_MSC (0x9800)
3435
#define USBD_PID_CDC_HID (0x9801)
3536
#define USBD_PID_CDC (0x9802)
@@ -52,7 +53,7 @@ MP_DECLARE_CONST_FUN_OBJ(pyb_have_cdc_obj); // deprecated
5253
MP_DECLARE_CONST_FUN_OBJ(pyb_hid_send_report_obj); // deprecated
5354

5455
void pyb_usb_init0(void);
55-
void pyb_usb_dev_init(uint16_t pid, usb_device_mode_t mode, USBD_HID_ModeInfoTypeDef *hid_info);
56+
bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_HID_ModeInfoTypeDef *hid_info);
5657
void pyb_usb_dev_deinit(void);
5758
bool usb_vcp_is_enabled(void);
5859
void usb_vcp_set_interrupt_char(int c);

stmhal/usbd_desc.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,14 @@ __ALIGN_BEGIN static uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_EN
8080

8181
__ALIGN_BEGIN static uint8_t USBD_StrDesc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END;
8282

83-
// set the PID
84-
void USBD_SetPID(uint16_t pid) {
83+
// set the VID, PID and device release number
84+
void USBD_SetVIDPIDRelease(uint16_t vid, uint16_t pid, uint16_t device_release_num) {
85+
hUSBDDeviceDesc[8] = LOBYTE(pid);
86+
hUSBDDeviceDesc[9] = HIBYTE(pid);
8587
hUSBDDeviceDesc[10] = LOBYTE(pid);
8688
hUSBDDeviceDesc[11] = HIBYTE(pid);
89+
hUSBDDeviceDesc[12] = LOBYTE(device_release_num);
90+
hUSBDDeviceDesc[13] = HIBYTE(device_release_num);
8791
}
8892

8993
/**

stmhal/usbd_desc.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@
2626

2727
extern const USBD_DescriptorsTypeDef USBD_Descriptors;
2828

29-
void USBD_SetPID(uint16_t pid);
29+
void USBD_SetVIDPIDRelease(uint16_t vid, uint16_t pid, uint16_t device_release_num);

stmhal/usbdev/class/inc/usbd_cdc_msc_hid.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ extern const uint8_t USBD_HID_KEYBOARD_ReportDesc[USBD_HID_KEYBOARD_REPORT_DESC_
9292

9393
extern USBD_ClassTypeDef USBD_CDC_MSC_HID;
9494

95-
void USBD_SelectMode(uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info);
95+
// returns 0 on success, -1 on failure
96+
int USBD_SelectMode(uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info);
9697

9798
uint8_t USBD_CDC_RegisterInterface (USBD_HandleTypeDef *pdev, USBD_CDC_ItfTypeDef *fops);
9899
uint8_t USBD_CDC_SetTxBuffer (USBD_HandleTypeDef *pdev, uint8_t *pbuff, uint16_t length);

stmhal/usbdev/class/src/usbd_cdc_msc_hid.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ __ALIGN_BEGIN const uint8_t USBD_HID_KEYBOARD_ReportDesc[USBD_HID_KEYBOARD_REPOR
559559
0xC0 // End Collection
560560
};
561561

562-
void USBD_SelectMode(uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info) {
562+
int USBD_SelectMode(uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info) {
563563
// save mode
564564
usbd_mode = mode;
565565

@@ -593,10 +593,14 @@ void USBD_SelectMode(uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info) {
593593
hid_iface_num = HID_IFACE_NUM_WITH_MSC;
594594
break;
595595
*/
596+
597+
default:
598+
// mode not supported
599+
return -1;
596600
}
597601

602+
// configure the HID descriptor, if needed
598603
if (usbd_mode & USBD_MODE_HID) {
599-
// configure the HID descriptor
600604
hid_desc[HID_DESC_OFFSET_SUBCLASS] = hid_info->subclass;
601605
hid_desc[HID_DESC_OFFSET_PROTOCOL] = hid_info->protocol;
602606
hid_desc[HID_DESC_OFFSET_REPORT_DESC_LEN] = hid_info->report_desc_len;
@@ -605,6 +609,7 @@ void USBD_SelectMode(uint32_t mode, USBD_HID_ModeInfoTypeDef *hid_info) {
605609
hid_report_desc = hid_info->report_desc;
606610
}
607611

612+
return 0;
608613
}
609614

610615
static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) {

0 commit comments

Comments
 (0)