Skip to content
Open
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
48 changes: 48 additions & 0 deletions adapter_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package bluetooth
import (
"errors"
"fmt"
"syscall"
"unsafe"

"github.com/go-ole/go-ole"
"github.com/saltosystems/winrt-go"
Expand Down Expand Up @@ -55,11 +57,57 @@ func awaitAsyncOperation(asyncOperation *foundation.IAsyncOperation, genericPara
<-waitChan

if status != foundation.AsyncStatusCompleted {
if err := getAsyncError(asyncOperation); err != nil {
return fmt.Errorf("async operation failed with status %d: %w", status, err)
}
return fmt.Errorf("async operation failed with status %d", status)
}
return nil
}

// getAsyncError queries IAsyncInfo from an IAsyncOperation to retrieve
// the error code of a failed async operation. If the HRESULT corresponds
// to a Bluetooth ATT error (facility 0x65), it returns an AttributeProtocolError.
func getAsyncError(asyncOperation *foundation.IAsyncOperation) error {
iid := ole.NewGUID(foundation.GUIDIAsyncInfo)

var asyncInfo *foundation.IAsyncInfo
hr, _, _ := syscall.SyscallN(
asyncOperation.VTable().QueryInterface,
uintptr(unsafe.Pointer(asyncOperation)),
uintptr(unsafe.Pointer(iid)),
uintptr(unsafe.Pointer(&asyncInfo)),
)
if hr != 0 {
return nil
}
defer asyncInfo.Release()

result, err := asyncInfo.GetErrorCode()
if err != nil {
return err
}
if result.Value == 0 {
return nil
}

return hresultToError(uint32(result.Value))
}

// hresultToError converts an HRESULT to an appropriate error type.
// For Bluetooth ATT errors (facility 0x65), it returns an error with the ATT error code.
// For other errors, it returns a generic error with the HRESULT value.
func hresultToError(hr uint32) error {
facility := (hr >> 16) & 0x1FFF
code := hr & 0xFFFF

if facility == 0x65 { // FACILITY_BLUETOOTH_ATT
return fmt.Errorf("Bluetooth ATT error (code 0x%04X)", code)
}

return fmt.Errorf("HRESULT 0x%08X", hr)
}

func (a *Adapter) Address() (MACAddress, error) {
// TODO: get mac address
return MACAddress{}, errors.New("not implemented")
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.22.1
require (
github.com/go-ole/go-ole v1.2.6
github.com/godbus/dbus/v5 v5.1.0
github.com/saltosystems/winrt-go v0.0.0-20240509164145-4f7860a3bd2b
github.com/saltosystems/winrt-go v0.0.0-20260317170058-9c2fec580d96
github.com/soypat/cyw43439 v0.0.0-20250505012923-830110c8f4af
github.com/tinygo-org/cbgo v0.0.4
golang.org/x/crypto v0.12.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/saltosystems/winrt-go v0.0.0-20240509164145-4f7860a3bd2b h1:du3zG5fd8snsFN6RBoLA7fpaYV9ZQIsyH9snlk2Zvik=
github.com/saltosystems/winrt-go v0.0.0-20240509164145-4f7860a3bd2b/go.mod h1:CIltaIm7qaANUIvzr0Vmz71lmQMAIbGJ7cvgzX7FMfA=
github.com/saltosystems/winrt-go v0.0.0-20260317170058-9c2fec580d96 h1:IXxzj3yjfDNXZJ35foY+RpFShqPsZZ81hhCckgfh5PI=
github.com/saltosystems/winrt-go v0.0.0-20260317170058-9c2fec580d96/go.mod h1:CIltaIm7qaANUIvzr0Vmz71lmQMAIbGJ7cvgzX7FMfA=
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
Expand Down
Loading