@@ -18,6 +18,108 @@ type Address struct {
1818 MACAddress
1919}
2020
21+ type Advertisement struct {
22+ advertisement * advertisement.BluetoothLEAdvertisement
23+ publisher * advertisement.BluetoothLEAdvertisementPublisher
24+ }
25+
26+ // DefaultAdvertisement returns the default advertisement instance but does not
27+ // configure it.
28+ func (a * Adapter ) DefaultAdvertisement () * Advertisement {
29+ if a .defaultAdvertisement == nil {
30+ a .defaultAdvertisement = & Advertisement {}
31+ }
32+
33+ return a .defaultAdvertisement
34+ }
35+
36+ // Configure this advertisement.
37+ // on Windows we're only able to set "Manufacturer Data" for advertisements.
38+ // https://learn.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.advertisement.bluetoothleadvertisementpublisher?view=winrt-22621#remarks
39+ // following this c# source for this implementation: https://github.com/microsoft/Windows-universal-samples/blob/main/Samples/BluetoothAdvertisement/cs/Scenario2_Publisher.xaml.cs
40+ // adding service data / localname leads to errors when starting the advertisement.
41+ func (a * Advertisement ) Configure (options AdvertisementOptions ) error {
42+ // we can only advertise manufacturer / company data on windows, so no need to continue if we have none
43+ if len (options .ManufacturerData ) == 0 {
44+ return nil
45+ }
46+
47+ if a .publisher != nil {
48+ a .publisher .Release ()
49+ }
50+
51+ if a .advertisement != nil {
52+ a .advertisement .Release ()
53+ }
54+
55+ pub , err := advertisement .NewBluetoothLEAdvertisementPublisher ()
56+ if err != nil {
57+ return err
58+ }
59+
60+ a .publisher = pub
61+
62+ ad , err := a .publisher .GetAdvertisement ()
63+ if err != nil {
64+ return err
65+ }
66+
67+ a .advertisement = ad
68+
69+ vec , err := ad .GetManufacturerData ()
70+ if err != nil {
71+ return err
72+ }
73+
74+ for _ , optManData := range options .ManufacturerData {
75+ writer , err := streams .NewDataWriter ()
76+ if err != nil {
77+ return err
78+ }
79+ defer writer .Release ()
80+
81+ err = writer .WriteBytes (uint32 (len (optManData .Data )), optManData .Data )
82+ if err != nil {
83+ return err
84+ }
85+
86+ buf , err := writer .DetachBuffer ()
87+ if err != nil {
88+ return err
89+ }
90+
91+ manData , err := advertisement .BluetoothLEManufacturerDataCreate (optManData .CompanyID , buf )
92+ if err != nil {
93+ return err
94+ }
95+
96+ if err = vec .Append (unsafe .Pointer (& manData .IUnknown .RawVTable )); err != nil {
97+ return err
98+ }
99+ }
100+
101+ return nil
102+ }
103+
104+ // Start advertisement. May only be called after it has been configured.
105+ func (a * Advertisement ) Start () error {
106+ // publisher will be present if we actually have manufacturer data to advertise.
107+ if a .publisher != nil {
108+ return a .publisher .Start ()
109+ }
110+
111+ return nil
112+ }
113+
114+ // Stop advertisement. May only be called after it has been started.
115+ func (a * Advertisement ) Stop () error {
116+ if a .publisher != nil {
117+ return a .publisher .Stop ()
118+ }
119+
120+ return nil
121+ }
122+
21123// Scan starts a BLE scan. It is stopped by a call to StopScan. A common pattern
22124// is to cancel the scan when a particular device has been found.
23125func (a * Adapter ) Scan (callback func (* Adapter , ScanResult )) (err error ) {
0 commit comments