Esempio n. 1
0
 private void OnBluetoothError(BluetoothException exception)
 {
     if (!SuppressDisconnectionEvents)
     {
         BluetoothError?.Invoke(this, exception);
     }
 }
Esempio n. 2
0
        internal int StartScan()
        {
            _adapterLeScanResultChangedCallback = (int result, ref BluetoothLeScanDataStruct scanData, IntPtr userData) =>
            {
                Log.Info(Globals.LogTag, "Inside Le scan callback ");
                BluetoothLeScanData scanDataInfo = BluetoothUtils.ConvertStructToLeScanData(scanData);

                BluetoothLeDevice device = new BluetoothLeDevice(scanDataInfo);
                BluetoothError    res    = (BluetoothError)result;

                AdapterLeScanResultChangedEventArgs e = new AdapterLeScanResultChangedEventArgs(res,
                                                                                                device);
                _adapterLeScanResultChanged?.Invoke(null, e);
            };

            IntPtr data = IntPtr.Zero;
            int    ret  = Interop.Bluetooth.StartScan(_adapterLeScanResultChangedCallback, data);

            if (ret != (int)BluetoothError.None)
            {
                Log.Error(Globals.LogTag, "Failed to start BLE scan - " + (BluetoothError)ret);
                BluetoothErrorFactory.ThrowBluetoothException(ret);
            }
            _scanStarted = true;
            return(ret);
        }
Esempio n. 3
0
 internal AcceptStateChangedEventArgs(BluetoothError result, BluetoothSocketState state, SocketConnection connection, BluetoothSocket server)
 {
     _result     = result;
     _state      = state;
     _connection = connection;
     _server     = (IBluetoothServerSocket)server;
 }
Esempio n. 4
0
        private async Task <RfcommDeviceServicesResult> GetRfcommServicesAsyncImpl(BluetoothCacheMode cacheMode)
        {
            BluetoothError             error    = BluetoothError.Success;
            List <RfcommDeviceService> services = new List <RfcommDeviceService>();

            return(new RfcommDeviceServicesResult(error, services.AsReadOnly()));
        }
Esempio n. 5
0
        private void WatcherStopped(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementWatcherStoppedEventArgs args)
        {
            BluetoothError a = args.Error;

            //AssertSameThreadAndContext();
            GlobalCounters.IncrementWatchersClosed();
        }
Esempio n. 6
0
        /// <summary>
        /// Invoked as an event handler when the status of the publisher changes.
        /// </summary>
        /// <param name="publisher">Instance of publisher that triggered the event.</param>
        /// <param name="eventArgs">Event data containing information about the publisher status change event.</param>
        private async void OnPublisherStatusChanged(
            BluetoothLEAdvertisementPublisher publisher,
            BluetoothLEAdvertisementPublisherStatusChangedEventArgs eventArgs)
        {
            // This event handler can be used to monitor the status of the publisher.
            // We can catch errors if the publisher is aborted by the system
            BluetoothLEAdvertisementPublisherStatus status = eventArgs.Status;
            BluetoothError error = eventArgs.Error;

            StatusChanged?.Invoke(publisher, eventArgs);
        }
Esempio n. 7
0
        private async Task <RfcommDeviceServicesResult> GetRfcommServicesAsyncImpl(BluetoothCacheMode cacheMode)
        {
            BluetoothError             error    = BluetoothError.Success;
            List <RfcommDeviceService> services = new List <Rfcomm.RfcommDeviceService>();

            foreach (Guid g in GetRfcommServices(ref _info))
            {
                services.Add(new Rfcomm.RfcommDeviceService(this, Rfcomm.RfcommServiceId.FromUuid(g)));
            }

            return(new Rfcomm.RfcommDeviceServicesResult(error, services.AsReadOnly()));
        }
Esempio n. 8
0
 public static void HandleResult(int result)
 {
     if (!Enum.IsDefined(typeof(BluetoothError), result))
     {
         throw new Win32Exception(result);
     }
     else
     {
         BluetoothError error = (BluetoothError)result;
         if (error != BluetoothError.BTH_ERROR_SUCCESS)
         {
             throw new Win32Exception(result, error.ToString());
         }
     }
 }
