Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: BLE HID Support #48

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
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
194 changes: 194 additions & 0 deletions ble/ble.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
//go:build tinygo && nrf52840

package ble

import (
"machine/usb/descriptor"
k "machine/usb/hid/keyboard"

"tinygo.org/x/bluetooth"
)

var adapter = bluetooth.DefaultAdapter
var reportIn bluetooth.Characteristic
var rx bluetooth.DeviceCharacteristic

var reportMap = descriptor.CDCHID.HID[2]

func init() {
adapter.Enable()
}

type bleKeyboard struct {
keyboard
Name string
report [9]byte
connected bool
}

func NewKeyboard(name string) *bleKeyboard {
return &bleKeyboard{
Name: name,
}
}

func (k *bleKeyboard) Connect() error {
var err error

bluetooth.SetSecParamsBonding()
bluetooth.SetSecCapabilities(bluetooth.NoneGapIOCapability)

name := k.Name
if len(name) > 14 {
name = name[:14]
}

adv := adapter.DefaultAdvertisement()
adv.Configure(bluetooth.AdvertisementOptions{
LocalName: name,
ServiceUUIDs: []bluetooth.UUID{
bluetooth.ServiceUUIDDeviceInformation,
bluetooth.ServiceUUIDBattery,
bluetooth.ServiceUUIDHumanInterfaceDevice,
},
})

err = adv.Start()
if err != nil {
return err
}

k.registerHID()

return nil
}

func (k *bleKeyboard) registerHID() error {
adapter.AddService(&bluetooth.Service{
UUID: bluetooth.ServiceUUIDDeviceInformation,
Characteristics: []bluetooth.CharacteristicConfig{
{
UUID: bluetooth.CharacteristicUUIDManufacturerNameString,
Flags: bluetooth.CharacteristicReadPermission,
Value: []byte("Nice Keyboards"),
},
{
UUID: bluetooth.CharacteristicUUIDModelNumberString,
Flags: bluetooth.CharacteristicReadPermission,
Value: []byte("nice!nano"),
},
{
UUID: bluetooth.CharacteristicUUIDPnPID,
Flags: bluetooth.CharacteristicReadPermission,
Value: []byte{0x02, 0x8a, 0x24, 0x66, 0x82, 0x34, 0x36},
//Value: []byte{0x02, uint8(0x10C4 >> 8), uint8(0x10C4 & 0xff), uint8(0x0001 >> 8), uint8(0x0001 & 0xff)},
},
},
})
adapter.AddService(&bluetooth.Service{
UUID: bluetooth.ServiceUUIDBattery,
Characteristics: []bluetooth.CharacteristicConfig{
{
UUID: bluetooth.CharacteristicUUIDBatteryLevel,
Value: []byte{80},
Flags: bluetooth.CharacteristicReadPermission | bluetooth.CharacteristicNotifyPermission,
},
},
})
// gacc
/*
device name r
apperance r
peripheral prefreed connection

*/

adapter.AddService(&bluetooth.Service{
UUID: bluetooth.ServiceUUIDGenericAccess,
Characteristics: []bluetooth.CharacteristicConfig{
{
UUID: bluetooth.CharacteristicUUIDDeviceName,
Flags: bluetooth.CharacteristicReadPermission,
Value: []byte("tinygo-corne"),
},
{

UUID: bluetooth.New16BitUUID(0x2A01),
Flags: bluetooth.CharacteristicReadPermission,
Value: []byte{uint8(0x03c4 >> 8), uint8(0x03c4 & 0xff)}, /// []byte(strconv.Itoa(961)),
},
// {
// UUID: bluetooth.CharacteristicUUIDPeripheralPreferredConnectionParameters,
// Flags: bluetooth.CharacteristicReadPermission,
// Value: []byte{0x02},
// },

// // //
},
})

// hid
adapter.AddService(&bluetooth.Service{
UUID: bluetooth.ServiceUUIDHumanInterfaceDevice,
/*
- hid information r
- report map r
- report nr
- client charecteristic configuration
- report reference
- report nr
- client charecteristic configuration
- report reference
- hid control point wnr
*/
Characteristics: []bluetooth.CharacteristicConfig{
// {
// UUID: bluetooth.CharacteristicUUIDHIDInformation,
// Flags: bluetooth.CharacteristicReadPermission,
// Value: []byte{uint8(0x0111 >> 8), uint8(0x0111 & 0xff), uint8(0x0002 >> 8), uint8(0x0002 & 0xff)},
// },
{
//Handle: &reportmap,
UUID: bluetooth.CharacteristicUUIDReportMap,
Flags: bluetooth.CharacteristicReadPermission,
Value: reportMap,
},
{

Handle: &reportIn,
UUID: bluetooth.CharacteristicUUIDReport,
Value: k.report[:],
Flags: bluetooth.CharacteristicReadPermission | bluetooth.CharacteristicNotifyPermission,
},
{
// protocl mode
UUID: bluetooth.New16BitUUID(0x2A4E),
Flags: bluetooth.CharacteristicWriteWithoutResponsePermission | bluetooth.CharacteristicReadPermission,
// Value: []byte{uint8(1)},
// WriteEvent: func(client bluetooth.Connection, offset int, value []byte) {
// print("protocol mode")
// },
},
{
UUID: bluetooth.CharacteristicUUIDHIDControlPoint,
Flags: bluetooth.CharacteristicWriteWithoutResponsePermission,
// Value: []byte{0x02},
},
},
})

return nil
}

