private void EmulatorOnInputReportReceived(object o, InputReportReceivedEventArgs args) { foreach (var plugin in SinkPlugins.Select(p => p.Value)) { plugin.InputReportReceived(args.Device, args.Report); } }
public void Start() { if (!Directory.Exists(SourcesPath)) { Log.Fatal("{@SourcesPath} doesn't exist; service has nothing to do without sources", SourcesPath); Stop(); return; } if (!Directory.Exists(SinksPath)) { Log.Warning("{@SinksPath} doesn't exist; service has nothing to do without sinks", SinksPath); } _childDevices.CollectionChanged += (sender, args) => { switch (args.Action) { case NotifyCollectionChangedAction.Add: foreach (IDualShockDevice item in args.NewItems) { Log.Information("Device {Device} got attached via {ConnectionType}", item, item.ConnectionType); foreach (var plugin in SinkPlugins.Select(p => p.Value)) { plugin.DeviceArrived(item); } } break; case NotifyCollectionChangedAction.Remove: foreach (IDualShockDevice item in args.OldItems) { Log.Information("Device {Device} got removed via {ConnectionType}", item, item.ConnectionType); foreach (var plugin in SinkPlugins.Select(p => p.Value)) { plugin.DeviceRemoved(item); } } break; } }; #region MEF //Creating an instance of aggregate catalog. It aggregates other catalogs var aggregateCatalog = new AggregateCatalog(); //Load parts from the current assembly if available var asmCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); //Add to the aggregate catalog aggregateCatalog.Catalogs.Add(new DirectoryCatalog(SourcesPath, "*.dll")); aggregateCatalog.Catalogs.Add(new DirectoryCatalog(SinksPath, "*.dll")); aggregateCatalog.Catalogs.Add(asmCatalog); //Crete the composition container var container = new CompositionContainer(aggregateCatalog); // Composable parts are created here i.e. // the Import and Export components assembles here container.ComposeParts(this); #endregion // Log loaded sink plugins foreach (var plugin in SinkPlugins) { Log.Information("Loaded sink plugin {Plugin}", plugin.Metadata["Name"]); plugin.Value.RumbleRequestReceived += (sender, args) => _childDevices[(IDualShockDevice)sender].Rumble(args.LargeMotor, args.SmallMotor); } // Log and enable sources foreach (var emulator in BusEmulators) { Log.Information("Loaded bus emulator {Emulator}", emulator.Metadata["Name"]); emulator.Value.ChildDeviceAttached += (sender, args) => _childDevices.Add(args.Device); emulator.Value.ChildDeviceRemoved += (sender, args) => _childDevices.Remove(args.Device); emulator.Value.InputReportReceived += EmulatorOnInputReportReceived; try { Log.Information("Starting bus emulator {Emulator}", emulator.Metadata["Name"]); emulator.Value.Start(); Log.Information("Bus emulator {Emulator} started successfully", emulator.Metadata["Name"]); } catch (Exception ex) { Log.Error("Failed to start {@emulator}: {@ex}", emulator.Metadata["Name"], ex); } } #region IPC var services = new DelegateServiceFactory(); services.Register <IPairingService>(() => { var service = new PairingService(); service.DeviceListRequested += (sender, args) => _childDevices .Where(d => d.ConnectionType.Equals(DualShockConnectionType.USB)) .Select(d => new DualShockDeviceDescriptor { ClientAddress = new UniqueAddress(d.ClientAddress), ConnectionType = d.ConnectionType, DeviceType = d.DeviceType, HostAddress = new UniqueAddress(d.HostAddress) }).ToList(); service.DevicePairingRequested += (device, args) => _childDevices[device.ClientAddress].PairTo(new PhysicalAddress(args.HostAddress.AddressBytes)); return(service); }); _ipcServer = new HalibutRuntime(services, Configuration.ServerCertificate); _ipcServer.Listen(Configuration.ServerEndpoint); _ipcServer.Trust(Configuration.ClientCertificate.Thumbprint); #endregion }
public void Start() { if (!Directory.Exists(SourcesPath)) { Log.Fatal("{@SourcesPath} doesn't exist; service has nothing to do without sources", SourcesPath); Stop(); return; } if (!Directory.Exists(SinksPath)) { Log.Warning("{@SinksPath} doesn't exist; service has nothing to do without sinks", SinksPath); } _childDevices.CollectionChanged += (sender, args) => { switch (args.Action) { case NotifyCollectionChangedAction.Add: foreach (IDualShockDevice item in args.NewItems) { Log.Information("Device {Device} got attached via {ConnectionType}", item, item.ConnectionType); // Crude auto-pairing mechanism in case BthPS3 is present if (item.ConnectionType.Equals(DualShockConnectionType.USB) && BusEmulators.Select(be => be.Value).Any(b => b.Name == "BthPS3BusEmulator") && BluetoothAdapter.GetDefault() != null) { // Check if newly connected USB device is already connected via Bluetooth if (item.ConnectionType.Equals(DualShockConnectionType.USB)) { var emulator = BusEmulators.Select(be => be.Value).Where(b => b.Name == "BthPS3BusEmulator").First(); foreach (var otherItem in _childDevices) { if (otherItem.ConnectionType.Equals(DualShockConnectionType.Bluetooth)) { if (otherItem.ClientAddress.Equals(item.ClientAddress)) // If found remove bluetooth device { emulator.RemoveDevice(otherItem); break; } } } } // Get address of detected primary radio var hostAddress = new PhysicalAddress(BitConverter .GetBytes(BluetoothAdapter.GetDefault().BluetoothAddress).Take(6).Reverse() .ToArray()); if (!item.HostAddress.Equals(hostAddress)) { Log.Information("Auto-pairing device {Device} to {HostAddress}", item, hostAddress.AsFriendlyName()); // Pair USB device item.PairTo(hostAddress); } else { Log.Information("Device {Device} already paired to this radio {HostAddress}.", item, hostAddress.AsFriendlyName()); } } else { Log.Warning("Auto-pairing not supported as BthPS3 and/or Bluetooth Host Radio not found"); } foreach (var plugin in SinkPlugins.Where(p => p.Value.IsEnabled).Select(p => p.Value)) { plugin.DeviceArrived(item); } } break; case NotifyCollectionChangedAction.Remove: foreach (IDualShockDevice item in args.OldItems) { Log.Information("Device {Device} got removed via {ConnectionType}", item, item.ConnectionType); foreach (var plugin in SinkPlugins.Where(p => p.Value.IsEnabled).Select(p => p.Value)) { plugin.DeviceRemoved(item); } } break; } UpdateLEDS(); }; #region MEF //Creating an instance of aggregate catalog. It aggregates other catalogs var aggregateCatalog = new AggregateCatalog(); //Load parts from the current assembly if available var asmCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); //Add to the aggregate catalog aggregateCatalog.Catalogs.Add(new DirectoryCatalog(SourcesPath, "*.dll")); aggregateCatalog.Catalogs.Add(new DirectoryCatalog(SinksPath, "*.dll")); aggregateCatalog.Catalogs.Add(asmCatalog); //Crete the composition container var container = new CompositionContainer(aggregateCatalog); // Composable parts are created here i.e. // the Import and Export components assembles here container.ComposeParts(this); #endregion // Log loaded sink plugins foreach (var plugin in SinkPlugins.Where(p => p.Value.IsEnabled)) { Log.Information("Loaded sink plugin {Plugin}", plugin.Metadata["Name"]); plugin.Value.RumbleRequestReceived += (sender, args) => _childDevices[(IDualShockDevice)sender].Rumble(args.LargeMotor, args.SmallMotor); } // Log and enable sources foreach (var emulator in BusEmulators.Where(p => p.Value.IsEnabled)) { Log.Information("Loaded bus emulator {Emulator}", emulator.Metadata["Name"]); emulator.Value.ChildDeviceAttached += (sender, args) => _childDevices.Add(args.Device); emulator.Value.ChildDeviceRemoved += (sender, args) => _childDevices.Remove(args.Device); emulator.Value.InputReportReceived += EmulatorOnInputReportReceived; try { Log.Information("Starting bus emulator {Emulator}", emulator.Metadata["Name"]); emulator.Value.Start(); Log.Information("Bus emulator {Emulator} started successfully", emulator.Metadata["Name"]); } catch (Exception ex) { Log.Error("Failed to start {@emulator}: {@ex}", emulator.Metadata["Name"], ex); } } #region IPC if (Config.Global.Core.Halibut.IsEnabled) { var services = new DelegateServiceFactory(); services.Register <IPairingService>(() => { var service = new PairingService(); service.DeviceListRequested += (sender, args) => _childDevices .Where(d => d.ConnectionType.Equals(DualShockConnectionType.USB)) .Select(d => new DualShockDeviceDescriptor { ClientAddress = new UniqueAddress(d.ClientAddress), ConnectionType = d.ConnectionType, DeviceType = d.DeviceType, HostAddress = new UniqueAddress(d.HostAddress) }).ToList(); service.DevicePairingRequested += (device, args) => _childDevices[device.ClientAddress].PairTo(new PhysicalAddress(args.HostAddress.AddressBytes)); return(service); }); _ipcServer = new HalibutRuntime(services, Configuration.ServerCertificate); _ipcServer.Listen(Configuration.ServerEndpoint); _ipcServer.Trust(Configuration.ClientCertificate.Thumbprint); } #endregion Task.Factory.StartNew(PollBatteryLevel, _inputCancellationTokenSource.Token); }