summaryrefslogtreecommitdiffstatshomepage
path: root/examples/usb/usb_simple_device.py
blob: 0b0921f547325dd1dbd993d7550bc8cfb0a96905 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# Implementation of a very simple, custom USB device in Python.  The device has an
# IN and OUT endpoint, accepts up to 64 bytes of data on the OUT endpoint, and echos
# that data back to the IN endpoint.
#
# To run, just execute this file on a device with machine.USBDevice support.  The device
# will then change to the custom USB device.
#
# For example, use `mpremote` (the `--no-follow` option starts the script running
# without waiting for a response, because there won't be a response after the device
# changes its USB mode):
#
# $ mpremote run --no-follow usb_simple_device.py
#
# Then, run the host side of the example on your PC using:
#
# $ sudo python usb_simple_host_pyusb.py
#
# You'll need to have `pyusb` installed via `pip install pyusb` to run the host PC code.
# And `sudo` is most likely needed to access the custom USB device.
#
# Once you have finished running the code, you will need to reset or unplug the USB
# device to stop it.

import machine

# VID and PID of the USB device.
VID = 0xF055
PID = 0x9999

# USB endpoints used by the device.
EP_OUT = 0x01
EP_IN = 0x81

# USB device descriptor.
_desc_dev = bytes(
    [
        0x12,  # bLength
        0x01,  # bDescriptorType: Device
        0x00,
        0x02,  # USB version: 2.00
        0xFF,  # bDeviceClass: vendor
        0x00,  # bDeviceSubClass
        0x01,  # bDeviceProtocol
        0x40,  # bMaxPacketSize
        VID & 0xFF,
        VID >> 8 & 0xFF,  # VID
        PID & 0xFF,
        PID >> 8 & 0xFF,  # PID
        0x00,
        0x01,  # bcdDevice: 1.00
        0x11,  # iManufacturer
        0x12,  # iProduct
        0x13,  # iSerialNumber
        0x01,  # bNumConfigurations: 1
    ]
)

# USB configuration descriptor.
_desc_cfg = bytes(
    [
        # Configuration Descriptor.
        0x09,  # bLength
        0x02,  # bDescriptorType: configuration
        0x20,
        0x00,  # wTotalLength: 32
        0x01,  # bNumInterfaces
        0x01,  # bConfigurationValue
        0x14,  # iConfiguration
        0xA0,  # bmAttributes
        0x96,  # bMaxPower
        # Interface Descriptor.
        0x09,  # bLength
        0x04,  # bDescriptorType: interface
        0x00,  # bInterfaceNumber
        0x00,  # bAlternateSetting
        0x02,  # bNumEndpoints
        0xFF,  # bInterfaceClass
        0x03,  # bInterfaceSubClass
        0x00,  # bInterfaceProtocol
        0x15,  # iInterface
        # Endpoint IN1.
        0x07,  # bLength
        0x05,  # bDescriptorType: endpoint
        EP_IN,  # bEndpointAddress
        0x03,  # bmAttributes: interrupt
        0x40,
        0x00,  # wMaxPacketSize
        0x0A,  # bInterval
        # Endpoint OUT1.
        0x07,  # bLength
        0x05,  # bDescriptorType: endpoint
        EP_OUT,  # bEndpointAddress
        0x02,  # bmAttributes: bulk
        0x40,
        0x00,  # wMaxPacketSize
        0x00,  # bInterval
    ]
)

# USB strings.
_desc_strs = {
    0x11: b"iManufacturer",
    0x12: b"iProduct",
    0x13: b"iSerial",
    0x14: b"iInterface",
    0x15: b"iInterface",
    0x16: b"Extra information",
}


# USB callback for when our custom USB interface is opened by the host.
def _open_itf_cb(interface_desc_view):
    print("_open_itf_cb", bytes(interface_desc_view))
    # Prepare to receive first data packet on the OUT endpoint.
    usbd.submit_xfer(EP_OUT, usbd_buf)


# USB callback for when a data transfer (IN or OUT) has completed.
def _xfer_cb(ep_addr, result, xferred_bytes):
    print("_xfer_cb", ep_addr, result, xferred_bytes)
    if ep_addr == EP_OUT:
        # Received data packet from the host, print it out.
        print(usbd_buf)
        # And then echo the data back to the host.
        usbd.submit_xfer(EP_IN, memoryview(usbd_buf)[:xferred_bytes])
    elif ep_addr == EP_IN:
        # Host got our data, prepare to receive the next data packet.
        usbd.submit_xfer(EP_OUT, usbd_buf)


# USB data buffer, for IN and OUT transfers.
usbd_buf = bytearray(64)

# Switch the USB device to our custom USB driver.
usbd = machine.USBDevice()
usbd.builtin_driver = usbd.BUILTIN_NONE
usbd.config(
    desc_dev=_desc_dev,
    desc_cfg=_desc_cfg,
    desc_strs=_desc_strs,
    open_itf_cb=_open_itf_cb,
    xfer_cb=_xfer_cb,
)
usbd.active(1)