public LovehoneyDesireProtocol(IButtplugLogManager aLogManager,
                                       IButtplugDeviceImpl aInterface)
            : base(aLogManager,
                   "Lovehoney Desire Device",
                   aInterface)
        {
            if (_deviceMap.TryGetValue(aInterface.Name, out var dev))
            {
                _devInfo = dev;
                Name     = $"Lovehoney Desire {dev.Name}";
            }
            else
            {
                _devInfo = new LovehoneyDesireType()
                {
                    Name      = "Unknown Lovehoney Desire Device",
                    VibeCount = 1,
                };
            }

            AddMessageHandler <SingleMotorVibrateCmd>(HandleSingleMotorVibrateCmd);
            AddMessageHandler <VibrateCmd>(HandleVibrateCmd, new MessageAttributes()
            {
                FeatureCount = _devInfo.VibeCount
            });
            AddMessageHandler <StopDeviceCmd>(HandleStopDeviceCmd);
        }
예제 #2
0
        public CuemeProtocol(IButtplugLogManager aLogManager,
                             IButtplugDeviceImpl aInterface)
            : base(aLogManager,
                   "Cueme Unknown",
                   aInterface)
        {
            var bits = aInterface.Name.Split('_');

            if (bits.Length == 3 && uint.TryParse(bits[2], out var typeNum) && DevInfos.ContainsKey(typeNum))
            {
                _devInfo = DevInfos[typeNum];
            }
            else
            {
                BpLogger.Warn($"Cannot identify Cueme device {Name}, defaulting to Womens settings.");
                _devInfo = DevInfos[3];
            }

            Name = $"Cueme {_devInfo.Name}";

            // Create a new timer that wont fire any events just yet
            _updateValueTimer.Interval = DelayTimeMS;
            _updateValueTimer.Elapsed += CuemeUpdateHandler;
            _updateValueTimer.Enabled  = false;
            aInterface.DeviceRemoved  += OnDeviceRemoved;

            AddMessageHandler <StopDeviceCmd>(HandleStopDeviceCmd);
            AddMessageHandler <SingleMotorVibrateCmd>(HandleSingleMotorVibrateCmd);
            AddMessageHandler <VibrateCmd>(HandleVibrateCmd, new MessageAttributes {
                FeatureCount = _devInfo.VibeCount
            });
        }
예제 #3
0
        public KiirooGen1Protocol([NotNull] IButtplugLogManager aLogManager,
                                  [NotNull] IButtplugDeviceImpl aInterface)
            : base(aLogManager,
                   $"Kiiroo {aInterface.Name}",
                   aInterface)
        {
            AddMessageHandler <KiirooCmd>(HandleKiirooRawCmd);
            AddMessageHandler <StopDeviceCmd>(HandleStopDeviceCmd);

            // ReSharper disable once ConvertIfStatementToSwitchStatement
            if (aInterface.Name == "PEARL")
            {
                AddMessageHandler <VibrateCmd>(HandleVibrateCmd, new MessageAttributes()
                {
                    FeatureCount = 1
                });
                AddMessageHandler <SingleMotorVibrateCmd>(HandleSingleMotorVibrateCmd);
            }
            else if (aInterface.Name == "ONYX")
            {
                AddMessageHandler <LinearCmd>(HandleLinearCmd, new MessageAttributes()
                {
                    FeatureCount = 1
                });
                AddMessageHandler <FleshlightLaunchFW12Cmd>(HandleFleshlightLaunchFW12Cmd);
            }
        }
예제 #4
0
        public LiBoProtocol(IButtplugLogManager aLogManager,
                            IButtplugDeviceImpl aInterface)
            : base(aLogManager,
                   $"LiBo ({aInterface.Name})",
                   aInterface)
        {
            if (DevInfos.ContainsKey(aInterface.Name))
            {
                _devInfo = DevInfos[aInterface.Name];
                Name     = $"LiBo {_devInfo.Name}";
            }
            else
            {
                // Pick the single vibe baseline
                BpLogger.Warn($"Cannot identify device {Name}, defaulting to LuLu settings.");
                _devInfo = DevInfos["LuXiaoHan"];
            }

            AddMessageHandler <StopDeviceCmd>(HandleStopDeviceCmd);
            if (_devInfo.VibeCount > 0)
            {
                AddMessageHandler <SingleMotorVibrateCmd>(HandleSingleMotorVibrateCmd);
                AddMessageHandler <VibrateCmd>(HandleVibrateCmd,
                                               new MessageAttributes {
                    FeatureCount = _devInfo.VibeCount
                });
            }

            // TODO Add an explicit handler for Estim shocking, kegel pressure and add a battery handler.
        }
