github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/machine/usb/cdc/buffer.go (about)

     1  package cdc
     2  
     3  import (
     4  	"runtime/volatile"
     5  )
     6  
     7  const rxRingBufferSize = 128
     8  
     9  // rxRingBuffer is ring buffer implementation inspired by post at
    10  // https://www.embeddedrelated.com/showthread/comp.arch.embedded/77084-1.php
    11  type rxRingBuffer struct {
    12  	buffer [rxRingBufferSize]volatile.Register8
    13  	head   volatile.Register8
    14  	tail   volatile.Register8
    15  }
    16  
    17  // NewRxRingBuffer returns a new ring buffer.
    18  func NewRxRingBuffer() *rxRingBuffer {
    19  	return &rxRingBuffer{}
    20  }
    21  
    22  // Used returns how many bytes in buffer have been used.
    23  func (rb *rxRingBuffer) Used() uint8 {
    24  	return uint8(rb.head.Get() - rb.tail.Get())
    25  }
    26  
    27  // Put stores a byte in the buffer. If the buffer is already
    28  // full, the method will return false.
    29  func (rb *rxRingBuffer) Put(val byte) bool {
    30  	if rb.Used() != rxRingBufferSize {
    31  		rb.head.Set(rb.head.Get() + 1)
    32  		rb.buffer[rb.head.Get()%rxRingBufferSize].Set(val)
    33  		return true
    34  	}
    35  	return false
    36  }
    37  
    38  // Get returns a byte from the buffer. If the buffer is empty,
    39  // the method will return a false as the second value.
    40  func (rb *rxRingBuffer) Get() (byte, bool) {
    41  	if rb.Used() != 0 {
    42  		rb.tail.Set(rb.tail.Get() + 1)
    43  		return rb.buffer[rb.tail.Get()%rxRingBufferSize].Get(), true
    44  	}
    45  	return 0, false
    46  }
    47  
    48  // Clear resets the head and tail pointer to zero.
    49  func (rb *rxRingBuffer) Clear() {
    50  	rb.head.Set(0)
    51  	rb.tail.Set(0)
    52  }
    53  
    54  const txRingBufferSize = 8
    55  
    56  // txRingBuffer is ring buffer implementation inspired by post at
    57  // https://www.embeddedrelated.com/showthread/comp.arch.embedded/77084-1.php
    58  type txRingBuffer struct {
    59  	buffer [txRingBufferSize]struct {
    60  		buf  [64]byte
    61  		size int
    62  	}
    63  	head volatile.Register8
    64  	tail volatile.Register8
    65  }
    66  
    67  // NewTxRingBuffer returns a new ring buffer.
    68  func NewTxRingBuffer() *txRingBuffer {
    69  	return &txRingBuffer{}
    70  }
    71  
    72  // Used returns how many bytes in buffer have been used.
    73  func (rb *txRingBuffer) Used() uint8 {
    74  	return uint8(rb.head.Get() - rb.tail.Get())
    75  }
    76  
    77  // Put stores a byte in the buffer. If the buffer is already
    78  // full, the method will return false.
    79  func (rb *txRingBuffer) Put(val []byte) bool {
    80  	if rb.Used() == txRingBufferSize {
    81  		return false
    82  	}
    83  
    84  	if rb.Used() == 0 {
    85  		rb.head.Set(rb.head.Get() + 1)
    86  		rb.buffer[rb.head.Get()%txRingBufferSize].size = 0
    87  	}
    88  	buf := &rb.buffer[rb.head.Get()%txRingBufferSize]
    89  
    90  	for i := 0; i < len(val); i++ {
    91  		if buf.size == 64 {
    92  			// next
    93  			// TODO: Make sure that data is not corrupted even when the buffer is full
    94  			rb.head.Set(rb.head.Get() + 1)
    95  			buf = &rb.buffer[rb.head.Get()%txRingBufferSize]
    96  			rb.buffer[rb.head.Get()%txRingBufferSize].size = 0
    97  		}
    98  		buf.buf[buf.size] = val[i]
    99  		buf.size++
   100  	}
   101  	return true
   102  }
   103  
   104  // Get returns a byte from the buffer. If the buffer is empty,
   105  // the method will return a false as the second value.
   106  func (rb *txRingBuffer) Get() ([]byte, bool) {
   107  	if rb.Used() != 0 {
   108  		rb.tail.Set(rb.tail.Get() + 1)
   109  		size := rb.buffer[rb.tail.Get()%txRingBufferSize].size
   110  		return rb.buffer[rb.tail.Get()%txRingBufferSize].buf[:size], true
   111  	}
   112  	return nil, false
   113  }
   114  
   115  // Clear resets the head and tail pointer to zero.
   116  func (rb *txRingBuffer) Clear() {
   117  	rb.head.Set(0)
   118  	rb.tail.Set(0)
   119  }