Esempio n. 9
0
        private void RegisterBondCreatedEvent()
        {
            _bondCreatedCallback = (int result, ref BluetoothDeviceStruct device, IntPtr userData) =>
            {
                if (_bondCreated != null)
                {
                    BluetoothError res = (BluetoothError)result;
                    _bondCreated(null, new BondCreatedEventArgs(res, BluetoothUtils.ConvertStructToDeviceClass(device)));
                }
            };
            int ret = Interop.Bluetooth.SetBondCreatedCallback(_bondCreatedCallback, IntPtr.Zero);

            if (ret != (int)BluetoothError.None)
            {
                Log.Error(Globals.LogTag, "Failed to set bond created callback, Error - " + (BluetoothError)ret);
            }
        }
Esempio n. 10
0
        private void RegisterBondDestroyedEvent()
        {
            _bondDestroyedCallback = (int result, string deviceAddress, IntPtr userData) =>
            {
                if (_bondDestroyed != null)
                {
                    BluetoothError res = (BluetoothError)result;
                    _bondDestroyed(null, new BondDestroyedEventArgs(res, deviceAddress));
                }
            };
            int ret = Interop.Bluetooth.SetBondDestroyedCallback(_bondDestroyedCallback, IntPtr.Zero);

            if (ret != (int)BluetoothError.None)
            {
                Log.Error(Globals.LogTag, "Failed to set bond destroyed callback, Error - " + (BluetoothError)ret);
            }
        }
Esempio n. 11
0
        /// <summary>
        /// Invoked as an event handler when the status of the publisher changes.
        /// </summary>
        /// <param name="publisher">Instance of publisher that triggered the event.</param>
        /// <param name="eventArgs">Event data containing information about the publisher status change event.</param>
        private async void OnAdvertiserStatusChanged(
            BluetoothLEAdvertisementPublisher publisher,
            BluetoothLEAdvertisementPublisherStatusChangedEventArgs eventArgs)
        {
            // This event handler can be used to monitor the status of the publisher.
            // We can catch errors if the publisher is aborted by the system
            BluetoothLEAdvertisementPublisherStatus status = eventArgs.Status;
            BluetoothError error = eventArgs.Error;

            if (error == BluetoothError.Success)
            {
                setStatus(status.ToString());

                switch (status)
                {
                case BluetoothLEAdvertisementPublisherStatus.Started:
                    setStatus("Connecting...");
                    try
                    {
                        var connectionTask   = this.AncsManager.Connect();
                        var connectionResult = await connectionTask;

                        //var connectionResult = await this.AncsManager.Connect();
                        if (connectionResult == true)
                        {
                            setStatus("Waiting for device...");
                        }
                        else
                        {
                            setStatus("No suitable device");
                        }
                    }
                    catch (Exception ex)
                    {
                        setStatus(ex.Message);
                    }

                    break;
                }
            }
            else
            {
                setStatus(String.Format("Error: {0}", error.ToString()));
            }
        }
Esempio n. 12
0
        private void RegisterVisibilityChangedEvent()
        {
            _visibilityChangedCallback = (int result, int mode, IntPtr userData) =>
            {
                if (_visibilityModeChanged != null)
                {
                    VisibilityMode visibility = (VisibilityMode)mode;
                    BluetoothError res        = (BluetoothError)result;
                    _visibilityModeChanged(null, new VisibilityModeChangedEventArgs(res, visibility));
                }
            };
            int ret = Interop.Bluetooth.SetVisibilityModeChangedCallback(_visibilityChangedCallback, IntPtr.Zero);

            if (ret != (int)BluetoothError.None)
            {
                Log.Error(Globals.LogTag, "Failed to set visibility mode changed callback, Error - " + (BluetoothError)ret);
            }
        }
