ScpService/Ds3Service.cs (181 lines of code) (raw):

using System; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.InteropServices; using System.ServiceProcess; using System.Threading; using System.Threading.Tasks; using log4net; using ScpControl; using ScpControl.Bluetooth; using ScpControl.Database; using ScpControl.ScpCore; using ScpControl.Shared.Core; using ScpControl.Usb.Ds3; using ScpControl.Usb.Ds4; using ScpControl.Usb.Gamepads; namespace ScpService { public partial class Ds3Service : ServiceBase { #region Private fields private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private IntPtr _bthNotify = IntPtr.Zero; private ScpDevice.ServiceControlHandlerEx _mControlHandler; private IntPtr _ds3Notify = IntPtr.Zero; private IntPtr _ds4Notify = IntPtr.Zero; private IntPtr _mServiceHandle = IntPtr.Zero; private IntPtr _genericNotify = IntPtr.Zero; private readonly Timer _mTimer; #endregion public Ds3Service() { InitializeComponent(); AppDomain.CurrentDomain.UnhandledException += (sender, args) => { Log.FatalFormat("An unhandled exception occured: {0}", args.ExceptionObject); }; _mTimer = new Timer(OnTimer, null, Timeout.Infinite, Timeout.Infinite); } protected override void OnStart(string[] args) { var sw = Stopwatch.StartNew(); Log.Info("Scarlet.Crush Productions DSx Service Started"); Log.DebugFormat("++ {0} {1}", Assembly.GetExecutingAssembly().Location, Assembly.GetExecutingAssembly().GetName().Version); Log.DebugFormat("Setting working directory to {0}", GlobalConfiguration.AppDirectory); Directory.SetCurrentDirectory(GlobalConfiguration.AppDirectory); Log.DebugFormat("Setting process priority to {0}", GlobalConfiguration.Instance.ServiceProcessPriority); Process.GetCurrentProcess().PriorityClass = GlobalConfiguration.Instance.ServiceProcessPriority; _mControlHandler = ServiceControlHandler; _mServiceHandle = ScpDevice.RegisterServiceCtrlHandlerEx(ServiceName, _mControlHandler, IntPtr.Zero); var installTask = Task.Factory.StartNew(() => { using (var db = new ScpDb()) { #if FIXME var bthDevices = db.Engine.GetAllDbEntities<WdiDeviceInfo>(ScpDb.TableDevices) .Where(d => d.Value.DeviceType == WdiUsbDeviceType.BluetoothHost) .Select(d => d.Value); if (GlobalConfiguration.Instance.ForceBluetoothDriverReinstallation) DriverInstaller.InstallBluetoothDongles(bthDevices); var ds3Devices = db.Engine.GetAllDbEntities<WdiDeviceInfo>(ScpDb.TableDevices) .Where(d => d.Value.DeviceType == WdiUsbDeviceType.DualShock3) .Select(d => d.Value); if (GlobalConfiguration.Instance.ForceDs3DriverReinstallation) DriverInstaller.InstallDualShock3Controllers(ds3Devices); var ds4Devices = db.Engine.GetAllDbEntities<WdiDeviceInfo>(ScpDb.TableDevices) .Where(d => d.Value.DeviceType == WdiUsbDeviceType.DualShock4) .Select(d => d.Value); if (GlobalConfiguration.Instance.ForceDs4DriverReinstallation) DriverInstaller.InstallDualShock4Controllers(ds4Devices); #endif } }); installTask.ContinueWith(task => { Log.FatalFormat("Error during driver installation: {0}", task.Exception); Stop(); }, TaskContinuationOptions.OnlyOnFaulted); Log.DebugFormat("Time spent 'till Root Hub start: {0}", sw.Elapsed); var hubStartTask = Task.Factory.StartNew(() => { rootHub.Open(); rootHub.Start(); }); hubStartTask.ContinueWith(task => { Log.FatalFormat("Couldn't start the root hub: {0}", task.Exception); Stop(); }, TaskContinuationOptions.OnlyOnFaulted); Log.DebugFormat("Time spent 'till registering notifications: {0}", sw.Elapsed); ScpDevice.RegisterNotify(_mServiceHandle, UsbDs3.DeviceClassGuid, ref _ds3Notify, false); ScpDevice.RegisterNotify(_mServiceHandle, UsbDs4.DeviceClassGuid, ref _ds4Notify, false); ScpDevice.RegisterNotify(_mServiceHandle, BthDongle.DeviceClassGuid, ref _bthNotify, false); ScpDevice.RegisterNotify(_mServiceHandle, UsbGenericGamepad.DeviceClassGuid, ref _genericNotify, false); Log.DebugFormat("Total Time spent in Service Start method: {0}", sw.Elapsed); } protected override void OnStop() { if (_ds3Notify != IntPtr.Zero) ScpDevice.UnregisterNotify(_ds3Notify); if (_ds4Notify != IntPtr.Zero) ScpDevice.UnregisterNotify(_ds4Notify); if (_bthNotify != IntPtr.Zero) ScpDevice.UnregisterNotify(_bthNotify); if (_genericNotify != IntPtr.Zero) ScpDevice.UnregisterNotify(_genericNotify); rootHub.Stop(); rootHub.Close(); Log.Info("Scarlet.Crush Productions DSx Service Stopped"); } private int ServiceControlHandler(int control, int type, IntPtr data, IntPtr context) { switch (control) { case ScpDevice.SERVICE_CONTROL_STOP: case ScpDevice.SERVICE_CONTROL_SHUTDOWN: Stop(); break; case ScpDevice.SERVICE_CONTROL_POWEREVENT: switch (type) { case ScpDevice.PBT_APMSUSPEND: Log.Info("Scp DS3 Service Suspending"); rootHub.Suspend(); break; case ScpDevice.PBT_APMRESUMEAUTOMATIC: Log.Info("Scp DS3 Service Resuming"); _mTimer.Change(10000, Timeout.Infinite); break; } break; case ScpDevice.SERVICE_CONTROL_DEVICEEVENT: switch (type) { case ScpDevice.DBT_DEVICEARRIVAL: case ScpDevice.DBT_DEVICEREMOVECOMPLETE: ScpDevice.DEV_BROADCAST_HDR hdr; hdr = (ScpDevice.DEV_BROADCAST_HDR) Marshal.PtrToStructure(data, typeof(ScpDevice.DEV_BROADCAST_HDR)); if (hdr.dbch_devicetype == ScpDevice.DBT_DEVTYP_DEVICEINTERFACE) { ScpDevice.DEV_BROADCAST_DEVICEINTERFACE_M deviceInterface; deviceInterface = (ScpDevice.DEV_BROADCAST_DEVICEINTERFACE_M) Marshal.PtrToStructure(data, typeof(ScpDevice.DEV_BROADCAST_DEVICEINTERFACE_M)); var Class = "{" + new Guid(deviceInterface.dbcc_classguid).ToString().ToUpper() + "}"; var path = new string(deviceInterface.dbcc_name); path = path.Substring(0, path.IndexOf('\0')).ToUpper(); var pad = rootHub.Notify((ScpDevice.Notified)type, Class, path); if (pad != DsPadId.None) { if (rootHub.Pairable && !rootHub.BluetoothHostAddress.Equals(rootHub.Pads[(byte)pad].HostAddress)) { if(rootHub.Pads[(byte)pad].Pair(rootHub.BluetoothHostAddress)) { Log.InfoFormat("Paired DualShock Device {0} to Bluetooth host {1}", rootHub.Pads[(byte) pad].DeviceAddress, rootHub.BluetoothHostAddress); } else { Log.ErrorFormat("Couldn't pair DualShock Device {0} to Bluetooth host {1}", rootHub.Pads[(byte) pad].DeviceAddress, rootHub.BluetoothHostAddress); } } } } break; } break; } return 0; // NO_ERROR } private void OnTimer(object state) { lock (this) { rootHub.Resume(); Log.Info("Scp DS3 Service Resumed"); } } } }