mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-10 05:53:39 +00:00
samd21,samd51,nrf52840: move usbcdc to machine/usb/cdc (#2972)
* samd21,samd51,nrf52840: move usbcdc to machine/usb/cdc
This commit is contained in:
+65
-123
@@ -14,25 +14,25 @@ type USBDevice struct {
|
||||
|
||||
var (
|
||||
USBDev = &USBDevice{}
|
||||
USBCDC Serialer
|
||||
)
|
||||
|
||||
type Serialer interface {
|
||||
WriteByte(c byte) error
|
||||
Write(data []byte) (n int, err error)
|
||||
Configure(config UARTConfig) error
|
||||
Buffered() int
|
||||
ReadByte() (byte, error)
|
||||
}
|
||||
|
||||
var usbDescriptor = descriptorCDC
|
||||
|
||||
var (
|
||||
errUSBCDCBufferEmpty = errors.New("USB-CDC buffer empty")
|
||||
errUSBCDCWriteByteTimeout = errors.New("USB-CDC write byte timeout")
|
||||
errUSBCDCReadTimeout = errors.New("USB-CDC read timeout")
|
||||
errUSBCDCBytesRead = errors.New("USB-CDC invalid number of bytes read")
|
||||
const (
|
||||
usbDescriptorConfigCDC = 1 << iota
|
||||
usbDescriptorConfigHID
|
||||
)
|
||||
|
||||
const cdcLineInfoSize = 7
|
||||
|
||||
type cdcLineInfo struct {
|
||||
dwDTERate uint32
|
||||
bCharFormat uint8
|
||||
bParityType uint8
|
||||
bDataBits uint8
|
||||
lineState uint8
|
||||
}
|
||||
var usbDescriptorConfig uint8 = usbDescriptorConfigCDC
|
||||
|
||||
// strToUTF16LEDescriptor converts a utf8 string into a string descriptor
|
||||
// note: the following code only converts ascii characters to UTF16LE. In order
|
||||
@@ -54,22 +54,25 @@ var (
|
||||
usb_STRING_LANGUAGE = [2]uint16{(3 << 8) | (2 + 2), 0x0409} // English
|
||||
)
|
||||
|
||||
var (
|
||||
usbEndpointDescriptors [8]usbDeviceDescriptor
|
||||
const cdcLineInfoSize = 7
|
||||
|
||||
udd_ep_in_cache_buffer [7][128]uint8
|
||||
udd_ep_out_cache_buffer [7][128]uint8
|
||||
var (
|
||||
ErrUSBReadTimeout = errors.New("USB read timeout")
|
||||
ErrUSBBytesRead = errors.New("USB invalid number of bytes read")
|
||||
)
|
||||
|
||||
var (
|
||||
usbEndpointDescriptors [numberOfEndpoints]usbDeviceDescriptor
|
||||
|
||||
udd_ep_control_cache_buffer [256]uint8
|
||||
udd_ep_in_cache_buffer [7][64]uint8
|
||||
udd_ep_out_cache_buffer [7][64]uint8
|
||||
|
||||
isEndpointHalt = false
|
||||
isRemoteWakeUpEnabled = false
|
||||
endPoints = []uint32{usb_ENDPOINT_TYPE_CONTROL,
|
||||
(usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn),
|
||||
(usb_ENDPOINT_TYPE_BULK | usbEndpointOut),
|
||||
(usb_ENDPOINT_TYPE_BULK | usbEndpointIn)}
|
||||
|
||||
usbConfiguration uint8
|
||||
usbSetInterface uint8
|
||||
usbLineInfo = cdcLineInfo{115200, 0x00, 0x00, 0x08, 0x00}
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -77,6 +80,7 @@ const (
|
||||
usb_IPRODUCT = 2
|
||||
usb_ISERIAL = 3
|
||||
|
||||
usb_ENDPOINT_TYPE_DISABLE = 0xFF
|
||||
usb_ENDPOINT_TYPE_CONTROL = 0x00
|
||||
usb_ENDPOINT_TYPE_ISOCHRONOUS = 0x01
|
||||
usb_ENDPOINT_TYPE_BULK = 0x02
|
||||
@@ -95,8 +99,8 @@ const (
|
||||
usbEndpointOut = 0x00
|
||||
usbEndpointIn = 0x80
|
||||
|
||||
numberOfEndpoints = 8
|
||||
usbEndpointPacketSize = 64 // 64 for Full Speed, EPT size max is 1024
|
||||
usb_EPT_NUM = 7
|
||||
|
||||
// standard requests
|
||||
usb_GET_STATUS = 0
|
||||
@@ -123,12 +127,15 @@ const (
|
||||
usb_CONFIG_SELF_POWERED = 0xC0
|
||||
usb_CONFIG_REMOTE_WAKEUP = 0x20
|
||||
|
||||
// CDC
|
||||
// Interface
|
||||
numberOfInterfaces = 3
|
||||
usb_CDC_ACM_INTERFACE = 0 // CDC ACM
|
||||
usb_CDC_DATA_INTERFACE = 1 // CDC Data
|
||||
usb_CDC_FIRST_ENDPOINT = 1
|
||||
usb_HID_INTERFACE = 2 // HID
|
||||
|
||||
// Endpoint
|
||||
usb_CONTROL_ENDPOINT = 0
|
||||
usb_CDC_ENDPOINT_ACM = 1
|
||||
usb_CDC_ENDPOINT_OUT = 2
|
||||
usb_CDC_ENDPOINT_IN = 3
|
||||
@@ -153,27 +160,20 @@ const (
|
||||
usb_REQUEST_DEVICETOHOST_CLASS_INTERFACE = (usb_REQUEST_DEVICETOHOST | usb_REQUEST_CLASS | usb_REQUEST_INTERFACE)
|
||||
usb_REQUEST_HOSTTODEVICE_CLASS_INTERFACE = (usb_REQUEST_HOSTTODEVICE | usb_REQUEST_CLASS | usb_REQUEST_INTERFACE)
|
||||
usb_REQUEST_DEVICETOHOST_STANDARD_INTERFACE = (usb_REQUEST_DEVICETOHOST | usb_REQUEST_STANDARD | usb_REQUEST_INTERFACE)
|
||||
)
|
||||
|
||||
// CDC Class requests
|
||||
usb_CDC_SET_LINE_CODING = 0x20
|
||||
usb_CDC_GET_LINE_CODING = 0x21
|
||||
usb_CDC_SET_CONTROL_LINE_STATE = 0x22
|
||||
usb_CDC_SEND_BREAK = 0x23
|
||||
var (
|
||||
usbTxHandler [numberOfEndpoints]func()
|
||||
usbRxHandler [numberOfEndpoints]func([]byte)
|
||||
usbSetupHandler [numberOfInterfaces]func(USBSetup) bool
|
||||
|
||||
usb_CDC_V1_10 = 0x0110
|
||||
usb_CDC_COMMUNICATION_INTERFACE_CLASS = 0x02
|
||||
|
||||
usb_CDC_CALL_MANAGEMENT = 0x01
|
||||
usb_CDC_ABSTRACT_CONTROL_MODEL = 0x02
|
||||
usb_CDC_HEADER = 0x00
|
||||
usb_CDC_ABSTRACT_CONTROL_MANAGEMENT = 0x02
|
||||
usb_CDC_UNION = 0x06
|
||||
usb_CDC_CS_INTERFACE = 0x24
|
||||
usb_CDC_CS_ENDPOINT = 0x25
|
||||
usb_CDC_DATA_INTERFACE_CLASS = 0x0A
|
||||
|
||||
usb_CDC_LINESTATE_DTR = 0x01
|
||||
usb_CDC_LINESTATE_RTS = 0x02
|
||||
endPoints = []uint32{
|
||||
usb_CONTROL_ENDPOINT: usb_ENDPOINT_TYPE_CONTROL,
|
||||
usb_CDC_ENDPOINT_ACM: (usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn),
|
||||
usb_CDC_ENDPOINT_OUT: (usb_ENDPOINT_TYPE_BULK | usbEndpointOut),
|
||||
usb_CDC_ENDPOINT_IN: (usb_ENDPOINT_TYPE_BULK | usbEndpointIn),
|
||||
usb_HID_ENDPOINT_IN: (usb_ENDPOINT_TYPE_DISABLE), // Interrupt In
|
||||
}
|
||||
)
|
||||
|
||||
// usbDeviceDescBank is the USB device endpoint descriptor.
|
||||
@@ -209,73 +209,6 @@ func newUSBSetup(data []byte) USBSetup {
|
||||
return u
|
||||
}
|
||||
|
||||
// USBCDC is the serial interface that works over the USB port.
|
||||
// To implement the USBCDC interface for a board, you must declare a concrete type as follows:
|
||||
//
|
||||
// type USBCDC struct {
|
||||
// Buffer *RingBuffer
|
||||
// }
|
||||
//
|
||||
// You can also add additional members to this struct depending on your implementation,
|
||||
// but the *RingBuffer is required.
|
||||
// When you are declaring the USBCDC for your board, make sure that you also declare the
|
||||
// RingBuffer using the NewRingBuffer() function:
|
||||
//
|
||||
// USBCDC{Buffer: NewRingBuffer()}
|
||||
//
|
||||
|
||||
// Read from the RX buffer.
|
||||
func (usbcdc *USBCDC) Read(data []byte) (n int, err error) {
|
||||
// check if RX buffer is empty
|
||||
size := usbcdc.Buffered()
|
||||
if size == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Make sure we do not read more from buffer than the data slice can hold.
|
||||
if len(data) < size {
|
||||
size = len(data)
|
||||
}
|
||||
|
||||
// only read number of bytes used from buffer
|
||||
for i := 0; i < size; i++ {
|
||||
v, _ := usbcdc.ReadByte()
|
||||
data[i] = v
|
||||
}
|
||||
|
||||
return size, nil
|
||||
}
|
||||
|
||||
// Write data to the USBCDC.
|
||||
func (usbcdc *USBCDC) Write(data []byte) (n int, err error) {
|
||||
for _, v := range data {
|
||||
usbcdc.WriteByte(v)
|
||||
}
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
// ReadByte reads a single byte from the RX buffer.
|
||||
// If there is no data in the buffer, returns an error.
|
||||
func (usbcdc *USBCDC) ReadByte() (byte, error) {
|
||||
// check if RX buffer is empty
|
||||
buf, ok := usbcdc.Buffer.Get()
|
||||
if !ok {
|
||||
return 0, errUSBCDCBufferEmpty
|
||||
}
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
// Buffered returns the number of bytes currently stored in the RX buffer.
|
||||
func (usbcdc *USBCDC) Buffered() int {
|
||||
return int(usbcdc.Buffer.Used())
|
||||
}
|
||||
|
||||
// Receive handles adding data to the UART's data buffer.
|
||||
// Usually called by the IRQ handler for a machine.
|
||||
func (usbcdc *USBCDC) Receive(data byte) {
|
||||
usbcdc.Buffer.Put(data)
|
||||
}
|
||||
|
||||
// sendDescriptor creates and sends the various USB descriptor types that
|
||||
// can be requested by the host.
|
||||
func sendDescriptor(setup USBSetup) {
|
||||
@@ -285,6 +218,11 @@ func sendDescriptor(setup USBSetup) {
|
||||
return
|
||||
case usb_DEVICE_DESCRIPTOR_TYPE:
|
||||
// composite descriptor
|
||||
if (usbDescriptorConfig & usbDescriptorConfigHID) > 0 {
|
||||
usbDescriptor = descriptorCDCHID
|
||||
} else {
|
||||
usbDescriptor = descriptorCDC
|
||||
}
|
||||
usbDescriptor.Configure(usb_VID, usb_PID)
|
||||
sendUSBPacket(0, usbDescriptor.Device, setup.WLength)
|
||||
return
|
||||
@@ -402,17 +340,21 @@ func handleStandardSetup(setup USBSetup) bool {
|
||||
}
|
||||
}
|
||||
|
||||
// EnableHID enables HID. This function must be executed from the init().
|
||||
func EnableHID(callback func()) {
|
||||
usbDescriptor = descriptorCDCHID
|
||||
endPoints = []uint32{usb_ENDPOINT_TYPE_CONTROL,
|
||||
(usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn),
|
||||
(usb_ENDPOINT_TYPE_BULK | usbEndpointOut),
|
||||
(usb_ENDPOINT_TYPE_BULK | usbEndpointIn),
|
||||
(usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn)}
|
||||
|
||||
hidCallback = callback
|
||||
func EnableCDC(txHandler func(), rxHandler func([]byte), setupHandler func(USBSetup) bool) {
|
||||
usbDescriptorConfig |= usbDescriptorConfigCDC
|
||||
endPoints[usb_CDC_ENDPOINT_ACM] = (usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn)
|
||||
endPoints[usb_CDC_ENDPOINT_OUT] = (usb_ENDPOINT_TYPE_BULK | usbEndpointOut)
|
||||
endPoints[usb_CDC_ENDPOINT_IN] = (usb_ENDPOINT_TYPE_BULK | usbEndpointIn)
|
||||
usbRxHandler[usb_CDC_ENDPOINT_OUT] = rxHandler
|
||||
usbTxHandler[usb_CDC_ENDPOINT_IN] = txHandler
|
||||
usbSetupHandler[usb_CDC_ACM_INTERFACE] = setupHandler // 0x02 (Communications and CDC Control)
|
||||
usbSetupHandler[usb_CDC_DATA_INTERFACE] = nil // 0x0A (CDC-Data)
|
||||
}
|
||||
|
||||
// hidCallback is a variable that holds the callback when using HID.
|
||||
var hidCallback func()
|
||||
// EnableHID enables HID. This function must be executed from the init().
|
||||
func EnableHID(txHandler func(), rxHandler func([]byte), setupHandler func(USBSetup) bool) {
|
||||
usbDescriptorConfig |= usbDescriptorConfigHID
|
||||
endPoints[usb_HID_ENDPOINT_IN] = (usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn)
|
||||
usbTxHandler[usb_HID_ENDPOINT_IN] = txHandler
|
||||
usbSetupHandler[usb_HID_INTERFACE] = setupHandler // 0x03 (HID - Human Interface Device)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user