mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-17 11:13:27 +00:00
add basic CDC-ACM UART Rx capability
This commit is contained in:
+4
-11
@@ -505,11 +505,10 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
|||||||
// CDC-ACM (single)
|
// CDC-ACM (single)
|
||||||
case classDeviceCDCACM:
|
case classDeviceCDCACM:
|
||||||
// line coding must contain exactly 7 bytes
|
// line coding must contain exactly 7 bytes
|
||||||
if uint16(descCDCACMCodingSize) == sup.wLength {
|
if uint16(descCDCACMLineCodingSize) == sup.wLength {
|
||||||
d.setup = sup
|
|
||||||
d.controlReceive(
|
d.controlReceive(
|
||||||
uintptr(unsafe.Pointer(&descCDCACM[d.cc.config-1].cx[0])),
|
uintptr(unsafe.Pointer(&descCDCACM[d.cc.config-1].cx[0])),
|
||||||
uint32(descCDCACMCodingSize), true)
|
uint32(descCDCACMLineCodingSize), true)
|
||||||
// CDC Line Coding packet receipt handling occurs in method
|
// CDC Line Coding packet receipt handling occurs in method
|
||||||
// controlComplete().
|
// controlComplete().
|
||||||
return dcdStageDataOut
|
return dcdStageDataOut
|
||||||
@@ -534,7 +533,7 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
|||||||
// Control/status interface:
|
// Control/status interface:
|
||||||
case descCDCACMInterfaceCtrl:
|
case descCDCACMInterfaceCtrl:
|
||||||
// DTR is bit 0 (mask 0x01), RTS is bit 1 (mask 0x02)
|
// DTR is bit 0 (mask 0x01), RTS is bit 1 (mask 0x02)
|
||||||
d.uartSetLineState(0 != sup.wValue&0x01, 0 != sup.wValue&0x02)
|
d.uartSetLineState(sup.wValue)
|
||||||
d.controlReceive(uintptr(0), 0, false)
|
d.controlReceive(uintptr(0), 0, false)
|
||||||
return dcdStageStatusOut
|
return dcdStageStatusOut
|
||||||
|
|
||||||
@@ -570,7 +569,6 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
|
|||||||
// HID
|
// HID
|
||||||
case classDeviceHID:
|
case classDeviceHID:
|
||||||
if sup.wLength <= descHIDSxSize {
|
if sup.wLength <= descHIDSxSize {
|
||||||
d.setup = sup
|
|
||||||
descHID[d.cc.config-1].cx[0] = 0xE9
|
descHID[d.cc.config-1].cx[0] = 0xE9
|
||||||
d.controlReceive(
|
d.controlReceive(
|
||||||
uintptr(unsafe.Pointer(&descHID[d.cc.config-1].cx[0])),
|
uintptr(unsafe.Pointer(&descHID[d.cc.config-1].cx[0])),
|
||||||
@@ -687,12 +685,7 @@ func (d *dcd) controlComplete() {
|
|||||||
case descCDCACMInterfaceCtrl:
|
case descCDCACMInterfaceCtrl:
|
||||||
// Notify PHY to handle triggers like special baud rates, which
|
// Notify PHY to handle triggers like special baud rates, which
|
||||||
// signal to reboot into bootloader or begin receiving OTA updates
|
// signal to reboot into bootloader or begin receiving OTA updates
|
||||||
d.uartSetLineCoding(descCDCACMLineCoding{
|
d.uartSetLineCoding(acm.cx[:])
|
||||||
baud: packU32(acm.cx[:]),
|
|
||||||
stopBits: acm.cx[4],
|
|
||||||
parity: acm.cx[5],
|
|
||||||
numBits: acm.cx[6],
|
|
||||||
})
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Unhandled device interface
|
// Unhandled device interface
|
||||||
|
|||||||
+45
-7
@@ -1,7 +1,5 @@
|
|||||||
package usb
|
package usb
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
const descUSBSpecVersion = uint16(0x0200) // USB 2.0
|
const descUSBSpecVersion = uint16(0x0200) // USB 2.0
|
||||||
|
|
||||||
const descLanguageEnglish = uint16(0x0409) // (US) English
|
const descLanguageEnglish = uint16(0x0409) // (US) English
|
||||||
@@ -140,6 +138,9 @@ const (
|
|||||||
const (
|
const (
|
||||||
descDirOut = descRequestTypeDirOut >> descRequestTypeDirPos
|
descDirOut = descRequestTypeDirOut >> descRequestTypeDirPos
|
||||||
descDirIn = descRequestTypeDirIn >> descRequestTypeDirPos
|
descDirIn = descRequestTypeDirIn >> descRequestTypeDirPos
|
||||||
|
|
||||||
|
descDirRx = descDirOut // "IN" and "OUT" terms are from host's perspective,
|
||||||
|
descDirTx = descDirIn // which is opposite from USB device. Kinda awkward.
|
||||||
)
|
)
|
||||||
|
|
||||||
// device returns the enumerated device descriptor value, defined per USB
|
// device returns the enumerated device descriptor value, defined per USB
|
||||||
@@ -429,15 +430,55 @@ const (
|
|||||||
// descEndpointInvalid represents an invalid endpoint address.
|
// descEndpointInvalid represents an invalid endpoint address.
|
||||||
const descEndpointInvalid = ^uint8(descEndptAddrNumberMsk | descEndptAddrDirectionMsk)
|
const descEndpointInvalid = ^uint8(descEndptAddrNumberMsk | descEndptAddrDirectionMsk)
|
||||||
|
|
||||||
// descCDCACMCodingSize defines the length of a CDC-ACM UART line coding buffer.
|
// descCDCACMLineCodingSize defines the length of a CDC-ACM UART line coding
|
||||||
const descCDCACMCodingSize = unsafe.Sizeof(descCDCACMLineCoding{})
|
// buffer. Note that the actual buffer may be padded for alignment; but for
|
||||||
|
// Rx/Tx transfer purposes, descCDCACMLineCodingSize defines the number of bytes
|
||||||
|
// that are transferred following a control SETUP request.
|
||||||
|
const descCDCACMLineCodingSize = 7
|
||||||
|
|
||||||
// descCDCACMLineCoding represents an emulated UART's line configuration.
|
// descCDCACMLineCoding represents an emulated UART's line configuration.
|
||||||
|
//
|
||||||
|
// Use descCDCACMLineCodingSize instead of unsafe.Sizeof(descCDCACMLineCoding)
|
||||||
|
// in any transfer requests, because the actual struct is padded for alignment.
|
||||||
type descCDCACMLineCoding struct {
|
type descCDCACMLineCoding struct {
|
||||||
baud uint32
|
baud uint32
|
||||||
stopBits uint8
|
stopBits uint8
|
||||||
parity uint8
|
parity uint8
|
||||||
numBits uint8
|
numBits uint8
|
||||||
|
_ uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse initializes the receiver descCDCACMLineCoding from the given []uint8 v.
|
||||||
|
// Argument v is a Rx transfer buffer, filled following the completion of a
|
||||||
|
// control transfer from a CDC SET_LINE_CODING (0x20) request
|
||||||
|
func (s *descCDCACMLineCoding) parse(v []uint8) bool {
|
||||||
|
if len(v) >= descCDCACMLineCodingSize {
|
||||||
|
s.baud = packU32(v[:])
|
||||||
|
s.stopBits = v[4]
|
||||||
|
s.parity = v[5]
|
||||||
|
s.numBits = v[6]
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// descCDCACMLineState represents an emulated UART's line state.
|
||||||
|
type descCDCACMLineState struct {
|
||||||
|
// dataTerminalReady indicates if DTE is present or not.
|
||||||
|
// Corresponds to V.24 signal 108/2 and RS-232 signal DTR.
|
||||||
|
dataTerminalReady bool // DTR
|
||||||
|
// requestToSend is the carrier control for half-duplex modems.
|
||||||
|
// Corresponds to V.24 signal 105 and RS-232 signal RTS.
|
||||||
|
requestToSend bool // RTS
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse initializes the receiver descCDCACMLineState from the given uint16 v.
|
||||||
|
// Argument v corresponds to the wValue field in a control SETUP packet, which
|
||||||
|
// carries the line state from a CDC SET_CONTROL_LINE_STATE (0x22) request.
|
||||||
|
func (s *descCDCACMLineState) parse(v uint16) bool {
|
||||||
|
s.dataTerminalReady = 0 != v&0x1
|
||||||
|
s.requestToSend = 0 != v&0x2
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Common configuration constants for the USB CDC-ACM (single) device class.
|
// Common configuration constants for the USB CDC-ACM (single) device class.
|
||||||
@@ -465,9 +506,6 @@ const (
|
|||||||
type descCDCACMClass struct {
|
type descCDCACMClass struct {
|
||||||
*descCDCACMClassData // Target-defined, class-specific data
|
*descCDCACMClassData // Target-defined, class-specific data
|
||||||
|
|
||||||
line descCDCACMLineCoding
|
|
||||||
term struct{ dtr, rts bool }
|
|
||||||
|
|
||||||
locale *[descCDCACMLanguageCount]descStringLanguage // string descriptors
|
locale *[descCDCACMLanguageCount]descStringLanguage // string descriptors
|
||||||
device *[descLengthDevice]uint8 // device descriptor
|
device *[descLengthDevice]uint8 // device descriptor
|
||||||
qualif *[descLengthQualification]uint8 // device qualification descriptor
|
qualif *[descLengthQualification]uint8 // device qualification descriptor
|
||||||
|
|||||||
@@ -38,9 +38,6 @@ const (
|
|||||||
|
|
||||||
descMaxEndpoints = 8 // SAMx51 maximum number of endpoints
|
descMaxEndpoints = 8 // SAMx51 maximum number of endpoints
|
||||||
|
|
||||||
descBankOut = 0 // descriptor bank 0 holds OUT endpoints
|
|
||||||
descBankIn = 1 // descriptor bank 1 holds IN endpoints
|
|
||||||
|
|
||||||
descControlPacketSize = 64
|
descControlPacketSize = 64
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -69,8 +66,8 @@ const (
|
|||||||
|
|
||||||
// CDC-ACM Data Buffers
|
// CDC-ACM Data Buffers
|
||||||
|
|
||||||
descCDCACMRxSize = 4 * descCDCACMDataRxPacketSize
|
descCDCACMRxSize = 1 * descCDCACMDataRxPacketSize
|
||||||
descCDCACMTxSize = 4 * descCDCACMDataTxPacketSize
|
descCDCACMTxSize = 1 * descCDCACMDataTxPacketSize
|
||||||
|
|
||||||
descCDCACMTxTimeoutMs = 120 // millisec
|
descCDCACMTxTimeoutMs = 120 // millisec
|
||||||
descCDCACMTxSyncUs = 75 // microsec
|
descCDCACMTxSyncUs = 75 // microsec
|
||||||
@@ -221,6 +218,16 @@ var descCDCACM0Rx [descCDCACMRxSize]uint8
|
|||||||
//go:align 32
|
//go:align 32
|
||||||
var descCDCACM0Tx [descCDCACMTxSize]uint8
|
var descCDCACM0Tx [descCDCACMTxSize]uint8
|
||||||
|
|
||||||
|
// descCDCACM0LC is the emulated UART's line coding configuration for the
|
||||||
|
// default CDC-ACM (single) device class configuration (index 1).
|
||||||
|
//go:align 32
|
||||||
|
var descCDCACM0LC descCDCACMLineCoding
|
||||||
|
|
||||||
|
// descCDCACM0LS is the emulated UART's line state for the default CDC-ACM
|
||||||
|
// (single) device class configuration (index 1).
|
||||||
|
//go:align 32
|
||||||
|
var descCDCACM0LS descCDCACMLineState
|
||||||
|
|
||||||
// descCDCACMClassData holds the buffers and control states for all CDC-ACM
|
// descCDCACMClassData holds the buffers and control states for all CDC-ACM
|
||||||
// (single) device class configurations, ordered by index (offset by -1), for
|
// (single) device class configurations, ordered by index (offset by -1), for
|
||||||
// SAMx51 targets only.
|
// SAMx51 targets only.
|
||||||
@@ -245,9 +252,15 @@ type descCDCACMClassData struct {
|
|||||||
rx *[descCDCACMRxSize]uint8 // bulk data endpoint Rx (OUT) transfer buffer
|
rx *[descCDCACMRxSize]uint8 // bulk data endpoint Rx (OUT) transfer buffer
|
||||||
tx *[descCDCACMTxSize]uint8 // bulk data endpoint Tx (IN) transfer buffer
|
tx *[descCDCACMTxSize]uint8 // bulk data endpoint Tx (IN) transfer buffer
|
||||||
|
|
||||||
sxSize uint16
|
lc *descCDCACMLineCoding // UART line coding
|
||||||
rxSize uint16
|
ls *descCDCACMLineState // UART line state
|
||||||
txSize uint16
|
|
||||||
|
rq *Queue
|
||||||
|
tq *Queue
|
||||||
|
|
||||||
|
sxSize uint32
|
||||||
|
rxSize uint32
|
||||||
|
txSize uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
// descCDCACMData holds statically-allocated instances for each of the target-
|
// descCDCACMData holds statically-allocated instances for each of the target-
|
||||||
@@ -271,6 +284,12 @@ var descCDCACMData = [dcdCount]descCDCACMClassData{
|
|||||||
rx: &descCDCACM0Rx,
|
rx: &descCDCACM0Rx,
|
||||||
tx: &descCDCACM0Tx,
|
tx: &descCDCACM0Tx,
|
||||||
|
|
||||||
|
lc: &descCDCACM0LC,
|
||||||
|
ls: &descCDCACM0LS,
|
||||||
|
|
||||||
|
rq: &Queue{},
|
||||||
|
tq: &Queue{},
|
||||||
|
|
||||||
sxSize: descCDCACMStatusPacketSize,
|
sxSize: descCDCACMStatusPacketSize,
|
||||||
rxSize: descCDCACMDataRxPacketSize,
|
rxSize: descCDCACMDataRxPacketSize,
|
||||||
txSize: descCDCACMDataTxPacketSize,
|
txSize: descCDCACMDataTxPacketSize,
|
||||||
|
|||||||
+108
-102
@@ -9,6 +9,7 @@ package usb
|
|||||||
import (
|
import (
|
||||||
"device/arm"
|
"device/arm"
|
||||||
"device/sam"
|
"device/sam"
|
||||||
|
"math/bits"
|
||||||
"runtime/interrupt"
|
"runtime/interrupt"
|
||||||
"runtime/volatile"
|
"runtime/volatile"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
@@ -34,31 +35,11 @@ type dhw struct {
|
|||||||
|
|
||||||
ep [descMaxEndpoints]dhwEPAddrStatus
|
ep [descMaxEndpoints]dhwEPAddrStatus
|
||||||
|
|
||||||
log [2048][64]byte
|
|
||||||
logCount uint
|
|
||||||
|
|
||||||
setup dcdSetup
|
setup dcdSetup
|
||||||
stage dcdStage
|
stage dcdStage
|
||||||
address uint16
|
address uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
var a uint
|
|
||||||
|
|
||||||
func (d *dhw) logEvent(s string) {
|
|
||||||
d.enableInterrupts(false)
|
|
||||||
copy(d.log[d.logCount][:], s)
|
|
||||||
d.logCount++
|
|
||||||
if d.logCount > 20 {
|
|
||||||
d.logReset()
|
|
||||||
}
|
|
||||||
d.enableInterrupts(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:noinline
|
|
||||||
func (d *dhw) logReset() {
|
|
||||||
a = d.logCount
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteCache(addr, size uintptr) {}
|
func deleteCache(addr, size uintptr) {}
|
||||||
func flushCache(addr, size uintptr) {}
|
func flushCache(addr, size uintptr) {}
|
||||||
func runBootloader() {}
|
func runBootloader() {}
|
||||||
@@ -86,20 +67,12 @@ func allocDHW(port, instance int, speed Speed, dc *dcd) *dhw {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SAMx51 has only one USB PHY, which is full-speed
|
// SAMx51 has only one USB PHY, which is full-speed
|
||||||
if 0 == speed {
|
if speed == 0 {
|
||||||
speed = FullSpeed
|
speed = FullSpeed
|
||||||
}
|
}
|
||||||
dhwInstance[instance].speed = speed
|
dhwInstance[instance].speed = speed
|
||||||
dhwInstance[instance].ready = false
|
dhwInstance[instance].ready = false
|
||||||
|
|
||||||
// initialize the transfer descriptors
|
|
||||||
for i := range dhwInstance[instance].ep {
|
|
||||||
dhwInstance[instance].ep[i][descBankOut].init(
|
|
||||||
&dhwInstance[instance], rxEndpoint(uint8(i)))
|
|
||||||
dhwInstance[instance].ep[i][descBankIn].init(
|
|
||||||
&dhwInstance[instance], txEndpoint(uint8(i)))
|
|
||||||
}
|
|
||||||
|
|
||||||
return &dhwInstance[instance]
|
return &dhwInstance[instance]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,12 +300,12 @@ func (d *dhw) interrupt() {
|
|||||||
sam.USB_DEVICE_ENDPOINT_EPINTFLAG_RXSTP |
|
sam.USB_DEVICE_ENDPOINT_EPINTFLAG_RXSTP |
|
||||||
sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT0)
|
sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT0)
|
||||||
|
|
||||||
d.logEvent("setup received")
|
|
||||||
|
|
||||||
// Parse the SETUP packet immediately, clearing room in the (one and only)
|
// Parse the SETUP packet immediately, clearing room in the (one and only)
|
||||||
// control buffer for the next SETUP packet received.
|
// control buffer for the next SETUP packet received.
|
||||||
sup := setupFrom(d.controlSetupBuffer())
|
sup := setupFrom(d.controlSetupBuffer())
|
||||||
dir := sup.direction()
|
dir := sup.direction()
|
||||||
|
|
||||||
|
// We've copied the SETUP packet elsewhere and are ready to receive another.
|
||||||
d.prepareSetup()
|
d.prepareSetup()
|
||||||
|
|
||||||
// Although there is only one control buffer, EP0 has two transfer queues:
|
// Although there is only one control buffer, EP0 has two transfer queues:
|
||||||
@@ -350,14 +323,12 @@ func (d *dhw) interrupt() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// maybe transfer complete
|
epints := d.bus.EPINTSMRY.Get() & ((1 << descMaxEndpoints) - 1)
|
||||||
|
|
||||||
epints := d.bus.EPINTSMRY.Get()
|
for epints != 0 {
|
||||||
|
|
||||||
for ep := uint8(0); ep < descMaxEndpoints; ep++ {
|
ep := uint8(bits.TrailingZeros16(epints))
|
||||||
if (epints & (1 << ep)) == 0 {
|
epints &^= 1 << ep
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
intFlag := d.bus.DEVICE_ENDPOINT[ep].EPINTFLAG.Get()
|
intFlag := d.bus.DEVICE_ENDPOINT[ep].EPINTFLAG.Get()
|
||||||
|
|
||||||
@@ -378,22 +349,20 @@ func (d *dhw) interrupt() {
|
|||||||
|
|
||||||
d.bus.DEVICE_ENDPOINT[ep].EPINTFLAG.Set(
|
d.bus.DEVICE_ENDPOINT[ep].EPINTFLAG.Set(
|
||||||
sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
|
sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
|
||||||
d.controlStall(false, descDirIn)
|
|
||||||
|
|
||||||
if ep == d.controlEndpoint() {
|
if ep == d.controlEndpoint() {
|
||||||
d.logEvent("EP0 Tx packet complete")
|
d.controlStall(false, descDirTx)
|
||||||
// check if there is more data to transfer or if we need to notify the
|
// check if there is more data to transfer or if we need to notify the
|
||||||
// upper-layer device driver of a control transfer completion event.
|
// upper-layer device driver of a control transfer completion event.
|
||||||
if count == 0 || count < size {
|
if count == 0 || count < size {
|
||||||
d.logEvent("EP0 Tx transfer complete")
|
|
||||||
d.controlTransferComplete(txEndpoint(ep), count, total)
|
d.controlTransferComplete(txEndpoint(ep), count, total)
|
||||||
} else {
|
} else {
|
||||||
d.controlTransferContinue(txEndpoint(ep), count, total)
|
d.controlTransferContinue(txEndpoint(ep), count, total)
|
||||||
}
|
}
|
||||||
} else if nil != d.ep[ep][descBankIn].callback {
|
} else if nil != d.ep[ep][descDirTx].callback {
|
||||||
// call our device class-specific callback, if defined, on endpoint
|
// call our device class-specific callback, if defined, on endpoint
|
||||||
// data transfer complete events.
|
// data transfer complete events.
|
||||||
d.ep[ep][descBankIn].callback(txEndpoint(ep), count)
|
d.ep[ep][descDirTx].callback(txEndpoint(ep), count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,22 +381,20 @@ func (d *dhw) interrupt() {
|
|||||||
|
|
||||||
d.bus.DEVICE_ENDPOINT[ep].EPINTFLAG.Set(
|
d.bus.DEVICE_ENDPOINT[ep].EPINTFLAG.Set(
|
||||||
sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT0)
|
sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT0)
|
||||||
d.controlStall(false, descDirOut)
|
|
||||||
|
|
||||||
if ep == d.controlEndpoint() {
|
if ep == d.controlEndpoint() {
|
||||||
d.logEvent("EP0 Rx packet complete")
|
d.controlStall(false, descDirRx)
|
||||||
// check if there is more data to transfer or if we need to notify the
|
// check if there is more data to transfer or if we need to notify the
|
||||||
// upper-layer device driver of a control transfer completion event.
|
// upper-layer device driver of a control transfer completion event.
|
||||||
if count == 0 || count < size {
|
if count == 0 || count < size {
|
||||||
d.logEvent("EP0 Rx transfer complete")
|
|
||||||
d.controlTransferComplete(rxEndpoint(ep), count, total)
|
d.controlTransferComplete(rxEndpoint(ep), count, total)
|
||||||
} else {
|
} else {
|
||||||
d.controlTransferContinue(rxEndpoint(ep), count, total)
|
d.controlTransferContinue(rxEndpoint(ep), count, total)
|
||||||
}
|
}
|
||||||
} else if nil != d.ep[ep][descBankOut].callback {
|
} else if nil != d.ep[ep][descDirRx].callback {
|
||||||
// call our device class-specific callback, if defined, on endpoint
|
// call our device class-specific callback, if defined, on endpoint
|
||||||
// data transfer complete events.
|
// data transfer complete events.
|
||||||
d.ep[ep][descBankOut].callback(rxEndpoint(ep), count)
|
d.ep[ep][descDirRx].callback(rxEndpoint(ep), count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -532,10 +499,11 @@ func (d *dhw) controlStatusStart(endpoint uint8) {
|
|||||||
|
|
||||||
num, dir := unpackEndpoint(endpoint)
|
num, dir := unpackEndpoint(endpoint)
|
||||||
|
|
||||||
|
// Swap direction of the given endpoint Rx->Tx and Tx->Rx
|
||||||
switch dir {
|
switch dir {
|
||||||
case descDirOut:
|
case descDirRx:
|
||||||
endpoint = txEndpoint(num)
|
endpoint = txEndpoint(num)
|
||||||
case descDirIn:
|
case descDirTx:
|
||||||
endpoint = rxEndpoint(num)
|
endpoint = rxEndpoint(num)
|
||||||
}
|
}
|
||||||
d.endpointTransfer(endpoint, 0, 0)
|
d.endpointTransfer(endpoint, 0, 0)
|
||||||
@@ -543,8 +511,6 @@ func (d *dhw) controlStatusStart(endpoint uint8) {
|
|||||||
|
|
||||||
func (d *dhw) controlStatusComplete(endpoint uint8) {
|
func (d *dhw) controlStatusComplete(endpoint uint8) {
|
||||||
|
|
||||||
d.logEvent("setup processing complete")
|
|
||||||
|
|
||||||
if (d.setup.bmRequestType&descRequestTypeTypeMsk == descRequestTypeTypeStandard) &&
|
if (d.setup.bmRequestType&descRequestTypeTypeMsk == descRequestTypeTypeStandard) &&
|
||||||
(d.setup.bmRequestType&(descRequestTypeRecipientMsk|descRequestTypeDirMsk) ==
|
(d.setup.bmRequestType&(descRequestTypeRecipientMsk|descRequestTypeDirMsk) ==
|
||||||
descRequestTypeRecipientDevice|descRequestTypeDirOut) &&
|
descRequestTypeRecipientDevice|descRequestTypeDirOut) &&
|
||||||
@@ -564,7 +530,6 @@ func (d *dhw) controlTransferStart(endpoint uint8) {
|
|||||||
|
|
||||||
// Dequeue the next transfer descriptor available.
|
// Dequeue the next transfer descriptor available.
|
||||||
if xfer, ok := d.ep[num][dir].pendingTransfer(); ok {
|
if xfer, ok := d.ep[num][dir].pendingTransfer(); ok {
|
||||||
d.logEvent("setup processing begin")
|
|
||||||
// Update the active transfer descriptor on the corresponding endpoint.
|
// Update the active transfer descriptor on the corresponding endpoint.
|
||||||
d.ep[num][dir].setActiveTransfer(xfer)
|
d.ep[num][dir].setActiveTransfer(xfer)
|
||||||
// Invoke the DCD event handler for SETUP processing, which will enqueue
|
// Invoke the DCD event handler for SETUP processing, which will enqueue
|
||||||
@@ -593,8 +558,6 @@ func (d *dhw) controlTransferComplete(endpoint uint8, count, total uint32) {
|
|||||||
setupDir := d.setup.direction()
|
setupDir := d.setup.direction()
|
||||||
setupAddress := packEndpoint(num, setupDir)
|
setupAddress := packEndpoint(num, setupDir)
|
||||||
|
|
||||||
d.logEvent("setup packet complete")
|
|
||||||
|
|
||||||
// If endpoint direction is opposite the direction in the original SETUP
|
// If endpoint direction is opposite the direction in the original SETUP
|
||||||
// packet, then this is the end of the STATUS stage, i.e., end of transfer.
|
// packet, then this is the end of the STATUS stage, i.e., end of transfer.
|
||||||
if dir != setupDir {
|
if dir != setupDir {
|
||||||
@@ -607,7 +570,6 @@ func (d *dhw) controlTransferComplete(endpoint uint8, count, total uint32) {
|
|||||||
// Start processing any pending control transfers.
|
// Start processing any pending control transfers.
|
||||||
d.controlTransferStart(setupAddress)
|
d.controlTransferStart(setupAddress)
|
||||||
} else {
|
} else {
|
||||||
d.logEvent("control status phase")
|
|
||||||
// Initiate ZLP transfer in opposite direction.
|
// Initiate ZLP transfer in opposite direction.
|
||||||
d.controlStatusStart(endpoint)
|
d.controlStatusStart(endpoint)
|
||||||
}
|
}
|
||||||
@@ -619,7 +581,7 @@ func (d *dhw) controlTransferComplete(endpoint uint8, count, total uint32) {
|
|||||||
func (d *dhw) controlReceive(data uintptr, size uint32, notify bool) {
|
func (d *dhw) controlReceive(data uintptr, size uint32, notify bool) {
|
||||||
ep := d.controlEndpoint()
|
ep := d.controlEndpoint()
|
||||||
if size > 0 && data > 0 {
|
if size > 0 && data > 0 {
|
||||||
if xfer, ok := d.ep[ep][descBankOut].activeTransfer(); ok {
|
if xfer, ok := d.ep[ep][descDirRx].activeTransfer(); ok {
|
||||||
next := xfer.packetStart(data, size)
|
next := xfer.packetStart(data, size)
|
||||||
d.endpointTransfer(rxEndpoint(ep), data, next)
|
d.endpointTransfer(rxEndpoint(ep), data, next)
|
||||||
}
|
}
|
||||||
@@ -634,7 +596,7 @@ func (d *dhw) controlReceive(data uintptr, size uint32, notify bool) {
|
|||||||
func (d *dhw) controlTransmit(data uintptr, size uint32, notify bool) {
|
func (d *dhw) controlTransmit(data uintptr, size uint32, notify bool) {
|
||||||
ep := d.controlEndpoint()
|
ep := d.controlEndpoint()
|
||||||
if size > 0 && data > 0 {
|
if size > 0 && data > 0 {
|
||||||
if xfer, ok := d.ep[ep][descBankIn].activeTransfer(); ok {
|
if xfer, ok := d.ep[ep][descDirTx].activeTransfer(); ok {
|
||||||
next := xfer.packetStart(data, size)
|
next := xfer.packetStart(data, size)
|
||||||
d.endpointTransfer(txEndpoint(ep), data, next)
|
d.endpointTransfer(txEndpoint(ep), data, next)
|
||||||
}
|
}
|
||||||
@@ -658,9 +620,9 @@ type dhwTransfer struct {
|
|||||||
|
|
||||||
// dhwTransferDepth defines the size of the dhwEPStatus.xferQueue buffered channel,
|
// dhwTransferDepth defines the size of the dhwEPStatus.xferQueue buffered channel,
|
||||||
// which affects the number of transfers each endpoint can enqueue for processing.
|
// which affects the number of transfers each endpoint can enqueue for processing.
|
||||||
// const dhwTransferDepth = 8
|
const dhwTransferDepth = 8
|
||||||
|
|
||||||
type dhwTransferLUT [QueueSize]dhwTransfer
|
type dhwTransferLUT [dhwTransferDepth]dhwTransfer
|
||||||
|
|
||||||
func (t *dhwTransfer) init(endpoint uint8, maxPacketSize uint32) {
|
func (t *dhwTransfer) init(endpoint uint8, maxPacketSize uint32) {
|
||||||
t.endpoint = endpoint
|
t.endpoint = endpoint
|
||||||
@@ -741,6 +703,7 @@ type dhwEPStatus struct {
|
|||||||
callback func(endpoint uint8, size uint32)
|
callback func(endpoint uint8, size uint32)
|
||||||
flags volatile.Register8
|
flags volatile.Register8
|
||||||
xferActive volatile.Register32
|
xferActive volatile.Register32
|
||||||
|
xferFIFO [dhwTransferDepth]uint8
|
||||||
xferQueue Queue
|
xferQueue Queue
|
||||||
xferTable dhwTransferLUT
|
xferTable dhwTransferLUT
|
||||||
}
|
}
|
||||||
@@ -761,7 +724,8 @@ func (s *dhwEPStatus) init(dhw *dhw, endpoint uint8) {
|
|||||||
s.endpoint = endpoint
|
s.endpoint = endpoint
|
||||||
s.callback = nil
|
s.callback = nil
|
||||||
s.flags.Set(0)
|
s.flags.Set(0)
|
||||||
s.xferQueue.Reset()
|
fifo := s.xferFIFO[:]
|
||||||
|
s.xferQueue.Init(&fifo, dhwTransferDepth, QueueFullDiscardLast)
|
||||||
mps := dhw.endpointMaxPacketSize(endpoint)
|
mps := dhw.endpointMaxPacketSize(endpoint)
|
||||||
for i := range s.xferTable {
|
for i := range s.xferTable {
|
||||||
s.xferTable[i].init(endpoint, mps)
|
s.xferTable[i].init(endpoint, mps)
|
||||||
@@ -955,7 +919,6 @@ func (s *dhwEPStatus) scheduleTransfer(data uintptr, size uint32) (ready bool, o
|
|||||||
// returned for both return values.
|
// returned for both return values.
|
||||||
func (s *dhwEPStatus) scheduleSetup(setup dcdSetup) (ready bool, ok bool) {
|
func (s *dhwEPStatus) scheduleSetup(setup dcdSetup) (ready bool, ok bool) {
|
||||||
var i int
|
var i int
|
||||||
s.device.logEvent("setup queued")
|
|
||||||
if i, ok = s.claimSchedule(); ok {
|
if i, ok = s.claimSchedule(); ok {
|
||||||
defer s.device.enableInterrupts(true)
|
defer s.device.enableInterrupts(true)
|
||||||
s.xferTable[i].reset()
|
s.xferTable[i].reset()
|
||||||
@@ -1157,14 +1120,18 @@ func (d *dhw) endpointEnable(endpoint uint8, control bool, config uint32) {
|
|||||||
|
|
||||||
if enum, ok := endpointSizeEncode(descControlPacketSize); ok {
|
if enum, ok := endpointSizeEncode(descControlPacketSize); ok {
|
||||||
|
|
||||||
|
num := endpointNumber(d.controlEndpoint())
|
||||||
|
|
||||||
|
// Initialize IN and OUT transfer descriptors on control endpoint 0.
|
||||||
|
d.ep[num][descDirRx].init(d, rxEndpoint(num))
|
||||||
|
d.ep[num][descDirTx].init(d, txEndpoint(num))
|
||||||
|
|
||||||
// Conigure packet size for control endpoints.
|
// Conigure packet size for control endpoints.
|
||||||
out.packetSize.ReplaceBits(enum,
|
out.packetSize.ReplaceBits(enum,
|
||||||
USB_DEVICE_PCKSIZE_SIZE_Msk, USB_DEVICE_PCKSIZE_SIZE_Pos)
|
USB_DEVICE_PCKSIZE_SIZE_Msk, USB_DEVICE_PCKSIZE_SIZE_Pos)
|
||||||
in.packetSize.ReplaceBits(enum,
|
in.packetSize.ReplaceBits(enum,
|
||||||
USB_DEVICE_PCKSIZE_SIZE_Msk, USB_DEVICE_PCKSIZE_SIZE_Pos)
|
USB_DEVICE_PCKSIZE_SIZE_Msk, USB_DEVICE_PCKSIZE_SIZE_Pos)
|
||||||
|
|
||||||
num := endpointNumber(d.controlEndpoint())
|
|
||||||
|
|
||||||
// rxType/txType uses the same rationale as epType (defined below in the
|
// rxType/txType uses the same rationale as epType (defined below in the
|
||||||
// else-branch that handles non-control endpoints).
|
// else-branch that handles non-control endpoints).
|
||||||
// Thus, we add +1 to the value below.
|
// Thus, we add +1 to the value below.
|
||||||
@@ -1193,11 +1160,15 @@ func (d *dhw) endpointEnable(endpoint uint8, control bool, config uint32) {
|
|||||||
|
|
||||||
if enum, ok := endpointSizeEncode(d.endpointMaxPacketSize(endpoint)); ok {
|
if enum, ok := endpointSizeEncode(d.endpointMaxPacketSize(endpoint)); ok {
|
||||||
|
|
||||||
|
num, dir := unpackEndpoint(endpoint)
|
||||||
|
|
||||||
|
// Initialize transfer descriptors now that the device class configuration
|
||||||
|
// has been defined, which affects maximum packet size.
|
||||||
|
d.ep[num][dir].init(d, endpoint)
|
||||||
|
|
||||||
desc.packetSize.ReplaceBits(enum,
|
desc.packetSize.ReplaceBits(enum,
|
||||||
USB_DEVICE_PCKSIZE_SIZE_Msk, USB_DEVICE_PCKSIZE_SIZE_Pos)
|
USB_DEVICE_PCKSIZE_SIZE_Msk, USB_DEVICE_PCKSIZE_SIZE_Pos)
|
||||||
|
|
||||||
num := endpointNumber(endpoint)
|
|
||||||
|
|
||||||
// config contains the bmAttributes field per USB standard EP descriptor,
|
// config contains the bmAttributes field per USB standard EP descriptor,
|
||||||
// i.e., ctrl=0, iso=1, bulk=2, int=3, which corresponds to the EPCFG
|
// i.e., ctrl=0, iso=1, bulk=2, int=3, which corresponds to the EPCFG
|
||||||
// register's EPTYPE0/1 bitfield+1: ctrl=1, iso=2, bulk=3, int=4, dual=5.
|
// register's EPTYPE0/1 bitfield+1: ctrl=1, iso=2, bulk=3, int=4, dual=5.
|
||||||
@@ -1217,9 +1188,8 @@ func (d *dhw) endpointEnable(endpoint uint8, control bool, config uint32) {
|
|||||||
sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_STALLRQ0 |
|
sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_STALLRQ0 |
|
||||||
sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_DTGLOUT)
|
sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_DTGLOUT)
|
||||||
|
|
||||||
d.bus.DEVICE_ENDPOINT[num].EPINTENSET.ReplaceBits(
|
d.bus.DEVICE_ENDPOINT[num].EPINTENSET.Set(
|
||||||
sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0,
|
sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0)
|
||||||
sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0_Msk, 0)
|
|
||||||
|
|
||||||
case txEndpoint(endpoint):
|
case txEndpoint(endpoint):
|
||||||
|
|
||||||
@@ -1234,15 +1204,16 @@ func (d *dhw) endpointEnable(endpoint uint8, control bool, config uint32) {
|
|||||||
sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_STALLRQ1 |
|
sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_STALLRQ1 |
|
||||||
sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_DTGLIN)
|
sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_DTGLIN)
|
||||||
|
|
||||||
d.bus.DEVICE_ENDPOINT[num].EPINTENSET.ReplaceBits(
|
d.bus.DEVICE_ENDPOINT[num].EPINTENSET.Set(
|
||||||
sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT1,
|
sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT1)
|
||||||
sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT1_Msk, 0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dhw) endpointConfigure(endpoint uint8) {
|
func (d *dhw) endpointConfigure(endpoint uint8, callback func(endpoint uint8, size uint32)) {
|
||||||
|
num, dir := unpackEndpoint(endpoint)
|
||||||
|
d.ep[num][dir].callback = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
// endpointStall sets or clears a stall on the given endpoint.
|
// endpointStall sets or clears a stall on the given endpoint.
|
||||||
@@ -1299,7 +1270,7 @@ func (d *dhw) endpointTransfer(endpoint uint8, data uintptr, size uint32) {
|
|||||||
|
|
||||||
switch num, dir := unpackEndpoint(endpoint); dir {
|
switch num, dir := unpackEndpoint(endpoint); dir {
|
||||||
|
|
||||||
case descDirOut: // Rx
|
case descDirRx: // OUT
|
||||||
|
|
||||||
// overwrite the BYTE_COUNT and MULTI_PACKET_SIZE bitfields only (with 0 and
|
// overwrite the BYTE_COUNT and MULTI_PACKET_SIZE bitfields only (with 0 and
|
||||||
// size, respectively).
|
// size, respectively).
|
||||||
@@ -1315,7 +1286,7 @@ func (d *dhw) endpointTransfer(endpoint uint8, data uintptr, size uint32) {
|
|||||||
d.bus.DEVICE_ENDPOINT[num].EPINTFLAG.SetBits(
|
d.bus.DEVICE_ENDPOINT[num].EPINTFLAG.SetBits(
|
||||||
sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRFAIL0)
|
sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRFAIL0)
|
||||||
|
|
||||||
case descDirIn: // Tx
|
case descDirTx: // IN
|
||||||
|
|
||||||
// overwrite the BYTE_COUNT and MULTI_PACKET_SIZE bitfields only (with size
|
// overwrite the BYTE_COUNT and MULTI_PACKET_SIZE bitfields only (with size
|
||||||
// and 0, respectively).
|
// and 0, respectively).
|
||||||
@@ -1364,54 +1335,89 @@ func (d *dhw) uartConfigure() {
|
|||||||
acm := &descCDCACM[d.cc.config-1]
|
acm := &descCDCACM[d.cc.config-1]
|
||||||
|
|
||||||
// SAMx51 only supports USB full-speed (FS) operation
|
// SAMx51 only supports USB full-speed (FS) operation
|
||||||
|
acm.sxSize = descCDCACMStatusFSPacketSize
|
||||||
acm.rxSize = descCDCACMDataRxFSPacketSize
|
acm.rxSize = descCDCACMDataRxFSPacketSize
|
||||||
acm.txSize = descCDCACMDataTxFSPacketSize
|
acm.txSize = descCDCACMDataTxFSPacketSize
|
||||||
|
|
||||||
d.endpointEnable(descCDCACMEndpointStatus,
|
rq := acm.rx[:]
|
||||||
|
tq := acm.tx[:]
|
||||||
|
|
||||||
|
// Rx gives priority to incoming data, Tx gives priority to outgoing data
|
||||||
|
acm.rq.Init(&rq, descCDCACMRxSize, QueueFullDiscardFirst)
|
||||||
|
acm.tq.Init(&tq, descCDCACMTxSize, QueueFullDiscardLast)
|
||||||
|
|
||||||
|
d.endpointEnable(txEndpoint(descCDCACMEndpointStatus),
|
||||||
false, descCDCACMConfigAttrStatus)
|
false, descCDCACMConfigAttrStatus)
|
||||||
d.endpointEnable(descCDCACMEndpointDataRx,
|
d.endpointEnable(rxEndpoint(descCDCACMEndpointDataRx),
|
||||||
false, descCDCACMConfigAttrDataRx)
|
false, descCDCACMConfigAttrDataRx)
|
||||||
d.endpointEnable(descCDCACMEndpointDataTx,
|
d.endpointEnable(txEndpoint(descCDCACMEndpointDataTx),
|
||||||
false, descCDCACMConfigAttrDataTx)
|
false, descCDCACMConfigAttrDataTx)
|
||||||
/*
|
|
||||||
d.endpointConfigureTx(descCDCACMEndpointStatus,
|
|
||||||
acm.sxSize, false, nil)
|
|
||||||
d.endpointConfigureRx(descCDCACMEndpointDataRx,
|
|
||||||
acm.rxSize, false, d.uartNotify)
|
|
||||||
d.endpointConfigureTx(descCDCACMEndpointDataTx,
|
|
||||||
acm.txSize, true, nil)
|
|
||||||
|
|
||||||
for i := range acm.rd {
|
d.endpointConfigure(txEndpoint(descCDCACMEndpointStatus),
|
||||||
d.uartReceive(uint8(i))
|
nil)
|
||||||
|
d.endpointConfigure(rxEndpoint(descCDCACMEndpointDataRx),
|
||||||
|
d.uartReceiveComplete)
|
||||||
|
d.endpointConfigure(txEndpoint(descCDCACMEndpointDataTx),
|
||||||
|
nil)
|
||||||
|
|
||||||
|
d.uartReceive(descCDCACMEndpointDataRx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dhw) uartSetLineState(state uint16) {
|
||||||
|
acm := &descCDCACM[d.cc.config-1]
|
||||||
|
if acm.ls.parse(state) {
|
||||||
|
// TBD: respond to changes in line state?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dhw) uartSetLineCoding(coding []uint8) {
|
||||||
|
acm := &descCDCACM[d.cc.config-1]
|
||||||
|
if acm.lc.parse(coding) {
|
||||||
|
switch acm.lc.baud {
|
||||||
|
case 1200:
|
||||||
|
if acm.ls.dataTerminalReady {
|
||||||
|
// reboot CPU
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
d.timerConfigure(0, descCDCACMTxSyncUs, d.uartSync)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *dhw) uartSetLineState(dtr, rts bool) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *dhw) uartSetLineCoding(coding descCDCACMLineCoding) {
|
|
||||||
if 134 == coding.baud {
|
|
||||||
d.enableSOF(true, descCDCACMInterfaceCount)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dhw) uartReady() bool {
|
func (d *dhw) uartReady() bool {
|
||||||
acm := &descCDCACM[d.cc.config-1]
|
return d.dcd.state() == dcdStateConfigured
|
||||||
_ = acm // TODO(ardnew): elaborate stub
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dhw) uartReceive(endpoint uint8) {
|
func (d *dhw) uartReceive(endpoint uint8) {
|
||||||
acm := &descCDCACM[d.cc.config-1]
|
acm := &descCDCACM[d.cc.config-1]
|
||||||
num := uint16(endpoint) & descEndptAddrNumberMsk
|
num := uint16(endpoint) & descEndptAddrNumberMsk
|
||||||
_, _ = acm, num // TODO(ardnew): elaborate stub
|
|
||||||
|
ready, _ := d.ep[num][descDirRx].scheduleTransfer(
|
||||||
|
uintptr(unsafe.Pointer(&acm.rx[0])), acm.rxSize)
|
||||||
|
if ready {
|
||||||
|
if xfer, ok := d.ep[num][descDirRx].pendingTransfer(); ok {
|
||||||
|
// Update the active transfer descriptor on the corresponding endpoint.
|
||||||
|
d.ep[num][descDirRx].setActiveTransfer(xfer)
|
||||||
|
next := xfer.packetStart(xfer.data, xfer.size)
|
||||||
|
d.endpointTransfer(endpoint, xfer.data, next)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dhw) uartNotify(endpoint uint8, size uint32) {
|
func (d *dhw) uartReceiveComplete(endpoint uint8, size uint32) {
|
||||||
acm := &descCDCACM[d.cc.config-1]
|
acm := &descCDCACM[d.cc.config-1]
|
||||||
|
num := uint16(endpoint) & descEndptAddrNumberMsk
|
||||||
_ = acm // TODO(ardnew): elaborate stub
|
_ = acm // TODO(ardnew): elaborate stub
|
||||||
|
|
||||||
|
if xfer, ok := d.ep[num][descDirRx].activeTransfer(); ok {
|
||||||
|
for ptr := xfer.data + uintptr(xfer.sent); ptr < xfer.data+uintptr(size); ptr++ {
|
||||||
|
acm.rq.Enq(*(*uint8)(unsafe.Pointer(ptr)))
|
||||||
|
}
|
||||||
|
if data, size := xfer.packetComplete(size); size > 0 {
|
||||||
|
d.endpointTransfer(endpoint, data, size)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.ep[num][descDirRx].setActiveTransfer(nil)
|
||||||
|
d.uartReceive(endpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
// uartFlush discards all buffered input (Rx) data.
|
// uartFlush discards all buffered input (Rx) data.
|
||||||
@@ -1445,7 +1451,7 @@ func (d *dhw) uartRead(data []uint8) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *dhw) uartWriteByte(c uint8) bool {
|
func (d *dhw) uartWriteByte(c uint8) bool {
|
||||||
return 1 == d.uartWrite([]uint8{c})
|
return d.uartWrite([]uint8{c}) == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dhw) uartWrite(data []uint8) int {
|
func (d *dhw) uartWrite(data []uint8) int {
|
||||||
|
|||||||
+212
-54
@@ -5,12 +5,19 @@ import (
|
|||||||
"runtime/volatile"
|
"runtime/volatile"
|
||||||
)
|
)
|
||||||
|
|
||||||
const QueueSize = 8
|
type QueueFullDiscardMode uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
QueueFullDiscardLast QueueFullDiscardMode = iota // Drop incoming data
|
||||||
|
QueueFullDiscardFirst // Drop outgoing data
|
||||||
|
)
|
||||||
|
|
||||||
type Queue struct {
|
type Queue struct {
|
||||||
fifo [QueueSize]uint8
|
mode QueueFullDiscardMode
|
||||||
tail volatile.Register32
|
size volatile.Register32
|
||||||
head volatile.Register32
|
fifo *[]uint8
|
||||||
|
tail volatile.Register32 // New elements are enqueued at index tail
|
||||||
|
head volatile.Register32 // Oldest element in queue is at index head
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -18,28 +25,94 @@ var (
|
|||||||
ErrWriteBuffer = errors.New("cannot copy from write buffer")
|
ErrWriteBuffer = errors.New("cannot copy from write buffer")
|
||||||
ErrQueueEmpty = errors.New("data queue empty") // Read Error
|
ErrQueueEmpty = errors.New("data queue empty") // Read Error
|
||||||
ErrQueueFull = errors.New("data queue full") // Write error
|
ErrQueueFull = errors.New("data queue full") // Write error
|
||||||
|
ErrQueueNoMode = errors.New("unknown FIFO copy mode")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Reset discards all buffered data.
|
// Init initializes the receiver queue's backing data store with the given byte
|
||||||
|
// slice fifo and logical capacity size. If size is greater than the slice's
|
||||||
|
// physical length, uses the slice's physical length.
|
||||||
|
func (q *Queue) Init(fifo *[]uint8, size int, mode QueueFullDiscardMode) {
|
||||||
|
q.mode = mode
|
||||||
|
q.fifo = fifo
|
||||||
|
q.Reset(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset discards all buffered data and sets the FIFO logical capacity.
|
||||||
|
// If size is less than 0 or greater than FIFO physical length, uses FIFO
|
||||||
|
// physical length.
|
||||||
//go:inline
|
//go:inline
|
||||||
func (q *Queue) Reset() {
|
func (q *Queue) Reset(size int) {
|
||||||
for i := range q.fifo {
|
if phy := len(*q.fifo); size < 0 || size > phy {
|
||||||
q.fifo[i] = 0
|
size = phy
|
||||||
}
|
}
|
||||||
|
q.size.Set(uint32(size))
|
||||||
q.tail.Set(0)
|
q.tail.Set(0)
|
||||||
q.head.Set(0)
|
q.head.Set(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cap returns the logical capacity of the receiver FIFO.
|
||||||
|
//go:inline
|
||||||
|
func (q *Queue) Cap() int {
|
||||||
|
return int(q.size.Get())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns the number of elements enqueued in the receiver FIFO.
|
||||||
//go:inline
|
//go:inline
|
||||||
func (q *Queue) Len() int {
|
func (q *Queue) Len() int {
|
||||||
return int(q.tail.Get() - q.head.Get())
|
return int(q.tail.Get() - q.head.Get())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rem returns the number of elements not enqueued in the receiver FIFO.
|
||||||
//go:inline
|
//go:inline
|
||||||
func (q *Queue) Cap() int {
|
func (q *Queue) Rem() int {
|
||||||
return cap(q.fifo)
|
return q.Cap() - q.Len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deq dequeues and returns the element at the front of the receiver FIFO and true.
|
||||||
|
// If the FIFO is empty and no element was dequeued, returns 0 and false.
|
||||||
|
func (q *Queue) Deq() (uint8, bool) {
|
||||||
|
|
||||||
|
head := q.head.Get()
|
||||||
|
if head == q.tail.Get() {
|
||||||
|
return 0, false
|
||||||
|
} // empty queue
|
||||||
|
|
||||||
|
data := (*q.fifo)[head%q.size.Get()]
|
||||||
|
q.head.Set(head + 1)
|
||||||
|
|
||||||
|
return data, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enq enqueues the given element data at the back of the receiver FIFO and
|
||||||
|
// returns true.
|
||||||
|
// If the FIFO is full and no element can be enqueued, returns false.
|
||||||
|
//
|
||||||
|
// TODO(ardnew): Document both operations based on receiver's QueueFullMode.
|
||||||
|
func (q *Queue) Enq(data uint8) bool {
|
||||||
|
|
||||||
|
tail := q.tail.Get()
|
||||||
|
head := q.head.Get()
|
||||||
|
if tail-head == q.size.Get() {
|
||||||
|
switch q.mode {
|
||||||
|
case QueueFullDiscardLast:
|
||||||
|
// drop incoming data
|
||||||
|
return false
|
||||||
|
case QueueFullDiscardFirst:
|
||||||
|
// drop outgoing data
|
||||||
|
q.head.Set(head + 1)
|
||||||
|
}
|
||||||
|
} // full queue
|
||||||
|
|
||||||
|
(*q.fifo)[tail%q.size.Get()] = data
|
||||||
|
q.tail.Set(tail + 1)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read implements the io.Reader interface. It dequeues min(q.Len(), len(data))
|
||||||
|
// elements from the receiver FIFO into the given slice data.
|
||||||
|
// If len(data) equals 0, returns 0 and ErrReadBuffer.
|
||||||
|
// Otherwise, if q.Len() equals 0, returns 0 and ErrQueueEmpty.
|
||||||
func (q *Queue) Read(data []uint8) (int, error) {
|
func (q *Queue) Read(data []uint8) (int, error) {
|
||||||
|
|
||||||
less := uint32(len(data))
|
less := uint32(len(data))
|
||||||
@@ -59,7 +132,7 @@ func (q *Queue) Read(data []uint8) (int, error) {
|
|||||||
} // only get from used space
|
} // only get from used space
|
||||||
|
|
||||||
for i := uint32(0); i < less; i++ {
|
for i := uint32(0); i < less; i++ {
|
||||||
data[i] = q.fifo[head%QueueSize]
|
data[i] = (*q.fifo)[head%q.size.Get()]
|
||||||
head++
|
head++
|
||||||
}
|
}
|
||||||
q.head.Set(head)
|
q.head.Set(head)
|
||||||
@@ -67,65 +140,150 @@ func (q *Queue) Read(data []uint8) (int, error) {
|
|||||||
return int(less), nil
|
return int(less), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write implements the io.Writer interface. It enqueues min(q.Rem(), len(data))
|
||||||
|
// elements from the given slice data into the receiver FIFO.
|
||||||
|
// If len(data) equals 0, returns 0 and ErrWriteBuffer.
|
||||||
|
// Otherwise, if q.Rem() equals 0, returns 0 and ErrQueueFull.
|
||||||
|
//
|
||||||
|
// TODO(ardnew): Document both operations based on receiver's QueueFullMode.
|
||||||
func (q *Queue) Write(data []uint8) (int, error) {
|
func (q *Queue) Write(data []uint8) (int, error) {
|
||||||
|
|
||||||
more := uint32(len(data))
|
more := uint32(len(data))
|
||||||
|
|
||||||
|
// Nothing to copy from is an error regardless of mode.
|
||||||
if more == 0 {
|
if more == 0 {
|
||||||
return 0, ErrWriteBuffer
|
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
|
switch q.mode {
|
||||||
}
|
case QueueFullDiscardLast:
|
||||||
|
// drop incoming data
|
||||||
func (q *Queue) Deq() (uint8, bool) {
|
|
||||||
|
tail := q.tail.Get()
|
||||||
tail := q.head.Get()
|
used := tail - q.head.Get()
|
||||||
if tail == q.tail.Get() {
|
|
||||||
return 0, false
|
// Full queue, cannot add any data.
|
||||||
} // empty queue
|
if used == q.size.Get() {
|
||||||
|
return 0, ErrQueueFull
|
||||||
data := q.fifo[tail%QueueSize]
|
}
|
||||||
q.head.Set(tail + 1)
|
|
||||||
|
// xOnly put to unused space.
|
||||||
return data, true
|
if used+more > q.size.Get() {
|
||||||
|
more = q.size.Get() - used
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy a potentially-limited number of elements from data, depending on the
|
||||||
|
// current length of FIFO.
|
||||||
|
for i := uint32(0); i < more; i++ {
|
||||||
|
(*q.fifo)[tail%q.size.Get()] = data[i]
|
||||||
|
tail++
|
||||||
|
}
|
||||||
|
q.tail.Set(tail)
|
||||||
|
|
||||||
|
return int(more), nil
|
||||||
|
|
||||||
|
case QueueFullDiscardFirst:
|
||||||
|
// drop outgoing data
|
||||||
|
|
||||||
|
// Trying to write more data than the FIFO will hold will simply overwrite
|
||||||
|
// some of the given data, so there is no point writing that data.
|
||||||
|
from := uint32(0)
|
||||||
|
if more >= q.size.Get() {
|
||||||
|
// Begin copying only the data that will be kept.
|
||||||
|
from = more - q.size.Get()
|
||||||
|
// We can fill the entire FIFO.
|
||||||
|
more = q.size.Get()
|
||||||
|
// Reset the indices
|
||||||
|
q.head.Set(0)
|
||||||
|
q.tail.Set(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
tail := q.tail.Get()
|
||||||
|
used := tail - q.head.Get()
|
||||||
|
|
||||||
|
// Make space for incoming data by discarding only as many FIFO elements as
|
||||||
|
// is necessary to store incoming data.
|
||||||
|
if used+more > q.size.Get() {
|
||||||
|
q.head.Set(tail + more - q.size.Get())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy a potentially-limited number of elements from data, depending on the
|
||||||
|
// current length of FIFO.
|
||||||
|
for i := uint32(0); i < more; i++ {
|
||||||
|
(*q.fifo)[tail%q.size.Get()] = data[i]
|
||||||
|
tail++
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Front returns the next element that would be dequeued from the receiver FIFO
|
||||||
|
// and true.
|
||||||
|
// If the FIFO is empty and no element would be dequeued, returns 0 and false.
|
||||||
func (q *Queue) Front() (uint8, bool) {
|
func (q *Queue) Front() (uint8, bool) {
|
||||||
|
|
||||||
tail := q.head.Get()
|
head := q.head.Get()
|
||||||
if tail == q.tail.Get() {
|
if head == q.tail.Get() {
|
||||||
return 0, false
|
return 0, false
|
||||||
} // empty queue
|
} // empty queue
|
||||||
|
|
||||||
return q.fifo[tail%QueueSize], true
|
return (*q.fifo)[head%q.size.Get()], true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queue) Enq(data uint8) bool {
|
// Back returns the last element that would be dequeued from the receiver FIFO
|
||||||
|
// and true.
|
||||||
|
// If the FIFO is empty and no element would be dequeued, returns 0 and false.
|
||||||
|
func (q *Queue) Back() (uint8, bool) {
|
||||||
|
|
||||||
head := q.tail.Get()
|
tail := q.tail.Get()
|
||||||
if head-q.head.Get() == QueueSize {
|
if tail == q.head.Get() {
|
||||||
return false
|
return 0, false
|
||||||
} // full queue
|
} // empty queue
|
||||||
|
|
||||||
q.fifo[head%QueueSize] = data
|
return (*q.fifo)[(tail-1)%q.size.Get()], true
|
||||||
q.tail.Set(head + 1)
|
}
|
||||||
|
|
||||||
return true
|
// index returns an index into the receiver FIFO based on sign and magnitude of i:
|
||||||
|
// 1. If i is greater than or equal to zero and less then q.Len(), returns the
|
||||||
|
// (i+1)'th element that would be dequeued from the receiver FIFO and true.
|
||||||
|
// 2. Otherwise, if i is negative and -i is less than or equal to q.Len(), returns
|
||||||
|
// the -(i+1)'th from the last element that would be dequeued from the receiver
|
||||||
|
// FIFO and true.
|
||||||
|
// 3. Otherwise, returns 0 and false.
|
||||||
|
func (q *Queue) index(i int) (int, bool) {
|
||||||
|
if n := q.Len(); i < 0 {
|
||||||
|
if -i <= n {
|
||||||
|
return (int(q.tail.Get()) + i) % int(q.size.Get()), true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if i < n {
|
||||||
|
return (int(q.head.Get()) + i) % int(q.size.Get()), true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the value of an element in the receiver FIFO, offset by i from the
|
||||||
|
// front of the queue if i is positive, or from the back of the queue if i is
|
||||||
|
// negative. For example:
|
||||||
|
// Get(0) == Get(-Len()) == Front(), and
|
||||||
|
// Get(-1) == Get(Len()-1) == Back().
|
||||||
|
// If the offset is beyond queue boundaries, returns 0 and false.
|
||||||
|
func (q *Queue) Get(i int) (uint8, bool) {
|
||||||
|
|
||||||
|
if n, ok := q.index(i); ok {
|
||||||
|
return (*q.fifo)[n], true
|
||||||
|
}
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set modifies the value of an element in the receiver FIFO.
|
||||||
|
// Set uses the same logic as Get to select an element in the FIFO.
|
||||||
|
func (q *Queue) Set(i int, data uint8) bool {
|
||||||
|
|
||||||
|
if n, ok := q.index(i); ok {
|
||||||
|
(*q.fifo)[n] = data
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user