Skip to content

Commit 5841a86

Browse files
committed
Update
1 parent 788e20d commit 5841a86

File tree

5 files changed

+384
-7
lines changed

5 files changed

+384
-7
lines changed

ble/ble.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//go:build nrf52840
1+
//go:build tinygo && nrf52840
22

33
package ble
44

@@ -15,10 +15,15 @@ var rx bluetooth.DeviceCharacteristic
1515

1616
var reportMap = descriptor.CDCHID.HID[2]
1717

18+
func init() {
19+
adapter.Enable()
20+
}
21+
1822
type bleKeyboard struct {
1923
keyboard
20-
Name string
21-
report [9]byte
24+
Name string
25+
report [9]byte
26+
connected bool
2227
}
2328

2429
func NewKeyboard(name string) *bleKeyboard {
@@ -28,10 +33,7 @@ func NewKeyboard(name string) *bleKeyboard {
2833
}
2934

3035
func (k *bleKeyboard) Connect() error {
31-
err := adapter.Enable()
32-
if err != nil {
33-
return err
34-
}
36+
var err error
3537

3638
bluetooth.SetSecParamsBonding()
3739
bluetooth.SetSecCapabilities(bluetooth.NoneGapIOCapability)

ble/blesplit.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
//go:build tinygo && nrf52840
2+
3+
package ble
4+
5+
import (
6+
k "machine/usb/hid/keyboard"
7+
8+
"tinygo.org/x/bluetooth"
9+
)
10+
11+
var tx = &bluetooth.Characteristic{}
12+
13+
type bleSplitKeyboard struct {
14+
keyboard
15+
Name string
16+
report [9]byte
17+
pressed []k.Keycode
18+
connected bool
19+
}
20+
21+
func NewSplitKeyboard(name string) *bleSplitKeyboard {
22+
return &bleSplitKeyboard{
23+
Name: name,
24+
}
25+
}
26+
27+
//// SetConnectHandler sets a handler function to be called whenever the adaptor connects
28+
//// or disconnects. You must call this before you call adaptor.Connect() for centrals
29+
//// or adaptor.Start() for peripherals in order for it to work.
30+
//func (a *Adapter) SetConnectHandler(c func(device Address, connected bool)) {
31+
// a.connectHandler = c
32+
//}
33+
34+
func (k *bleSplitKeyboard) Connect() error {
35+
var err error
36+
37+
name := k.Name
38+
if len(name) > 14 {
39+
name = name[:14]
40+
}
41+
adapter.SetConnectHandler(func(device bluetooth.Address, connected bool) {
42+
println("connected:", connected)
43+
})
44+
45+
adv := adapter.DefaultAdvertisement()
46+
err = adv.Configure(bluetooth.AdvertisementOptions{
47+
LocalName: name,
48+
})
49+
err = adv.Start()
50+
if err != nil {
51+
return err
52+
}
53+
54+
adapter.AddService(&bluetooth.Service{
55+
UUID: bluetooth.ServiceUUIDNordicUART,
56+
Characteristics: []bluetooth.CharacteristicConfig{
57+
{
58+
Handle: tx,
59+
UUID: bluetooth.CharacteristicUUIDUARTTX,
60+
Value: k.report[:3],
61+
Flags: bluetooth.CharacteristicReadPermission | bluetooth.CharacteristicNotifyPermission,
62+
},
63+
},
64+
})
65+
return nil
66+
}
67+
68+
func (k *bleSplitKeyboard) Up(c k.Keycode) error {
69+
for i, p := range k.pressed {
70+
if c == p {
71+
k.pressed = append(k.pressed[:i], k.pressed[i+1:]...)
72+
row := byte(c >> 8)
73+
col := byte(c)
74+
_, err := tx.Write([]byte{0x55, byte(row), byte(col)})
75+
return err
76+
}
77+
}
78+
return nil
79+
}
80+
81+
func (k *bleSplitKeyboard) Down(c k.Keycode) error {
82+
found := false
83+
for _, p := range k.pressed {
84+
if c == p {
85+
found = true
86+
}
87+
}
88+
if !found {
89+
k.pressed = append(k.pressed, c)
90+
row := byte(c >> 8)
91+
col := byte(c)
92+
_, err := tx.Write([]byte{0xAA, byte(row), byte(col)})
93+
return err
94+
}
95+
return nil
96+
}

ble/keyboard.go

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

35
import (

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)