mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-03 02:27:48 +00:00
USB CDC-ACM UART Rx/Tx functioning for baseline target (Teensy 4.0/4.1)
This commit is contained in:
@@ -105,9 +105,8 @@ func init() {
|
||||
var (
|
||||
// USBCDC is a legacy class being retained here as temporary wrapper.
|
||||
// See godoc comments on type USBCDC struct definition for details.
|
||||
USBCDC0 = USBCDC{
|
||||
port: 0, // USB_OTG1 (Micro-B port on Teensy 4.0)
|
||||
buff: NewRingBuffer(),
|
||||
UART0 = USBCDC{
|
||||
port: 0, // USB_OTG1 (Micro-B port on Teensy 4.0/4.1)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
// +build mimxrt1062
|
||||
|
||||
// Compatibility wrapper for legacy type USBCDC, which provides USB CDC-ACM
|
||||
// device class emulation for serial UART communication.
|
||||
// This functionality is being replaced by a platform-agnostic type usb.UART in
|
||||
// package "machine/usb".
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
@@ -18,7 +13,6 @@ import (
|
||||
// be removed and usb.UART should be used directly instead.
|
||||
type USBCDC struct {
|
||||
port uint8
|
||||
buff *RingBuffer
|
||||
uart usb2.UART
|
||||
}
|
||||
|
||||
@@ -27,3 +21,29 @@ type USBCDC struct {
|
||||
func (cdc *USBCDC) Configure(config UARTConfig) {
|
||||
cdc.uart.Configure(usb2.UARTConfig{BaudRate: config.BaudRate})
|
||||
}
|
||||
|
||||
// Buffered returns the number of bytes currently stored in the RX buffer.
|
||||
func (cdc USBCDC) Buffered() int {
|
||||
return cdc.uart.Buffered()
|
||||
}
|
||||
|
||||
// ReadByte reads a single byte from the RX buffer.
|
||||
// If there is no data in the buffer, returns an error.
|
||||
func (cdc USBCDC) ReadByte() (byte, error) {
|
||||
return cdc.uart.ReadByte()
|
||||
}
|
||||
|
||||
// Read from the RX buffer.
|
||||
func (cdc USBCDC) Read(data []byte) (n int, err error) {
|
||||
return cdc.uart.Read(data)
|
||||
}
|
||||
|
||||
// WriteByte writes a single byte of data to the UART interface.
|
||||
func (cdc USBCDC) WriteByte(c byte) error {
|
||||
return cdc.uart.WriteByte(c)
|
||||
}
|
||||
|
||||
// Write data to the UART.
|
||||
func (cdc USBCDC) Write(data []byte) (n int, err error) {
|
||||
return cdc.uart.Write(data)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package usb2
|
||||
import "unsafe"
|
||||
|
||||
type dcd interface {
|
||||
class() class
|
||||
init() status
|
||||
enable(enable bool) status
|
||||
critical(enter bool) status
|
||||
|
||||
+241
-152
@@ -22,10 +22,10 @@ const dcdInterruptPriority = 3
|
||||
|
||||
// deviceController implements USB device controller driver (dcd) interface.
|
||||
type deviceController struct {
|
||||
core *core // Parent USB core this instance is attached to
|
||||
port int // USB port index
|
||||
class class // USB device class
|
||||
id int // deviceControllerInstance index
|
||||
core *core // Parent USB core this instance is attached to
|
||||
port int // USB port index
|
||||
cc class // USB device class
|
||||
id int // deviceControllerInstance index
|
||||
|
||||
bus *nxp.USB_Type
|
||||
phy *nxp.USBPHY_Type
|
||||
@@ -37,8 +37,6 @@ type deviceController struct {
|
||||
stat *dcdEndpoint // endpoint 0 Rx ("out" direction)
|
||||
ctrl *dcdEndpoint // endpoint 0 Tx ("in" direction)
|
||||
|
||||
acm *descCDCACMClass
|
||||
|
||||
timerInterrupt [2]func()
|
||||
controlNotify uint32
|
||||
endpointNotify uint32
|
||||
@@ -84,7 +82,7 @@ func initDCD(port int, class class) (dcd, status) {
|
||||
// Initialize device controller.
|
||||
deviceControllerInstance[i].core = &coreInstance[port]
|
||||
deviceControllerInstance[i].port = port
|
||||
deviceControllerInstance[i].class = class
|
||||
deviceControllerInstance[i].cc = class
|
||||
deviceControllerInstance[i].id = i
|
||||
switch port {
|
||||
case 0:
|
||||
@@ -105,17 +103,14 @@ func initDCD(port int, class class) (dcd, status) {
|
||||
//coreInstance[1].dc.interrupt()
|
||||
})
|
||||
}
|
||||
switch class.id {
|
||||
case classDeviceCDCACM:
|
||||
deviceControllerInstance[i].acm = &descCDCACM[class.config-1]
|
||||
default:
|
||||
}
|
||||
return &deviceControllerInstance[i], statusOK
|
||||
}
|
||||
}
|
||||
return nil, statusBusy // No free device controller instances available.
|
||||
}
|
||||
|
||||
func (dc *deviceController) class() class { return dc.cc }
|
||||
|
||||
func (dc *deviceController) init() status {
|
||||
// reset the controller
|
||||
dc.phy.CTRL_SET.Set(nxp.USBPHY_CTRL_SFTRST)
|
||||
@@ -277,7 +272,7 @@ func (dc *deviceController) interrupt() {
|
||||
dc.bus.ENDPTFLUSH.Set(0xFFFFFFFF)
|
||||
// if dc.bus.PORTSC1.HasBits(nxp.USB_PORTSC1_PR) {
|
||||
// }
|
||||
switch dc.class.id {
|
||||
switch dc.cc.id {
|
||||
case classDeviceCDCACM:
|
||||
// TBD: reset CDC-ACM UART?
|
||||
default:
|
||||
@@ -431,21 +426,21 @@ func (dc *deviceController) control(setup dcdSetup) {
|
||||
|
||||
// SET CONFIGURATION (0x09):
|
||||
case descRequestStandardSetConfiguration:
|
||||
dc.class.config = int(setup.wValue)
|
||||
if 0 == dc.class.config || dc.class.config > dcdCount {
|
||||
dc.cc.config = int(setup.wValue)
|
||||
if 0 == dc.cc.config || dc.cc.config > dcdCount {
|
||||
// Use default if invalid index received
|
||||
dc.class.config = 1
|
||||
dc.cc.config = 1
|
||||
}
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch dc.class.id {
|
||||
switch dc.cc.id {
|
||||
|
||||
// CDC-ACM (single)
|
||||
case classDeviceCDCACM:
|
||||
dc.bus.ENDPTCTRL2.Set(descCDCACMConfigAttrStatus) // Status Tx
|
||||
dc.bus.ENDPTCTRL3.Set(descCDCACMConfigAttrDataRx) // Bulk data Rx
|
||||
dc.bus.ENDPTCTRL4.Set(descCDCACMConfigAttrDataTx) // Bulk data Tx
|
||||
dc.serialConfigure()
|
||||
dc.uartConfigure()
|
||||
dc.controlReceive(dcdPointerNil, 0, false)
|
||||
|
||||
default:
|
||||
@@ -478,7 +473,7 @@ func (dc *deviceController) control(setup dcdSetup) {
|
||||
|
||||
// GET CONFIGURATION (0x08):
|
||||
case descRequestStandardGetConfiguration:
|
||||
dc.controlReply[0] = uint8(dc.class.config)
|
||||
dc.controlReply[0] = uint8(dc.cc.config)
|
||||
dc.controlTransmit(
|
||||
uintptr(unsafe.Pointer(&dc.controlReply[0])), 1, false)
|
||||
return
|
||||
@@ -585,7 +580,7 @@ func (dc *deviceController) control(setup dcdSetup) {
|
||||
case descCDCRequestSetLineCoding:
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch dc.class.id {
|
||||
switch dc.cc.id {
|
||||
|
||||
// CDC-ACM (single)
|
||||
case classDeviceCDCACM:
|
||||
@@ -593,7 +588,7 @@ func (dc *deviceController) control(setup dcdSetup) {
|
||||
if descCDCACMCodingSize == setup.wLength {
|
||||
dc.setup = setup
|
||||
dc.controlReceive(
|
||||
uintptr(unsafe.Pointer(&descCDCACM[dc.class.config-1].cx[0])),
|
||||
uintptr(unsafe.Pointer(&descCDCACM[dc.cc.config-1].cx[0])),
|
||||
descCDCACMCodingSize, true)
|
||||
return
|
||||
}
|
||||
@@ -606,7 +601,7 @@ func (dc *deviceController) control(setup dcdSetup) {
|
||||
case descCDCRequestSetControlLineState:
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch dc.class.id {
|
||||
switch dc.cc.id {
|
||||
|
||||
// CDC-ACM (single)
|
||||
case classDeviceCDCACM:
|
||||
@@ -616,9 +611,11 @@ func (dc *deviceController) control(setup dcdSetup) {
|
||||
|
||||
// Control/status interface:
|
||||
case descCDCACMInterfaceCtrl:
|
||||
acm := &descCDCACM[dc.class.config-1]
|
||||
acm.cticks = ticks()
|
||||
acm.rtsdtr = uint8(setup.wValue)
|
||||
// acm := &descCDCACM[dc.cc.config-1]
|
||||
// update our emulated UART terminal status
|
||||
// acm.lineActive = ticks()
|
||||
// acm.lineCoding.dtr = 0 != setup.wValue&0x01
|
||||
// acm.lineCoding.rts = 0 != setup.wValue&0x02
|
||||
dc.controlReceive(dcdPointerNil, 0, false)
|
||||
return
|
||||
|
||||
@@ -634,7 +631,7 @@ func (dc *deviceController) control(setup dcdSetup) {
|
||||
case descCDCRequestSendBreak:
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch dc.class.id {
|
||||
switch dc.cc.id {
|
||||
|
||||
// CDC-ACM (single)
|
||||
case classDeviceCDCACM:
|
||||
@@ -666,9 +663,9 @@ func (dc *deviceController) control(setup dcdSetup) {
|
||||
//go:inline
|
||||
func (dc *deviceController) controlTransfers() (dat, ack *dcdTransfer) {
|
||||
// control endpoint is device class-specific
|
||||
switch dc.class.id {
|
||||
switch dc.cc.id {
|
||||
case classDeviceCDCACM:
|
||||
return descCDCACM[dc.class.config-1].cd, descCDCACM[dc.class.config-1].ad
|
||||
return descCDCACM[dc.cc.config-1].cd, descCDCACM[dc.cc.config-1].ad
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
@@ -677,11 +674,11 @@ func (dc *deviceController) controlTransfers() (dat, ack *dcdTransfer) {
|
||||
func (dc *deviceController) controlDescriptor(setup dcdSetup) {
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch dc.class.id {
|
||||
switch dc.cc.id {
|
||||
|
||||
// CDC-ACM (single)
|
||||
case classDeviceCDCACM:
|
||||
acm := &descCDCACM[dc.class.config-1]
|
||||
acm := &descCDCACM[dc.cc.config-1]
|
||||
dxn := uint8(0)
|
||||
|
||||
// Determine the type of descriptor being requested
|
||||
@@ -699,64 +696,61 @@ func (dc *deviceController) controlDescriptor(setup dcdSetup) {
|
||||
|
||||
// String descriptor
|
||||
case descTypeString:
|
||||
var sd []uint8
|
||||
if 0 == uint8(setup.wValue) {
|
||||
// setup.wIndex contains an arbitrary index referring to a collection of
|
||||
// strings in some given language. This (setup.wValue = 0x03[00]) is a
|
||||
// request from the host to determine what that language is. Subsequent
|
||||
// string requests will populate setup.wIndex with the language code
|
||||
// returned here in this string descriptor.
|
||||
sd = acm.locale[int(setup.wIndex)].descriptor[setup.wValue&0xFF][:]
|
||||
} else {
|
||||
// setup.wIndex now contains a language code, which we notified in a
|
||||
// previous request (above: setup.wValue = 0x03[00]). We need to locate
|
||||
// the set of strings whose language matches the language code given in
|
||||
// this new setup.wIndex.
|
||||
for code := range acm.locale {
|
||||
if setup.wIndex == acm.locale[code].language {
|
||||
// Found language, check if string descriptor at given index exists
|
||||
if int(setup.wValue&0xFF) < len(acm.locale[code].descriptor) {
|
||||
// Found language with a string defined at the requested index.
|
||||
// Construct a string descriptor dynamically to be transmitted on
|
||||
// the serial bus.
|
||||
|
||||
var s []uint8
|
||||
// TODO: Add fields to deviceController and design an API that
|
||||
// allows the user to define and provide these strings
|
||||
// prior to deviceController initialization.
|
||||
// For now, we just always use the descCommon* strings.
|
||||
var s string
|
||||
switch uint8(setup.wValue) {
|
||||
case 1:
|
||||
s = descCommonManufacturer
|
||||
case 2:
|
||||
s = descCommonProduct
|
||||
case 3:
|
||||
s = descCommonSerialNumber
|
||||
}
|
||||
|
||||
// Determine the string index requested
|
||||
switch uint8(setup.wValue) {
|
||||
|
||||
// Language
|
||||
case 0:
|
||||
if int(setup.wIndex) < len(acm.locstr) {
|
||||
s = acm.locstr[setup.wIndex].index[0][:]
|
||||
}
|
||||
|
||||
// Manufacturer
|
||||
case 1:
|
||||
for i := range acm.locstr {
|
||||
if acm.locstr[i].language == setup.wIndex {
|
||||
s = acm.locstr[i].index[1][:]
|
||||
// copy manufacturer string to uint8 buffer as UTF-16
|
||||
for n, c := range descManufacturer {
|
||||
s[2+2*n] = uint8(c)
|
||||
s[3+2*n] = 0
|
||||
// Copy string into string descriptor as UTF-16
|
||||
sd = acm.locale[code].descriptor[int(setup.wValue&0xFF)][:]
|
||||
sd[0] = uint8(2 + 2*len(s))
|
||||
sd[1] = descTypeString
|
||||
for n, c := range s {
|
||||
if 2+2*n >= len(sd) {
|
||||
break
|
||||
}
|
||||
sd[2+2*n] = uint8(c)
|
||||
sd[3+2*n] = 0
|
||||
}
|
||||
break // end search for matching language code
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Product
|
||||
case 2:
|
||||
for i := range acm.locstr {
|
||||
if acm.locstr[i].language == setup.wIndex {
|
||||
s = acm.locstr[i].index[2][:]
|
||||
// copy product string to uint8 buffer as UTF-16
|
||||
for n, c := range descProduct {
|
||||
s[2+2*n] = uint8(c)
|
||||
s[3+2*n] = 0
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Serial number
|
||||
case 3:
|
||||
for i := range acm.locstr {
|
||||
if acm.locstr[i].language == setup.wIndex {
|
||||
s = acm.locstr[i].index[3][:]
|
||||
// copy serial number string to uint8 buffer as UTF-16
|
||||
for n, c := range descSerialNumber {
|
||||
s[2+2*n] = uint8(c)
|
||||
s[3+2*n] = 0
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if nil != s && len(s) > 0 {
|
||||
dxn = s[0]
|
||||
_ = copy(acm.dx[:], s[:dxn])
|
||||
// Copy string descriptor into descriptor transmit buffer
|
||||
if nil != sd && len(sd) >= 0 {
|
||||
dxn = sd[0]
|
||||
_ = copy(acm.dx[:], sd[:dxn])
|
||||
}
|
||||
|
||||
// Device qualification descriptor
|
||||
@@ -766,7 +760,10 @@ func (dc *deviceController) controlDescriptor(setup dcdSetup) {
|
||||
|
||||
// Alternate configuration descriptor
|
||||
case descTypeOtherSpeedConfiguration:
|
||||
// TODO
|
||||
|
||||
default:
|
||||
// Unhandled descriptor type
|
||||
}
|
||||
|
||||
if dxn > 0 {
|
||||
@@ -884,23 +881,19 @@ func (dc *deviceController) controlComplete() {
|
||||
case descCDCRequestSetLineCoding:
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch dc.class.id {
|
||||
switch dc.cc.id {
|
||||
|
||||
// CDC-ACM (single)
|
||||
case classDeviceCDCACM:
|
||||
acm := &descCDCACM[dc.cc.config-1]
|
||||
|
||||
// Determine interface destination of the notification
|
||||
switch dc.setup.wIndex {
|
||||
|
||||
// Control/status interface:
|
||||
case descCDCACMInterfaceCtrl:
|
||||
|
||||
_ = copy(descCDCACM[dc.class.config-1].coding[:],
|
||||
// descCDCACM[dc.class.config-1].costat[:descCDCACMCodingSize])
|
||||
descCDCACM[dc.class.config-1].cx[:])
|
||||
var coding descCDCACMLineCoding
|
||||
if coding.parse(descCDCACM[dc.class.config-1].coding[:]) {
|
||||
if 134 == coding.baud {
|
||||
if acm.lineCoding.parse(acm.cx[:]) {
|
||||
if 134 == acm.lineCoding.baud {
|
||||
dc.enableSofInterrupts(true, descCDCACMInterfaceCount)
|
||||
dc.rebootTimer = 80
|
||||
}
|
||||
@@ -925,46 +918,6 @@ func (dc *deviceController) controlComplete() {
|
||||
default:
|
||||
// Unhandled request type
|
||||
}
|
||||
|
||||
// // determine interface destination of the notification
|
||||
// switch dc.setup.wIndex {
|
||||
// // communication/control interface:
|
||||
// case descCDCACMInterfaceCtrl:
|
||||
// // switch on the type and recepient of the request
|
||||
// switch dc.setup.bmRequestType &
|
||||
// (descRequestTypeTypeMsk | descRequestTypeRecipientMsk) {
|
||||
// // interface class request:
|
||||
// case descRequestTypeRecipientInterface | descRequestTypeTypeClass:
|
||||
// // identify which request was received
|
||||
// switch dc.setup.bRequest {
|
||||
// // CDC_SET_LINE_CODING:
|
||||
// case descCDCRequestSetLineCoding:
|
||||
// // respond according to our device class
|
||||
// switch dc.class.id {
|
||||
// // CDC-ACM (single)
|
||||
// case classDeviceCDCACM:
|
||||
// _ = copy(descCDCACM[dc.class.config-1].coding[:],
|
||||
// // descCDCACM[dc.class.config-1].costat[:descCDCACMCodingSize])
|
||||
// descCDCACM[dc.class.config-1].cx[:])
|
||||
// var coding descCDCACMLineCoding
|
||||
// if coding.parse(descCDCACM[dc.class.config-1].coding[:]) {
|
||||
// if 134 == coding.baud {
|
||||
// dc.enableSofInterrupts(true, descCDCACMInterfaceCount)
|
||||
// dc.rebootTimer = 80
|
||||
// }
|
||||
// }
|
||||
// default:
|
||||
// // unhandled device class
|
||||
// }
|
||||
// default:
|
||||
// // unhandled request
|
||||
// }
|
||||
// default:
|
||||
// // unhandled request type or recepient
|
||||
// }
|
||||
// default:
|
||||
// // unhandled interface
|
||||
// }
|
||||
}
|
||||
|
||||
// endpointQueueHead returns the queue head for the given endpoint address,
|
||||
@@ -972,9 +925,9 @@ func (dc *deviceController) controlComplete() {
|
||||
//go:inline
|
||||
func (dc *deviceController) endpointQueueHead(endpoint uint8) *dcdEndpoint {
|
||||
// endpoint queue head is device class-specific
|
||||
switch dc.class.id {
|
||||
switch dc.cc.id {
|
||||
case classDeviceCDCACM:
|
||||
return &descCDCACM[dc.class.config-1].qh[endpointIndex(endpoint)]
|
||||
return &descCDCACM[dc.cc.config-1].qh[endpointIndex(endpoint)]
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
@@ -1144,8 +1097,8 @@ func (dc *deviceController) timerStop(timer int) {
|
||||
}
|
||||
}
|
||||
|
||||
func (dc *deviceController) serialConfigure() {
|
||||
acm := &descCDCACM[dc.class.config-1]
|
||||
func (dc *deviceController) uartConfigure() {
|
||||
acm := &descCDCACM[dc.cc.config-1]
|
||||
switch dc.speed {
|
||||
case descDeviceSpeedHigh:
|
||||
acm.rxSize = descCDCACMDataRxHSPacketSize
|
||||
@@ -1162,22 +1115,33 @@ func (dc *deviceController) serialConfigure() {
|
||||
dc.endpointConfigureTx(descCDCACMEndpointStatus,
|
||||
acm.cxSize, false, nil)
|
||||
dc.endpointConfigureRx(descCDCACMEndpointDataRx,
|
||||
acm.rxSize, false, dc.serialNotify)
|
||||
acm.rxSize, false, dc.uartNotify)
|
||||
dc.endpointConfigureTx(descCDCACMEndpointDataTx,
|
||||
acm.txSize, true, nil)
|
||||
for i := range acm.rd {
|
||||
dc.serialReceive(uint8(i))
|
||||
dc.uartReceive(uint8(i))
|
||||
}
|
||||
dc.timerConfigure(0, 75, dc.serialFlush)
|
||||
dc.timerConfigure(0, descCDCACMTxSyncUs, dc.uartSync)
|
||||
}
|
||||
|
||||
func (dc *deviceController) serialNotify(transfer *dcdTransfer) {
|
||||
acm := &descCDCACM[dc.class.config-1]
|
||||
func (dc *deviceController) uartReceive(endpoint uint8) {
|
||||
acm := &descCDCACM[dc.cc.config-1]
|
||||
num := uint16(endpoint) & descEndptAddrNumberMsk
|
||||
buf := &acm.rx[num*descCDCACMRxSize]
|
||||
dc.irq.Disable()
|
||||
dc.transferPrepare(&acm.rd[num], buf, acm.rxSize, uint32(endpoint))
|
||||
nxp.DeleteDcache(uintptr(unsafe.Pointer(buf)), uintptr(acm.rxSize))
|
||||
dc.receive(descCDCACMEndpointDataRx, &acm.rd[num])
|
||||
dc.irq.Enable()
|
||||
}
|
||||
|
||||
func (dc *deviceController) uartNotify(transfer *dcdTransfer) {
|
||||
acm := &descCDCACM[dc.cc.config-1]
|
||||
len := acm.rxSize - (uint16(transfer.token>>16) & 0x7FFF)
|
||||
p := transfer.param
|
||||
if 0 == len {
|
||||
// zero-length packet (ZLP)
|
||||
dc.serialReceive(uint8(p))
|
||||
dc.uartReceive(uint8(p))
|
||||
} else {
|
||||
// data packet
|
||||
h := acm.rxHead
|
||||
@@ -1191,7 +1155,7 @@ func (dc *deviceController) serialNotify(transfer *dcdTransfer) {
|
||||
acm.rx[p*descCDCACMRxSize:uint16(p)*descCDCACMRxSize+len])
|
||||
acm.rxCount[q] = n + len
|
||||
acm.rxFree += len
|
||||
dc.serialReceive(uint8(p))
|
||||
dc.uartReceive(uint8(p))
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1208,23 +1172,148 @@ func (dc *deviceController) serialNotify(transfer *dcdTransfer) {
|
||||
}
|
||||
}
|
||||
|
||||
func (dc *deviceController) serialReceive(endpoint uint8) {
|
||||
ivm := arm.DisableInterrupts()
|
||||
num := uint16(endpoint) & descEndptAddrNumberMsk
|
||||
acm := &descCDCACM[dc.class.config-1]
|
||||
buf := &acm.rx[num*descCDCACMRxSize]
|
||||
dc.transferPrepare(&acm.rd[num], buf, acm.rxSize, uint32(endpoint))
|
||||
nxp.DeleteDcache(uintptr(unsafe.Pointer(buf)), uintptr(acm.rxSize))
|
||||
dc.receive(descCDCACMEndpointDataRx, &acm.rd[num])
|
||||
arm.EnableInterrupts(ivm)
|
||||
// uartFlush discards all buffered input (Rx) data.
|
||||
func (dc *deviceController) uartFlush() {
|
||||
acm := &descCDCACM[dc.cc.config-1]
|
||||
tail := acm.rxTail
|
||||
for tail != acm.rxHead {
|
||||
tail += 1
|
||||
if tail > descCDCACMRDCount {
|
||||
tail = 0
|
||||
}
|
||||
i := acm.rxQueue[tail]
|
||||
acm.rxFree -= acm.rxCount[i] - acm.rxIndex[i]
|
||||
dc.uartReceive(uint8(i))
|
||||
acm.rxTail = tail
|
||||
}
|
||||
}
|
||||
|
||||
func (dc *deviceController) serialFlush() {
|
||||
func (dc *deviceController) uartAvailable() int {
|
||||
return int(descCDCACM[dc.cc.config-1].rxFree)
|
||||
}
|
||||
|
||||
func (dc *deviceController) uartPeek() (uint8, bool) {
|
||||
acm := &descCDCACM[dc.cc.config-1]
|
||||
tail := acm.rxTail
|
||||
if tail == acm.rxHead {
|
||||
return 0, false
|
||||
}
|
||||
tail += 1
|
||||
if tail > descCDCACMRDCount {
|
||||
tail = 0
|
||||
}
|
||||
i := acm.rxQueue[tail]
|
||||
return acm.rx[i*descCDCACMRxSize+acm.rxIndex[i]], true
|
||||
}
|
||||
|
||||
func (dc *deviceController) uartReadByte() (uint8, bool) {
|
||||
b := []uint8{0}
|
||||
ok := dc.uartRead(b) > 0
|
||||
return b[0], ok
|
||||
}
|
||||
|
||||
func (dc *deviceController) uartRead(data []uint8) int {
|
||||
acm := &descCDCACM[dc.cc.config-1]
|
||||
read := uint16(0)
|
||||
size := uint16(len(data))
|
||||
tail := acm.rxTail
|
||||
dest := uint16(0)
|
||||
dc.irq.Disable()
|
||||
for read < size && tail != acm.rxHead {
|
||||
tail += 1
|
||||
if tail > descCDCACMRDCount {
|
||||
tail = 0
|
||||
}
|
||||
i := acm.rxQueue[tail]
|
||||
count := uint16(size - read)
|
||||
avail := acm.rxCount[i] - acm.rxIndex[i]
|
||||
start := i*descCDCACMRxSize + acm.rxIndex[i]
|
||||
if avail > count {
|
||||
// partially consume packet
|
||||
_ = copy(data[dest:], acm.rx[start:start+count])
|
||||
acm.rxFree -= count
|
||||
acm.rxIndex[i] += count
|
||||
read += count
|
||||
} else {
|
||||
// fully consume packet
|
||||
_ = copy(data[dest:], acm.rx[start:start+avail])
|
||||
dest += avail //* uint16(unsafe.Sizeof(&data[0]))
|
||||
read += avail
|
||||
acm.rxFree -= avail
|
||||
acm.rxTail = tail
|
||||
dc.uartReceive(uint8(i))
|
||||
}
|
||||
}
|
||||
dc.irq.Enable()
|
||||
return int(read)
|
||||
}
|
||||
|
||||
func (dc *deviceController) uartWriteByte(c uint8) bool {
|
||||
return 1 == dc.uartWrite([]uint8{c})
|
||||
}
|
||||
|
||||
func (dc *deviceController) uartWrite(data []uint8) int {
|
||||
acm := &descCDCACM[dc.cc.config-1]
|
||||
sent := 0
|
||||
size := len(data)
|
||||
for size > 0 {
|
||||
xfer := &acm.td[acm.txHead]
|
||||
wait := false
|
||||
when := int64(0)
|
||||
for 0 == acm.txFree {
|
||||
if 0 == xfer.token&0x80 {
|
||||
if 0 != xfer.token&0x68 {
|
||||
// TODO: token contains error, how to handle?
|
||||
}
|
||||
acm.txFree = descCDCACMTxSize
|
||||
acm.txPrev = false
|
||||
break
|
||||
}
|
||||
if !wait {
|
||||
wait = true
|
||||
when = ticks()
|
||||
}
|
||||
if acm.txPrev {
|
||||
return sent
|
||||
}
|
||||
if ticks()-when > descCDCACMTxTimeoutMs {
|
||||
acm.txPrev = true
|
||||
return sent
|
||||
}
|
||||
}
|
||||
buff := acm.tx[(int(acm.txHead)*descCDCACMTxSize)+
|
||||
(descCDCACMTxSize-int(acm.txFree)):]
|
||||
if size > int(acm.txFree) {
|
||||
_ = copy(buff, data[sent:sent+int(acm.txFree)])
|
||||
tx := &acm.tx[int(acm.txHead)*descCDCACMTxSize]
|
||||
dc.transferPrepare(xfer, tx, descCDCACMTxSize, 0)
|
||||
nxp.FlushDeleteDcache(uintptr(unsafe.Pointer(tx)), descCDCACMTxSize)
|
||||
dc.transmit(descCDCACMEndpointDataTx, xfer)
|
||||
acm.txHead += 1
|
||||
if acm.txHead >= descCDCACMTDCount {
|
||||
acm.txHead = 0
|
||||
}
|
||||
size -= int(acm.txFree)
|
||||
sent += int(acm.txFree)
|
||||
acm.txFree = 0
|
||||
dc.timerStop(0)
|
||||
} else {
|
||||
_ = copy(buff, data[:size])
|
||||
acm.txFree -= uint16(size)
|
||||
sent += size
|
||||
size = 0
|
||||
dc.timerOneShot(0)
|
||||
}
|
||||
}
|
||||
return sent
|
||||
}
|
||||
|
||||
func (dc *deviceController) uartSync() {
|
||||
const autoFlushTx = true
|
||||
if !autoFlushTx {
|
||||
return
|
||||
}
|
||||
acm := &descCDCACM[dc.class.config-1]
|
||||
acm := &descCDCACM[dc.cc.config-1]
|
||||
if 0 == acm.txFree {
|
||||
return
|
||||
}
|
||||
|
||||
+70
-58
@@ -4,12 +4,6 @@ const descUSBSpecVersion = uint16(0x0200) // USB 2.0
|
||||
|
||||
const descLanguageEnglish = uint16(0x0409)
|
||||
|
||||
type descIndexStrings [4][64]uint8
|
||||
type descLocalStrings struct {
|
||||
language uint16
|
||||
index descIndexStrings // UTF-16, 32-character maximum length
|
||||
}
|
||||
|
||||
// USB constants defined per specification.
|
||||
const (
|
||||
|
||||
@@ -335,55 +329,27 @@ const (
|
||||
descCDCACMConfigAttrInterrupt = descCDCACMConfigAttr | descEndptAttrSyncTypeSync
|
||||
)
|
||||
|
||||
// descCDCACM0String holds the default string descriptors for CDC-ACM[0], i.e.,
|
||||
// configuration index 1.
|
||||
var descCDCACM0String = [descCDCACMLanguageCount]descLocalStrings{
|
||||
{
|
||||
language: descLanguageEnglish,
|
||||
index: descIndexStrings{
|
||||
{ // 0: language string
|
||||
4,
|
||||
descTypeString,
|
||||
lsU8(descLanguageEnglish),
|
||||
msU8(descLanguageEnglish),
|
||||
},
|
||||
{ // 1: manufacturer
|
||||
uint8(2 + 2*len(descManufacturer)),
|
||||
descTypeString,
|
||||
},
|
||||
{ // 2: product
|
||||
uint8(2 + 2*len(descProduct)),
|
||||
descTypeString,
|
||||
},
|
||||
{ // 3: serial number
|
||||
uint8(2 + 2*len(descSerialNumber)),
|
||||
descTypeString,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// descCDCACM0Device holds the default device descriptor for CDC-ACM[0], i.e.,
|
||||
// configuration index 1.
|
||||
var descCDCACM0Device = [descLengthDevice]uint8{
|
||||
descLengthDevice, // Size of this descriptor in bytes
|
||||
descTypeDevice, // Descriptor Type
|
||||
lsU8(descUSBSpecVersion), // USB Specification Release Number in BCD (low)
|
||||
msU8(descUSBSpecVersion), // USB Specification Release Number in BCD (high)
|
||||
descCDCTypeComm, // Class code (assigned by the USB-IF).
|
||||
descCDCSubNone, // Subclass code (assigned by the USB-IF).
|
||||
descCDCProtoNone, // Protocol code (assigned by the USB-IF).
|
||||
descEndptMaxPktSize, // Maximum packet size for endpoint zero (8, 16, 32, or 64)
|
||||
lsU8(descVendorID), // Vendor ID (low) (assigned by the USB-IF)
|
||||
msU8(descVendorID), // Vendor ID (high) (assigned by the USB-IF)
|
||||
lsU8(descProductID), // Product ID (low) (assigned by the manufacturer)
|
||||
msU8(descProductID), // Product ID (high) (assigned by the manufacturer)
|
||||
lsU8(descReleaseID), // Device release number in BCD (low)
|
||||
msU8(descReleaseID), // Device release number in BCD (high)
|
||||
1, // Index of string descriptor describing manufacturer
|
||||
2, // Index of string descriptor describing product
|
||||
3, // Index of string descriptor describing the device's serial number
|
||||
descCDCACMCount, // Number of possible configurations
|
||||
descLengthDevice, // Size of this descriptor in bytes
|
||||
descTypeDevice, // Descriptor Type
|
||||
lsU8(descUSBSpecVersion), // USB Specification Release Number in BCD (low)
|
||||
msU8(descUSBSpecVersion), // USB Specification Release Number in BCD (high)
|
||||
descCDCTypeComm, // Class code (assigned by the USB-IF).
|
||||
descCDCSubNone, // Subclass code (assigned by the USB-IF).
|
||||
descCDCProtoNone, // Protocol code (assigned by the USB-IF).
|
||||
descEndptMaxPktSize, // Maximum packet size for endpoint zero (8, 16, 32, or 64)
|
||||
lsU8(descCommonVendorID), // Vendor ID (low) (assigned by the USB-IF)
|
||||
msU8(descCommonVendorID), // Vendor ID (high) (assigned by the USB-IF)
|
||||
lsU8(descCommonProductID), // Product ID (low) (assigned by the manufacturer)
|
||||
msU8(descCommonProductID), // Product ID (high) (assigned by the manufacturer)
|
||||
lsU8(descCommonReleaseID), // Device release number in BCD (low)
|
||||
msU8(descCommonReleaseID), // Device release number in BCD (high)
|
||||
1, // Index of string descriptor describing manufacturer
|
||||
2, // Index of string descriptor describing product
|
||||
3, // Index of string descriptor describing the device's serial number
|
||||
descCDCACMCount, // Number of possible configurations
|
||||
}
|
||||
|
||||
// descCDCACM0Qualif holds the default device qualification descriptor for
|
||||
@@ -497,24 +463,24 @@ var descCDCACM0Config = [descCDCACMConfigSize]uint8{
|
||||
// descCDCACMCodingSize defines the length of a CDC-ACM UART line coding buffer.
|
||||
const descCDCACMCodingSize = 7
|
||||
|
||||
// descCDCACM0Coding holds the default UART line coding for CDC-ACM[0], i.e.,
|
||||
// configuration index 1.
|
||||
var descCDCACM0Coding [descCDCACMCodingSize]uint8
|
||||
// descCDCACM0LineCoding holds the default UART line coding for CDC-ACM[0],
|
||||
// i.e., configuration index 1.
|
||||
var descCDCACM0LineCoding descCDCACMLineCoding
|
||||
|
||||
type descCDCACMLineCoding struct {
|
||||
baud uint32
|
||||
stopBits uint8
|
||||
parity uint8
|
||||
numBits uint8
|
||||
dtr bool
|
||||
rts bool
|
||||
rtsdtr uint8
|
||||
}
|
||||
|
||||
func (lc *descCDCACMLineCoding) parse(buffer []uint8) bool {
|
||||
if len(buffer) < descCDCACMCodingSize {
|
||||
return false
|
||||
}
|
||||
lc.baud = packU32(buffer)
|
||||
_ = copy(buffer[:], buffer)
|
||||
lc.baud = packU32(buffer[:])
|
||||
lc.stopBits = buffer[4]
|
||||
if 0 == lc.stopBits {
|
||||
lc.stopBits = 1
|
||||
@@ -523,3 +489,49 @@ func (lc *descCDCACMLineCoding) parse(buffer []uint8) bool {
|
||||
lc.numBits = buffer[6]
|
||||
return true
|
||||
}
|
||||
|
||||
const (
|
||||
descStringIndexCount = 4 // Language, Manufacturer, Product, Serial Number
|
||||
descStringSize = 64 // (64-2)/2 = 31 chars each (UTF-16 code points)
|
||||
// The maximum allowable string descriptor size is 255, or (255-2)/2 = 126
|
||||
// available UTF-16 code points. Considering we are allocating this storage at
|
||||
// compile-time, it seems like an awful waste of space (255*4 = ~1 KiB) just
|
||||
// to store four strings, which, in all likelihood, will not be modified by
|
||||
// anyone other than TinyGo devs; 64*4 = 256 B (i.e., 31 UTF-16 code points
|
||||
// for each string) seems a good compromise.
|
||||
)
|
||||
|
||||
type (
|
||||
// descString is the actual byte array used to hold string descriptors. The
|
||||
// first two bytes are a USB-specified header (0=length, 1=type), and the
|
||||
// remaining bytes are UTF-16 code points, ordered low byte-first. If you just
|
||||
// want to use UTF-8 (or even ASCII), you still need to reserve 2 bytes for
|
||||
// each symbol, but you can set all of their high bytes 0.
|
||||
descString [descStringSize]uint8
|
||||
// descStringIndex defines an indexed collection of string descriptors for a
|
||||
// given language.
|
||||
descStringIndex [descStringIndexCount]descString
|
||||
// descStringLanguage contains a language code and an indexed collection of
|
||||
// string descriptors encoded in that language.
|
||||
descStringLanguage struct {
|
||||
language uint16
|
||||
descriptor descStringIndex
|
||||
}
|
||||
)
|
||||
|
||||
// descCDCACM0String holds the default string descriptors for CDC-ACM[0], i.e.,
|
||||
// configuration index 1.
|
||||
var descCDCACM0String = [descCDCACMLanguageCount]descStringLanguage{
|
||||
{ // US English string descriptors
|
||||
language: descLanguageEnglish,
|
||||
descriptor: descStringIndex{
|
||||
{ // Language (index 0)
|
||||
4,
|
||||
descTypeString,
|
||||
lsU8(descLanguageEnglish),
|
||||
msU8(descLanguageEnglish),
|
||||
},
|
||||
// Actual string descriptors (index > 0) are copied into here at runtime!
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -7,13 +7,14 @@ const descCPUFrequencyHz = 600000000
|
||||
|
||||
// General USB device identification constants.
|
||||
const (
|
||||
descVendorID = 0x16C0
|
||||
descProductID = 0x0483
|
||||
descReleaseID = 0x0101
|
||||
descCommonVendorID = 0x16C0
|
||||
descCommonProductID = 0x0483
|
||||
descCommonReleaseID = 0x0101 // BCD (1.1)
|
||||
|
||||
descManufacturer = "NXP Semiconductors"
|
||||
descProduct = "TinyGo USB"
|
||||
descSerialNumber = "0000000000"
|
||||
descCommonLanguage = descLanguageEnglish
|
||||
descCommonManufacturer = "NXP Semiconductors"
|
||||
descCommonProduct = "TinyGo USB"
|
||||
descCommonSerialNumber = "1"
|
||||
)
|
||||
|
||||
// Constants for USB CDC-ACM device classes.
|
||||
@@ -31,6 +32,9 @@ const (
|
||||
|
||||
descCDCACMMaxPower = 50 // 100 mA
|
||||
|
||||
descCDCACMTxTimeoutMs = 120 // millisec
|
||||
descCDCACMTxSyncUs = 75 // microsec
|
||||
|
||||
descCDCACMStatusPacketSize = 16
|
||||
descCDCACMDataRxPacketSize = descCDCACMDataRxHSPacketSize // high-speed
|
||||
descCDCACMDataTxPacketSize = descCDCACMDataTxHSPacketSize // high-speed
|
||||
@@ -117,14 +121,13 @@ var descCDCACM0RDIdx [descCDCACMRDCount]uint16
|
||||
var descCDCACM0RDQue [descCDCACMRDCount + 1]uint16
|
||||
|
||||
type descCDCACMClass struct {
|
||||
locstr *[descCDCACMLanguageCount]descLocalStrings // string descriptors
|
||||
device *[descLengthDevice]uint8 // device descriptor
|
||||
qualif *[descLengthQualification]uint8 // device qualification descriptor
|
||||
config *[descCDCACMConfigSize]uint8 // configuration descriptor
|
||||
locale *[descCDCACMLanguageCount]descStringLanguage // string descriptors
|
||||
device *[descLengthDevice]uint8 // device descriptor
|
||||
qualif *[descLengthQualification]uint8 // device qualification descriptor
|
||||
config *[descCDCACMConfigSize]uint8 // configuration descriptor
|
||||
|
||||
coding *[descCDCACMCodingSize]uint8 // UART line coding
|
||||
cticks int64
|
||||
rtsdtr uint8
|
||||
lineCoding *descCDCACMLineCoding // UART line coding active state
|
||||
// lineActive int64 // time since last UART DTR/RTS
|
||||
|
||||
qh *[descCDCACMQHCount]dcdEndpoint // endpoint queue heads
|
||||
|
||||
@@ -144,6 +147,7 @@ type descCDCACMClass struct {
|
||||
|
||||
txHead uint8
|
||||
txFree uint16
|
||||
txPrev bool
|
||||
|
||||
rxHead uint8
|
||||
rxTail uint8
|
||||
@@ -157,14 +161,15 @@ type descCDCACMClass struct {
|
||||
// descCDCACM holds the configuration, endpoint, and transfer descriptors, along
|
||||
// with the buffers and control states, for all of the CDC-ACM (single) device
|
||||
// class configurations, ordered by configuration index (offset by -1).
|
||||
//go:align 32
|
||||
var descCDCACM = [descCDCACMCount]descCDCACMClass{
|
||||
{
|
||||
locstr: &descCDCACM0String,
|
||||
locale: &descCDCACM0String,
|
||||
device: &descCDCACM0Device,
|
||||
qualif: &descCDCACM0Qualif,
|
||||
config: &descCDCACM0Config,
|
||||
|
||||
coding: &descCDCACM0Coding,
|
||||
lineCoding: &descCDCACM0LineCoding,
|
||||
|
||||
qh: &descCDCACM0QH,
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package usb2
|
||||
|
||||
type hcd interface {
|
||||
class() class
|
||||
init() status
|
||||
enable(enable bool) status
|
||||
critical(enter bool) status
|
||||
|
||||
@@ -20,10 +20,10 @@ const hcdInterruptPriority = 3
|
||||
|
||||
// hostController implements USB host controller driver (hcd) interface.
|
||||
type hostController struct {
|
||||
core *core // Parent USB core this instance is attached to
|
||||
port int // USB port index
|
||||
class class // USB host class
|
||||
id int // hostControllerInstance index
|
||||
core *core // Parent USB core this instance is attached to
|
||||
port int // USB port index
|
||||
cc class // USB host class
|
||||
id int // hostControllerInstance index
|
||||
|
||||
bus *nxp.USB_Type
|
||||
phy *nxp.USBPHY_Type
|
||||
@@ -50,6 +50,7 @@ func initHCD(port int, class class) (hcd, status) {
|
||||
// Initialize host controller.
|
||||
hostControllerInstance[i].core = &coreInstance[port]
|
||||
hostControllerInstance[i].port = port
|
||||
hostControllerInstance[i].cc = class
|
||||
hostControllerInstance[i].id = i
|
||||
switch port {
|
||||
case 0:
|
||||
@@ -76,6 +77,8 @@ func initHCD(port int, class class) (hcd, status) {
|
||||
return nil, statusBusy // No free host controller instances available.
|
||||
}
|
||||
|
||||
func (hc *hostController) class() class { return hc.cc }
|
||||
|
||||
func (hc *hostController) init() status {
|
||||
|
||||
return statusOK
|
||||
|
||||
@@ -5,7 +5,10 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidPort = errors.New("invalid USB port")
|
||||
ErrUARTInvalidPort = errors.New("invalid USB port")
|
||||
ErrUARTInvalidCore = errors.New("invalid USB core")
|
||||
ErrUARTEmptyBuffer = errors.New("USB receive buffer empty")
|
||||
ErrUARTWriteFailed = errors.New("USB write failure")
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -24,14 +27,67 @@ type (
|
||||
func (uart *UART) Configure(config UARTConfig) error {
|
||||
|
||||
if uart.port >= CoreCount || uart.port >= dcdCount {
|
||||
return ErrInvalidPort
|
||||
return ErrUARTInvalidPort
|
||||
}
|
||||
|
||||
// verify we have a free USB port and take ownership of it
|
||||
var st status
|
||||
uart.core, st = initCore(uart.port, class{id: classDeviceCDCACM, config: 1})
|
||||
if !st.ok() {
|
||||
return ErrInvalidPort
|
||||
return ErrUARTInvalidPort
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Buffered returns the number of bytes currently stored in the RX buffer.
|
||||
func (uart UART) Buffered() int {
|
||||
dc, ok := uart.core.dc.(*deviceController)
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
return dc.uartAvailable()
|
||||
}
|
||||
|
||||
// ReadByte reads a single byte from the RX buffer.
|
||||
// If there is no data in the buffer, returns an error.
|
||||
func (uart UART) ReadByte() (byte, error) {
|
||||
dc, ok := uart.core.dc.(*deviceController)
|
||||
if !ok {
|
||||
return 0, ErrUARTInvalidCore
|
||||
}
|
||||
n, ok := dc.uartReadByte()
|
||||
if !ok {
|
||||
return 0, ErrUARTEmptyBuffer
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Read from the RX buffer.
|
||||
func (uart UART) Read(data []byte) (n int, err error) {
|
||||
dc, ok := uart.core.dc.(*deviceController)
|
||||
if !ok {
|
||||
return 0, ErrUARTInvalidCore
|
||||
}
|
||||
return dc.uartRead(data), nil
|
||||
}
|
||||
|
||||
// WriteByte writes a single byte of data to the UART interface.
|
||||
func (uart UART) WriteByte(c byte) error {
|
||||
dc, ok := uart.core.dc.(*deviceController)
|
||||
if !ok {
|
||||
return ErrUARTInvalidCore
|
||||
}
|
||||
if !dc.uartWriteByte(c) {
|
||||
return ErrUARTWriteFailed
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Write data to the UART.
|
||||
func (uart UART) Write(data []byte) (n int, err error) {
|
||||
dc, ok := uart.core.dc.(*deviceController)
|
||||
if !ok {
|
||||
return 0, ErrUARTInvalidCore
|
||||
}
|
||||
return dc.uartWrite(data), nil
|
||||
}
|
||||
|
||||
@@ -48,6 +48,13 @@ func (cl class) mode() int {
|
||||
}
|
||||
}
|
||||
|
||||
// equals returns true if and only if all fields of the given class are equal to
|
||||
// those of the receiver cl.
|
||||
//go:inline
|
||||
func (cl class) equals(class class) bool {
|
||||
return cl.id == class.id && cl.config == class.config
|
||||
}
|
||||
|
||||
// CoreCount defines the total number of USB cores to configure in device or
|
||||
// host mode.
|
||||
const CoreCount = dcdCount + hcdCount
|
||||
@@ -79,7 +86,25 @@ func initCore(port int, class class) (*core, status) {
|
||||
if port < 0 || port >= CoreCount || 0 == class.config {
|
||||
return nil, statusInvalid
|
||||
}
|
||||
|
||||
if modeIdle != coreInstance[port].mode {
|
||||
// Check if requested port is already configured as requested class. If so,
|
||||
// just return a reference to the existing core instead of an error.
|
||||
// For instance, this will allow TinyGo examples that try to reconfigure the
|
||||
// USB (CDC-ACM) UART port (which is already configured by the runtime) to
|
||||
// continue without error.
|
||||
if coreInstance[port].mode == class.mode() {
|
||||
switch class.mode() {
|
||||
case modeDevice:
|
||||
if coreInstance[port].dc.class().equals(class) {
|
||||
return &coreInstance[port], statusOK
|
||||
}
|
||||
case modeHost:
|
||||
if coreInstance[port].hc.class().equals(class) {
|
||||
return &coreInstance[port], statusOK
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, statusBusy
|
||||
}
|
||||
|
||||
|
||||
@@ -125,13 +125,12 @@ func initUART() {
|
||||
}
|
||||
|
||||
func initUSB() {
|
||||
machine.USBCDC0.Configure(machine.UARTConfig{})
|
||||
machine.UART0.Configure(machine.UARTConfig{})
|
||||
}
|
||||
|
||||
func putchar(c byte) {
|
||||
// ** TESTING: print byte to both serial UART interfaces **
|
||||
//machine.USBCDC0.WriteByte(c) // print to USB UART
|
||||
machine.UART1.WriteByte(c) // print to hardware UART
|
||||
machine.UART0.WriteByte(c) // print to USB UART
|
||||
// machine.UART1.WriteByte(c) // print to hardware UART
|
||||
}
|
||||
|
||||
func abort() {
|
||||
|
||||
Reference in New Issue
Block a user