private Task <ButtplugMessage> HandleFleshlightLaunchCmd(ButtplugDeviceMessage aMsg) { if (!(aMsg is FleshlightLaunchFW12Cmd cmdMsg)) { return(Task.FromResult <ButtplugMessage>(BpLogger.LogErrorMsg(aMsg.Id, Error.ErrorClass.ERROR_DEVICE, "Wrong Handler"))); } lock (_movementLock) { _speed = (Convert.ToDouble(cmdMsg.Speed) / 99) * 100; _position = (Convert.ToDouble(cmdMsg.Position) / 99) * 100; _position = _position < 0 ? 0 : _position; _position = _position > 100 ? 100 : _position; _speed = _speed < 20 ? 20 : _speed; _speed = _speed > 100 ? 100 : _speed; // This is @funjack's algorithm for converting Fleshlight Launch // commands into absolute distance (percent) / duration (millisecond) values var distance = Math.Abs(_position - _currentPosition); var duration = FleshlightHelper.GetDuration(distance / 100, _speed / 100); // We convert those into "position" increments for our OnUpdate() timer event. _increment = 1.5 * (distance / (duration / _updateInterval)); return(Task.FromResult <ButtplugMessage>(new Ok(aMsg.Id))); } }
protected override void RunScan() { try { // TODO this should scan in a loop on a timer until told to stop var controllers = new[] { new Controller(UserIndex.One), new Controller(UserIndex.Two), new Controller(UserIndex.Three), new Controller(UserIndex.Four), }; foreach (var c in controllers) { if (!c.IsConnected) { continue; } BpLogger.Debug($"Found connected XInput Gamepad for Index {c.UserIndex}"); var deviceImpl = new XInputGamepadDevice(LogManager, c); var device = new ButtplugDevice(LogManager, new XInputProtocol(LogManager, deviceImpl), deviceImpl); InvokeDeviceAdded(new DeviceAddedEventArgs(device)); // Do not invoke ScanningFinished here, the parent class will handle that for us. } } catch (DllNotFoundException e) { // TODO Should we maybe try testing for this in construction instead of during scanning? BpLogger.Error($"Required DirectX DLL not found: {e.Message}\nThis probably means you need to install the DirectX Runtime from June 2010: https://www.microsoft.com/en-us/download/details.aspx?id=8109"); throw e; } }
private async Task <ButtplugMessage> HandleLinearCmd(ButtplugDeviceMessage aMsg) { var cmdMsg = aMsg as LinearCmd; if (cmdMsg is null) { return(BpLogger.LogErrorMsg(aMsg.Id, Error.ErrorClass.ERROR_DEVICE, "Wrong Handler")); } if (cmdMsg.Vectors.Count != 1) { return(new Error( "LinearCmd requires 1 vector for this device.", Error.ErrorClass.ERROR_DEVICE, cmdMsg.Id)); } foreach (var v in cmdMsg.Vectors) { if (v.Index != 0) { return(new Error( $"Index {v.Index} is out of bounds for LinearCmd for this device.", Error.ErrorClass.ERROR_DEVICE, cmdMsg.Id)); } return(await HandleFleshlightLaunchRawCmd(new FleshlightLaunchFW12Cmd(cmdMsg.DeviceIndex, Convert.ToUInt32(FleshlightHelper.GetSpeed(Math.Abs(_lastPosition - v.Position), v.Duration) * 99), Convert.ToUInt32(v.Position * 99), cmdMsg.Id))); } return(new Ok(aMsg.Id)); }
public override void StartScanning() { BpLogger.Info("Starting Scanning Serial Ports for ErosTek Devices"); _isScanning = true; _scanThread = new Thread(() => ScanSerialPorts(null)); _scanThread.Start(); }
public KiirooGen2Vibe([NotNull] IButtplugLogManager aLogManager, [NotNull] IBluetoothDeviceInterface aInterface, [NotNull] IBluetoothDeviceInfo aInfo) : base(aLogManager, "Kiiroo Unknown", aInterface, aInfo) { 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); }
private Task <ButtplugMessage> HandleSingleMotorVibrateCmd(ButtplugDeviceMessage aMsg) { var cmdMsg = aMsg as SingleMotorVibrateCmd; if (cmdMsg is null) { return(Task.FromResult <ButtplugMessage>(BpLogger.LogErrorMsg(aMsg.Id, Error.ErrorClass.ERROR_DEVICE, "Wrong Handler"))); } var v = new Vibration { LeftMotorSpeed = (ushort)(cmdMsg.Speed * ushort.MaxValue), RightMotorSpeed = (ushort)(cmdMsg.Speed * ushort.MaxValue), }; try { _device?.SetVibration(v); } catch (Exception e) { if (_device?.IsConnected != true) { InvokeDeviceRemoved(); // Don't throw a spanner in the works return(Task.FromResult <ButtplugMessage>(new Ok(aMsg.Id))); } return(Task.FromResult <ButtplugMessage>(BpLogger.LogErrorMsg(aMsg.Id, Error.ErrorClass.ERROR_DEVICE, e.Message))); } return(Task.FromResult <ButtplugMessage>(new Ok(aMsg.Id))); }
private async Task <ButtplugMessage> HandleRotateCmd(ButtplugDeviceMessage aMsg) { if (!(aMsg is RotateCmd cmdMsg)) { return(BpLogger.LogErrorMsg(aMsg.Id, Error.ErrorClass.ERROR_DEVICE, "Wrong Handler")); } if (cmdMsg.Rotations.Count != 1) { return(new Error( "RotateCmd requires 1 vector for this device.", Error.ErrorClass.ERROR_DEVICE, cmdMsg.Id)); } foreach (var i in cmdMsg.Rotations) { if (i.Index != 0) { return(new Error( $"Index {i.Index} is out of bounds for RotateCmd for this device.", Error.ErrorClass.ERROR_DEVICE, cmdMsg.Id)); } return(await HandleVorzeA10CycloneCmd(new VorzeA10CycloneCmd(cmdMsg.DeviceIndex, Convert.ToUInt32(i.Speed * 99), i.Clockwise, cmdMsg.Id))); } return(new Ok(cmdMsg.Id)); }
public MagicMotion(IButtplugLogManager aLogManager, IBluetoothDeviceInterface aInterface, IBluetoothDeviceInfo aInfo) : base(aLogManager, $"Unknown MagicMotion Device ({aInterface.Name})", aInterface, aInfo) { if (DevInfos.ContainsKey(aInterface.Name)) { Name = $"MagicMotion {DevInfos[aInterface.Name].Name}"; _devInfo = DevInfos[aInterface.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); }
public override void StartScanning() { BpLogger.Info("XInputGamepadManager start scanning"); try { var controllers = new[] { new Controller(UserIndex.One), new Controller(UserIndex.Two), new Controller(UserIndex.Three), new Controller(UserIndex.Four), }; foreach (var c in controllers) { if (!c.IsConnected) { continue; } BpLogger.Debug($"Found connected XInput Gamepad for Index {c.UserIndex}"); var device = new XInputGamepadDevice(LogManager, c); InvokeDeviceAdded(new DeviceAddedEventArgs(device)); InvokeScanningFinished(); } } catch (DllNotFoundException e) { // TODO Should we maybe try testing for this in construction instead of during scanning? BpLogger.Error($"Required DirectX DLL not found: {e.Message}\nThis probably means you need to install the DirectX Runtime from June 2010: https://www.microsoft.com/en-us/download/details.aspx?id=8109"); InvokeScanningFinished(); } }
private async Task <ButtplugMessage> HandleSingleMotorVibrateCmd(ButtplugDeviceMessage aMsg) { var cmdMsg = aMsg as SingleMotorVibrateCmd; if (cmdMsg is null) { return(BpLogger.LogErrorMsg(aMsg.Id, Error.ErrorClass.ERROR_DEVICE, "Wrong Handler")); } var rSpeed = Convert.ToUInt16(cmdMsg.Speed * 15); // 0f 03 00 bc 00 00 00 00 var data = new byte[] { 0x0f, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00 }; data[3] = Convert.ToByte(rSpeed); // External data[3] |= Convert.ToByte(rSpeed << 4); // Internal if (rSpeed == 0) { data[1] = 0x00; data[5] = 0x00; } return(await Interface.WriteValue(aMsg.Id, Info.Characteristics[(uint)WeVibeBluetoothInfo.Chrs.Tx], data)); }
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 }); }
public VorzeSA(IButtplugLogManager aLogManager, IBluetoothDeviceInterface aInterface, IBluetoothDeviceInfo aInfo) : base(aLogManager, "Vorze SA Unknown", aInterface, aInfo) { if (aInterface.Name == "CycSA") { _deviceType = DeviceType.CycloneOrUnknown; Name = "Vorze A10 Cyclone SA"; } else if (aInterface.Name == "UFOSA") { _deviceType = DeviceType.UFO; Name = "Vorze UFO SA"; } else { // 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."); } MsgFuncs.Add(typeof(VorzeA10CycloneCmd), new ButtplugDeviceWrapper(HandleVorzeA10CycloneCmd)); MsgFuncs.Add(typeof(RotateCmd), new ButtplugDeviceWrapper(HandleRotateCmd, new MessageAttributes() { FeatureCount = 1 })); MsgFuncs.Add(typeof(StopDeviceCmd), new ButtplugDeviceWrapper(HandleStopDeviceCmd)); }
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. }
private async Task <ButtplugMessage> HandleVibrateCmd([NotNull] ButtplugDeviceMessage aMsg) { if (!(aMsg is VibrateCmd cmdMsg)) { return(BpLogger.LogErrorMsg(aMsg.Id, Error.ErrorClass.ERROR_DEVICE, "Wrong Handler")); } if (cmdMsg.Speeds.Count != 1) { return(new Error( "VibrateCmd requires 1 vector for this device.", Error.ErrorClass.ERROR_DEVICE, cmdMsg.Id)); } foreach (var v in cmdMsg.Speeds) { if (v.Index != 0) { return(new Error( $"Index {v.Index} is out of bounds for VibrateCmd for this device.", Error.ErrorClass.ERROR_DEVICE, cmdMsg.Id)); } _vibratorSpeed = v.Speed; } return(await HandleKiirooRawCmd(new KiirooCmd(aMsg.DeviceIndex, Convert.ToUInt16(_vibratorSpeed * 4), aMsg.Id))); }
public VorzeSA(IButtplugLogManager aLogManager, IBluetoothDeviceInterface aInterface, IBluetoothDeviceInfo aInfo) : base(aLogManager, "Vorze SA Unknown", aInterface, aInfo) { 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); }
private async void CuemeUpdateHandler(object aEvent, ElapsedEventArgs aArgs) { if (_vibratorSpeeds.SequenceEqual(NullSpeed)) { _updateValueTimer.Enabled = false; _vibeIndex = 0; } var data = Convert.ToByte((int)(_vibratorSpeeds[_vibeIndex] * 15)); if (data != 0x00) { data |= (byte)((byte)(_vibeIndex + 1) << 4); } // We'll have to use an internal token here since this is timer triggered. try { // todo This throw doesn't actually go anywhere. This should bubble upward. await Interface.WriteValueAsync(new[] { data }, _stopUpdateCommandSource.Token).ConfigureAwait(false); } catch (ButtplugDeviceException ex) { BpLogger.Error($"Cannot send update to Cueme {_devInfo.Name}, device may stick on a single vibrator."); _updateValueTimer.Enabled = false; } if (!_updateValueTimer.Enabled || aArgs == null) { return; } // Move to the next active vibe var nextVibe = _vibeIndex; while (true) { nextVibe++; // Wrap back to 0 if (nextVibe == _devInfo.VibeCount) { nextVibe = 0; } if (Math.Abs(_vibratorSpeeds[nextVibe]) > 0.0) { _vibeIndex = nextVibe; break; } if (nextVibe == _vibeIndex) { // Stop the timer: there's only one vibe running _updateValueTimer.Enabled = false; break; } } }
private async Task <ButtplugMessage> HandleVibrateCmd(ButtplugDeviceMessage aMsg) { if (!(aMsg is VibrateCmd cmdMsg)) { return(BpLogger.LogErrorMsg(aMsg.Id, Error.ErrorClass.ERROR_DEVICE, "Wrong Handler")); } if (cmdMsg.Speeds.Count < 1 || cmdMsg.Speeds.Count > _vibratorCount) { return(new Error( $"VibrateCmd requires between 1 and {_vibratorCount} vectors for this device.", Error.ErrorClass.ERROR_DEVICE, cmdMsg.Id)); } var changed = false; foreach (var v in cmdMsg.Speeds) { if (v.Index >= _vibratorCount) { return(new Error( $"Index {v.Index} is out of bounds for VibrateCmd for this device.", Error.ErrorClass.ERROR_DEVICE, cmdMsg.Id)); } if (!(Math.Abs(v.Speed - _vibratorSpeed[v.Index]) > 0.001)) { continue; } changed = true; _vibratorSpeed[v.Index] = v.Speed; } if (!changed) { return(new Ok(cmdMsg.Id)); } var rSpeedInt = Convert.ToUInt16(_vibratorSpeed[0] * 15); var rSpeedExt = Convert.ToUInt16(_vibratorSpeed[_vibratorCount - 1] * 15); // 0f 03 00 bc 00 00 00 00 var data = new byte[] { 0x0f, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00 }; data[3] = Convert.ToByte(rSpeedExt); // External data[3] |= Convert.ToByte(rSpeedInt << 4); // Internal // ReSharper disable once InvertIf if (rSpeedInt == 0 && rSpeedExt == 0) { data[1] = 0x00; data[5] = 0x00; } return(await Interface.WriteValue(aMsg.Id, (uint)WeVibeBluetoothInfo.Chrs.Tx, data)); }
public override async Task <ButtplugMessage> Initialize() { BpLogger.Trace($"Initializing {Name}"); return(await Interface.WriteValue(ButtplugConsts.SystemMsgId, Info.Characteristics[(uint)FleshlightLaunchBluetoothInfo.Chrs.Cmd], new byte[] { 0 }, true)); }
private Task <ButtplugMessage> HandleStopDeviceCmd([NotNull] ButtplugDeviceMessage aMsg) { // Right now, this is a nop. The Onyx doesn't have any sort of permanent movement state, // and its longest movement is like 150ms or so. The Pearl is supposed to vibrate but I've // never gotten that to work. So for now, we just return ok. BpLogger.Debug("Stopping Device " + Name); return(Task.FromResult <ButtplugMessage>(new Ok(aMsg.Id))); }
private async Task <ButtplugMessage> HandleStopDeviceCmd(ButtplugDeviceMessage aMsg, CancellationToken aToken) { BpLogger.Debug("Stopping Device " + Name); await HandleSingleMotorVibrateCmd(new SingleMotorVibrateCmd(aMsg.DeviceIndex, 0, aMsg.Id), aToken).ConfigureAwait(false); await HandleRotateCmd(RotateCmd.Create(0, false, 1), aToken); return(new Ok(aMsg.Id)); }
public override void StopScanning() { // todo We need to be able to kill a CancellationToken here, otherwise things like ET312 connects will stall here. _scanLock.Wait(); _scanTimer.Enabled = false; _scanLock.Release(); BpLogger.Info($"Stopping timed-repeat scanning for {GetType().Name}"); InvokeScanningFinished(); }
private async Task <ButtplugMessage> HandleSingleMotorVibrateCmd(ButtplugDeviceMessage aMsg) { if (!(aMsg is SingleMotorVibrateCmd cmdMsg)) { return(BpLogger.LogErrorMsg(aMsg.Id, Error.ErrorClass.ERROR_DEVICE, "Wrong Handler")); } return(await HandleVibrateCmd(VibrateCmd.Create(cmdMsg.DeviceIndex, cmdMsg.Id, cmdMsg.Speed, _vibratorCount))); }
private async Task <ButtplugMessage> HandleStopDeviceCmd(ButtplugDeviceMessage aMsg, CancellationToken aToken) { BpLogger.Debug("Stopping Device " + Name); await Interface.WriteValueAsync(new byte[] { (byte)_deviceType, (byte)_commandType, 0 }, aToken).ConfigureAwait(false); return(new Ok(aMsg.Id)); }
public override async Task InitializeAsync(CancellationToken aToken) { BpLogger.Trace($"Initializing {Name}"); // Kick Vibrator into motor control mode, just copying what the app sends when you go to // create pattern mode. await Interface.WriteValueAsync(new byte[] { 0x43, 0x02, 0x00 }, new ButtplugDeviceWriteOptions { Endpoint = Endpoints.TxMode, WriteWithResponse = true }, aToken).ConfigureAwait(false); }
private async Task <ButtplugMessage> HandleStopDeviceCmd(ButtplugDeviceMessage aMsg, CancellationToken aToken) { BpLogger.Debug("Stopping Device " + Name); // Stop commands start with 0x01 var cmd = GetCommandArray(new[] { (byte)0x01, (byte)RealTouchComponents.A }); await Interface.WriteValueAsync(cmd, aToken); return(new Ok(aMsg.Id)); //return await HandleRotateCmd(new RotateCmd(aMsg.DeviceIndex, 0, _clockwise, aMsg.Id), aToken).ConfigureAwait(false); }
private async Task <ButtplugMessage> HandleKiirooRawCmd([NotNull] ButtplugDeviceMessage aMsg) { if (!(aMsg is KiirooCmd cmdMsg)) { return(BpLogger.LogErrorMsg(aMsg.Id, Error.ErrorClass.ERROR_DEVICE, "Wrong Handler")); } return(await Interface.WriteValue(cmdMsg.Id, Encoding.ASCII.GetBytes($"{cmdMsg.Position},\n"))); }
private Task <ButtplugMessage> HandleStopDeviceCmd(ButtplugDeviceMessage aMsg) { // This probably shouldn't be a nop, but right now we don't have a good way to know // if the launch is moving or not, and surprisingly enough, setting speed to 0 does not // actually stop movement. It just makes it move really slow. // However, since each move it makes is finite (unlike setting vibration on some devices), // so we can assume it will be a short move, similar to what we do for the Kiiroo toys. BpLogger.Debug("Stopping Device " + Name); return(Task.FromResult <ButtplugMessage>(new Ok(aMsg.Id))); }
public override async Task <ButtplugMessage> InitializeAsync(CancellationToken aToken) { BpLogger.Trace($"Initializing {Name}"); // Kick Vibrator into motor control mode, just copying what the app sends when you go to // create pattern mode. return(await Interface.WriteValueAsync(ButtplugConsts.SystemMsgId, (uint)MysteryVibeBluetoothInfo.Chrs.ModeControl, new byte[] { 0x43, 0x02, 0x00 }, true, aToken).ConfigureAwait(false)); }
public override void StartScanning() { BpLogger.Info("Starting BLE Scanning"); _seenAddresses.Clear(); var t = Task.Run(async() => { BpLogger.Info("Start BLE Scanning"); await _adapter.StartScanningForDevicesAsync(); }); }
public override void StopScanning() { BpLogger.Info("Stopping BLE Scanning"); var t = Task.Run(async() => { await _adapter.StopScanningForDevicesAsync(); BpLogger.Info("Stopped BLE Scanning"); InvokeScanningFinished(); }); }