public IList <Pebble> Detect(string adapterName, bool doDiscovery, bool pairDiscovered, bool unpairFailed) { //these properties are defined by bluez in /doc/profile-api.txt //but it turns out the defaults work just fine var properties = new Dictionary <string, object> (); //properties ["AutoConnect"] = true; //properties ["Name"] = "Serial Port"; //properties ["Service"] = pebbleSerialUUID; //properties ["Role"] = "client"; //properties ["PSM"] = (ushort)1; //properties ["RequireAuthentication"] = false; //properties ["RequireAuthorization"] = false; //properties ["Channel"] = (ushort)0; //get a proxy for the profile manager so we can register our profile _profileManager = _connection.System.GetObject <ProfileManager1> (BlueZPath.Service, BlueZPath.Root); //create and register our profile _profile = new PebbleProfile(); _connection.System.Register(ProfilePath, _profile); _profileManager.RegisterProfile(ProfilePath, PebbleSerialUUID, properties); _profile.NewConnectionAction = (path, fd, props) => { if (_pebbles [path].Pebble == null) { //new connection //System.Console.WriteLine("Connected to " + path); _pebbles [path].FileDescriptor = fd; _pebbles [path].FileDescriptor.SetBlocking(); var stream = _pebbles [path].FileDescriptor.OpenAsStream(true); _pebbles [path].Stream = stream; var blueZPebble = new BlueZ5Pebble(new PebbleBluetoothConnection(stream), _pebbles[path].Device, _pebbles [path].Name); _pebbles [path].Pebble = blueZPebble; } else { //reconnect //if the descriptor is new, close the old one and replace it if (fd.FD != _pebbles [path].FileDescriptor.FD) { //dispose of the old fd _pebbles [path].FileDescriptor.Close(); _pebbles [path].FileDescriptor.Dispose(); //setup the new fd _pebbles [path].FileDescriptor = fd; _pebbles [path].FileDescriptor.SetBlocking(); var stream = _pebbles [path].FileDescriptor.OpenAsStream(true); _pebbles [path].Stream = stream; } ((PebbleBluetoothConnection)_pebbles [path].Pebble.Connection).Reconnect(_pebbles [path].Stream); } }; //get a copy of the object manager so we can browse the "tree" of bluetooth items _objectManager = _connection.System.GetObject <org.freedesktop.DBus.ObjectManager> (BlueZPath.Service, ObjectPath.Root); //register these events so we can tell when things are added/removed (eg: discovery) //_objectManager .InterfacesAdded += (p, i) => { //System.Console.WriteLine ("Discovered "+p); //}; //_objectManager .InterfacesRemoved += (p, i) => { //System.Console.WriteLine ("Lost" + p); //}; //get the agent manager so we can register our agent _agentManager = _connection.System.GetObject <AgentManager1> (BlueZPath.Service, BlueZPath.Root); _agent = new PebbleAgent(); //register our agent and make it the default _connection.System.Register(AgentPath, _agent); _agentManager.RegisterAgent(AgentPath, "KeyboardDisplay"); _agentManager.RequestDefaultAgent(AgentPath); //get the bluetooth object tree var managedObjects = _objectManager.GetManagedObjects(); //find our adapter ObjectPath adapterPath = null; foreach (var obj in managedObjects.Keys) { if (managedObjects [obj].ContainsKey(typeof(Adapter1).DBusInterfaceName())) { if (string.IsNullOrEmpty(adapterName) || obj.ToString().EndsWith(adapterName)) { adapterPath = obj; break; } } } if (adapterPath == null) { throw new ArgumentException("Could not find bluetooth adapter"); } //get a dbus proxy to the adapter _adapter = _connection.System.GetObject <Adapter1> (BlueZPath.Service, BlueZPath.Adapter(adapterName)); if (doDiscovery) { System.Console.WriteLine("Starting Discovery..."); //scan for any new devices _adapter.StartDiscovery(); Thread.Sleep(5000); //totally arbitrary constant, the best kind //Thread.Sleep ((int)adapter.DiscoverableTimeout * 1000); //refresh the object graph to get any devices that were discovered //arguably we should do this in the objectmanager added/removed events and skip the full //refresh, but I'm lazy. managedObjects = _objectManager.GetManagedObjects(); } foreach (var obj in managedObjects.Keys) { if (obj.ToString().StartsWith(adapterPath.ToString())) { if (managedObjects [obj].ContainsKey(typeof(Device1).DBusInterfaceName())) { var managedObject = managedObjects [obj]; if (managedObject [typeof(Device1).DBusInterfaceName()].ContainsKey("Name")) { var name = (string)managedObject [typeof(Device1).DBusInterfaceName()] ["Name"]; if (name.StartsWith("Pebble") && !name.Contains(" LE ")) { var device = _connection.System.GetObject <Device1> (BlueZPath.Service, obj); //we also check for the UUID because that's how we tell the //LE address from the regular address try { System.Console.WriteLine("Attempting connection to " + obj); if (!device.Paired && pairDiscovered) { device.Pair(); } if (!device.Trusted && pairDiscovered) { device.Trusted = true; } _pebbles [obj] = new DiscoveredPebble() { Name = name, Device = device }; try { device.ConnectProfile(PebbleSerialUUID); } catch (Exception ex) { if (unpairFailed) { //this prevents us from falling into a failing loop //if the pebble has unpaired but bluez has not System.Console.WriteLine("Failed to connect to " + obj + ", attempting to re-pair"); //if we can't connect then try to re-pair then reconnect _adapter.RemoveDevice(obj); if (pairDiscovered) { //re-discover if (!_adapter.Discovering) { _adapter.StartDiscovery(); } System.Threading.Thread.Sleep(10000); //re-pair device.Pair(); device.Trusted = true; //re-connect device.ConnectProfile(PebbleSerialUUID); } } else { throw; } } } catch (Exception ex) { System.Console.WriteLine("Failed to connect to " + obj + " " + ex.Message); //we don't need to do anything, it simply won't be added to the collection if we can't connect to it } } } //if it doesn't have the Name Property we can safely assume it is not a pebble } } } //wait for devices to connect Thread.Sleep(2000); var results = _pebbles.Values.Where(x => x.Pebble != null).Select(x => (Pebble)x.Pebble).ToList(); return(results); }
public override void Load() { Kernel.Bind <DBusConnection> () .ToSelf() .InSingletonScope(); Kernel.Bind <Adapter1> () .ToMethod(x => { var adapterName = ConfigurationHelper.ReadStringAppSetting("BtAdapterName", "hci0"); var connection = x.Kernel.Get <DBusConnection> (); var adapter = connection.System.GetObject <Adapter1>(BlueZPath.Service, BlueZPath.Adapter(adapterName)); return(adapter); }).InSingletonScope(); //we default to true so that it works "out of the box", but once your devices are paired you //could turn discovery off to speed up startup time var doDiscovery = ConfigurationHelper.ReadBoolAppSetting("BtEnableDiscovery", true); var discoveryWait = ConfigurationHelper.ReadIntAppSetting("BtDiscoveryWait", 5); //HACK: very odd to be doing this sort of work in a DI module, but I don't have a better place right now if (doDiscovery) { StartDiscovery(discoveryWait); } }