Esempio n. 13
0
        private void RegisterStateChangedEvent()
        {
            _stateChangedCallback = (int result, int state, IntPtr userData) =>
            {
                if (_stateChanged != null)
                {
                    BluetoothState st  = (BluetoothState)state;
                    BluetoothError res = (BluetoothError)result;
                    _stateChanged(null, new StateChangedEventArgs(res, st));
                }
            };
            int ret = Interop.Bluetooth.SetStateChangedCallback(_stateChangedCallback, IntPtr.Zero);

            if (ret != (int)BluetoothError.None)
            {
                Log.Error(Globals.LogTag, "Failed to set state changed callback, Error - " + (BluetoothError)ret);
            }
        }
        /// <summary>
        /// Invoked as an event handler when the status of the publisher changes.
        /// </summary>
        /// <param name="publisher">Instance of publisher that triggered the event.</param>
        /// <param name="eventArgs">Event data containing information about the publisher status change event.</param>
        private async void OnPublisherStatusChanged(
            BluetoothLEAdvertisementPublisher publisher,
            BluetoothLEAdvertisementPublisherStatusChangedEventArgs eventArgs)
        {
            // This event handler can be used to monitor the status of the publisher.
            // We can catch errors if the publisher is aborted by the system
            BluetoothLEAdvertisementPublisherStatus status = eventArgs.Status;
            BluetoothError error = eventArgs.Error;

            // Update the publisher status displayed in the sample
            // Serialize UI update to the main UI thread
            await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                PublisherStatusBlock.Text = string.Format("Published Status: {0}, Error: {1}",
                                                          status.ToString(),
                                                          error.ToString());
            });
        }
Esempio n. 15
0
        private void RegisterServiceSearchedEvent()
        {
            _serviceSearchedCallback = (int result, ref BluetoothDeviceSdpStruct sdp, IntPtr userData) =>
            {
                Log.Info(Globals.LogTag, "Servicesearched cb is called");
                if (_serviceSearched != null)
                {
                    BluetoothError res = (BluetoothError)result;
                    _serviceSearched(null, new ServiceSearchedEventArgs(res, BluetoothUtils.ConvertStructToSdpData(sdp)));
                }
            };
            int ret = Interop.Bluetooth.SetServiceSearchedCallback(_serviceSearchedCallback, IntPtr.Zero);

            if (ret != (int)BluetoothError.None)
            {
                Log.Error(Globals.LogTag, "Failed to set service searched callback, Error - " + (BluetoothError)ret);
            }
        }
Esempio n. 16
0
 public static void HandleError(int result)
 {
     if (Enum.IsDefined(typeof(BluetoothError), result))
     {
         BluetoothError error = (BluetoothError)result;
         if (error != BluetoothError.BTH_ERROR_SUCCESS)
         {
             throw new Win32Exception(error.ToString());
         }
     }
     if (result == 0)
     {
         result = Marshal.GetLastWin32Error();
     }
     if (result != 0 && result != 1008 && result != 1168)
     {
         throw new Win32Exception(result);
     }
 }
Esempio n. 17
0
        public static AdvertisementWatcherError ToAdvertisementWatcherError(this BluetoothError error)
        {
            switch (error)
            {
            case BluetoothError.Success:
                return(AdvertisementWatcherError.None);

            default:
                return(AdvertisementWatcherError.Unknown);

            case BluetoothError.ConsentRequired:
                return(AdvertisementWatcherError.Unauthorized);

            case BluetoothError.NotSupported:
                return(AdvertisementWatcherError.Unsupported);

            case BluetoothError.RadioNotAvailable:
                return(AdvertisementWatcherError.TurnedOff);
            }
        }
Esempio n. 18
0
        private async Task <RfcommDeviceServicesResult> GetRfcommServicesAsyncImpl(BluetoothCacheMode cacheMode)
        {
            BluetoothError             error    = BluetoothError.Success;
            List <RfcommDeviceService> services = new List <RfcommDeviceService>();

#if WINDOWS_PHONE_APP || WINDOWS_PHONE
            foreach (RfcommDeviceService service in _device.RfcommServices)
            {
                services.Add(service);
            }
#else
            var result = await _device.GetRfcommServicesAsync((Windows.Devices.Bluetooth.BluetoothCacheMode)((int)cacheMode));

            error = (BluetoothError)((int)result.Error);
            foreach (Windows.Devices.Bluetooth.Rfcomm.RfcommDeviceService service in result.Services)
            {
                services.Add(service);
            }
#endif
            return(new RfcommDeviceServicesResult(error, services.AsReadOnly()));
        }