예제 #5
0
        public WeVibeProtocol(IButtplugLogManager aLogManager,
                              IButtplugDeviceImpl aInterface)
            : base(aLogManager,
                   $"WeVibe {aInterface.Name}",
                   aInterface)
        {
            if (DualVibes.Contains(aInterface.Name))
            {
                _vibratorCount = 2;
            }

            if (NameMap.ContainsKey(aInterface.Name))
            {
                Name = $"WeVibe {NameMap[aInterface.Name]}";
            }

            if (EightBitSpeed.Contains(aInterface.Name))
            {
                _eightBitSpeed = true;
            }

            AddMessageHandler <SingleMotorVibrateCmd>(HandleSingleMotorVibrateCmd);
            AddMessageHandler <VibrateCmd>(HandleVibrateCmd, new MessageAttributes()
            {
                FeatureCount = _vibratorCount
            });
            AddMessageHandler <StopDeviceCmd>(HandleStopDeviceCmd);
        }
 public TestProtocolDoubleAdd(ButtplugLogManager aLogger, IButtplugDeviceImpl aDevice)
     : base(aLogger, aDevice)
 {
     // Add HandleRotateCmd twice, should throw
     AddMessageHandler <RotateCmd>(HandleRotateCmd);
     AddMessageHandler <RotateCmd>(HandleRotateCmd);
 }
예제 #7
0
 public LovenseProtocol(IButtplugLogManager aLogManager,
                        IButtplugDeviceImpl aInterface)
     : base(aLogManager,
            "Lovense Device (Uninitialized)",
            aInterface)
 {
     AddMessageHandler <StopDeviceCmd>(HandleStopDeviceCmd);
 }
예제 #8
0
 public RealTouchProtocol(IButtplugLogManager aLogManager, IButtplugDeviceImpl aDevice)
     : base(aLogManager, "RealTouch", aDevice)
 {
     // TODO How do we get a product string here, to tell what firmware version we're on?
     // AddMessageHandler<RotateCmd>(HandleRotateCmd, new MessageAttributes() { FeatureCount = 1 });
     AddMessageHandler <StopDeviceCmd>(HandleStopDeviceCmd);
     AddMessageHandler <FleshlightLaunchFW12Cmd>(HandleFleshlightLaunchFW12Cmd);
     AddMessageHandler <LinearCmd>(HandleLinearCmd);
 }
예제 #9
0
        public static ButtplugDevice Create <T>(IButtplugLogManager aLogManager,
                                                IButtplugDeviceImpl aDevice,
                                                Func <IButtplugLogManager, IButtplugDeviceImpl, T> aProtocolCreationFunc)
            where T : IButtplugDeviceProtocol, new()
        {
            var p = aProtocolCreationFunc(aLogManager, aDevice);

            return(new ButtplugDevice(aLogManager, p, aDevice));
        }
예제 #10
0
        public VorzeSAProtocol(IButtplugLogManager aLogManager,
                               IButtplugDeviceImpl aInterface)
            : base(aLogManager,
                   "Vorze SA Unknown",
                   aInterface)
        {
            switch (aInterface.Name)
            {
            case "CycSA":
                _deviceType  = DeviceType.CycloneOrUnknown;
                _commandType = CommandType.Rotate;
                Name         = "Vorze A10 Cyclone SA";
                break;

            case "UFOSA":
                _deviceType  = DeviceType.UFO;
                _commandType = CommandType.Rotate;
                Name         = "Vorze UFO SA";
                break;

            case "Bach smart":
                _deviceType  = DeviceType.Bach;
                _commandType = CommandType.Vibrate;
                Name         = "Vorze Bach";
                break;

            default:
                // If the device doesn't identify, warn and try sending it Cyclone packets.
                BpLogger.Warn($"Vorze product with unrecognized name ({Name}) found. This product may not work with B******g. Contact the developers for more info.");
                break;
            }

            switch (_commandType)
            {
            case CommandType.Rotate:
                AddMessageHandler <VorzeA10CycloneCmd>(HandleVorzeA10CycloneCmd);
                AddMessageHandler <RotateCmd>(HandleRotateCmd, new MessageAttributes()
                {
                    FeatureCount = 1
                });
                break;

            case CommandType.Vibrate:
                AddMessageHandler <SingleMotorVibrateCmd>(HandleSingleMotorVibrateCmd);
                AddMessageHandler <VibrateCmd>(HandleVibrateCmd, new MessageAttributes()
                {
                    FeatureCount = 1
                });
                break;

            default:
                BpLogger.Error("Unhandled command type.");
                break;
            }

            AddMessageHandler <StopDeviceCmd>(HandleStopDeviceCmd);
        }
