Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions src/examples/serial-stress/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package main

import (
"machine"
"strconv"
"time"
)

func main() {
time.Sleep(2 * time.Second) // connect via serial
buf1 := makeBuffer('|', 600)
buf2 := makeBuffer('/', 600)
println("start")
serialWrite(buf1)
serialWrite(buf2)

// machine.Serial.
}

func makeBuffer(sep byte, size int) []byte {
buf := make([]byte, size)
for i := 0; i < size-5; i += 5 {
buf[i] = sep
strconv.AppendInt(buf[i+1:i+1:i+5], int64(i), 10)
}
return buf
}

func serialWrite(b []byte) {
machine.Serial.Write(b)
}
1 change: 1 addition & 0 deletions src/machine/machine_atsamd51.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"device/sam"
"errors"
"internal/binary"

"runtime/interrupt"
"unsafe"
)
Expand Down
119 changes: 0 additions & 119 deletions src/machine/usb/cdc/buffer.go

This file was deleted.

7 changes: 3 additions & 4 deletions src/machine/usb/cdc/cdc.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//go:build baremetal

package cdc

const (
Expand All @@ -9,10 +11,7 @@ const (
// New returns USBCDC struct.
func New() *USBCDC {
if USB == nil {
USB = &USBCDC{
rxBuffer: NewRxRingBuffer(),
txBuffer: NewTxRingBuffer(),
}
USB = &USBCDC{}
}
return USB
}
Expand Down
99 changes: 99 additions & 0 deletions src/machine/usb/cdc/ring.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package cdc

import "sync/atomic"

// ring512 is an interrupt/concurrent-safe ring buffer for a single-producer,
// single-consumer (SPSC) pair. The writer calls Put, the reader calls
// Peek/Discard. Reset may only be called when neither side is active.
//
// Implementation uses monotonic counters (head/tail) instead of bounded
// offsets. This eliminates full/empty ambiguity and removes all CAS
// recovery paths. Unsigned subtraction (head - tail) always yields
// correct used count regardless of uint32 overflow.
type ring512 struct {
buf [ringBufLen]byte // power of 2 so compiler can optimize & mask.
// head counts total bytes written. Only the writer stores to head.
head atomic.Uint32
// tail counts total bytes read. Only the reader stores to tail.
tail atomic.Uint32
}

const (
ringBufLen = 512
ringMask = ringBufLen - 1 // 0x1FF
)

// Reset empties the ring buffer. Must not be called concurrently with
// Put, Peek, or Discard.
func (r *ring512) Reset() {
r.head.Store(0)
r.tail.Store(0)
}

// Free returns number of bytes that can be written via Put.
func (r *ring512) Free() uint32 {
return ringBufLen - r.Used()
}

// Used returns number of bytes ready to be peeked/discarded.
func (r *ring512) Used() uint32 {
return r.head.Load() - r.tail.Load()
}

// Peek returns a contiguous view into the readable portions of the buffer
// without advancing the read position. When data wraps around the end of
// the internal buffer, two segments are returned. Second data2 is nil on fully contiguous buffer.
// Returns nil,nil when empty.
func (r *ring512) Peek() (data1, data2 []byte) {
head, tail := r.lims()
used := head - tail
if used == 0 {
return nil, nil
}
pos := tail & ringMask
contig := ringBufLen - pos
if contig >= used {
return r.buf[pos : pos+used], nil
}
return r.buf[pos:], r.buf[:used-contig]
}

// Discard marks numBytes as read, advancing the read position.
// Panics if numBytes exceeds Used (indicates a race violating SPSC)
func (r *ring512) Discard(numBytes uint32) {
if numBytes == 0 {
return
}
head, tail := r.lims()
used := head - tail
if numBytes > used {
panic("ring: discard exceeds used")
}
r.tail.Store(tail + numBytes)
}

// Put writes data into the ring buffer. Returns true if all data was
// written, false if insufficient free space (no partial writes).
func (r *ring512) Put(data []byte) bool {
wlen := uint32(len(data))
if wlen == 0 {
return true
}
head, tail := r.lims()
used := head - tail
free := uint32(ringBufLen) - used
if wlen > free {
return false
}
pos := head & ringMask
n := uint32(copy(r.buf[pos:], data))
if n < wlen {
copy(r.buf[:], data[n:])
}
r.head.Store(head + wlen)
return true
}

func (r *ring512) lims() (head, tail uint32) {
return r.head.Load(), r.tail.Load()
}
Loading
Loading