Skip to content

Commit fcbe49d

Browse files
committed
Change to pass through ringbuffer
1 parent 1fa3bd5 commit fcbe49d

File tree

2 files changed

+106
-20
lines changed

2 files changed

+106
-20
lines changed

blekeyboard.go

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//go:build tinygo && nrf52840
2+
13
package keyboard
24

35
import (
@@ -81,11 +83,18 @@ func (k *BleTxKeyboard) Connect() error {
8183
return nil
8284
}
8385

86+
type bleKeyEvent struct {
87+
Index int
88+
IsHigh bool
89+
}
90+
8491
type BleKeyboard struct {
8592
RxBleName string
8693
State []State
8794
Keys [][]Keycode
8895
callback Callback
96+
ringbuf *RingBuffer[bleKeyEvent]
97+
processed []int
8998

9099
adapter *bluetooth.Adapter
91100
buf []byte
@@ -105,6 +114,7 @@ func (d *Device) AddBleKeyboard(size int, rxname string, keys [][]Keycode) *BleK
105114
}
106115
}
107116

117+
var rb [32]bleKeyEvent
108118
k := &BleKeyboard{
109119
RxBleName: rxname,
110120
State: state,
@@ -113,6 +123,8 @@ func (d *Device) AddBleKeyboard(size int, rxname string, keys [][]Keycode) *BleK
113123
callback: func(layer, index int, state State) {},
114124
buf: make([]byte, 3),
115125
changed: false,
126+
ringbuf: NewRingBuffer(rb[:]),
127+
processed: make([]int, 0, 8),
116128
}
117129

118130
d.kb = append(d.kb, k)
@@ -134,25 +146,26 @@ func (d *BleKeyboard) Get() []State {
134146
}
135147
}
136148

137-
if !d.changed {
138-
return d.State
139-
}
140-
141-
d.changed = false
149+
d.processed = d.processed[:0]
142150

143-
if len(d.buf) == 3 {
144-
index := (int(d.buf[1]) << 8) + int(d.buf[2])
145-
current := false
146-
switch d.buf[0] {
147-
case 0xAA: // press
148-
current = true
149-
case 0x55: // release
150-
current = false
151-
default:
152-
d.buf[0], d.buf[1] = d.buf[1], d.buf[2]
153-
d.buf = d.buf[:2]
151+
cont := true
152+
for cont {
153+
b, ok := d.ringbuf.Peek()
154+
if !ok {
154155
return d.State
155156
}
157+
index := b.Index
158+
current := b.IsHigh
159+
160+
for _, idx := range d.processed {
161+
if index == idx {
162+
return d.State
163+
}
164+
}
165+
d.processed = append(d.processed, index)
166+
167+
d.ringbuf.Get()
168+
156169
switch d.State[index] {
157170
case None:
158171
if current {
@@ -236,10 +249,18 @@ func (d *BleKeyboard) Init() error {
236249
if offset != 0 || len(value) != 3 {
237250
return
238251
}
239-
d.buf[0] = value[0]
240-
d.buf[1] = value[1]
241-
d.buf[2] = value[2]
242-
d.changed = true
252+
index := (int(value[1]) << 8) + int(value[2])
253+
isHigh := false
254+
switch value[0] {
255+
case 0xAA: // press
256+
isHigh = true
257+
case 0x55: // release
258+
isHigh = false
259+
}
260+
d.ringbuf.Put(bleKeyEvent{
261+
Index: index,
262+
IsHigh: isHigh,
263+
})
243264
},
244265
},
245266
},

buffer.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//go:build tinygo
2+
3+
package keyboard
4+
5+
import (
6+
"runtime/volatile"
7+
)
8+
9+
// RingBuffer is ring buffer implementation inspired by post at
10+
// https://www.embeddedrelated.com/showthread/comp.arch.embedded/77084-1.php
11+
type RingBuffer[T any] struct {
12+
buffer []T
13+
head volatile.Register8
14+
tail volatile.Register8
15+
}
16+
17+
// NewRingBuffer returns a new ring buffer.
18+
func NewRingBuffer[T any](buf []T) *RingBuffer[T] {
19+
return &RingBuffer[T]{
20+
buffer: buf,
21+
}
22+
}
23+
24+
// Used returns how many bytes in buffer have been used.
25+
func (rb *RingBuffer[T]) Used() uint8 {
26+
return uint8(rb.head.Get() - rb.tail.Get())
27+
}
28+
29+
// Put stores a byte in the buffer. If the buffer is already
30+
// full, the method will return false.
31+
func (rb *RingBuffer[T]) Put(val T) bool {
32+
if rb.Used() != uint8(len(rb.buffer)) {
33+
rb.head.Set(rb.head.Get() + 1)
34+
rb.buffer[rb.head.Get()%uint8(len(rb.buffer))] = val
35+
return true
36+
}
37+
return false
38+
}
39+
40+
// Get returns a byte from the buffer. If the buffer is empty,
41+
// the method will return a false as the second value.
42+
func (rb *RingBuffer[T]) Get() (T, bool) {
43+
if rb.Used() != 0 {
44+
rb.tail.Set(rb.tail.Get() + 1)
45+
return rb.buffer[rb.tail.Get()%uint8(len(rb.buffer))], true
46+
}
47+
var ret T
48+
return ret, false
49+
}
50+
51+
// Peek peeks a byte from the buffer. If the buffer is empty,
52+
// the method will return a false as the second value.
53+
func (rb *RingBuffer[T]) Peek() (T, bool) {
54+
if rb.Used() != 0 {
55+
return rb.buffer[(rb.tail.Get()+1)%uint8(len(rb.buffer))], true
56+
}
57+
var ret T
58+
return ret, false
59+
}
60+
61+
// Clear resets the head and tail pointer to zero.
62+
func (rb *RingBuffer[T]) Clear() {
63+
rb.head.Set(0)
64+
rb.tail.Set(0)
65+
}

0 commit comments

Comments
 (0)