예제 #1
0
        public virtual void Start()
        {
            ChildDevices.CollectionChanged += (sender, args) =>
            {
                switch (args.Action)
                {
                case NotifyCollectionChangedAction.Add:
                    foreach (IDualShockDevice item in args.NewItems)
                    {
                        ChildDeviceAttached?.Invoke(this, new ChildDeviceAttachedEventArgs(item));
                    }
                    break;

                case NotifyCollectionChangedAction.Remove:
                    foreach (IDualShockDevice item in args.OldItems)
                    {
                        ChildDeviceRemoved?.Invoke(this, new ChildDeviceRemovedEventArgs(item));
                    }
                    break;
                }
            };

            _deviceLookupTask = _deviceLookupSchedule.Subscribe(OnLookup);
            OnLookup(0);
        }
예제 #2
0
        private void OnLookup(long l)
        {
            if (!Monitor.TryEnter(_hostLookupTask))
            {
                return;
            }

            try
            {
                var instanceId = 0;

                while (Devcon.Find(AirBenderHost.ClassGuid, out var path, out var instance, instanceId++))
                {
                    if (_hosts.Any(h => h.DevicePath.Equals(path)))
                    {
                        continue;
                    }

                    Log.Information("Found AirBender device {Path} ({Instance})", path, instance);

                    var host = new AirBenderHost(path);

                    host.HostDeviceDisconnected += (sender, args) =>
                    {
                        var device = (AirBenderHost)sender;
                        _hosts.Remove(device);
                        device.Dispose();
                    };
                    host.ChildDeviceAttached += (o, eventArgs) =>
                                                ChildDeviceAttached?.Invoke(this, new ChildDeviceAttachedEventArgs(eventArgs.Device));
                    host.ChildDeviceRemoved += (o, eventArgs) =>
                                               ChildDeviceRemoved?.Invoke(this, new ChildDeviceRemovedEventArgs(eventArgs.Device));
                    host.InputReportReceived += (sender, args) =>
                                                InputReportReceived?.Invoke(this, new InputReportReceivedEventArgs(args.Device, args.Report));

                    _hosts.Add(host);
                }
            }
            finally
            {
                Monitor.Exit(_hostLookupTask);
            }
        }
예제 #3
0
        /// <summary>
        ///     Opens an AirBender device by its device path.
        /// </summary>
        /// <param name="devicePath">The device path to open.</param>
        public AirBenderHost(string devicePath)
        {
            DevicePath = devicePath;
            Children   = new ObservableCollection <AirBenderChildDevice>();

            Children.CollectionChanged += (sender, args) =>
            {
                switch (args.Action)
                {
                case NotifyCollectionChangedAction.Add:

                    foreach (IDualShockDevice item in args.NewItems)
                    {
                        ChildDeviceAttached?.Invoke(this, new ChildDeviceAttachedEventArgs(item));
                    }

                    break;

                case NotifyCollectionChangedAction.Remove:

                    foreach (IDualShockDevice item in args.OldItems)
                    {
                        ChildDeviceRemoved?.Invoke(this, new ChildDeviceRemovedEventArgs(item));
                    }

                    break;

                default:
                    break;
                }
            };

            //
            // Open device
            //
            DeviceHandle = Kernel32.CreateFile(DevicePath,
                                               Kernel32.ACCESS_MASK.GenericRight.GENERIC_READ | Kernel32.ACCESS_MASK.GenericRight.GENERIC_WRITE,
                                               Kernel32.FileShare.FILE_SHARE_READ | Kernel32.FileShare.FILE_SHARE_WRITE,
                                               IntPtr.Zero, Kernel32.CreationDisposition.OPEN_EXISTING,
                                               Kernel32.CreateFileFlags.FILE_ATTRIBUTE_NORMAL
                                               | Kernel32.CreateFileFlags.FILE_FLAG_NO_BUFFERING
                                               | Kernel32.CreateFileFlags.FILE_FLAG_WRITE_THROUGH
                                               | Kernel32.CreateFileFlags.FILE_FLAG_OVERLAPPED,
                                               Kernel32.SafeObjectHandle.Null
                                               );

            if (DeviceHandle.IsInvalid)
            {
                throw new ArgumentException($"Couldn't open device {DevicePath}");
            }

            var  length = Marshal.SizeOf(typeof(AirbenderGetHostBdAddr));
            var  pData  = Marshal.AllocHGlobal(length);
            bool ret;

            try
            {
                //
                // Request host MAC address
                //
                ret = DeviceHandle.OverlappedDeviceIoControl(
                    IoctlAirbenderGetHostBdAddr,
                    IntPtr.Zero, 0, pData, length,
                    out _);

                if (!ret)
                {
                    throw new AirBenderGetHostBdAddrFailedException(
                              "Failed to request host MAC address.",
                              new Win32Exception(Marshal.GetLastWin32Error()));
                }

                HostAddress =
                    new PhysicalAddress(Marshal.PtrToStructure <AirbenderGetHostBdAddr>(pData).Host.Address.Reverse()
                                        .ToArray());
            }
            finally
            {
                Marshal.FreeHGlobal(pData);
            }

            Log.Information("Bluetooth Host Address: {HostAddress}", HostAddress.AsFriendlyName());

            //
            // Request host controller to reset and clean up resources
            //
            ret = DeviceHandle.OverlappedDeviceIoControl(
                IoctlAirbenderHostReset,
                IntPtr.Zero, 0, IntPtr.Zero, 0,
                out _);

            if (!ret)
            {
                throw new AirBenderHostResetFailedException(
                          "Failed to reset host.",
                          new Win32Exception(Marshal.GetLastWin32Error()));
            }

            Task.Factory.StartNew(ChildDeviceArrivalWorker, _arrivalCancellationTokenSourcePrimary.Token);
            Task.Factory.StartNew(ChildDeviceArrivalWorker, _arrivalCancellationTokenSourceSecondary.Token);

            Task.Factory.StartNew(ChildDeviceRemovalWorker, _removalCancellationTokenSourcePrimary.Token);
            Task.Factory.StartNew(ChildDeviceRemovalWorker, _removalCancellationTokenSourceSecondary.Token);
        }