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 }