예제 #11
0
 public XInputProtocol(IButtplugLogManager aLogManager, IButtplugDeviceImpl aDevice)
     : base(aLogManager, "XBox Compatible Gamepad (XInput)", aDevice)
 {
     AddMessageHandler <SingleMotorVibrateCmd>(HandleSingleMotorVibrateCmd);
     AddMessageHandler <VibrateCmd>(HandleVibrateCmd, new MessageAttributes()
     {
         FeatureCount = 2
     });
     AddMessageHandler <StopDeviceCmd>(HandleStopDeviceCmd);
 }
예제 #12
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ButtplugDevice"/> class.
 /// </summary>
 /// <param name="aLogManager">The log manager.</param>
 /// <param name="aDevice">The device implementation (Bluetooth, USB, etc).</param>
 /// <param name="aProtocolType">A Type for a protocol, which we will create an instance of.</param>
 public ButtplugDevice([NotNull] IButtplugLogManager aLogManager,
                       [NotNull] Type aProtocolType,
                       [NotNull] IButtplugDeviceImpl aDevice)
     : this(aLogManager,
            // A lot of trust happening in the structure of protocol constructors here.
            // todo should probably document the many ways this can throw.
            (IButtplugDeviceProtocol)Activator.CreateInstance(aProtocolType, aLogManager, aDevice),
            aDevice)
 {
 }
예제 #13
0
 public CycloneX10Protocol(IButtplugLogManager aLogManager, IButtplugDeviceImpl aDevice)
     : base(aLogManager, "Vorze Cyclone X10", aDevice)
 {
     AddMessageHandler <VorzeA10CycloneCmd>(HandleVorzeA10CycloneCmd);
     AddMessageHandler <RotateCmd>(HandleRotateCmd, new MessageAttributes()
     {
         FeatureCount = 1
     });
     AddMessageHandler <StopDeviceCmd>(HandleStopDeviceCmd);
 }
예제 #14
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ButtplugDevice"/> class.
 /// </summary>
 /// <param name="aLogManager">The log manager.</param>
 /// <param name="aDevice">The device implementation (Bluetooth, USB, etc).</param>
 /// <param name="aProtocol">The device protocol (Lovense, Launch, etc).</param>
 public ButtplugDevice([NotNull] IButtplugLogManager aLogManager,
                       [NotNull] IButtplugDeviceProtocol aProtocol,
                       [NotNull] IButtplugDeviceImpl aDevice)
 {
     // Protocol can be null if activator construction from type constructor fails
     ButtplugUtils.ArgumentNotNull(aProtocol, nameof(aProtocol));
     _protocol              = aProtocol;
     _device                = aDevice;
     BpLogger               = aLogManager.GetLogger(GetType());
     _device.DeviceRemoved += OnDeviceRemoved;
 }
예제 #15
0
 public VibratissimoProtocol(IButtplugLogManager aLogManager,
                             IButtplugDeviceImpl aInterface)
     : base(aLogManager,
            $"Vibratissimo Device ({aInterface.Name})",
            aInterface)
 {
     AddMessageHandler <SingleMotorVibrateCmd>(HandleSingleMotorVibrateCmd);
     AddMessageHandler <VibrateCmd>(HandleVibrateCmd, new MessageAttributes {
         FeatureCount = 1
     });
     AddMessageHandler <StopDeviceCmd>(HandleStopDeviceCmd);
 }
예제 #16
0
 public TestProtocol(IButtplugLogManager aLogManager,
                     IButtplugDeviceImpl aInterface)
     : base(aLogManager, "Test Device", aInterface)
 {
     Name = aInterface.Name;
     AddMessageHandler <SingleMotorVibrateCmd>(HandleSingleMotorVibrateCmd);
     AddMessageHandler <VibrateCmd>(HandleVibrateCmd, new MessageAttributes()
     {
         FeatureCount = 2
     });
     AddMessageHandler <StopDeviceCmd>(HandleStopDeviceCmd);
 }