Esempio n. 19
0
        private async Task <RfcommDeviceServicesResult> GetRfcommServicesAsyncImpl(BluetoothCacheMode cacheMode)
        {
            BluetoothError             error    = BluetoothError.Success;
            List <RfcommDeviceService> services = new List <RfcommDeviceService>();

            if (cacheMode == BluetoothCacheMode.Uncached)
            {
                error = _device.FetchUuidsWithSdp() ? BluetoothError.Success : BluetoothError.DeviceNotConnected;
            }

            ParcelUuid[] uuids = _device.GetUuids();
            if (uuids != null)
            {
                foreach (ParcelUuid g in uuids)
                {
                    services.Add(new RfcommDeviceService(this, RfcommServiceId.FromUuid(new Guid(g.Uuid.ToString()))));
                }
            }

            return(new RfcommDeviceServicesResult(error, services.AsReadOnly()));
        }
Esempio n. 20
0
        private void RegisterDiscoveryStateChangedEvent()
        {
            _discoveryStateChangedCallback = (int result, BluetoothDeviceDiscoveryState state, IntPtr deviceInfo, IntPtr userData) =>
            {
                Log.Info(Globals.LogTag, "Discovery state changed callback is called");
                if (_discoveryStateChanged != null)
                {
                    BluetoothError res = (BluetoothError)result;
                    switch (state)
                    {
                    case BluetoothDeviceDiscoveryState.Started:
                        _discoveryStateChanged(null, new DiscoveryStateChangedEventArgs(res, state));
                        break;

                    case BluetoothDeviceDiscoveryState.Finished:
                    {
                        _discoveryStateChanged(null, new DiscoveryStateChangedEventArgs(res, state));
                        break;
                    }

                    case BluetoothDeviceDiscoveryState.Found:
                    {
                        BluetoothDiscoveredDeviceStruct info = (BluetoothDiscoveredDeviceStruct)Marshal.PtrToStructure(deviceInfo, typeof(BluetoothDiscoveredDeviceStruct));
                        _discoveryStateChanged(null, new DiscoveryStateChangedEventArgs(res, state, BluetoothUtils.ConvertStructToDiscoveredDevice(info)));
                        break;
                    }

                    default:
                        break;
                    }
                }
            };
            int ret = Interop.Bluetooth.SetDiscoveryStateChangedCallback(_discoveryStateChangedCallback, IntPtr.Zero);

            if (ret != (int)BluetoothError.None)
            {
                Log.Error(Globals.LogTag, "Failed to set discovery state changed callback, Error - " + (BluetoothError)ret);
            }
        }
