add basic CDC-ACM UART Rx capability

This commit is contained in:
ardnew
2022-02-18 12:09:04 -06:00
committed by sago35
parent 2f50d24fec
commit 5f6489d3cf
5 changed files with 396 additions and 182 deletions
+4 -11
View File
@@ -505,11 +505,10 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
// CDC-ACM (single)
case classDeviceCDCACM:
// line coding must contain exactly 7 bytes
if uint16(descCDCACMCodingSize) == sup.wLength {
d.setup = sup
if uint16(descCDCACMLineCodingSize) == sup.wLength {
d.controlReceive(
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
// controlComplete().
return dcdStageDataOut
@@ -534,7 +533,7 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
// Control/status interface:
case descCDCACMInterfaceCtrl:
// 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)
return dcdStageStatusOut
@@ -570,7 +569,6 @@ func (d *dcd) controlSetup(sup dcdSetup) dcdStage {
// HID
case classDeviceHID:
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])),
@@ -687,12 +685,7 @@ func (d *dcd) controlComplete() {
case descCDCACMInterfaceCtrl:
// Notify PHY to handle triggers like special baud rates, which
// signal to reboot into bootloader or begin receiving OTA updates
d.uartSetLineCoding(descCDCACMLineCoding{
baud: packU32(acm.cx[:]),
stopBits: acm.cx[4],
parity: acm.cx[5],
numBits: acm.cx[6],
})
d.uartSetLineCoding(acm.cx[:])
default:
// Unhandled device interface
+45 -7
View File
@@ -1,7 +1,5 @@
package usb
import "unsafe"
const descUSBSpecVersion = uint16(0x0200) // USB 2.0
const descLanguageEnglish = uint16(0x0409) // (US) English
@@ -140,6 +138,9 @@ const (
const (
descDirOut = descRequestTypeDirOut >> 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
@@ -429,15 +430,55 @@ const (
// 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 = unsafe.Sizeof(descCDCACMLineCoding{})
// descCDCACMLineCodingSize defines the length of a CDC-ACM UART line coding
// 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.
//
// Use descCDCACMLineCodingSize instead of unsafe.Sizeof(descCDCACMLineCoding)
// in any transfer requests, because the actual struct is padded for alignment.
type descCDCACMLineCoding struct {
baud uint32
stopBits uint8
parity 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.
@@ -465,9 +506,6 @@ 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
+27 -8
View File
@@ -38,9 +38,6 @@ const (
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
)
@@ -69,8 +66,8 @@ const (
// CDC-ACM Data Buffers
descCDCACMRxSize = 4 * descCDCACMDataRxPacketSize
descCDCACMTxSize = 4 * descCDCACMDataTxPacketSize
descCDCACMRxSize = 1 * descCDCACMDataRxPacketSize
descCDCACMTxSize = 1 * descCDCACMDataTxPacketSize
descCDCACMTxTimeoutMs = 120 // millisec
descCDCACMTxSyncUs = 75 // microsec
@@ -221,6 +218,16 @@ var descCDCACM0Rx [descCDCACMRxSize]uint8
//go:align 32
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
// (single) device class configurations, ordered by index (offset by -1), for
// SAMx51 targets only.
@@ -245,9 +252,15 @@ type descCDCACMClassData struct {
rx *[descCDCACMRxSize]uint8 // bulk data endpoint Rx (OUT) transfer buffer
tx *[descCDCACMTxSize]uint8 // bulk data endpoint Tx (IN) transfer buffer
sxSize uint16
rxSize uint16
txSize uint16
lc *descCDCACMLineCoding // UART line coding
ls *descCDCACMLineState // UART line state
rq *Queue
tq *Queue
sxSize uint32
rxSize uint32
txSize uint32
}
// descCDCACMData holds statically-allocated instances for each of the target-
@@ -271,6 +284,12 @@ var descCDCACMData = [dcdCount]descCDCACMClassData{
rx: &descCDCACM0Rx,
tx: &descCDCACM0Tx,
lc: &descCDCACM0LC,
ls: &descCDCACM0LS,
rq: &Queue{},
tq: &Queue{},
sxSize: descCDCACMStatusPacketSize,
rxSize: descCDCACMDataRxPacketSize,
txSize: descCDCACMDataTxPacketSize,
+108 -102
View File
@@ -9,6 +9,7 @@ package usb
import (
"device/arm"
"device/sam"
"math/bits"
"runtime/interrupt"
"runtime/volatile"
"unsafe"
@@ -34,31 +35,11 @@ type dhw struct {
ep [descMaxEndpoints]dhwEPAddrStatus
log [2048][64]byte
logCount uint
setup dcdSetup
stage dcdStage
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 flushCache(addr, size uintptr) {}
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
if 0 == speed {
if speed == 0 {
speed = FullSpeed
}
dhwInstance[instance].speed = speed
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]
}
@@ -327,12 +300,12 @@ func (d *dhw) interrupt() {
sam.USB_DEVICE_ENDPOINT_EPINTFLAG_RXSTP |
sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT0)
d.logEvent("setup received")
// Parse the SETUP packet immediately, clearing room in the (one and only)
// control buffer for the next SETUP packet received.
sup := setupFrom(d.controlSetupBuffer())
dir := sup.direction()
// We've copied the SETUP packet elsewhere and are ready to receive another.
d.prepareSetup()
// 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++ {
if (epints & (1 << ep)) == 0 {
continue
}
ep := uint8(bits.TrailingZeros16(epints))
epints &^= 1 << ep
intFlag := d.bus.DEVICE_ENDPOINT[ep].EPINTFLAG.Get()
@@ -378,22 +349,20 @@ func (d *dhw) interrupt() {
d.bus.DEVICE_ENDPOINT[ep].EPINTFLAG.Set(
sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
d.controlStall(false, descDirIn)
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
// upper-layer device driver of a control transfer completion event.
if count == 0 || count < size {
d.logEvent("EP0 Tx transfer complete")
d.controlTransferComplete(txEndpoint(ep), count, total)
} else {
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
// 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(
sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT0)
d.controlStall(false, descDirOut)
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
// upper-layer device driver of a control transfer completion event.
if count == 0 || count < size {
d.logEvent("EP0 Rx transfer complete")
d.controlTransferComplete(rxEndpoint(ep), count, total)
} else {
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
// 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)
// Swap direction of the given endpoint Rx->Tx and Tx->Rx
switch dir {
case descDirOut:
case descDirRx:
endpoint = txEndpoint(num)
case descDirIn:
case descDirTx:
endpoint = rxEndpoint(num)
}
d.endpointTransfer(endpoint, 0, 0)
@@ -543,8 +511,6 @@ func (d *dhw) controlStatusStart(endpoint uint8) {
func (d *dhw) controlStatusComplete(endpoint uint8) {
d.logEvent("setup processing complete")
if (d.setup.bmRequestType&descRequestTypeTypeMsk == descRequestTypeTypeStandard) &&
(d.setup.bmRequestType&(descRequestTypeRecipientMsk|descRequestTypeDirMsk) ==
descRequestTypeRecipientDevice|descRequestTypeDirOut) &&
@@ -564,7 +530,6 @@ func (d *dhw) controlTransferStart(endpoint uint8) {
// Dequeue the next transfer descriptor available.
if xfer, ok := d.ep[num][dir].pendingTransfer(); ok {
d.logEvent("setup processing begin")
// Update the active transfer descriptor on the corresponding endpoint.
d.ep[num][dir].setActiveTransfer(xfer)
// 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()
setupAddress := packEndpoint(num, setupDir)
d.logEvent("setup packet complete")
// 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.
if dir != setupDir {
@@ -607,7 +570,6 @@ func (d *dhw) controlTransferComplete(endpoint uint8, count, total uint32) {
// Start processing any pending control transfers.
d.controlTransferStart(setupAddress)
} else {
d.logEvent("control status phase")
// Initiate ZLP transfer in opposite direction.
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) {
ep := d.controlEndpoint()
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)
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) {
ep := d.controlEndpoint()
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)
d.endpointTransfer(txEndpoint(ep), data, next)
}
@@ -658,9 +620,9 @@ type dhwTransfer struct {
// dhwTransferDepth defines the size of the dhwEPStatus.xferQueue buffered channel,
// 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) {
t.endpoint = endpoint
@@ -741,6 +703,7 @@ type dhwEPStatus struct {
callback func(endpoint uint8, size uint32)
flags volatile.Register8
xferActive volatile.Register32
xferFIFO [dhwTransferDepth]uint8
xferQueue Queue
xferTable dhwTransferLUT
}
@@ -761,7 +724,8 @@ func (s *dhwEPStatus) init(dhw *dhw, endpoint uint8) {
s.endpoint = endpoint
s.callback = nil
s.flags.Set(0)
s.xferQueue.Reset()
fifo := s.xferFIFO[:]
s.xferQueue.Init(&fifo, dhwTransferDepth, QueueFullDiscardLast)
mps := dhw.endpointMaxPacketSize(endpoint)
for i := range s.xferTable {
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.
func (s *dhwEPStatus) scheduleSetup(setup dcdSetup) (ready bool, ok bool) {
var i int
s.device.logEvent("setup queued")
if i, ok = s.claimSchedule(); ok {
defer s.device.enableInterrupts(true)
s.xferTable[i].reset()
@@ -1157,14 +1120,18 @@ func (d *dhw) endpointEnable(endpoint uint8, control bool, config uint32) {
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.
out.packetSize.ReplaceBits(enum,
USB_DEVICE_PCKSIZE_SIZE_Msk, USB_DEVICE_PCKSIZE_SIZE_Pos)
in.packetSize.ReplaceBits(enum,
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
// else-branch that handles non-control endpoints).
// 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 {
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,
USB_DEVICE_PCKSIZE_SIZE_Msk, USB_DEVICE_PCKSIZE_SIZE_Pos)
num := endpointNumber(endpoint)
// 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
// 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_DTGLOUT)
d.bus.DEVICE_ENDPOINT[num].EPINTENSET.ReplaceBits(
sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0,
sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0_Msk, 0)
d.bus.DEVICE_ENDPOINT[num].EPINTENSET.Set(
sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0)
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_DTGLIN)
d.bus.DEVICE_ENDPOINT[num].EPINTENSET.ReplaceBits(
sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT1,
sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT1_Msk, 0)
d.bus.DEVICE_ENDPOINT[num].EPINTENSET.Set(
sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT1)
}
}
}
}
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.
@@ -1299,7 +1270,7 @@ func (d *dhw) endpointTransfer(endpoint uint8, data uintptr, size uint32) {
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
// size, respectively).
@@ -1315,7 +1286,7 @@ func (d *dhw) endpointTransfer(endpoint uint8, data uintptr, size uint32) {
d.bus.DEVICE_ENDPOINT[num].EPINTFLAG.SetBits(
sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRFAIL0)
case descDirIn: // Tx
case descDirTx: // IN
// overwrite the BYTE_COUNT and MULTI_PACKET_SIZE bitfields only (with size
// and 0, respectively).
@@ -1364,54 +1335,89 @@ func (d *dhw) uartConfigure() {
acm := &descCDCACM[d.cc.config-1]
// SAMx51 only supports USB full-speed (FS) operation
acm.sxSize = descCDCACMStatusFSPacketSize
acm.rxSize = descCDCACMDataRxFSPacketSize
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)
d.endpointEnable(descCDCACMEndpointDataRx,
d.endpointEnable(rxEndpoint(descCDCACMEndpointDataRx),
false, descCDCACMConfigAttrDataRx)
d.endpointEnable(descCDCACMEndpointDataTx,
d.endpointEnable(txEndpoint(descCDCACMEndpointDataTx),
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.uartReceive(uint8(i))
d.endpointConfigure(txEndpoint(descCDCACMEndpointStatus),
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 {
acm := &descCDCACM[d.cc.config-1]
_ = acm // TODO(ardnew): elaborate stub
return false
return d.dcd.state() == dcdStateConfigured
}
func (d *dhw) uartReceive(endpoint uint8) {
acm := &descCDCACM[d.cc.config-1]
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]
num := uint16(endpoint) & descEndptAddrNumberMsk
_ = 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.
@@ -1445,7 +1451,7 @@ func (d *dhw) uartRead(data []uint8) int {
}
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 {
+212 -54
View File
@@ -5,12 +5,19 @@ import (
"runtime/volatile"
)
const QueueSize = 8
type QueueFullDiscardMode uint8
const (
QueueFullDiscardLast QueueFullDiscardMode = iota // Drop incoming data
QueueFullDiscardFirst // Drop outgoing data
)
type Queue struct {
fifo [QueueSize]uint8
tail volatile.Register32
head volatile.Register32
mode QueueFullDiscardMode
size 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 (
@@ -18,28 +25,94 @@ var (
ErrWriteBuffer = errors.New("cannot copy from write buffer")
ErrQueueEmpty = errors.New("data queue empty") // Read 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
func (q *Queue) Reset() {
for i := range q.fifo {
q.fifo[i] = 0
func (q *Queue) Reset(size int) {
if phy := len(*q.fifo); size < 0 || size > phy {
size = phy
}
q.size.Set(uint32(size))
q.tail.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
func (q *Queue) Len() int {
return int(q.tail.Get() - q.head.Get())
}
// Rem returns the number of elements not enqueued in the receiver FIFO.
//go:inline
func (q *Queue) Cap() int {
return cap(q.fifo)
func (q *Queue) Rem() int {
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) {
less := uint32(len(data))
@@ -59,7 +132,7 @@ func (q *Queue) Read(data []uint8) (int, error) {
} // only get from used space
for i := uint32(0); i < less; i++ {
data[i] = q.fifo[head%QueueSize]
data[i] = (*q.fifo)[head%q.size.Get()]
head++
}
q.head.Set(head)
@@ -67,65 +140,150 @@ func (q *Queue) Read(data []uint8) (int, error) {
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) {
more := uint32(len(data))
// Nothing to copy from is an error regardless of mode.
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
switch q.mode {
case QueueFullDiscardLast:
// drop incoming data
tail := q.tail.Get()
used := tail - q.head.Get()
// Full queue, cannot add any data.
if used == q.size.Get() {
return 0, ErrQueueFull
}
// xOnly put to unused space.
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) {
tail := q.head.Get()
if tail == q.tail.Get() {
head := q.head.Get()
if head == q.tail.Get() {
return 0, false
} // 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()
if head-q.head.Get() == QueueSize {
return false
} // full queue
tail := q.tail.Get()
if tail == q.head.Get() {
return 0, false
} // empty queue
q.fifo[head%QueueSize] = data
q.tail.Set(head + 1)
return true
return (*q.fifo)[(tail-1)%q.size.Get()], 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
}