func (k *bleKeyboard) Up(c k.Keycode) error {
return k.keyboard.Up(Keycode(c))
}

func (k *bleKeyboard) Down(c k.Keycode) error {
return k.keyboard.Down(Keycode(c))
}

func sendBLEPacket(b []byte) error {
_, err := reportIn.Write(b)
return err
}
89 changes: 89 additions & 0 deletions ble/blesplit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//go:build tinygo && nrf52840

package ble

import (
k "machine/usb/hid/keyboard"

"tinygo.org/x/bluetooth"
)

var tx = &bluetooth.Characteristic{}

type bleSplitKeyboard struct {
keyboard
Name string
report [9]byte
pressed []k.Keycode
connected bool
}

func NewSplitKeyboard(name string) *bleSplitKeyboard {
return &bleSplitKeyboard{
Name: name,
}
}

func (k *bleSplitKeyboard) Connect() error {
var err error

name := k.Name
if len(name) > 14 {
name = name[:14]
}
adapter.SetConnectHandler(func(device bluetooth.Address, connected bool) {
println("connected:", connected)
})

adv := adapter.DefaultAdvertisement()
err = adv.Configure(bluetooth.AdvertisementOptions{
LocalName: name,
})
err = adv.Start()
if err != nil {
return err
}

adapter.AddService(&bluetooth.Service{
UUID: bluetooth.ServiceUUIDNordicUART,
Characteristics: []bluetooth.CharacteristicConfig{
{
Handle: tx,
UUID: bluetooth.CharacteristicUUIDUARTTX,
Value: k.report[:3],
Flags: bluetooth.CharacteristicReadPermission | bluetooth.CharacteristicNotifyPermission,
},
},
})
return nil
}

func (k *bleSplitKeyboard) Up(c k.Keycode) error {
for i, p := range k.pressed {
if c == p {
k.pressed = append(k.pressed[:i], k.pressed[i+1:]...)
row := byte(c >> 8)
col := byte(c)
_, err := tx.Write([]byte{0x55, byte(row), byte(col)})
return err
}
}
return nil
}

func (k *bleSplitKeyboard) Down(c k.Keycode) error {
found := false
for _, p := range k.pressed {
if c == p {
found = true
}
}
if !found {
k.pressed = append(k.pressed, c)
row := byte(c >> 8)
col := byte(c)
_, err := tx.Write([]byte{0xAA, byte(row), byte(col)})
return err
}
return nil
}
Loading
Loading