mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-04 19:17:47 +00:00
functioning USB-CDC class initialization
This commit is contained in:
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
uart := machine.UART0
|
||||
uart := machine.Serial
|
||||
uart.Write([]byte("Echo console enabled. Type something then press enter:\r\n"))
|
||||
|
||||
input := make([]byte, 4096)
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"machine/usb"
|
||||
)
|
||||
|
||||
// Digital pins
|
||||
const (
|
||||
// = Pin Alt. Function SERCOM PWM Timer Interrupt
|
||||
@@ -248,6 +252,8 @@ const (
|
||||
RESET_MAGIC_VALUE = 0xF01669EF // Used to reset into bootloader
|
||||
)
|
||||
|
||||
var USB = usb.UART{Port: 0}
|
||||
|
||||
// USB CDC pins
|
||||
const (
|
||||
USBCDC_HOSTEN_PIN = D77 // (PA27) host enable
|
||||
|
||||
@@ -1985,10 +1985,10 @@ type USBCDC struct {
|
||||
configured bool
|
||||
}
|
||||
|
||||
var (
|
||||
// USB is a USB CDC interface.
|
||||
USB = &USBCDC{Buffer: NewRingBuffer()}
|
||||
)
|
||||
// var (
|
||||
// // USB is a USB CDC interface.
|
||||
// USB = &USBCDC{Buffer: NewRingBuffer()}
|
||||
// )
|
||||
|
||||
const (
|
||||
usbcdcTxSizeMask uint8 = 0x3F
|
||||
@@ -2163,10 +2163,10 @@ func (usbcdc *USBCDC) Configure(config UARTConfig) {
|
||||
sam.USB_DEVICE.CTRLA.SetBits(sam.USB_DEVICE_CTRLA_ENABLE)
|
||||
|
||||
// enable IRQ at highest priority
|
||||
interrupt.New(sam.IRQ_USB_OTHER, handleUSBIRQ).Enable()
|
||||
interrupt.New(sam.IRQ_USB_SOF_HSOF, handleUSBIRQ).Enable()
|
||||
interrupt.New(sam.IRQ_USB_TRCPT0, handleUSBIRQ).Enable()
|
||||
interrupt.New(sam.IRQ_USB_TRCPT1, handleUSBIRQ).Enable()
|
||||
//interrupt.New(sam.IRQ_USB_OTHER, handleUSBIRQ).Enable()
|
||||
//interrupt.New(sam.IRQ_USB_SOF_HSOF, handleUSBIRQ).Enable()
|
||||
//interrupt.New(sam.IRQ_USB_TRCPT0, handleUSBIRQ).Enable()
|
||||
//interrupt.New(sam.IRQ_USB_TRCPT1, handleUSBIRQ).Enable()
|
||||
|
||||
usbcdc.configured = true
|
||||
}
|
||||
@@ -2240,7 +2240,7 @@ func handleUSBIRQ(interrupt.Interrupt) {
|
||||
|
||||
// Start of frame
|
||||
if (flags & sam.USB_DEVICE_INTFLAG_SOF) > 0 {
|
||||
USB.Flush()
|
||||
//USB.Flush()
|
||||
// if you want to blink LED showing traffic, this would be the place...
|
||||
}
|
||||
|
||||
@@ -2300,7 +2300,7 @@ func handleUSBIRQ(interrupt.Interrupt) {
|
||||
setEPINTFLAG(i, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
|
||||
|
||||
if i == usb_CDC_ENDPOINT_IN {
|
||||
USB.waitTxc = false
|
||||
//USB.waitTxc = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2614,7 +2614,7 @@ func handleEndpoint(ep uint32) {
|
||||
|
||||
// move to ring buffer
|
||||
for i := 0; i < count; i++ {
|
||||
USB.Receive(byte((udd_ep_out_cache_buffer[ep][i] & 0xFF)))
|
||||
//USB.Receive(byte((udd_ep_out_cache_buffer[ep][i] & 0xFF)))
|
||||
}
|
||||
|
||||
// set byte count to zero
|
||||
|
||||
@@ -5,3 +5,11 @@ package machine
|
||||
|
||||
// Serial is implemented via USB (USB-CDC).
|
||||
var Serial = USB
|
||||
|
||||
func init() {
|
||||
|
||||
// configure pins
|
||||
USBCDC_DM_PIN.Configure(PinConfig{Mode: PinCom})
|
||||
USBCDC_DP_PIN.Configure(PinConfig{Mode: PinCom})
|
||||
|
||||
}
|
||||
|
||||
+177
-79
@@ -7,7 +7,10 @@ package usb
|
||||
// implemented for each target, providing common/shared functionality and
|
||||
// defining a standard interface with which the dhw must adhere.
|
||||
|
||||
import "unsafe"
|
||||
import (
|
||||
"runtime/volatile"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// dcdCount defines the number of USB cores to configure for device mode. It is
|
||||
// computed as the sum of all declared device configuration descriptors.
|
||||
@@ -29,6 +32,8 @@ type dcd struct {
|
||||
port int // USB port index
|
||||
cc class // USB device class
|
||||
id int // USB device controller index
|
||||
|
||||
st volatile.Register8 // USB device state
|
||||
}
|
||||
|
||||
// initDCD initializes and assigns a free device controller instance to the
|
||||
@@ -54,6 +59,7 @@ func initDCD(port int, speed Speed, class class) (*dcd, status) {
|
||||
dcdInstance[i].port = port
|
||||
dcdInstance[i].cc = class
|
||||
dcdInstance[i].id = i
|
||||
dcdInstance[i].setState(dcdStateNotReady)
|
||||
return &dcdInstance[i], statusOK
|
||||
}
|
||||
}
|
||||
@@ -77,24 +83,19 @@ type dcdSetup struct {
|
||||
|
||||
// setupFrom decodes and returns a USB standard setup packet located at the
|
||||
// memory address pointed to by addr.
|
||||
func setupFrom(addr uintptr) dcdSetup {
|
||||
func setupFrom(addr uintptr) (s dcdSetup) {
|
||||
var u uint64
|
||||
for i := uintptr(0); i < 8; i++ {
|
||||
for i := uintptr(0); i < dcdSetupSize; i++ {
|
||||
u |= uint64(*(*uint8)(unsafe.Pointer(addr + i))) << (i << 3)
|
||||
}
|
||||
return dcdSetup{
|
||||
bmRequestType: uint8(u & 0xFF),
|
||||
bRequest: uint8((u & 0xFF00) >> 8),
|
||||
wValue: uint16((u & 0xFFFF0000) >> 16),
|
||||
wIndex: uint16((u & 0xFFFF00000000) >> 32),
|
||||
wLength: uint16((u & 0xFFFF000000000000) >> 48),
|
||||
}
|
||||
s.set(u)
|
||||
return
|
||||
}
|
||||
|
||||
// setup decodes and returns a USB standard setup packet stored in the given
|
||||
// byte slice b.
|
||||
func setup(b []uint8) dcdSetup {
|
||||
if len(b) >= 8 {
|
||||
if len(b) >= int(dcdSetupSize) {
|
||||
return dcdSetup{
|
||||
bmRequestType: b[0],
|
||||
bRequest: b[1],
|
||||
@@ -106,7 +107,17 @@ func setup(b []uint8) dcdSetup {
|
||||
return dcdSetup{}
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func (s *dcdSetup) set(u uint64) {
|
||||
s.bmRequestType = uint8(u & 0xFF)
|
||||
s.bRequest = uint8((u & 0xFF00) >> 8)
|
||||
s.wValue = uint16((u & 0xFFFF0000) >> 16)
|
||||
s.wIndex = uint16((u & 0xFFFF00000000) >> 32)
|
||||
s.wLength = uint16((u & 0xFFFF000000000000) >> 48)
|
||||
}
|
||||
|
||||
// pack returns the receiver USB standard setup packet s encoded as uint64.
|
||||
//go:inline
|
||||
func (s dcdSetup) pack() uint64 {
|
||||
return ((uint64(s.bmRequestType) & 0xFF) << 0) |
|
||||
((uint64(s.bRequest) & 0xFF) << 8) |
|
||||
@@ -115,6 +126,54 @@ func (s dcdSetup) pack() uint64 {
|
||||
((uint64(s.wLength) & 0xFFFF) << 48)
|
||||
}
|
||||
|
||||
// direction parses the direction bit from the bmRequestType field of a SETUP
|
||||
// packet, returning 0 for OUT (Rx) and 1 for IN (Tx) requests.
|
||||
//go:inline
|
||||
func (s dcdSetup) direction() uint8 {
|
||||
return (s.bmRequestType & descRequestTypeDirMsk) >> descRequestTypeDirPos
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func (s dcdSetup) equals(t dcdSetup) bool {
|
||||
return s.bmRequestType == t.bmRequestType && s.bRequest == t.bRequest &&
|
||||
s.wValue == t.wValue && s.wIndex == t.wIndex && s.wLength == t.wLength
|
||||
}
|
||||
|
||||
// dcdState defines the current state of the device class driver.
|
||||
type dcdState uint8
|
||||
|
||||
const (
|
||||
dcdStateNotReady dcdState = iota // initial state, before END_OF_RESET
|
||||
dcdStateDefault // after END_OF_RESET, before SET_ADDRESS
|
||||
dcdStateAddressed // after SET_ADDRESS, before SET_CONFIGURATION
|
||||
dcdStateConfigured // after SET_CONFIGURATION, operational state
|
||||
dcdStateSuspended // while operational, after SUSPEND
|
||||
)
|
||||
|
||||
func (d *dcd) state() dcdState { return dcdState(d.st.Get()) }
|
||||
|
||||
func (d *dcd) setState(state dcdState) (ok bool) {
|
||||
curr := d.state()
|
||||
switch state {
|
||||
case dcdStateNotReady:
|
||||
ok = true
|
||||
case dcdStateDefault:
|
||||
ok = curr == dcdStateNotReady || curr == dcdStateDefault
|
||||
case dcdStateAddressed:
|
||||
ok = curr == dcdStateDefault
|
||||
case dcdStateConfigured:
|
||||
ok = curr == dcdStateAddressed || curr == dcdStateConfigured || curr == dcdStateSuspended
|
||||
case dcdStateSuspended:
|
||||
ok = curr == dcdStateAddressed || curr == dcdStateConfigured || curr == dcdStateSuspended
|
||||
default:
|
||||
ok = false
|
||||
}
|
||||
if ok {
|
||||
d.st.Set(uint8(state))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// dcdEvent is used to describe virtual interrupts on the USB bus to a device
|
||||
// controller.
|
||||
//
|
||||
@@ -132,47 +191,85 @@ type dcdEvent struct {
|
||||
|
||||
// Enumerated constants for all possible USB device controller interrupt codes.
|
||||
const (
|
||||
dcdEventInvalid uint8 = iota // Invalid interrupt
|
||||
dcdEventStatusReset // USB reset received
|
||||
dcdEventStatusRun // USB controller entered run state
|
||||
dcdEventStatusSuspend // USB suspend received
|
||||
dcdEventStatusError // USB error condition detected on bus
|
||||
dcdEventControlSetup // USB setup received
|
||||
dcdEventPeripheralReady // USB PHY powered and ready to _go_
|
||||
dcdEventTransactComplete // USB transaction complete
|
||||
dcdEventTimer // USB (system) timer
|
||||
dcdEventInvalid uint8 = iota // Invalid interrupt
|
||||
dcdEventStatusReset // USB RESET received
|
||||
dcdEventStatusResume // USB RESUME condition
|
||||
dcdEventStatusSuspend // USB SUSPEND received
|
||||
dcdEventStatusError // USB error condition detected on bus
|
||||
dcdEventDeviceReady // USB PHY powered and ready to _go_
|
||||
dcdEventDeviceAddress // USB device SET_ADDRESS complete
|
||||
dcdEventDeviceConfiguration // USB device SET_CONFIGURATION complete
|
||||
dcdEventControlSetup // USB SETUP received
|
||||
dcdEventControlComplete // USB control request complete
|
||||
dcdEventTransferComplete // USB data transfer complete
|
||||
dcdEventTimer // USB (system) timer
|
||||
)
|
||||
|
||||
func (d *dcd) event(ev dcdEvent) {
|
||||
|
||||
switch ev.id {
|
||||
case dcdEventInvalid:
|
||||
|
||||
case dcdEventStatusReset:
|
||||
d.endpointMask = 0
|
||||
d.setState(dcdStateNotReady)
|
||||
|
||||
case dcdEventPeripheralReady:
|
||||
// Configure and enable control endpoint 0
|
||||
d.endpointEnable(0, true, 0)
|
||||
case dcdEventStatusResume:
|
||||
d.setState(dcdStateConfigured)
|
||||
|
||||
case dcdEventStatusRun:
|
||||
case dcdEventStatusSuspend:
|
||||
case dcdEventStatusError:
|
||||
case dcdEventControlSetup:
|
||||
// On control endpoint 0 setup events, the ev.setup field will be defined
|
||||
d.stage = d.controlSetup(ev.setup)
|
||||
switch d.stage {
|
||||
case dcdStageSetup:
|
||||
case dcdStageDataIn:
|
||||
case dcdStageDataOut:
|
||||
case dcdStageStatusIn:
|
||||
case dcdStageStatusOut:
|
||||
case dcdStageStall:
|
||||
d.controlStall()
|
||||
d.setState(dcdStateSuspended)
|
||||
|
||||
case dcdEventDeviceReady:
|
||||
if d.setState(dcdStateDefault) {
|
||||
// Configure and enable control endpoint 0
|
||||
d.endpointEnable(0, true, 0)
|
||||
}
|
||||
|
||||
case dcdEventTransactComplete:
|
||||
case dcdEventTimer:
|
||||
case dcdEventDeviceAddress:
|
||||
// -- ** IMPORTANT ** --
|
||||
// dcdEventDeviceAddress must be triggered by the target driver, because
|
||||
// different MCUs require setting the device address at different times
|
||||
// during the enumeration process.
|
||||
d.setState(dcdStateAddressed)
|
||||
|
||||
case dcdEventDeviceConfiguration:
|
||||
d.setState(dcdStateConfigured)
|
||||
|
||||
case dcdEventControlSetup:
|
||||
// On control endpoint 0 setup events, the ev.setup field will be defined.
|
||||
// We overwrite the receiver's setup field, leaving it unmodified throughout
|
||||
// all transactions of a control transfer. It is only cleared once the
|
||||
// completion event dcdEventControlComplete has been called and finished
|
||||
// processing, or if its initial processing fails due to error.
|
||||
d.setup = ev.setup
|
||||
d.stage = d.controlSetup(ev.setup)
|
||||
switch d.stage {
|
||||
case dcdStageDataIn, dcdStageDataOut:
|
||||
// TBD: control endpoint data transfer
|
||||
|
||||
case dcdStageStatusIn, dcdStageStatusOut:
|
||||
// TBD: control endpoint status transfer
|
||||
|
||||
case dcdStageStall:
|
||||
d.controlStall(true, ev.setup.direction())
|
||||
|
||||
case dcdStageSetup:
|
||||
fallthrough
|
||||
default:
|
||||
// TBD: no stage transition occurred
|
||||
}
|
||||
|
||||
case dcdEventControlComplete:
|
||||
d.controlComplete()
|
||||
// clear the active SETUP packet once the control transfer completes.
|
||||
d.setup = dcdSetup{}
|
||||
|
||||
case dcdEventTransferComplete:
|
||||
// TBD: data endpoint transfer complete
|
||||
|
||||
case dcdEventInvalid, dcdEventStatusError, dcdEventTimer:
|
||||
fallthrough
|
||||
default:
|
||||
// TBD: unhandled events
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,9 +289,6 @@ const (
|
||||
// controlSetup handles setup messages on control endpoint 0.
|
||||
func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
|
||||
// Reset endpoint 0 notify mask
|
||||
d.controlMask = 0
|
||||
|
||||
// First, switch on the type of request (standard, class, or vendor)
|
||||
switch sup.bmRequestType & descRequestTypeTypeMsk {
|
||||
|
||||
@@ -215,7 +309,7 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
case descRequestStandardSetAddress:
|
||||
d.setDeviceAddress(sup.wValue)
|
||||
d.controlReceive(uintptr(0), 0, false)
|
||||
return dcdStageSetup
|
||||
return dcdStageStatusOut
|
||||
|
||||
// SET CONFIGURATION (0x09):
|
||||
case descRequestStandardSetConfiguration:
|
||||
@@ -224,6 +318,7 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
// Use default if invalid index received
|
||||
d.cc.config = 1
|
||||
}
|
||||
d.event(dcdEvent{id: dcdEventDeviceConfiguration})
|
||||
|
||||
// Respond based on our device class configuration
|
||||
switch d.cc.id {
|
||||
@@ -244,7 +339,7 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
default:
|
||||
// Unhandled device class
|
||||
}
|
||||
return dcdStageSetup
|
||||
return dcdStageStatusOut
|
||||
|
||||
default:
|
||||
// Unhandled request
|
||||
@@ -258,11 +353,10 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
|
||||
// GET STATUS (0x00):
|
||||
case descRequestStandardGetStatus:
|
||||
d.controlReply[0] = 0
|
||||
d.controlReply[1] = 0
|
||||
d.controlTransmit(
|
||||
uintptr(unsafe.Pointer(&d.controlReply[0])), 2, false)
|
||||
return dcdStageSetup
|
||||
d.controlStatusBuffer([]uint8{0, 0}),
|
||||
2, false)
|
||||
return dcdStageDataIn
|
||||
|
||||
// GET DESCRIPTOR (0x06):
|
||||
case descRequestStandardGetDescriptor:
|
||||
@@ -273,12 +367,12 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
// CDC-ACM (single)
|
||||
case classDeviceCDCACM:
|
||||
d.controlDescriptorCDCACM(sup)
|
||||
return dcdStageSetup
|
||||
return dcdStageDataIn
|
||||
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
d.controlDescriptorHID(sup)
|
||||
return dcdStageSetup
|
||||
return dcdStageDataIn
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
@@ -286,10 +380,12 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
|
||||
// GET CONFIGURATION (0x08):
|
||||
case descRequestStandardGetConfiguration:
|
||||
d.controlReply[0] = uint8(d.cc.config)
|
||||
d.controlTransmit(
|
||||
uintptr(unsafe.Pointer(&d.controlReply[0])), 1, false)
|
||||
return dcdStageSetup
|
||||
d.controlStatusBuffer([]uint8{
|
||||
uint8(d.cc.config),
|
||||
}),
|
||||
1, false)
|
||||
return dcdStageDataIn
|
||||
|
||||
default:
|
||||
// Unhandled request
|
||||
@@ -310,12 +406,12 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
// CDC-ACM (single)
|
||||
case classDeviceCDCACM:
|
||||
d.controlDescriptorCDCACM(sup)
|
||||
return dcdStageSetup
|
||||
return dcdStageDataIn
|
||||
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
d.controlDescriptorHID(sup)
|
||||
return dcdStageSetup
|
||||
return dcdStageDataIn
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
@@ -330,7 +426,7 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
d.controlDescriptorHID(sup)
|
||||
return dcdStageSetup
|
||||
return dcdStageDataIn
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
@@ -350,13 +446,13 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
case descRequestStandardClearFeature:
|
||||
d.endpointClearFeature(uint8(sup.wIndex))
|
||||
d.controlReceive(uintptr(0), 0, false)
|
||||
return dcdStageSetup
|
||||
return dcdStageStatusOut
|
||||
|
||||
// SET FEATURE (0x03):
|
||||
case descRequestStandardSetFeature:
|
||||
d.endpointSetFeature(uint8(sup.wIndex))
|
||||
d.controlReceive(uintptr(0), 0, false)
|
||||
return dcdStageSetup
|
||||
return dcdStageStatusOut
|
||||
|
||||
default:
|
||||
// Unhandled request
|
||||
@@ -371,11 +467,13 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
// GET STATUS (0x00):
|
||||
case descRequestStandardGetStatus:
|
||||
status := d.endpointStatus(uint8(sup.wIndex))
|
||||
d.controlReply[0] = uint8(status)
|
||||
d.controlReply[1] = uint8(status >> 8)
|
||||
d.controlTransmit(
|
||||
uintptr(unsafe.Pointer(&d.controlReply[0])), 2, false)
|
||||
return dcdStageSetup
|
||||
d.controlStatusBuffer([]uint8{
|
||||
uint8(status),
|
||||
uint8(status >> 8),
|
||||
}),
|
||||
2, false)
|
||||
return dcdStageDataIn
|
||||
|
||||
default:
|
||||
// Unhandled request
|
||||
@@ -407,14 +505,14 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
// CDC-ACM (single)
|
||||
case classDeviceCDCACM:
|
||||
// line coding must contain exactly 7 bytes
|
||||
if descCDCACMCodingSize == sup.wLength {
|
||||
if uint16(descCDCACMCodingSize) == sup.wLength {
|
||||
d.setup = sup
|
||||
d.controlReceive(
|
||||
uintptr(unsafe.Pointer(&descCDCACM[d.cc.config-1].cx[0])),
|
||||
descCDCACMCodingSize, true)
|
||||
uint32(descCDCACMCodingSize), true)
|
||||
// CDC Line Coding packet receipt handling occurs in method
|
||||
// controlComplete().
|
||||
return dcdStageSetup
|
||||
return dcdStageDataOut
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -438,7 +536,7 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
// DTR is bit 0 (mask 0x01), RTS is bit 1 (mask 0x02)
|
||||
d.uartSetLineState(0 != sup.wValue&0x01, 0 != sup.wValue&0x02)
|
||||
d.controlReceive(uintptr(0), 0, false)
|
||||
return dcdStageSetup
|
||||
return dcdStageStatusOut
|
||||
|
||||
default:
|
||||
// Unhandled device interface
|
||||
@@ -457,7 +555,7 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
// CDC-ACM (single)
|
||||
case classDeviceCDCACM:
|
||||
d.controlReceive(uintptr(0), 0, false)
|
||||
return dcdStageSetup
|
||||
return dcdStageStatusOut
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
@@ -471,13 +569,13 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
if sup.wLength <= descHIDCxSize {
|
||||
if sup.wLength <= descHIDSxSize {
|
||||
d.setup = sup
|
||||
descHID[d.cc.config-1].cx[0] = 0xE9
|
||||
d.controlReceive(
|
||||
uintptr(unsafe.Pointer(&descHID[d.cc.config-1].cx[0])),
|
||||
uint32(sup.wLength), true)
|
||||
return dcdStageSetup
|
||||
return dcdStageDataOut
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -493,9 +591,11 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
// HID
|
||||
case classDeviceHID:
|
||||
idleRate := sup.wValue >> 8
|
||||
// TBD: do we need to handle this request? wIndex contains the target
|
||||
// interface of the request.
|
||||
_ = idleRate
|
||||
d.controlReceive(uintptr(0), 0, false)
|
||||
return dcdStageSetup
|
||||
return dcdStageStatusOut
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
@@ -521,12 +621,13 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
case classDeviceHID:
|
||||
reportType := uint8(sup.wValue >> 8)
|
||||
reportID := uint8(sup.wValue)
|
||||
// TBD: do we need to handle this request? wIndex contains the target
|
||||
// interface of the request.
|
||||
_, _ = reportType, reportID
|
||||
d.controlReply[0] = 0
|
||||
d.controlReply[1] = 0
|
||||
d.controlTransmit(
|
||||
uintptr(unsafe.Pointer(&d.controlReply[0])), 2, false)
|
||||
return dcdStageSetup
|
||||
d.controlStatusBuffer([]uint8{0, 0}),
|
||||
2, false)
|
||||
return dcdStageDataIn
|
||||
|
||||
default:
|
||||
// Unhandled device class
|
||||
@@ -551,10 +652,7 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
||||
}
|
||||
|
||||
// controlComplete handles the setup completion of control endpoint 0.
|
||||
func (d *dcd) controlComplete(status uint32) {
|
||||
|
||||
// Reset endpoint 0 notify mask
|
||||
d.controlMask = 0
|
||||
func (d *dcd) controlComplete() {
|
||||
|
||||
// First, switch on the type of request (standard, class, or vendor)
|
||||
switch d.setup.bmRequestType & descRequestTypeTypeMsk {
|
||||
|
||||
+18
-5
@@ -1,8 +1,10 @@
|
||||
package usb
|
||||
|
||||
import "unsafe"
|
||||
|
||||
const descUSBSpecVersion = uint16(0x0200) // USB 2.0
|
||||
|
||||
const descLanguageEnglish = uint16(0x0409)
|
||||
const descLanguageEnglish = uint16(0x0409) // (US) English
|
||||
|
||||
// USB constants defined per specification.
|
||||
const (
|
||||
@@ -135,6 +137,11 @@ const (
|
||||
descDeviceCapExtAttrBESLPos = 2
|
||||
)
|
||||
|
||||
const (
|
||||
descDirOut = descRequestTypeDirOut >> descRequestTypeDirPos
|
||||
descDirIn = descRequestTypeDirIn >> descRequestTypeDirPos
|
||||
)
|
||||
|
||||
// device returns the enumerated device descriptor value, defined per USB
|
||||
// specification, for the receiver Speed s.
|
||||
func (s Speed) device() uint32 {
|
||||
@@ -153,7 +160,7 @@ func (s Speed) device() uint32 {
|
||||
}
|
||||
|
||||
const (
|
||||
// Attributes of all endpoint descriptor configurations.
|
||||
// Common attributes for all endpoint descriptor configurations.
|
||||
descEndptConfigAttr = descConfigAttrD7Msk | // Bit 7: reserved (1)
|
||||
(0 << descConfigAttrSelfPoweredPos) | // Bit 6: self-powered
|
||||
(0 << descConfigAttrRemoteWakeupPos) | // Bit 5: remote wakeup
|
||||
@@ -161,8 +168,8 @@ const (
|
||||
|
||||
descEndptConfigAttrRxPos = 0
|
||||
descEndptConfigAttrTxPos = 16
|
||||
descEndptConfigAttrRxMsk = (descEndptConfigAttr | descEndptAttrSyncTypeMsk) << descEndptConfigAttrRxPos
|
||||
descEndptConfigAttrTxMsk = (descEndptConfigAttr | descEndptAttrSyncTypeMsk) << descEndptConfigAttrTxPos
|
||||
descEndptConfigAttrRxMsk = (descEndptAttrSyncTypeMsk | descEndptConfigAttr) << descEndptConfigAttrRxPos
|
||||
descEndptConfigAttrTxMsk = (descEndptAttrSyncTypeMsk | descEndptConfigAttr) << descEndptConfigAttrTxPos
|
||||
|
||||
descEndptConfigAttrRxUnused = 0x02 << descEndptConfigAttrRxPos
|
||||
descEndptConfigAttrTxUnused = 0x02 << descEndptConfigAttrTxPos
|
||||
@@ -419,8 +426,11 @@ const (
|
||||
// for each string) seems a good compromise.
|
||||
)
|
||||
|
||||
// descEndpointInvalid represents an invalid endpoint address.
|
||||
const descEndpointInvalid = ^uint8(descEndptAddrNumberMsk | descEndptAddrDirectionMsk)
|
||||
|
||||
// descCDCACMCodingSize defines the length of a CDC-ACM UART line coding buffer.
|
||||
const descCDCACMCodingSize = 7
|
||||
const descCDCACMCodingSize = unsafe.Sizeof(descCDCACMLineCoding{})
|
||||
|
||||
// descCDCACMLineCoding represents an emulated UART's line configuration.
|
||||
type descCDCACMLineCoding struct {
|
||||
@@ -455,6 +465,9 @@ const (
|
||||
type descCDCACMClass struct {
|
||||
*descCDCACMClassData // Target-defined, class-specific data
|
||||
|
||||
line descCDCACMLineCoding
|
||||
term struct{ dtr, rts bool }
|
||||
|
||||
locale *[descCDCACMLanguageCount]descStringLanguage // string descriptors
|
||||
device *[descLengthDevice]uint8 // device descriptor
|
||||
qualif *[descLengthQualification]uint8 // device qualification descriptor
|
||||
|
||||
@@ -41,7 +41,7 @@ const (
|
||||
descBankOut = 0 // descriptor bank 0 holds OUT endpoints
|
||||
descBankIn = 1 // descriptor bank 1 holds IN endpoints
|
||||
|
||||
descControlPacketSize = 16
|
||||
descControlPacketSize = 64
|
||||
)
|
||||
|
||||
// Constants for USB CDC-ACM device classes.
|
||||
@@ -64,7 +64,8 @@ const (
|
||||
// | than the data payload specified by PCKSIZE.SIZE minus two, both CRC
|
||||
// | data bytes are written to the data buffer.
|
||||
// Thus, we need to allocate 2 extra bytes for control endpoint 0 Rx (OUT).
|
||||
descCDCACMCxSize = 8 + 2
|
||||
descCDCACMSxSize = 8 + 2
|
||||
descCDCACMCxSize = descControlPacketSize
|
||||
|
||||
// CDC-ACM Data Buffers
|
||||
|
||||
@@ -85,7 +86,7 @@ const (
|
||||
// CDC-ACM Endpoint Configurations for Full-Speed Device
|
||||
|
||||
descCDCACMStatusFSInterval = 5 // Status
|
||||
descCDCACMStatusFSPacketSize = 16 // (full-speed)
|
||||
descCDCACMStatusFSPacketSize = 64 // (full-speed)
|
||||
|
||||
descCDCACMDataRxFSPacketSize = 64 // Data Rx (full-speed)
|
||||
descCDCACMDataTxFSPacketSize = 64 // Data Tx (full-speed)
|
||||
@@ -115,7 +116,8 @@ const (
|
||||
// | than the data payload specified by PCKSIZE.SIZE minus two, both CRC
|
||||
// | data bytes are written to the data buffer.
|
||||
// Thus, we need to allocate 2 extra bytes for control endpoint 0 Rx (OUT).
|
||||
descHIDCxSize = 8 + 2
|
||||
descHIDSxSize = 8 + 2
|
||||
descHIDCxSize = descControlPacketSize
|
||||
|
||||
// HID Serial Buffers
|
||||
|
||||
@@ -192,10 +194,15 @@ const (
|
||||
// DMA controller the buffer and transfer properties for each endpoint, for the
|
||||
// default CDC-ACM (single) device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descCDCACM0ED [descCDCACMEDCount]dhwEndptAddrDesc
|
||||
var descCDCACM0ED [descCDCACMEDCount]dhwEPAddrDesc
|
||||
|
||||
// descCDCACM0Cx is the buffer for control/status data received on endpoint 0 of
|
||||
// the default CDC-ACM (single) device class configuration (index 1).
|
||||
// descCDCACM0Sx is the receive (Rx) buffer for setup packets on control endpoint
|
||||
// 0 of the default CDC-ACM (single) device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descCDCACM0Sx [descCDCACMSxSize]uint8
|
||||
|
||||
// descCDCACM0Cx is the transmit (Tx) buffer for control/status packets on control
|
||||
// endpoint 0 of the default CDC-ACM (single) device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descCDCACM0Cx [descCDCACMCxSize]uint8
|
||||
|
||||
@@ -227,9 +234,10 @@ type descCDCACMClassData struct {
|
||||
|
||||
// CDC-ACM Control Buffers
|
||||
|
||||
ed *[descCDCACMEDCount]dhwEndptAddrDesc // endpoint descriptors
|
||||
ed *[descCDCACMEDCount]dhwEPAddrDesc // endpoint descriptors
|
||||
|
||||
cx *[descCDCACMCxSize]uint8 // control endpoint 0 Rx/Tx transfer buffer
|
||||
sx *[descCDCACMSxSize]uint8 // control endpoint 0 Rx (OUT) setup packets
|
||||
cx *[descCDCACMCxSize]uint8 // control endpoint 0 Tx (IN) control/status packets
|
||||
dx *[descCDCACMConfigSize]uint8 // control endpoint 0 Tx (IN) descriptor transfer buffer
|
||||
|
||||
// CDC-ACM Data Buffers
|
||||
@@ -254,6 +262,7 @@ var descCDCACMData = [dcdCount]descCDCACMClassData{
|
||||
|
||||
ed: &descCDCACM0ED,
|
||||
|
||||
sx: &descCDCACM0Sx,
|
||||
cx: &descCDCACM0Cx,
|
||||
dx: &descCDCACM0Dx,
|
||||
|
||||
@@ -272,10 +281,15 @@ var descCDCACMData = [dcdCount]descCDCACMClassData{
|
||||
// DMA controller the buffer and transfer properties for each endpoint, for the
|
||||
// default HID device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descHID0ED [descHIDEDCount]dhwEndptAddrDesc
|
||||
var descHID0ED [descHIDEDCount]dhwEPAddrDesc
|
||||
|
||||
// descHID0Cx is the buffer for control/status data received on endpoint 0 of
|
||||
// the default HID device class configuration (index 1).
|
||||
// descHID0Sx is the receive (Rx) buffer for setup packets on control endpoint 0
|
||||
// of the default HID device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descHID0Sx [descHIDSxSize]uint8
|
||||
|
||||
// descHID0Cx is the transmit (Tx) buffer for control/status packets on control
|
||||
// endpoint 0 of the default CDC-ACM (single) device class configuration (index 1).
|
||||
//go:align 32
|
||||
var descHID0Cx [descHIDCxSize]uint8
|
||||
|
||||
@@ -339,9 +353,10 @@ type descHIDClassData struct {
|
||||
|
||||
// HID Control Buffers
|
||||
|
||||
ed *[descHIDEDCount]dhwEndptAddrDesc // endpoint descriptors
|
||||
ed *[descHIDEDCount]dhwEPAddrDesc // endpoint descriptors
|
||||
|
||||
cx *[descHIDCxSize]uint8 // control endpoint 0 Rx/Tx transfer buffer
|
||||
sx *[descHIDSxSize]uint8 // control endpoint 0 Rx (OUT) setup packets
|
||||
cx *[descHIDCxSize]uint8 // control endpoint 0 Tx (IN) control/status packets
|
||||
dx *[descHIDConfigSize]uint8 // control endpoint 0 Tx (IN) descriptor transfer buffer
|
||||
|
||||
// HID Serial Buffers
|
||||
@@ -391,6 +406,7 @@ var descHIDData = [dcdCount]descHIDClassData{
|
||||
|
||||
ed: &descHID0ED,
|
||||
|
||||
sx: &descHID0Sx,
|
||||
cx: &descHID0Cx,
|
||||
dx: &descHID0Dx,
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build mimxrt1062
|
||||
// +build mimxrt1062
|
||||
|
||||
package usb
|
||||
|
||||
+1064
-384
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,4 @@
|
||||
//go:build mimxrt1062
|
||||
// +build mimxrt1062
|
||||
|
||||
package usb
|
||||
@@ -236,6 +237,8 @@ func (d *dhw) interrupt() {
|
||||
// wait for flush to complete
|
||||
for d.bus.ENDPTFLUSH.HasBits(0x00010001) {
|
||||
}
|
||||
// Reset notify mask for control endpoint 0
|
||||
d.controlMask = 0
|
||||
// Notify device controller driver
|
||||
d.event(dcdEvent{
|
||||
id: dcdEventControlSetup,
|
||||
@@ -248,7 +251,11 @@ func (d *dhw) interrupt() {
|
||||
if 0 != completeStatus {
|
||||
d.bus.ENDPTCOMPLETE.Set(completeStatus)
|
||||
if 0 != completeStatus&d.controlMask {
|
||||
d.controlComplete(completeStatus)
|
||||
// Clear notify mask for control endpoint 0
|
||||
d.controlMask = 0
|
||||
// Notify device controller driver, which invokes any appropriate
|
||||
// callback(s) for the current device class configuration.
|
||||
d.controlComplete()
|
||||
}
|
||||
completeStatus &= d.endpointMask
|
||||
if 0 != completeStatus {
|
||||
@@ -289,6 +296,7 @@ func (d *dhw) interrupt() {
|
||||
}
|
||||
d.bus.ENDPTFLUSH.Set(0xFFFFFFFF)
|
||||
d.event(dcdEvent{id: dcdEventStatusReset})
|
||||
d.endpointMask = 0
|
||||
}
|
||||
|
||||
// General Purpose Timer Interrupt 0(GPTINT0) - R/WC
|
||||
@@ -375,6 +383,7 @@ func (d *dhw) setDeviceAddress(addr uint16) {
|
||||
d.bus.DEVICEADDR.Set(nxp.USB_DEVICEADDR_USBADRA |
|
||||
((uint32(addr) << nxp.USB_DEVICEADDR_USBADR_Pos) &
|
||||
nxp.USB_DEVICEADDR_USBADR_Msk))
|
||||
d.event(dcdEvent{id: dcdEventDeviceAddress})
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -383,8 +392,8 @@ func (d *dhw) setDeviceAddress(addr uint16) {
|
||||
|
||||
// controlStall stalls a transfer on control endpoint 0. To stall a transfer on
|
||||
// any other endpoint, use method endpointStall().
|
||||
func (d *dhw) controlStall() {
|
||||
d.endpointStall(0)
|
||||
func (d *dhw) controlStall(stall bool) {
|
||||
d.endpointStall(0, stall)
|
||||
}
|
||||
|
||||
// controlReceive receives (Rx, OUT) data on control endpoint 0.
|
||||
@@ -554,7 +563,7 @@ func (d *dhw) endpointStatus(endpoint uint8) uint16 {
|
||||
}
|
||||
|
||||
// endpointStall stalls a transfer on the given endpoint.
|
||||
func (d *dhw) endpointStall(endpoint uint8) {
|
||||
func (d *dhw) endpointStall(endpoint uint8, stall bool) {
|
||||
// RXS and TXS bits at same position in all endpoint control registers.
|
||||
d.endpointControlRegister(endpoint).SetBits(
|
||||
nxp.USB_ENDPTCTRL0_RXS | nxp.USB_ENDPTCTRL0_TXS,
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
package usb
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"runtime/volatile"
|
||||
)
|
||||
|
||||
const QueueSize = 8
|
||||
|
||||
type Queue struct {
|
||||
fifo [QueueSize]uint8
|
||||
tail volatile.Register32
|
||||
head volatile.Register32
|
||||
}
|
||||
|
||||
var (
|
||||
ErrReadBuffer = errors.New("cannot copy into read buffer")
|
||||
ErrWriteBuffer = errors.New("cannot copy from write buffer")
|
||||
ErrQueueEmpty = errors.New("data queue empty") // Read Error
|
||||
ErrQueueFull = errors.New("data queue full") // Write error
|
||||
)
|
||||
|
||||
// Reset discards all buffered data.
|
||||
//go:inline
|
||||
func (q *Queue) Reset() {
|
||||
for i := range q.fifo {
|
||||
q.fifo[i] = 0
|
||||
}
|
||||
q.tail.Set(0)
|
||||
q.head.Set(0)
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func (q *Queue) Len() int {
|
||||
return int(q.tail.Get() - q.head.Get())
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func (q *Queue) Cap() int {
|
||||
return cap(q.fifo)
|
||||
}
|
||||
|
||||
func (q *Queue) Read(data []uint8) (int, error) {
|
||||
|
||||
less := uint32(len(data))
|
||||
if less == 0 {
|
||||
return 0, ErrReadBuffer
|
||||
} // nothing to copy into
|
||||
|
||||
head := q.head.Get()
|
||||
used := q.tail.Get() - head
|
||||
|
||||
if used == 0 {
|
||||
return 0, ErrQueueEmpty
|
||||
} // empty queue
|
||||
|
||||
if less > used {
|
||||
less = used
|
||||
} // only get from used space
|
||||
|
||||
for i := uint32(0); i < less; i++ {
|
||||
data[i] = q.fifo[head%QueueSize]
|
||||
head++
|
||||
}
|
||||
q.head.Set(head)
|
||||
|
||||
return int(less), nil
|
||||
}
|
||||
|
||||
func (q *Queue) Write(data []uint8) (int, error) {
|
||||
|
||||
more := uint32(len(data))
|
||||
if more == 0 {
|
||||
return 0, ErrWriteBuffer
|
||||
} // nothing to copy from
|
||||
|
||||
tail := q.tail.Get()
|
||||
used := tail - q.head.Get()
|
||||
|
||||
if used == QueueSize {
|
||||
return 0, ErrQueueFull
|
||||
} // full queue
|
||||
|
||||
if used+more > QueueSize {
|
||||
more = QueueSize - used
|
||||
} // only put to unused space
|
||||
|
||||
for i := uint32(0); i < more; i++ {
|
||||
q.fifo[tail%QueueSize] = data[i]
|
||||
tail++
|
||||
}
|
||||
q.tail.Set(tail)
|
||||
|
||||
return int(more), nil
|
||||
}
|
||||
|
||||
func (q *Queue) Deq() (uint8, bool) {
|
||||
|
||||
tail := q.head.Get()
|
||||
if tail == q.tail.Get() {
|
||||
return 0, false
|
||||
} // empty queue
|
||||
|
||||
data := q.fifo[tail%QueueSize]
|
||||
q.head.Set(tail + 1)
|
||||
|
||||
return data, true
|
||||
}
|
||||
|
||||
func (q *Queue) Front() (uint8, bool) {
|
||||
|
||||
tail := q.head.Get()
|
||||
if tail == q.tail.Get() {
|
||||
return 0, false
|
||||
} // empty queue
|
||||
|
||||
return q.fifo[tail%QueueSize], true
|
||||
}
|
||||
|
||||
func (q *Queue) Enq(data uint8) bool {
|
||||
|
||||
head := q.tail.Get()
|
||||
if head-q.head.Get() == QueueSize {
|
||||
return false
|
||||
} // full queue
|
||||
|
||||
q.fifo[head%QueueSize] = data
|
||||
q.tail.Set(head + 1)
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -37,14 +37,18 @@ func (uart *UART) Configure(config UARTConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uart *UART) Ready() bool {
|
||||
return uart.core.dc.uartReady()
|
||||
}
|
||||
|
||||
// Buffered returns the number of bytes currently stored in the RX buffer.
|
||||
func (uart UART) Buffered() int {
|
||||
func (uart *UART) Buffered() int {
|
||||
return uart.core.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) {
|
||||
func (uart *UART) ReadByte() (byte, error) {
|
||||
n, ok := uart.core.dc.uartReadByte()
|
||||
if !ok {
|
||||
return 0, ErrUARTEmptyBuffer
|
||||
@@ -53,12 +57,12 @@ func (uart UART) ReadByte() (byte, error) {
|
||||
}
|
||||
|
||||
// Read from the RX buffer.
|
||||
func (uart UART) Read(data []byte) (n int, err error) {
|
||||
func (uart *UART) Read(data []byte) (n int, err error) {
|
||||
return uart.core.dc.uartRead(data), nil
|
||||
}
|
||||
|
||||
// WriteByte writes a single byte of data to the UART interface.
|
||||
func (uart UART) WriteByte(c byte) error {
|
||||
func (uart *UART) WriteByte(c byte) error {
|
||||
if !uart.core.dc.uartWriteByte(c) {
|
||||
return ErrUARTWriteFailed
|
||||
}
|
||||
@@ -66,6 +70,6 @@ func (uart UART) WriteByte(c byte) error {
|
||||
}
|
||||
|
||||
// Write data to the UART.
|
||||
func (uart UART) Write(data []byte) (n int, err error) {
|
||||
func (uart *UART) Write(data []byte) (n int, err error) {
|
||||
return uart.core.dc.uartWrite(data), nil
|
||||
}
|
||||
|
||||
+27
-3
@@ -216,12 +216,33 @@ func cycles(microsec, cpuFreqHz uint32) uint32 {
|
||||
return uint32((uint64(microsec) * uint64(cpuFreqHz)) / 1000000)
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func endpointValid(address uint8) bool {
|
||||
return address&descEndpointInvalid == 0
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func unpackEndpoint(address uint8) (number, direction uint8) {
|
||||
return (address & descEndptAddrNumberMsk) >> descEndptAddrNumberPos,
|
||||
(address & descEndptAddrDirectionMsk) >> descEndptAddrDirectionPos
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func packEndpoint(number, direction uint8) (address uint8) {
|
||||
return ((number << descEndptAddrNumberPos) & descEndptAddrNumberMsk) |
|
||||
((direction << descEndptAddrDirectionPos) & descEndptAddrDirectionMsk)
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func endpointNumber(address uint8) (number uint8) {
|
||||
return (address & descEndptAddrNumberMsk) >> descEndptAddrNumberPos
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func endpointDirection(address uint8) (direction uint8) {
|
||||
return (address & descEndptAddrDirectionMsk) >> descEndptAddrDirectionPos
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func rxEndpoint(number uint8) uint8 {
|
||||
return (number & descEndptAddrNumberMsk) | descEndptAddrDirectionOut
|
||||
@@ -245,20 +266,23 @@ func indexEndpoint(index uint8) uint8 {
|
||||
}
|
||||
|
||||
// wrap computes the index into a circular buffer of length mod by walking
|
||||
// forward n elements if n is positive, or reverse n elements if n is negative.
|
||||
// For example, both wrap(42, 10) and wrap(-308, 10) return 2.
|
||||
// forward n elements if n is positive, or reverse -n elements if n is negative.
|
||||
// For example, both wrap(12, 10) and wrap(-18, 10) return 2.
|
||||
//go:inline
|
||||
func wrap(n, mod int) int {
|
||||
if mod <= 0 || n == mod {
|
||||
if mod <= 0 {
|
||||
// Buffer length (mod) must be positive.
|
||||
return 0
|
||||
}
|
||||
if n < 0 {
|
||||
if -n < mod {
|
||||
// Do not wrap around (no underflow).
|
||||
return mod + n
|
||||
}
|
||||
return mod - (-n % mod)
|
||||
}
|
||||
if n < mod {
|
||||
// Do not wrap around (no overflow).
|
||||
return n
|
||||
}
|
||||
return n % mod
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"device/arm"
|
||||
"device/sam"
|
||||
"machine"
|
||||
"machine/usb"
|
||||
"runtime/interrupt"
|
||||
"runtime/volatile"
|
||||
)
|
||||
@@ -25,13 +26,12 @@ func init() {
|
||||
initClocks()
|
||||
initRTC()
|
||||
initSERCOMClocks()
|
||||
initUSBClock()
|
||||
initADCClock()
|
||||
|
||||
// connect to USB CDC interface
|
||||
machine.Serial.Configure(machine.UARTConfig{})
|
||||
machine.Serial.Configure(usb.UARTConfig{})
|
||||
if !machine.USB.Configured() {
|
||||
machine.USB.Configure(machine.UARTConfig{})
|
||||
machine.USB.Configure(usb.UARTConfig{})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user