예제 #17
0
 public RealovProtocol(IButtplugLogManager aLogManager,
                       IButtplugDeviceImpl aInterface)
     : base(aLogManager,
            "Realov Device",
            aInterface)
 {
     AddMessageHandler <SingleMotorVibrateCmd>(HandleSingleMotorVibrateCmd);
     AddMessageHandler <VibrateCmd>(HandleVibrateCmd, new MessageAttributes()
     {
         FeatureCount = 1
     });
     AddMessageHandler <StopDeviceCmd>(HandleStopDeviceCmd);
 }
예제 #18
0
 public KiirooGen21Protocol([NotNull] IButtplugLogManager aLogManager,
                            IButtplugDeviceImpl aInterface)
     : base(aLogManager,
            "Kiiroo Onyx2.1",
            aInterface)
 {
     // Setup message function array
     AddMessageHandler <FleshlightLaunchFW12Cmd>(HandleFleshlightLaunchFW12Cmd);
     AddMessageHandler <LinearCmd>(HandleLinearCmd, new MessageAttributes()
     {
         FeatureCount = 1
     });
     AddMessageHandler <StopDeviceCmd>(HandleStopDeviceCmd);
 }
예제 #19
0
        public YoucupsProtocol(IButtplugLogManager aLogManager,
                               IButtplugDeviceImpl aInterface)
            : base(aLogManager,
                   "Youcups Unknown",
                   aInterface)
        {
            if (FriendlyNames.ContainsKey(aInterface.Name))
            {
                Name = $"Youcups {FriendlyNames[aInterface.Name]}";
            }

            AddMessageHandler <SingleMotorVibrateCmd>(HandleSingleMotorVibrateCmd);
            AddMessageHandler <VibrateCmd>(HandleVibrateCmd, new MessageAttributes()
            {
                FeatureCount = 1
            });
            AddMessageHandler <StopDeviceCmd>(HandleStopDeviceCmd);
        }
예제 #20
0
        public MysteryVibeProtocol(IButtplugLogManager aLogManager,
                                   IButtplugDeviceImpl aInterface)
            : base(aLogManager,
                   "MysteryVibe Crescendo",
                   aInterface)
        {
            // Create a new timer that wont fire any events just yet
            _updateValueTimer.Interval = DelayTimeMS;
            _updateValueTimer.Elapsed += MysteryVibeUpdateHandler;
            _updateValueTimer.Enabled  = false;
            aInterface.DeviceRemoved  += OnDeviceRemoved;

            AddMessageHandler <SingleMotorVibrateCmd>(HandleSingleMotorVibrateCmd);
            AddMessageHandler <VibrateCmd>(HandleVibrateCmd, new MessageAttributes {
                FeatureCount = 6
            });
            AddMessageHandler <StopDeviceCmd>(HandleStopDeviceCmd);
        }
예제 #21
0
        public PicobongProtocol(IButtplugLogManager aLogManager,
                                IButtplugDeviceImpl aInterface)
            : base(aLogManager,
                   $"Picobong {aInterface.Name}",
                   aInterface)
        {
            if (NameMap.ContainsKey(Name))
            {
                Name = NameMap[Name];
            }

            AddMessageHandler <SingleMotorVibrateCmd>(HandleSingleMotorVibrateCmd);
            AddMessageHandler <VibrateCmd>(HandleVibrateCmd, new MessageAttributes()
            {
                FeatureCount = 1
            });
            AddMessageHandler <StopDeviceCmd>(HandleStopDeviceCmd);
        }
예제 #22
0
        public KiirooGen2Protocol([NotNull] IButtplugLogManager aLogManager,
                                  IButtplugDeviceImpl aInterface)
            : base(aLogManager,
                   "Kiiroo V2 Protocol Device",
                   aInterface)
        {
            if (_brandNames.ContainsKey(aInterface.Name))
            {
                Name = $"{_brandNames[aInterface.Name]} {aInterface.Name}";
            }

            // Setup message function array
            AddMessageHandler <FleshlightLaunchFW12Cmd>(HandleFleshlightLaunchFW12Cmd);
            AddMessageHandler <LinearCmd>(HandleLinearCmd, new MessageAttributes()
            {
                FeatureCount = 1
            });
            AddMessageHandler <StopDeviceCmd>(HandleStopDeviceCmd);
        }
