Skip to content

Commit

Permalink
Winrt full support (#266)
Browse files Browse the repository at this point in the history
windows: full functionality
  • Loading branch information
Cartermel authored May 9, 2024
1 parent 6b08161 commit 314ca89
Show file tree
Hide file tree
Showing 8 changed files with 427 additions and 5 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ smoketest-windows:
GOOS=windows go build -o /tmp/go-build-discard ./examples/scanner
GOOS=windows go build -o /tmp/go-build-discard ./examples/discover
GOOS=windows go build -o /tmp/go-build-discard ./examples/heartrate-monitor
GOOS=windows go build -o /tmp/go-build-discard ./examples/advertisement
GOOS=windows go build -o /tmp/go-build-discard ./examples/heartrate

smoketest-macos:
# Test on macos.
Expand Down
8 changes: 8 additions & 0 deletions adapter_windows.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package bluetooth

import (
"errors"
"fmt"

"github.com/go-ole/go-ole"
Expand All @@ -13,6 +14,8 @@ type Adapter struct {
watcher *advertisement.BluetoothLEAdvertisementWatcher

connectHandler func(device Device, connected bool)

defaultAdvertisement *Advertisement
}

// DefaultAdapter is the default adapter on the system.
Expand Down Expand Up @@ -56,3 +59,8 @@ func awaitAsyncOperation(asyncOperation *foundation.IAsyncOperation, genericPara
}
return nil
}

func (a *Adapter) Address() (MACAddress, error) {
// TODO: get mac address
return MACAddress{}, errors.New("not implemented")
}
102 changes: 102 additions & 0 deletions gap_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,108 @@ type Address struct {
MACAddress
}

type Advertisement struct {
advertisement *advertisement.BluetoothLEAdvertisement
publisher *advertisement.BluetoothLEAdvertisementPublisher
}

// DefaultAdvertisement returns the default advertisement instance but does not
// configure it.
func (a *Adapter) DefaultAdvertisement() *Advertisement {
if a.defaultAdvertisement == nil {
a.defaultAdvertisement = &Advertisement{}
}

return a.defaultAdvertisement
}

// Configure this advertisement.
// on Windows we're only able to set "Manufacturer Data" for advertisements.
// https://learn.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.advertisement.bluetoothleadvertisementpublisher?view=winrt-22621#remarks
// following this c# source for this implementation: https://github.com/microsoft/Windows-universal-samples/blob/main/Samples/BluetoothAdvertisement/cs/Scenario2_Publisher.xaml.cs
// adding service data / localname leads to errors when starting the advertisement.
func (a *Advertisement) Configure(options AdvertisementOptions) error {
// we can only advertise manufacturer / company data on windows, so no need to continue if we have none
if len(options.ManufacturerData) == 0 {
return nil
}

if a.publisher != nil {
a.publisher.Release()
}

if a.advertisement != nil {
a.advertisement.Release()
}

pub, err := advertisement.NewBluetoothLEAdvertisementPublisher()
if err != nil {
return err
}

a.publisher = pub

ad, err := a.publisher.GetAdvertisement()
if err != nil {
return err
}

a.advertisement = ad

vec, err := ad.GetManufacturerData()
if err != nil {
return err
}

for _, optManData := range options.ManufacturerData {
writer, err := streams.NewDataWriter()
if err != nil {
return err
}
defer writer.Release()

err = writer.WriteBytes(uint32(len(optManData.Data)), optManData.Data)
if err != nil {
return err
}

buf, err := writer.DetachBuffer()
if err != nil {
return err
}

manData, err := advertisement.BluetoothLEManufacturerDataCreate(optManData.CompanyID, buf)
if err != nil {
return err
}

if err = vec.Append(unsafe.Pointer(&manData.IUnknown.RawVTable)); err != nil {
return err
}
}

return nil
}

// Start advertisement. May only be called after it has been configured.
func (a *Advertisement) Start() error {
// publisher will be present if we actually have manufacturer data to advertise.
if a.publisher != nil {
return a.publisher.Start()
}

return nil
}

// Stop advertisement. May only be called after it has been started.
func (a *Advertisement) Stop() error {
if a.publisher != nil {
return a.publisher.Stop()
}

return nil
}

// Scan starts a BLE scan. It is stopped by a call to StopScan. A common pattern
// is to cancel the scan when a particular device has been found.
func (a *Adapter) Scan(callback func(*Adapter, ScanResult)) (err error) {
Expand Down
4 changes: 3 additions & 1 deletion gatts.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ type Service struct {
Characteristics []CharacteristicConfig
}

type WriteEvent = func(client Connection, offset int, value []byte)

// CharacteristicConfig contains some parameters for the configuration of a
// single characteristic.
//
Expand All @@ -17,7 +19,7 @@ type CharacteristicConfig struct {
UUID
Value []byte
Flags CharacteristicPermissions
WriteEvent func(client Connection, offset int, value []byte)
WriteEvent WriteEvent
}

// CharacteristicPermissions lists a number of basic permissions/capabilities
Expand Down
2 changes: 1 addition & 1 deletion gatts_other.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build !linux
//go:build !linux && !windows

package bluetooth

Expand Down
Loading

0 comments on commit 314ca89

Please sign in to comment.