@@ -142,6 +142,27 @@ func (a *Adapter) Scan(callback func(*Adapter, ScanResult)) error {
142142 return errScanning
143143 }
144144
145+ signal := make (chan * dbus.Signal )
146+ a .bus .Signal (signal )
147+ defer a .bus .RemoveSignal (signal )
148+
149+ propertiesChangedMatchOptions := []dbus.MatchOption {dbus .WithMatchInterface ("org.freedesktop.DBus.Properties" )}
150+ a .bus .AddMatchSignal (propertiesChangedMatchOptions ... )
151+ defer a .bus .RemoveMatchSignal (propertiesChangedMatchOptions ... )
152+
153+ newObjectMatchOptions := []dbus.MatchOption {dbus .WithMatchInterface ("org.freedesktop.DBus.ObjectManager" )}
154+ a .bus .AddMatchSignal (newObjectMatchOptions ... )
155+ defer a .bus .RemoveMatchSignal (newObjectMatchOptions ... )
156+
157+ // Check if the adapter is powered on.
158+ powered , err := a .adapter .GetProperty ("org.bluez.Adapter1.Powered" )
159+ if err != nil {
160+ return err
161+ }
162+ if ! powered .Value ().(bool ) {
163+ return errAdaptorNotPowered
164+ }
165+
145166 // Channel that will be closed when the scan is stopped.
146167 // Detecting whether the scan is stopped can be done by doing a non-blocking
147168 // read from it. If it succeeds, the scan is stopped.
@@ -150,25 +171,13 @@ func (a *Adapter) Scan(callback func(*Adapter, ScanResult)) error {
150171
151172 // This appears to be necessary to receive any BLE discovery results at all.
152173 defer a .adapter .Call ("org.bluez.Adapter1.SetDiscoveryFilter" , 0 )
153- err : = a .adapter .Call ("org.bluez.Adapter1.SetDiscoveryFilter" , 0 , map [string ]interface {}{
174+ err = a .adapter .Call ("org.bluez.Adapter1.SetDiscoveryFilter" , 0 , map [string ]interface {}{
154175 "Transport" : "le" ,
155176 }).Err
156177 if err != nil {
157178 return err
158179 }
159180
160- signal := make (chan * dbus.Signal )
161- a .bus .Signal (signal )
162- defer a .bus .RemoveSignal (signal )
163-
164- propertiesChangedMatchOptions := []dbus.MatchOption {dbus .WithMatchInterface ("org.freedesktop.DBus.Properties" )}
165- a .bus .AddMatchSignal (propertiesChangedMatchOptions ... )
166- defer a .bus .RemoveMatchSignal (propertiesChangedMatchOptions ... )
167-
168- newObjectMatchOptions := []dbus.MatchOption {dbus .WithMatchInterface ("org.freedesktop.DBus.ObjectManager" )}
169- a .bus .AddMatchSignal (newObjectMatchOptions ... )
170- defer a .bus .RemoveMatchSignal (newObjectMatchOptions ... )
171-
172181 // Go through all connected devices and present the connected devices as
173182 // scan results. Also save the properties so that the full list of
174183 // properties is known on a PropertiesChanged signal. We can't present the
@@ -200,10 +209,9 @@ func (a *Adapter) Scan(callback func(*Adapter, ScanResult)) error {
200209 }
201210
202211 // Instruct BlueZ to start discovering.
203- err = a .adapter .Call ("org.bluez.Adapter1.StartDiscovery" , 0 ).Err
204- if err != nil {
205- return err
206- }
212+ // NOTE: We must call Go here, not Call, because it can block if adapter is
213+ // powered off, or was recently powered off.
214+ startDiscovery := a .adapter .Go ("org.bluez.Adapter1.StartDiscovery" , 0 , nil )
207215
208216 for {
209217 // Check whether the scan is stopped. This is necessary to avoid a race
@@ -217,6 +225,12 @@ func (a *Adapter) Scan(callback func(*Adapter, ScanResult)) error {
217225 }
218226
219227 select {
228+ case <- startDiscovery .Done :
229+ if startDiscovery .Err != nil {
230+ close (cancelChan )
231+ a .scanCancelChan = nil
232+ return startDiscovery .Err
233+ }
220234 case sig := <- signal :
221235 // This channel receives anything that we watch for, so we'll have
222236 // to check for signals that are relevant to us.
@@ -236,14 +250,16 @@ func (a *Adapter) Scan(callback func(*Adapter, ScanResult)) error {
236250 case "org.bluez.Adapter1" :
237251 // check power state
238252 changes := sig .Body [1 ].(map [string ]dbus.Variant )
239- for k , v := range changes {
240- if k == "Powered" && ! v .Value ().(bool ) {
241- // adapter is powered off, stop the scan
242- close (cancelChan )
243- close (a .scanCancelChan )
244- a .scanCancelChan = nil
245- return errAdaptorNotPowered
246- }
253+ if powered , ok := changes ["Powered" ]; ok && ! powered .Value ().(bool ) {
254+ // adapter is powered off, stop the scan
255+ close (cancelChan )
256+ a .scanCancelChan = nil
257+ return errAdaptorNotPowered
258+ } else if discovering , ok := changes ["Discovering" ]; ok && ! discovering .Value ().(bool ) {
259+ // adapter stopped discovering unexpectedly (e.g. due to external event)
260+ close (cancelChan )
261+ a .scanCancelChan = nil
262+ return errScanStopped
247263 }
248264
249265 case "org.bluez.Device1" :
0 commit comments