예제 #23
0
        public KiirooGen2VibeProtocol([NotNull] IButtplugLogManager aLogManager,
                                      [NotNull] IButtplugDeviceImpl aInterface)
            : base(aLogManager,
                   "Kiiroo Unknown",
                   aInterface)
        {
            if (DevInfos.ContainsKey(aInterface.Name))
            {
                Name     = $"{DevInfos[aInterface.Name].Brand} {aInterface.Name}";
                _devInfo = DevInfos[aInterface.Name];
            }
            else
            {
                BpLogger.Warn($"Cannot identify device {Name}, defaulting to Pearl2 settings.");
                _devInfo = DevInfos["Unknown"];
            }

            AddMessageHandler <StopDeviceCmd>(HandleStopDeviceCmd);
            AddMessageHandler <VibrateCmd>(HandleVibrateCmd, new MessageAttributes {
                FeatureCount = _devInfo.VibeCount
            });
            AddMessageHandler <SingleMotorVibrateCmd>(HandleSingleMotorVibrateCmd);
        }
예제 #24
0
        public MagicMotionProtocol(IButtplugLogManager aLogManager,
                                   IButtplugDeviceImpl aInterface)
            : base(aLogManager,
                   $"Unknown MagicMotion Device ({aInterface.Name})",
                   aInterface)
        {
            if (DevInfos.ContainsKey(aInterface.Name))
            {
                _devInfo = DevInfos[aInterface.Name];
                Name     = $"{_devInfo.Brand} {_devInfo.Name}";
            }
            else
            {
                BpLogger.Warn($"Cannot identify device {Name}, defaulting to Smart Mini Vibe settings.");
                _devInfo = DevInfos["Smart Mini Vibe"];
            }

            AddMessageHandler <SingleMotorVibrateCmd>(HandleSingleMotorVibrateCmd);
            AddMessageHandler <VibrateCmd>(HandleVibrateCmd, new MessageAttributes {
                FeatureCount = _devInfo.VibeCount
            });
            AddMessageHandler <StopDeviceCmd>(HandleStopDeviceCmd);
        }
예제 #25
0
 public ErostekET312Protocol(IButtplugLogManager aLogManager, IButtplugDeviceImpl aDevice)
     : base(aLogManager, $"Erostek ET312 - {aDevice.Name}", aDevice)
 {
 }
예제 #26
0
        private async void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher aObj,
                                                   BluetoothLEAdvertisementReceivedEventArgs aEvent)
        {
            if (aEvent?.Advertisement == null)
            {
                BpLogger.Debug("Null BLE advertisement received: skipping");
                return;
            }

            var advertName  = aEvent.Advertisement.LocalName ?? string.Empty;
            var advertGUIDs = new List <Guid>();

            advertGUIDs.AddRange(aEvent.Advertisement.ServiceUuids ?? new Guid[] { });
            var btAddr = aEvent.BluetoothAddress;

            // BpLogger.Trace($"Got BLE Advertisement for device: {aEvent.Advertisement.LocalName} / {aEvent.BluetoothAddress}");
            if (_seenAddresses.Contains(btAddr))
            {
                // BpLogger.Trace($"Ignoring advertisement for already connecting device:
                // {aEvent.Advertisement.LocalName} / {aEvent.BluetoothAddress}");
                return;
            }

            BpLogger.Trace("BLE device found: " + advertName);

            // We always need a name to match against.
            if (advertName == string.Empty)
            {
                return;
            }

            // todo Add advertGUIDs back in. Not sure that ever really gets used though.
            var deviceCriteria = new BluetoothLEProtocolConfiguration(advertName);

            var deviceFactory = DeviceConfigurationManager.Manager.Find(deviceCriteria);

            // If we don't have a protocol to match the device, we can't do anything with it.
            if (deviceFactory == null || !(deviceFactory.Config is BluetoothLEProtocolConfiguration bleConfig))
            {
                BpLogger.Debug($"No usable device factory available for {advertName}.");
                // If we've got an actual name this time around, and we don't have any factories
                // available that match the info we have, add to our seen list so we won't keep
                // rechecking. If a device does have a factory, but doesn't connect, we still want to
                // try again.
                _seenAddresses.Add(btAddr);
                return;
            }

            var fromBluetoothAddressAsync = BluetoothLEDevice.FromBluetoothAddressAsync(btAddr);

            // Can return null if the device no longer exists, for instance if it turned off between
            // advertising and us getting here. Since we didn't get a chance to try to connect,
            // remove it from seen devices, since the user may turn it back on during this scanning period.
            if (fromBluetoothAddressAsync == null)
            {
                return;
            }

            var dev = await fromBluetoothAddressAsync;

            // If a device is turned on after scanning has started, windows seems to lose the device
            // handle the first couple of times it tries to deal with the advertisement. Just log the
            // error and hope it reconnects on a later retry.
            IButtplugDeviceImpl bleDevice = null;
            IButtplugDevice     btDevice  = null;

            try
            {
                bleDevice = await UWPBluetoothDeviceInterface.Create(LogManager, bleConfig, dev).ConfigureAwait(false);

                btDevice = await deviceFactory.CreateDevice(LogManager, bleDevice).ConfigureAwait(false);

                InvokeDeviceAdded(new DeviceAddedEventArgs(btDevice));
            }
            catch (Exception ex)
            {
                if (btDevice != null)
                {
                    btDevice.Disconnect();
                }
                else
                {
                    bleDevice?.Disconnect();
                }

                BpLogger.Error(
                    $"Cannot connect to device {advertName} {btAddr}: {ex.Message}");
            }
        }