Esempio n. 21
0
        //---------------------------------------------------------------------
        // Event handlers for advertisements
        //---------------------------------------------------------------------

        //
        // Specifies behavior for when an advertisement is received by the
        // watcher. Because the IPv6 Over Bluetooth Low Energy project is based
        // on 6LoWPAN principles, routers actively watch for possible
        // recipients when they have a packet to deliver. Receiving an
        // advertisement means that there is a suitable node (or other router)
        // within range that can receive the packet, so we transmit it here.
        //
        private async void OnAdvertisementReceived(
            BluetoothLEAdvertisementWatcher watcher,
            BluetoothLEAdvertisementReceivedEventArgs eventArgs
            )
        {
            BluetoothError status = BluetoothError.Success;

            // Variables for the remote device, the IPv6ToBle packet processing
            // service, IPSS, and the device's characteristics
            BluetoothLEDevice device = null;
            GattDeviceService internetProtocolSupportService         = null;
            GattDeviceService ipv6ToBlePacketProcessingService       = null;
            IReadOnlyList <GattCharacteristic> deviceCharacteristics = null;

            // Variables to hold the characteristics with which we need to
            // interact
            GattCharacteristic ipv6PacketWriteCharacteristic = null;
            GattCharacteristic ipv6AddressCharacteristic     = null;
            IPAddress          deviceAddress = null;

            //
            // Step 1
            // Verify we have recevied a proper advertisement from the server
            // by checking its manufacturer data. This is kind of redundant
            // because we filter advertisements based on this, but it's not a
            // bad idea.
            //
            IList <BluetoothLEManufacturerData> manufacturerDataList = eventArgs.Advertisement.ManufacturerData;

            if (manufacturerDataList.Count == 0)
            {
                status = BluetoothError.OtherError;
                Debug.WriteLine("No manufacturer data in the advertisement.");
                goto Exit;
            }
            else
            {
                // There should only be one if it's one of our advertisements
                BluetoothLEManufacturerData manufacturerData = manufacturerDataList[0];

                // Verify it's the IPv6ToBle manufacturer name
                string manufacturerDataCompanyId = string.Format("0x{0}",
                                                                 manufacturerData.CompanyId.ToString("X")
                                                                 );
                if (manufacturerDataCompanyId != "0xDEDE")
                {
                    status = BluetoothError.OtherError;
                    Debug.WriteLine("Manufacturer Company ID did not match " +
                                    "IPv6ToBle."
                                    );
                    goto Exit;
                }
            }

            //
            // Step 2
            // Connect to the device
            //
            try
            {
                // Connect based on the device's Bluetooth address
                device = await BluetoothLEDevice.FromBluetoothAddressAsync(eventArgs.BluetoothAddress);

                if (device == null)
                {
                    status = BluetoothError.DeviceNotConnected;
                    Debug.WriteLine("Error connecting to device.");
                    goto Exit;
                }
            } catch (Exception e) when(e.HResult == Constants.E_DEVICE_NOT_AVAILABLE)
            {
                status = BluetoothError.RadioNotAvailable;
                Debug.WriteLine("Bluetooth radio is not on.");
                goto Exit;
            }

            //
            // Step 3
            // Enumerate the GATT services to get the
            // IPv6ToBlePacketProcessingService and Internet Protocol Support
            // Service (IPSS)
            //
            if (device != null)
            {
                // Retrieve the list of services from the device (uncached)
                GattDeviceServicesResult servicesResult = await device.GetGattServicesAsync(BluetoothCacheMode.Uncached);

                if (servicesResult.Status == GattCommunicationStatus.Success)
                {
                    var services = servicesResult.Services;
                    Debug.WriteLine($"Found {services.Count} services");

                    // Iterate through the list of services and check if
                    // both services we require are there
                    foreach (GattDeviceService service in services)
                    {
                        Guid uuid = service.Uuid;

                        // Check for IPv6ToBle Packet Write Service
                        if (uuid == Constants.IPv6ToBlePacketProcessingServiceUuid)
                        {
                            ipv6ToBlePacketProcessingService = service;
                            continue;
                        }

                        // Check for IPSS
                        ushort shortId = GattHelpers.ConvertUuidToShortId(uuid);
                        if (shortId == (ushort)GattHelpers.SigAssignedGattNativeUuid.InternetProtocolSupport)
                        {
                            internetProtocolSupportService = service;
                            continue;
                        }
                    }
                }
            }

            // Report error if the device was not running our packet processing
            // service for some reason
            if (ipv6ToBlePacketProcessingService == null ||
                internetProtocolSupportService == null)
            {
                status = BluetoothError.OtherError;
                Debug.WriteLine("Device did not have the " +
                                "IPv6ToBlePacketProcessingService running or" +
                                " available, or did not have the Internet" +
                                " Protocol Support Service running or " +
                                "available."
                                );
                goto Exit;
            }

            //
            // Step 4
            // Enumerate the GATT characteristics
            //
            try
            {
                // Verify we can access the service
                DeviceAccessStatus accessStatus = await ipv6ToBlePacketProcessingService.RequestAccessAsync();

                if (accessStatus == DeviceAccessStatus.Allowed)
                {
                    // Enumerate the characteristics
                    GattCharacteristicsResult characteristicsResult =
                        await ipv6ToBlePacketProcessingService.GetCharacteristicsAsync(BluetoothCacheMode.Uncached);

                    if (characteristicsResult.Status == GattCommunicationStatus.Success)
                    {
                        deviceCharacteristics = characteristicsResult.Characteristics;
                    }
                    else
                    {
                        status = BluetoothError.OtherError;
                        Debug.WriteLine("Could not access the packet " +
                                        "processing service."
                                        );
                        goto Exit;
                    }
                }
                else
                {
                    // Not granted access
                    status = BluetoothError.NotSupported;

                    Debug.WriteLine("Could not access the packet " +
                                    "processing service."
                                    );
                    goto Exit;
                }
            }
            catch (Exception e)
            {
                status = BluetoothError.DeviceNotConnected;
                Debug.WriteLine("Could not read characteristics due to " +
                                "permissions issues. " + e.Message
                                );
                goto Exit;
            }

            if (deviceCharacteristics != null)
            {
                // Find the IPv6 Address and packet write characteristics
                foreach (GattCharacteristic characteristic in deviceCharacteristics)
                {
                    if (characteristic.Uuid == Constants.IPv6ToBleIPv6AddressCharacteristicUuid)
                    {
                        ipv6AddressCharacteristic = characteristic;
                    }

                    if (characteristic.Uuid == Constants.IPv6ToBlePacketWriteCharacteristicUuid)
                    {
                        ipv6PacketWriteCharacteristic = characteristic;
                    }
                }
            }

            if (ipv6PacketWriteCharacteristic == null ||
                ipv6AddressCharacteristic == null)
            {
                status = BluetoothError.OtherError;
                Debug.WriteLine("Could not access the IPv6 address" +
                                " characteristic and the packet write" +
                                " characteristic.");
                goto Exit;
            }

            // Get the device's IPv6 address from the characteristic
            if (ipv6AddressCharacteristic != null)
            {
                GattReadResult readResult = await ipv6AddressCharacteristic.ReadValueAsync();

                if (readResult.Status == GattCommunicationStatus.Success)
                {
                    deviceAddress = new IPAddress(GattHelpers.ConvertBufferToByteArray(readResult.Value));
                }
                else
                {
                    status = BluetoothError.OtherError;
                    Debug.WriteLine("Could not read the device's IPv6 address" +
                                    " from the remote characteristic."
                                    );
                    goto Exit;
                }
            }

            //
            // Step 5
            // Write the packet now that we have verified that the device is
            // supported and is either the destination or in the path to the
            // destination
            //
            GattCommunicationStatus writeStatus =
                await ipv6PacketWriteCharacteristic.WriteValueAsync(GattHelpers.ConvertByteArrayToBuffer(Packet));

            if (writeStatus != GattCommunicationStatus.Success)
            {
                status = BluetoothError.OtherError;
                Debug.WriteLine("Could not write the IPv6 packet to the" +
                                " remote device");
            }

Exit:

            if (status != BluetoothError.Success)
            {
                TransmittedSuccessfully = false;
            }
            else
            {
                TransmittedSuccessfully = true;
            }
        }
Esempio n. 22
0
 internal BondDestroyedEventArgs(BluetoothError result, string address)
 {
     _result  = result;
     _address = address;
 }
Esempio n. 23
0
 internal StateChangedEventArgs(BluetoothError result, BluetoothState type)
 {
     _type   = type;
     _result = result;
 }
Esempio n. 24
0
 internal ServiceSearchedEventArgs(BluetoothError result, BluetoothDeviceSdpData sdpData)
 {
     _result  = result;
     _sdpData = sdpData;
 }
Esempio n. 25
0
 internal SocketConnectionStateChangedEventArgs(BluetoothError result, BluetoothSocketState state, SocketConnection connection)
 {
     _result     = result;
     _state      = state;
     _connection = connection;
 }
Esempio n. 26
0
        /// <summary>
        /// Writes a packet to a given device.
        /// </summary>
        /// <param name="targetDevice">The target device.</param>
        /// <param name="packet">The packet, compressed or not.</param>
        /// <param name="compressedHeaderLength">Optional. The length of the compressed header if the caller is sending a compressed packet.</param>
        /// <param name="payloadLength">Optional. The paylaod length of the packet. Only needed if the caller is sending a compressed packet.</param>
        /// <returns></returns>
        public static async Task <bool> WritePacketAsync(
            DeviceInformation targetDevice,
            byte[] packet,
            int compressedHeaderLength,
            int payloadLength
            )
        {
            BluetoothError status = BluetoothError.Success;

            // Variables for the remote device, the IPv6ToBle packet processing
            // service, IPSS, and the device's characteristics
            BluetoothLEDevice device = null;
            GattDeviceService ipv6ToBlePacketProcessingService       = null;
            IReadOnlyList <GattCharacteristic> deviceCharacteristics = null;

            // Variables for the remote packet write characteristic
            GattCharacteristic ipv6PacketWriteCharacteristic        = null;
            GattCharacteristic compressedHeaderLengthCharacteristic = null;
            GattCharacteristic payloadLengthCharacteristic          = null;

            // Variables for timing GATT communication latency and transmission time
            Stopwatch gattLatencyTimer      = new Stopwatch();
            Stopwatch gattTransmissionTimer = new Stopwatch();

            //
            // Step 1
            // Connect to the device
            //

            // Start timing how long it takes to perform pre-transmission GATT
            // communications
            gattLatencyTimer.Start();

            try
            {
                // Connect based on the device's Bluetooth address
                device = await BluetoothLEDevice.FromIdAsync(targetDevice.Id);

                if (device == null)
                {
                    status = BluetoothError.DeviceNotConnected;
                    Debug.WriteLine("Error connecting to device.");
                    goto Exit;
                }
            }
            catch (Exception e) when(e.HResult == Constants.E_DEVICE_NOT_AVAILABLE)
            {
                status = BluetoothError.RadioNotAvailable;
                Debug.WriteLine("Bluetooth radio is not on.");
                goto Exit;
            }

            //
            // Step 2
            // Enumerate the GATT services to get the
            // IPv6ToBlePacketProcessingService
            //
            if (device != null)
            {
                // Retrieve the list of services from the device (uncached)
                GattDeviceServicesResult servicesResult = await device.GetGattServicesAsync(BluetoothCacheMode.Cached);

                if (servicesResult.Status == GattCommunicationStatus.Success)
                {
                    var services = servicesResult.Services;
                    Debug.WriteLine($"Found {services.Count} services when " +
                                    "querying services for packet writing."
                                    );

                    // Iterate through the list of services and check if
                    // both services we require are there
                    foreach (GattDeviceService service in services)
                    {
                        Guid uuid = service.Uuid;

                        // Check for IPv6ToBle Packet Write Service
                        if (uuid == Constants.IPv6ToBlePacketProcessingServiceUuid)
                        {
                            ipv6ToBlePacketProcessingService = service;
                            break;
                        }
                    }
                }
            }

            // Report error if the device was not running our packet processing
            // service for some reason
            if (ipv6ToBlePacketProcessingService == null)
            {
                status = BluetoothError.OtherError;
                Debug.WriteLine("Device did not have the " +
                                "IPv6ToBlePacketProcessingService running or" +
                                " available."
                                );
                goto Exit;
            }

            //
            // Step 3
            // Enumerate the GATT characteristics
            //
            try
            {
                // Verify we can access the service
                DeviceAccessStatus accessStatus = await ipv6ToBlePacketProcessingService.RequestAccessAsync();

                if (accessStatus == DeviceAccessStatus.Allowed)
                {
                    // Enumerate the characteristics
                    GattCharacteristicsResult characteristicsResult =
                        await ipv6ToBlePacketProcessingService.GetCharacteristicsAsync(BluetoothCacheMode.Cached);

                    if (characteristicsResult.Status == GattCommunicationStatus.Success)
                    {
                        deviceCharacteristics = characteristicsResult.Characteristics;
                    }
                    else
                    {
                        status = BluetoothError.OtherError;
                        Debug.WriteLine("Could not access the packet " +
                                        "processing service."
                                        );
                        goto Exit;
                    }
                }
                else
                {
                    // Not granted access
                    status = BluetoothError.NotSupported;

                    Debug.WriteLine("Could not access the packet " +
                                    "processing service."
                                    );
                    goto Exit;
                }
            }
            catch (Exception e)
            {
                status = BluetoothError.DeviceNotConnected;
                Debug.WriteLine("Could not read characteristics due to " +
                                " permissions issues. " + e.Message
                                );
                goto Exit;
            }

            // Find the required characteristics for packet writing
            if (deviceCharacteristics != null)
            {
                foreach (GattCharacteristic characteristic in deviceCharacteristics)
                {
                    if (characteristic.Uuid == Constants.IPv6ToBlePacketWriteCharacteristicUuid)
                    {
                        ipv6PacketWriteCharacteristic = characteristic;
                    }
                    if (characteristic.Uuid == Constants.IPv6ToBleCompressedHeaderLengthCharacteristicUuid)
                    {
                        compressedHeaderLengthCharacteristic = characteristic;
                    }
                    if (characteristic.Uuid == Constants.IPv6ToBlePayloadLengthCharacteristicUuid)
                    {
                        payloadLengthCharacteristic = characteristic;
                    }
                }
            }

            if (ipv6PacketWriteCharacteristic == null ||
                compressedHeaderLengthCharacteristic == null ||
                payloadLengthCharacteristic == null)
            {
                status = BluetoothError.OtherError;
                Debug.WriteLine("Could not access all three characteristics " +
                                "required for packet writing."
                                );
                goto Exit;
            }

            // Stop the GATT latency timer now that we are ready to do the actual
            // transmission
            gattLatencyTimer.Stop();
            Debug.WriteLine("GATT communications completed successfully. Total " +
                            $"time: {gattLatencyTimer.ElapsedMilliseconds} milliseconds."
                            );

            //
            // Step 5
            // Write the packet now that we have verified that the device is
            // supported and is either the destination or in the path to the
            // destination
            //

            // Start the GATT transmission timer
            gattTransmissionTimer.Start();

            //DataWriter writer = new DataWriter();

            //// Write the compressed header length
            //writer.WriteInt32(compressedHeaderLength);
            //GattCommunicationStatus writeStatus = await compressedHeaderLengthCharacteristic.WriteValueAsync(writer.DetachBuffer());
            //if (writeStatus != GattCommunicationStatus.Success)
            //{
            //    status = BluetoothError.OtherError;
            //    Debug.WriteLine("Could not write compressed header length.");
            //    goto Exit;
            //}

            //// Write the payload length
            //writer = new DataWriter();
            //writer.WriteInt32(payloadLength);
            //writeStatus = await payloadLengthCharacteristic.WriteValueAsync(writer.DetachBuffer());
            //if (writeStatus != GattCommunicationStatus.Success)
            //{
            //    status = BluetoothError.OtherError;
            //    Debug.WriteLine("Could not write payload length.");
            //    goto Exit;
            //}

            // Write the packet itself last so the receiver knows that it has
            // all needed data when this characteristic is written to
            GattCommunicationStatus writeStatus = await ipv6PacketWriteCharacteristic.WriteValueAsync(GattHelpers.ConvertByteArrayToBuffer(packet),
                                                                                                      GattWriteOption.WriteWithoutResponse
                                                                                                      );

            if (writeStatus != GattCommunicationStatus.Success)
            {
                status = BluetoothError.OtherError;
                Debug.WriteLine("Could not write the IPv6 packet to the" +
                                " remote device");
                goto Exit;
            }

            // Stop the GATT transmission timer and record the time if successful
            gattTransmissionTimer.Stop();
            long microseconds = gattTransmissionTimer.ElapsedTicks / (Stopwatch.Frequency / (1000L * 1000L));

            Debug.WriteLine("GATT transmission completed successfully. Total " +
                            $"time: {microseconds} microseconds."
                            );

Exit:

            // Dispose of the service and device that we accessed, then force
            // a garbage collection to destroy the objects and fully disconnect
            // from the remote GATT server and device. This is as a workaround
            // for a current Windows bug that doesn't properly disconnect
            // devices, as well as a workaround for the Broadcomm Bluetooth LE
            // driver on the Raspberry Pi 3 that can't handle multiple connects
            // and reconnects if it thinks it's still occupied.
            //
            // Additionally, at this step, if you had connected any events
            // to the services or characteristics, you'd have to do that first.
            // But we didn't do that here, so no need.

            ipv6ToBlePacketProcessingService?.Dispose();
            device?.Dispose();
            device = null;
            GC.Collect();

            if (status != BluetoothError.Success)
            {
                // Stop the timers if we failed
                if (gattLatencyTimer.IsRunning)
                {
                    gattLatencyTimer.Stop();
                }
                if (gattTransmissionTimer.IsRunning)
                {
                    gattTransmissionTimer.Stop();
                }

                return(false);
            }

            return(true);
        }
Esempio n. 27
0
 internal VisibilityModeChangedEventArgs(BluetoothError result, VisibilityMode mode)
 {
     _result = result;
     _mode   = mode;
 }
Esempio n. 28
0
 public BTError(BluetoothError btErrorCode)
 {
     BluetoothErrorCode = btErrorCode;
 }
        internal RfcommDeviceServicesResult(BluetoothError error, IReadOnlyList <RfcommDeviceService> services)
#endif
        {
            _error    = error;
            _services = services;
        }
 internal RfcommDeviceServicesResult(BluetoothError error, ReadOnlyCollection <RfcommDeviceService> services)