예제 #27
0
        private async void _adapter_DeviceAdvertised(object sender, Plugin.BLE.Abstractions.EventArgs.DeviceEventArgs e)
        {
            if (e?.Device == null)
            {
                BpLogger.Debug("Null BLE advertisement received: skipping");
                return;
            }
            string advertName = e.Device.GetPropValue <string>("BluetoothDevice.Name");

            var advertGUIDs = new List <Guid>();

            advertGUIDs.Add(e.Device.Id);
            var btAddr = e.Device.GetPropValue <string>("BluetoothDevice.Address");

            BpLogger.Trace($"Got BLE Advertisement for device: {advertName} / {btAddr}");
            if (_seenAddresses.Contains(btAddr))
            {
                BpLogger.Trace($"Ignoring advertisement for already connecting device: {btAddr}");
                return;
            }
            _seenAddresses.Add(btAddr);
            BpLogger.Trace("BLE device found: " + advertName);

            // We always need a name to match against.
            if (String.IsNullOrEmpty(advertName))
            {
                return;
            }

            // todo Add advertGUIDs back in. Not sure that ever really gets used though.
            var deviceCriteria = new BluetoothLEProtocolConfiguration(advertName);

            var deviceFactory = DeviceConfigurationManager.Manager.Find(deviceCriteria);

            // If we don't have a protocol to match the device, we can't do anything with it.
            if (deviceFactory == null || !(deviceFactory.Config is BluetoothLEProtocolConfiguration bleConfig))
            {
                BpLogger.Debug($"No usable device factory available for {advertName}.");
                return;
            }

            // If a device is turned on after scanning has started, windows seems to lose the device
            // handle the first couple of times it tries to deal with the advertisement. Just log the
            // error and hope it reconnects on a later retry.
            IButtplugDeviceImpl bleDevice = null;
            IButtplugDevice     btDevice  = null;

            try
            {
                await _adapter.ConnectToDeviceAsync(e.Device);

                bleDevice = await XamarinBluetoothDeviceInterface.Create(LogManager, bleConfig, e.Device).ConfigureAwait(false);

                btDevice = await deviceFactory.CreateDevice(LogManager, bleDevice).ConfigureAwait(false);

                InvokeDeviceAdded(new DeviceAddedEventArgs(btDevice));
            }
            catch (Exception ex)
            {
                if (btDevice != null)
                {
                    btDevice.Disconnect();
                }
                else
                {
                    bleDevice?.Disconnect();
                }

                BpLogger.Error(
                    $"Cannot connect to device {advertName} {btAddr}: {ex.Message}");
            }
        }
        public async Task <IButtplugDevice> CreateDevice(IButtplugLogManager aLogManager, IButtplugDeviceImpl aDevice)
        {
            var device = new ButtplugDevice(aLogManager, _protocolType, aDevice);
            // Run initialization now, just to make sure we're ready to go when we hand the device back.
            // TODO should probably find a better cancellation token for this. Or like, any at all.
            await device.InitializeAsync(CancellationToken.None).ConfigureAwait(false);

            return(device);
        }