Example #1
0
        public async void ListCurrentDeviceServicesToLog()
        {
            //CheckBluetoothStatus(true);
            BluetoothLEDevice device = await BluetoothLEDevice.FromIdAsync(ChosenDevice.Id);

            if (device == null)
            {
                return;
            }
            DeviceAccessStatus accessStatus = await device.RequestAccessAsync();

            var deviceServicesResult = await device.GetGattServicesAsync();

            // build the string to add in the log
            string services = "[Services list of " + device.Name + "]";
            int    i        = 0;

            foreach (GattDeviceService service in deviceServicesResult.Services)
            {
                services += "\n -- Handle: \t" + service.AttributeHandle.ToString();
                services += "\n --> UUID: \t" + service.Uuid.ToString();
                services += "\n --> Access Info: \t" + service.DeviceAccessInformation.CurrentStatus.ToString();
                i++;
                if (i < deviceServicesResult.Services.Count)
                {
                    services += "\n----------------------------------------------------------------";
                }
            }
            services += "\n\nFor info on Bluetooth Standard codes and identifiers, please visit https://www.bluetooth.com/specifications/assigned-numbers" + "\n";
            // add log
            AddLog(services, AppLog.LogCategory.Debug);
        }
Example #2
0
        /// <summary>
        /// Retrieves the characteristics of the given service.
        /// The error logging is handled in the function.
        /// </summary>
        /// <param name="service"></param>
        /// <returns>The list of characteristic if it succeed, null otherwise</returns>
        public static async Task <IReadOnlyList <GattCharacteristic> > GetCharacteristics(GattDeviceService service)
        {
            try
            {
                DeviceAccessStatus status = await service.RequestAccessAsync();

                if (status == DeviceAccessStatus.Allowed)
                {
                    GattCharacteristicsResult result = await service.GetCharacteristicsAsync(BluetoothCacheMode.Uncached);

                    if (result.Status == GattCommunicationStatus.Success)
                    {
                        return(result.Characteristics);
                    }
                    else
                    {
                        LogHelper.Error("Error accessing device");
                        return(null);
                    }
                }
                else
                {
                    LogHelper.Error("Error accessing device: access not granted");
                    return(null);
                }
            }
            catch (Exception e)
            {
                LogHelper.Error("Restricted service. Can't read characteristics: " + e.Message);
                return(null);
            }
        }
Example #3
0
        /// <summary>
        ///  If you believe the Bluetooth device will eventually be paired with Windows,
        ///  you might want to pre-emptively get consent to access the device.
        ///  An explicit call to RequestAccessAsync() prompts the user for consent.
        ///  If this is not done, a device that's working before being paired,
        ///  will no longer work after being paired.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void RequestAccessButton_Click(object sender, RoutedEventArgs e)
        {
            // Make sure user has given consent to access device
            DeviceAccessStatus accessStatus = await bluetoothDevice.RequestAccessAsync();

            if (accessStatus != DeviceAccessStatus.Allowed)
            {
                NotifyUser("Access to the device is denied because the application was not granted access");
            }
            else
            {
                NotifyUser("Access granted, you are free to pair devices");
            }
        }
Example #4
0
        private static async void GetCharacteristics(GattDeviceService service)
        {
            IReadOnlyList <GattCharacteristic> characteristics = null;
            string device = service.Device.DeviceInformation.Id.Substring(41);

            try
            {
                DeviceAccessStatus accessStatus = await service.RequestAccessAsync();

                if (accessStatus == DeviceAccessStatus.Allowed)
                {
                    GattCharacteristicsResult result = await service.GetCharacteristicsAsync(BluetoothCacheMode.Uncached);

                    if (result.Status == GattCommunicationStatus.Success)
                    {
                        characteristics = result.Characteristics;
                        Console.WriteLine("Found Characteristics");
                    }
                    else
                    {
                        blePowermates[device].isSubscribing = false;
                        Console.WriteLine("Error accessing service.");
                        characteristics = new List <GattCharacteristic>();
                    }
                }
                else
                {
                    blePowermates[device].isSubscribing = false;
                    Console.WriteLine("Error accessing service.");
                }
            } catch (Exception ex)
            {
                blePowermates[device].isSubscribing = false;
                Console.WriteLine("Error: Restricted service. Can't read characteristics: " + ex.ToString());
            }

            if (characteristics != null)
            {
                foreach (GattCharacteristic characteristic in characteristics)
                {
                    Console.WriteLine("└Characteristic uuid: " + characteristic.Uuid.ToString());
                    if (UuidEquals(uuidRead, characteristic.Uuid))
                    {
                        SubscribeToValueChange(characteristic);
                        Console.WriteLine(" └Subscribing to Read Characteristic");
                    }
                }
            }
        }
Example #5
0
        private async void logRfTypes(RfcommDeviceServicesResult rfResultList)
        {
            try
            {
                string fileName = "BtServices.log";

                // can't use Syste.IO in UWP, use Windows.Storage instead:
                // https://docs.microsoft.com/en-us/windows/uwp/files/quickstart-reading-and-writing-files
                // path is determined when project is deployed, so it could change
                // currently C:\Users\Gordon.000\AppData\Local\Packages\aaa810d2-9117-4b86-9d5d-a47aaebb1c5c_3rdrqcfnf2zwp\LocalState
                StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
                StorageFile   logFile       = await storageFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);

                List <string> lines = new List <string>();

                BluetoothDevice device = rfResultList.Services[0].Device;
                lines.Add("Device.Name: " + device.Name);
                lines.Add("Device.ConnectionStatus: " + device.ConnectionStatus);
                lines.Add("Device.BluetoothAddress: " + device.BluetoothAddress);
                lines.Add("Device.BluetoothDeviceId: " + device.BluetoothDeviceId.Id);
                lines.Add("Device.ClassOfDevice: " + device.ClassOfDevice.ServiceCapabilities);
                lines.Add("");

                foreach (RfcommDeviceService rf in rfResultList.Services)
                {
                    lines.Add("ServiceId: " + rf.ServiceId.AsString());
                    lines.Add("ConnectionHostName: " + rf.ConnectionHostName);
                    lines.Add("ConnectionServiceName: " + rf.ConnectionServiceName);
                    //lines.Add("selector: " + RfcommDeviceService.GetDeviceSelectorForBluetoothDeviceAndServiceId(rf.Device, rf.ServiceId));

                    DeviceAccessStatus serviceAccessStatus = await rf.RequestAccessAsync();

                    lines.Add("serviceAccessStatus: " + serviceAccessStatus);

                    lines.Add("----------------------------");
                }

                await FileIO.WriteLinesAsync(logFile, lines);

                lines.Clear();
            }
            catch (Exception exc)
            {
                System.Diagnostics.Debug.WriteLine(exc.ToString());
                System.Diagnostics.Debugger.Break();
            }
        }
Example #6
0
        public static AccessStatus ToAccessStatus(this DeviceAccessStatus status)
        {
            switch (status)
            {
            case DeviceAccessStatus.Allowed:
                return(AccessStatus.Success);

            case DeviceAccessStatus.DeniedBySystem:
                return(AccessStatus.DeniedBySystem);

            case DeviceAccessStatus.DeniedByUser:
                return(AccessStatus.DeniedByUser);

            default:
                return(AccessStatus.UnknownError);
            }
        }
        private bool BluetoothSetup()
        {
            BluetoothLEDevice device = this.Waitfor(
                "connection to Bluetooth device",
                BluetoothLEDevice.FromBluetoothAddressAsync(System.Convert.ToUInt64("001580912553", 16)));

            if (device == null)
            {
                this.logEol("Device wasn't found");
                return(false);
            }

            GattDeviceServicesResult deviceServices = this.Waitfor(
                "device services", device.GetGattServicesAsync());

            DeviceAccessStatus deviceAccessStatus = this.Waitfor(
                "device access", device.RequestAccessAsync());

            this.logEol($"Device access status: {deviceAccessStatus}");

            System.Guid       gyroServiceGuid = System.Guid.Parse("0000ffe0-0000-1000-8000-00805f9b34fb");
            GattDeviceService gyroService     = deviceServices.Services.Single(x => x.Uuid.Equals(gyroServiceGuid));

            var gyroServiceAccessStatus = this.Waitfor(
                "gro data service access", gyroService.RequestAccessAsync());

            this.logEol($"Gyro service access status: {gyroServiceAccessStatus}");

            GattCharacteristicsResult characteristics = this.Waitfor(
                "gyro data service", gyroService.GetCharacteristicsAsync());

            this.txRxChannel = characteristics
                               .Characteristics
                               .SingleOrDefault(x => x.UserDescription.Replace(" ", "") == "TX&RX");

            if (this.txRxChannel == default(GattCharacteristic))
            {
                this.logEol("Couldn't find TXRX channel...disconnected?");
                return(false);
            }

            this.txRxChannel.ValueChanged += this.TxRx_ValueChanged;
            return(true);
        }
        private async void DeviceWatcher_Added(DeviceWatcher sender, DeviceInformation args)
        {
            try
            {
                mre.WaitOne();

                // Find the Surface Buds
                if (args.Name != null && args.Name == SurfaceBudsName)
                {
                    // check the device isnt already in the list.
                    foreach (var device in deviceList)
                    {
                        if (device.DeviceId == args.Id)
                        {
                            // done - drop right out.
                            return;
                        }
                    }

                    // check it's what we are after
                    DeviceAccessStatus accessStatus = DeviceAccessInformation.CreateFromId(args.Id).CurrentStatus;
                    if (accessStatus != DeviceAccessStatus.DeniedByUser &&
                        accessStatus != DeviceAccessStatus.DeniedBySystem)
                    {
                        var bluetoothDevice = await BluetoothDevice.FromIdAsync(args.Id);

                        if (bluetoothDevice != null)
                        {
                            // add it to the list.
                            var result = await bluetoothDevice.GetRfcommServicesForIdAsync(RfcommServiceId.FromUuid(RfcommLaunchCommandUuid));

                            if (result.Services.Count > 0)
                            {
                                var newDevice = new BudsDeviceInfo();
                                newDevice.DeviceId        = args.Id;
                                newDevice.oneTouchService = result.Services[0];

                                // now check to see if the device is connected
                                foreach (var prop in args.Properties)
                                {
                                    if (prop.Key == "System.Devices.Aep.IsConnected" && prop.Value.GetType() == typeof(bool) && (bool)prop.Value == true)
                                    {
                                        newDevice.IsConnected = true;
                                    }
                                }
                                deviceList.Add(newDevice);

                                var countConnected = 0;
                                foreach (var device in deviceList)
                                {
                                    if (device.IsConnected)
                                    {
                                        countConnected++;
                                    }
                                }

                                UpdateStatusMessage(string.Format("Found {0} device(s). Connected: {1}", deviceList.Count, countConnected));
                            }
                        }
                    }
                }
            }
            catch
            {
                // any exception means its not our device, just ignore it
            }
            finally
            {
                mre.Release();
            }
        }
Example #9
0
        public async Task <bool> TryToConnect(string deviceId)
        {
            if (string.IsNullOrWhiteSpace(deviceId))
            {
                this.logger.Error($"'{nameof(deviceId)}' argument is null or empty");
                return(false);
            }

            bool success = false;

            try
            {
                GattDeviceService  service = null;
                GattCharacteristic responseCharacteristic = null;
                BluetoothLEDevice  bluetoothLeDevice      = await BluetoothLEDevice.FromIdAsync(deviceId)
                                                            .AsTask()
                                                            .ConfigureAwait(false);

                if (bluetoothLeDevice == null)
                {
                    this.logger.Error($"failed to create BLE device with id = '{deviceId}'");
                    return(false);
                }

                this.bluetoothLeDevice = bluetoothLeDevice;
                bluetoothLeDevice.ConnectionStatusChanged += OnConnectionStatusChanged;

                DeviceAccessStatus deviceStatus = await bluetoothLeDevice.RequestAccessAsync()
                                                  .AsTask()
                                                  .ConfigureAwait(false);

                if (deviceStatus != DeviceAccessStatus.Allowed)
                {
                    this.logger.Error($"failed to get access to BLE device with id = '{deviceId}'");
                    return(false);
                }

                // the following method connects to BLE device (and will call OnConnectionStatusChanged)

                GattDeviceServicesResult result = await bluetoothLeDevice.GetGattServicesAsync(BluetoothCacheMode.Uncached)
                                                  .AsTask()
                                                  .ConfigureAwait(false);

                if (result.Status == GattCommunicationStatus.Success)
                {
                    service = result.Services.Where(s => s.Uuid == SERVICE_GUID)
                              .FirstOrDefault();

                    if (service == null)
                    {
                        this.logger.Error($"BLE device with id = '{deviceId}' doesn't have '{SERVICE_GUID}' service");
                        return(false);
                    }

                    GattOpenStatus status = await service.OpenAsync(GattSharingMode.Exclusive)
                                            .AsTask()
                                            .ConfigureAwait(false);

                    if (status != GattOpenStatus.Success)
                    {
                        this.logger.Error($"failed to open '{SERVICE_GUID}' service on BLE device with id = '{deviceId}', result = '{status}'");
                        return(false);
                    }

                    GattCharacteristicsResult characteristicsResult = characteristicsResult = await service.GetCharacteristicsForUuidAsync(RESPONSE_CHARACTERISTICS_GUID)
                                                                                              .AsTask()
                                                                                              .ConfigureAwait(false);

                    if (characteristicsResult.Status != GattCommunicationStatus.Success)
                    {
                        this.logger.Error($"failed to get '{RESPONSE_CHARACTERISTICS_GUID}' characteristic from '{SERVICE_GUID}' " +
                                          $"service on BLE device with id = '{deviceId}', result = '{characteristicsResult.Status}', protocol error = {characteristicsResult.ProtocolError}");
                        return(false);
                    }

                    responseCharacteristic = characteristicsResult.Characteristics.FirstOrDefault();

                    if (responseCharacteristic == null)
                    {
                        this.logger.Error($"'{RESPONSE_CHARACTERISTICS_GUID}' characteristic doesn't seem to have any characteristics in '{SERVICE_GUID}' service on BLE device with id = '{deviceId}'");
                        return(false);
                    }
                }
                else
                {
                    this.logger.Error($"failed to retreive services provided by BLE device with id = '{deviceId}', result = '{result.Status}', protocol error = '{result.ProtocolError}'");
                    return(false);
                }

                this.service = service;
                this.responseCharacteristic = responseCharacteristic;
                this.responseCharacteristic.ValueChanged += OnCharacteristicValueChanged;

                success = true;

                return(true);
            }
            catch (Exception e)
            {
                this.logger.Error(e, "unexpected exception while connecting to BLE device");
                return(false);
            }
            finally
            {
                if (!success)
                {
                    Disconnect();
                }
            }
        }
        /// <summary>
        /// Invoked once the user has selected the device to connect to.
        /// Once the user has selected the device,
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void ConnectButton_Click(object sender, RoutedEventArgs e)
        {
            // Make sure user has selected a device first
            if (resultsListView.SelectedItem != null)
            {
                rootPage.NotifyUser("Connecting to remote device. Please wait...", NotifyType.StatusMessage);
            }
            else
            {
                rootPage.NotifyUser("Please select an item to connect to", NotifyType.ErrorMessage);
                return;
            }

            RfcommChatDeviceDisplay deviceInfoDisp = resultsListView.SelectedItem as RfcommChatDeviceDisplay;

            // Perform device access checks before trying to get the device.
            // First, we check if consent has been explicitly denied by the user.
            DeviceAccessStatus accessStatus = DeviceAccessInformation.CreateFromId(deviceInfoDisp.Id).CurrentStatus;

            if (accessStatus == DeviceAccessStatus.DeniedByUser)
            {
                rootPage.NotifyUser("This app does not have access to connect to the remote device (please grant access in Settings > Privacy > Other Devices", NotifyType.ErrorMessage);
                return;
            }

            // If not, try to get the Bluetooth device
            try
            {
                bluetoothDevice = await BluetoothDevice.FromIdAsync(deviceInfoDisp.Id);
            }
            catch (Exception ex)
            {
                rootPage.NotifyUser(ex.Message, NotifyType.ErrorMessage);
                return;
            }

            // If we were unable to get a valid Bluetooth device object,
            // it's most likely because the user has specified that all unpaired devices
            // should not be interacted with.
            if (bluetoothDevice == null)
            {
                rootPage.NotifyUser("Bluetooth Device returned null. Access Status = " + accessStatus.ToString(), NotifyType.ErrorMessage);
            }

            // This should return a list of uncached Bluetooth services (so if the server was not active when paired, it will still be detected by this call
            var rfcommServices = await bluetoothDevice.GetRfcommServicesForIdAsync(
                RfcommServiceId.FromUuid(Constants.RfcommChatServiceUuid), BluetoothCacheMode.Uncached);

            if (rfcommServices.Services.Count > 0)
            {
                chatService = rfcommServices.Services[0];
            }
            else
            {
                rootPage.NotifyUser(
                    "Could not discover the chat service on the remote device",
                    NotifyType.StatusMessage);
                return;
            }

            // Do various checks of the SDP record to make sure you are talking to a device that actually supports the Bluetooth Rfcomm Chat Service
            var attributes = await chatService.GetSdpRawAttributesAsync();

            if (!attributes.ContainsKey(Constants.SdpServiceNameAttributeId))
            {
                rootPage.NotifyUser(
                    "The Chat service is not advertising the Service Name attribute (attribute id=0x100). " +
                    "Please verify that you are running the BluetoothRfcommChat server.",
                    NotifyType.ErrorMessage);
                RunButton.IsEnabled = true;
                return;
            }

            var attributeReader = DataReader.FromBuffer(attributes[Constants.SdpServiceNameAttributeId]);
            var attributeType   = attributeReader.ReadByte();

            if (attributeType != Constants.SdpServiceNameAttributeType)
            {
                rootPage.NotifyUser(
                    "The Chat service is using an unexpected format for the Service Name attribute. " +
                    "Please verify that you are running the BluetoothRfcommChat server.",
                    NotifyType.ErrorMessage);
                RunButton.IsEnabled = true;
                return;
            }

            var serviceNameLength = attributeReader.ReadByte();

            // The Service Name attribute requires UTF-8 encoding.
            attributeReader.UnicodeEncoding = UnicodeEncoding.Utf8;

            deviceWatcher.Stop();

            lock (this)
            {
                chatSocket = new StreamSocket();
            }
            try
            {
                await chatSocket.ConnectAsync(chatService.ConnectionHostName, chatService.ConnectionServiceName);

                SetChatUI(attributeReader.ReadString(serviceNameLength), bluetoothDevice.Name);
                chatWriter = new DataWriter(chatSocket.OutputStream);

                DataReader chatReader = new DataReader(chatSocket.InputStream);
                ReceiveStringLoop(chatReader);
            }
            catch (Exception ex)
            {
                switch ((uint)ex.HResult)
                {
                case (0x80070490):     // ERROR_ELEMENT_NOT_FOUND
                    rootPage.NotifyUser("Please verify that you are running the BluetoothRfcommChat server.", NotifyType.ErrorMessage);
                    RunButton.IsEnabled = true;
                    break;

                default:
                    throw;
                }
            }
        }
        public async void Connect(String devID)
        {
            // Perform device access checks before trying to get the device.
            // First, we check if consent has been explicitly denied by the user.
            lastDevID   = devID;
            isCanceled  = false;
            isConnected = false;
            WriteDebug("Check Connection");

            DeviceAccessStatus accessStatus = DeviceAccessInformation.CreateFromId(devID).CurrentStatus;

            if (accessStatus == DeviceAccessStatus.DeniedByUser)
            {
                return;
            }
            // If not, try to get the Bluetooth device
            try
            {
                bluetoothDevice = await BluetoothDevice.FromIdAsync(devID);
            }
            catch (Exception)
            {
                return;
            }
            // If we were unable to get a valid Bluetooth device object,
            // it's most likely because the user has specified that all unpaired devices
            // should not be interacted with.
            if (bluetoothDevice == null)
            {
                return;
            }
            WriteDebug("Sync Devices..");

            // This should return a list of uncached Bluetooth services (so if the server was not active when paired, it will still be detected by this call
            long start = DateTime.Now.Ticks;

            RfcommDeviceServicesResult rfcommServices = null;

            while (true)
            {
                rfcommServices = await bluetoothDevice.GetRfcommServicesForIdAsync(
                    RfcommServiceId.FromUuid(guid), BluetoothCacheMode.Uncached);

                if (rfcommServices.Services.Count > 0)
                {
                    WriteDebug($"{rfcommServices.Error}.");
                    RfService = rfcommServices.Services[0];
                    break;
                }
                lock (this)
                {
                    long current = DateTime.Now.Ticks;
                    if (current - 10_00000000 > start)
                    {
                        break;
                    }
                }
            }

            if (RfService == null)
            {
                isCanceled = true;
                Disconnect();
                onDisconnect();
                return;
            }

            // Do various checks of the SDP record to make sure you are talking to a device that actually supports the Bluetooth Rfcomm Chat Service
            var attributes = await RfService.GetSdpRawAttributesAsync();

            if (!attributes.ContainsKey(0x100))
            {
                return;
            }
            var attributeReader = DataReader.FromBuffer(attributes[0x100]);
            var attributeType   = attributeReader.ReadByte();

            if (attributeType != ((4 << 3) | 5))
            {
                return;
            }
            var serviceNameLength = attributeReader.ReadByte();

            // The Service Name attribute requires UTF-8 encoding.
            attributeReader.UnicodeEncoding = UnicodeEncoding.Utf8;



            //------------bind Stream------
            lock (this)
            {
                streamSocket = new StreamSocket();
            }
            try
            {
                await streamSocket.ConnectAsync(RfService.ConnectionHostName, RfService.ConnectionServiceName);

                WriteDebug($"{RfService.ConnectionHostName} : {RfService.Device.ConnectionStatus}");

                dataRegister.conditionText.Text = "Checking Connection...";

                dataWriter = new DataWriter(streamSocket.OutputStream);

                DataReader chatReader = new DataReader(streamSocket.InputStream);

                isConnected = true;

                ReceiveStringLoop(chatReader);
            }
            catch (Exception ex) when((uint)ex.HResult == 0x80070490)  // ERROR_ELEMENT_NOT_FOUND
            {
                return;
            }
            catch (Exception ex) when((uint)ex.HResult == 0x80072740)  // WSAEADDRINUSE
            {
                return;
            }
            catch
            {
            }
        }
Example #12
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);
        }
Example #13
0
        /// <summary>
        /// Invoked once the user has selected the device to connect to.
        /// Once the user has selected the device,
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public async Task <bool> ConnectAsync(RomeRemoteSystem system)
        {
            // Make sure user has selected a device first
            if (system != null)
            {
                Debug.WriteLine("Connecting to remote device. Please wait...");
            }
            else
            {
                Debug.WriteLine("Please select an item to connect to");
                return(false);
            }

            // Perform device access checks before trying to get the device.
            // First, we check if consent has been explicitly denied by the user.
            DeviceAccessStatus accessStatus = DeviceAccessInformation.CreateFromId(system.Id).CurrentStatus;

            if (accessStatus == DeviceAccessStatus.DeniedByUser)
            {
                Debug.WriteLine("This app does not have access to connect to the remote device (please grant access in Settings > Privacy > Other Devices");
                return(false);
            }

            // If not, try to get the Bluetooth device
            try
            {
                _bluetoothDevice = await BluetoothDevice.FromIdAsync(system.Id);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
                StopWatcher();
                return(false);
            }

            // If we were unable to get a valid Bluetooth device object,
            // it's most likely because the user has specified that all unpaired devices
            // should not be interacted with.
            if (_bluetoothDevice == null)
            {
                Debug.WriteLine("Bluetooth Device returned null. Access Status = " + accessStatus.ToString());
            }

            if (_bluetoothDevice == null)
            {
                return(false);
            }

            // This should return a list of uncached Bluetooth services (so if the server was not active when paired, it will still be detected by this call
            var rfcommServices = await _bluetoothDevice?.GetRfcommServicesForIdAsync(
                RfcommServiceId.FromUuid(Constants.SERVICE_UUID), BluetoothCacheMode.Uncached);

            if (rfcommServices?.Services.Count > 0)
            {
                _chatService = rfcommServices.Services[0];
            }
            else
            {
                Debug.WriteLine("Could not discover the chat service on the remote device");
                StopWatcher();
                return(false);
            }

            // Do various checks of the SDP record to make sure you are talking to a device that actually supports the Bluetooth Rfcomm Chat Service
            var attributes = await _chatService.GetSdpRawAttributesAsync();

            if (!attributes.ContainsKey(Constants.SERVICE_ATTRIBUTE_ID))
            {
                Debug.WriteLine(
                    "The Chat service is not advertising the Service Name attribute (attribute id=0x100). " +
                    "Please verify that you are running the BluetoothRfcommChat server.");
                StopWatcher();
                return(false);
            }
            var attributeReader = DataReader.FromBuffer(attributes[Constants.SERVICE_ATTRIBUTE_ID]);
            var attributeType   = attributeReader.ReadByte();

            if (attributeType != Constants.SERVICE_ATTRIBUTE_TYPE)
            {
                Debug.WriteLine(
                    "The Chat service is using an unexpected format for the Service Name attribute. " +
                    "Please verify that you are running the BluetoothRfcommChat server.");
                StopWatcher();
                return(false);
            }

            var serviceNameLength = attributeReader.ReadByte();

            // The Service Name attribute requires UTF-8 encoding.
            attributeReader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;

            StopWatcher();

            lock (this)
            {
                _chatSocket = new StreamSocket();
            }
            try
            {
                await _chatSocket.ConnectAsync(_chatService.ConnectionHostName, _chatService.ConnectionServiceName);

                Debug.WriteLine("Connected to : " + attributeReader.ReadString(serviceNameLength) + _bluetoothDevice.Name);
                _chatWriter = new DataWriter(_chatSocket.OutputStream);

                DataReader chatReader = new DataReader(_chatSocket.InputStream);
                ReceiveStringLoop(chatReader);

                return(true);
            }
            catch (Exception ex) when((uint)ex.HResult == 0x80070490)  // ERROR_ELEMENT_NOT_FOUND
            {
                Debug.WriteLine("Please verify that you are running the BluetoothRfcommChat server.");
                StopWatcher();
            }
            catch (Exception ex) when((uint)ex.HResult == 0x80072740)  // WSAEADDRINUSE
            {
                Debug.WriteLine("Please verify that there is no other RFCOMM connection to the same device.");
                StopWatcher();
            }

            return(false);
        }
Example #14
0
        public async Task ConnectBTService()
        {
            BluetoothDevice btDevice;

            if (isSocketOpened)
            {
                Debug.WriteLine("すでにソケットが開かれています。");
                return;
            }

            // Perform device access checks before trying to get the device.
            // First, we check if consent has been explicitly denied by the user.
            DeviceAccessStatus accessStatus = DeviceAccessInformation.CreateFromId(BTDeviceInfo.Id).CurrentStatus;

            if (accessStatus == DeviceAccessStatus.DeniedByUser)
            {
                //rootPage.NotifyUser("This app does not have access to connect to the remote device (please grant access in Settings > Privacy > Other Devices", NotifyType.ErrorMessage);
                throw new UnauthorizedAccessException("ユーザーによってデバイスへのアクセスが拒否されました。");
            }
            // If not, try to get the Bluetooth device
            try
            {
                btDevice = await BluetoothDevice.FromIdAsync(BTDeviceInfo.Id);

                if (btDevice.ConnectionStatus == BluetoothConnectionStatus.Disconnected)
                {
                    //btDevice.RequestAccessAsync
                }
            }
            catch (Exception ex)
            {
                //rootPage.NotifyUser(ex.Message, NotifyType.ErrorMessage);
                //ResetMainUI();
                throw new Exception("Bluetooth Device の取得に失敗しました。", ex);
            }
            // If we were unable to get a valid Bluetooth device object,
            // it's most likely because the user has specified that all unpaired devices
            // should not be interacted with.
            if (btDevice == null)
            {
                throw new NullReferenceException("Bluetooth Device が空です。");
            }


            //Pairされているか確認する
            if (btDevice.DeviceInformation.Pairing.IsPaired == false)
            {
                var status = await btDevice.RequestAccessAsync();

                if (status == DeviceAccessStatus.Allowed)
                {
                    Debug.WriteLine("access granted");
                }
            }


            // This should return a list of uncached Bluetooth services (so if the server was not active when paired, it will still be detected by this call
            var rfcommServices = await btDevice.GetRfcommServicesForIdAsync(RfcommServiceId.FromUuid(Constants.RfcommChatServiceUuid), BluetoothCacheMode.Uncached);

            if (rfcommServices.Services.Count > 0)
            {
                BTDeviceService = rfcommServices.Services[0];
            }
            else
            {
                rfcommServices = await btDevice.GetRfcommServicesAsync();

                if (rfcommServices.Services.Count == 0)
                {
                    throw new NullReferenceException("対象のデバイスにBluetoothサービスが一つも見つかりません。正しい機器に接続していない可能性があります。");
                }
                else
                {
                    foreach (var service in rfcommServices.Services)
                    {
                        Debug.WriteLine(service.ConnectionServiceName + ":::" + service.Device.DeviceInformation.Kind.ToString());
                        if (service.ConnectionServiceName.Contains(Constants.RfcommChatServiceUuid.ToString()))
                        {
                            BTDeviceService = service;
                            break;
                        }
                    }
                    if (BTDeviceService == null)
                    {
                        throw new NullReferenceException("対象のデバイスにBluetoothサービスが一つも見つかりません。正しい機器に接続していない可能性があります。");
                    }
                }
            }

            // Do various checks of the SDP record to make sure you are talking to a device that actually supports the Bluetooth Rfcomm Chat Service
            var attributes = await BTDeviceService.GetSdpRawAttributesAsync();

            if (!attributes.ContainsKey(Constants.SdpServiceNameAttributeId))
            {
                throw new NullReferenceException("対象のデバイスにFantasmicサービスが見つかりません。正しい機器に接続していない可能性があります。");
            }
            var attributeReader = DataReader.FromBuffer(attributes[Constants.SdpServiceNameAttributeId]);
            var attributeType   = attributeReader.ReadByte();

            if (attributeType != Constants.SdpServiceNameAttributeType)
            {
                throw new NullReferenceException("対象のデバイスにFantasmicサービスが見つかりません。正しい機器に接続していない可能性があります。");
            }
            var serviceNameLength = attributeReader.ReadByte();

            // The Service Name attribute requires UTF-8 encoding.
            attributeReader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;

            lock (this)
            {
                BTStreamSocket = new StreamSocket();
            }
            try
            {
                await BTStreamSocket.ConnectAsync(BTDeviceService.ConnectionHostName, BTDeviceService.ConnectionServiceName);

                //SetChatUI(attributeReader.ReadString(serviceNameLength), bluetoothDevice.Name);
                BTWriter       = new DataWriter(BTStreamSocket.OutputStream);
                BTReader       = new DataReader(BTStreamSocket.InputStream);
                isSocketOpened = true;
            }
            catch (Exception ex) when((uint)ex.HResult == 0x80070490)  // ERROR_ELEMENT_NOT_FOUND
            {
                throw new NullReferenceException("ソケットのオープンに失敗しました。対象のデバイスでアプリケーションが起動されていることをご確認ください。(0x80070490: ERROR_ELEMENT_NOT_FOUND)", ex);
            }
            catch (Exception ex) when((uint)ex.HResult == 0x80072740)  // WSAEADDRINUSE
            {
                throw new InvalidOperationException("ソケットのオープンに失敗しました。対象のデバイスがすでに他のサーバーに接続されている可能性があります。(0x80072740: WSAEADDRINUSE)", ex);
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException("ソケットのオープンに失敗しました。", ex);
            }
        }
Example #15
0
        public async void ConnectAsync(RfcommChatDeviceDisplay deviceInfoDisp)
        {
            // Perform device access checks before trying to get the device.
            // First, we check if consent has been explicitly denied by the user.
            DeviceAccessStatus accessStatus = DeviceAccessInformation.CreateFromId(deviceInfoDisp.Id).CurrentStatus;

            if (accessStatus == DeviceAccessStatus.DeniedByUser)
            {
                throw new UnauthorizedAccessException("This app does not have access to connect to the remote device (please grant access in Settings > Privacy > Other Devices");
            }
            // If not, try to get the Bluetooth device
            try
            {
                bluetoothDevice = await BluetoothDevice.FromIdAsync(deviceInfoDisp.Id);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            // If we were unable to get a valid Bluetooth device object,
            // it's most likely because the user has specified that all unpaired devices
            // should not be interacted with.
            if (bluetoothDevice == null)
            {
                throw new InvalidOperationException("Bluetooth Device returned null. Access Status = " + accessStatus.ToString());
            }

            // This should return a list of uncached Bluetooth services (so if the server was not active when paired, it will still be detected by this call
            var rfcommServices = await bluetoothDevice.GetRfcommServicesForIdAsync(
                RfcommServiceId.FromUuid(RfcommChatServiceUuid), BluetoothCacheMode.Uncached);

            if (rfcommServices.Services.Count > 0)
            {
                chatService = rfcommServices.Services[0];
            }
            else
            {
                throw new InvalidOperationException("Could not discover the chat service on the remote device");
            }

            // Do various checks of the SDP record to make sure you are talking to a device that actually supports the Bluetooth Rfcomm Chat Service
            var attributes = await chatService.GetSdpRawAttributesAsync();

            if (!attributes.ContainsKey(SdpServiceNameAttributeId))
            {
                throw new InvalidOperationException("The Chat service is not advertising the Service Name attribute (attribute id=0x100). " +
                                                    "Please verify that you are running the BluetoothRfcommChat server.");
            }
            var attributeReader = DataReader.FromBuffer(attributes[SdpServiceNameAttributeId]);
            var attributeType   = attributeReader.ReadByte();

            if (attributeType != SdpServiceNameAttributeType)
            {
                throw new InvalidOperationException(
                          "The Chat service is using an unexpected format for the Service Name attribute. " +
                          "Please verify that you are running the BluetoothRfcommChat server.");
            }
            var serviceNameLength = attributeReader.ReadByte();

            // The Service Name attribute requires UTF-8 encoding.
            attributeReader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;

            lock (this)
            {
                chatSocket = new StreamSocket();
            }
            try
            {
                await chatSocket.ConnectAsync(chatService.ConnectionHostName, chatService.ConnectionServiceName);

                // TODO: powiadomienie, że połączono
                //SetChatUI(attributeReader.ReadString(serviceNameLength), bluetoothDevice.Name);

                chatWriter = new DataWriter(chatSocket.OutputStream);
                DataReader chatReader = new DataReader(chatSocket.InputStream);

                ReceiveDataLoop(chatReader);
            }
            catch (Exception ex) when((uint)ex.HResult == 0x80070490)  // ERROR_ELEMENT_NOT_FOUND
            {
                throw new InvalidOperationException("Please verify that you are running the BluetoothRfcommChat server.");
            }
            catch (Exception ex) when((uint)ex.HResult == 0x80072740)  // WSAEADDRINUSE
            {
                throw new InvalidOperationException("Please verify that there is no other RFCOMM connection to the same device.");
            }
        }
Example #16
0
        public async Task <bool> BtConnect(string deviceID)
        {
            try
            {
                //System.Diagnostics.Debug.Assert(Thread.CurrentThread.IsBackground, "SerialComm:BtConnect() cannot be called from the UI thread.");

                DeviceAccessStatus accessStatus = DeviceAccessInformation.CreateFromId(deviceID).CurrentStatus;
                if (accessStatus == DeviceAccessStatus.DeniedByUser)
                {
                    //await OBD2Xam.MainPage.Instance.DisplayAlert("Error",
                    //    "This app does not have access to connect to the remote device.  Please grant access in Settings > Privacy > Other Devices.",
                    //    "Cancel");
                    await Xamarin.Forms.Device.InvokeOnMainThreadAsync(
                        () => { OBD2Xam.MainPage.Instance.DisplayAlert("Error",
                                                                       "This app does not have access to connect to the remote device.  Please grant access in Settings > Privacy > Other Devices.",
                                                                       "Cancel"); }
                        );

                    return(false);
                }

                BluetoothDevice device = await BluetoothDevice.FromIdAsync(deviceID);

                if (device == null)
                {
                    //rootPage.NotifyUser("Bluetooth Device returned null. Access Status = " + accessStatus.ToString(), NotifyType.ErrorMessage);
                    System.Diagnostics.Debug.WriteLine("Bluetooth Device returned null. Access Status = " + accessStatus.ToString());
                    System.Diagnostics.Debugger.Break();
                    return(false);
                }
                //System.Diagnostics.Debug.WriteLine(device.ConnectionStatus);

                DeviceAccessStatus das;
                das = await device.RequestAccessAsync();  // might not always work...

                //System.Diagnostics.Debugger.Break();

                /*
                 * // RequestAccessAsync() needs to executed on the UI thread, which means the UI thread cannot be blocked
                 * // while waiting for all this other crap to run.  So this code needs to be executed in backround,
                 * // WITHOUT an await, because that would cause the UI thread to block.
                 * bool invokeComplete = false;
                 * Xamarin.Forms.Device.BeginInvokeOnMainThread( async () => {
                 *  das = await device.RequestAccessAsync();
                 *  invokeComplete = true;
                 * });
                 *
                 * // now we wait for the UI thread to finish it's task, without await
                 * // because BeginInvokeOnMainThread() isn't awaitable.
                 * while (!invokeComplete)
                 * {
                 *  System.Diagnostics.Debug.WriteLine("waiting...");
                 *  System.Threading.Thread.Sleep(100);
                 * }
                 */

                if (das == DeviceAccessStatus.Allowed)
                {
                    RfcommDeviceServicesResult rfResultList = await device.GetRfcommServicesAsync().AsTask().ConfigureAwait(false);

                    logRfTypes(rfResultList);

                    // https://blog.j2i.net/2018/07/29/connecting-to-bluetooth-rfcomm-with-uwp/
                    if (rfResultList.Services.Count > 0)
                    {
                        foreach (var service in rfResultList.Services)
                        {
                            if (service.ServiceId.AsString() == Constants.BT_SERIAL_PORT_INTERFACE)
                            {
                                streamSocket = new StreamSocket();
                                await streamSocket.ConnectAsync(service.ConnectionHostName, service.ConnectionServiceName);

                                dw = new DataWriter(streamSocket.OutputStream);
                                sr = new StreamReader(streamSocket.InputStream.AsStreamForRead(256));
                                break;
                            }
                        }
                        if (!IsOpen())
                        {
                            throw new Exception("Service not found)");
                        }
                    }
                }
            }
            catch (Exception exc)
            {
                if (exc.Message == "Element not found. (Exception from HRESULT: 0x80070490)")
                {
                    //System.Diagnostics.Debug.WriteLine("Device not listening.");
                    await Xamarin.Forms.Device.InvokeOnMainThreadAsync(
                        () => { OBD2Xam.MainPage.Instance.DisplayAlert("Error", "Device not listening.", "Cancel"); }
                        );

                    this.Close();
                }
                else
                {
                    System.Diagnostics.Debug.WriteLine(exc.Message);
                    System.Diagnostics.Debugger.Break();
                }
            }


            return(IsOpen());
        }
Example #17
0
        private async void Connect(DeviceInformation devInfo)
        {
            // Perform device access checks before trying to get the device.
            // First, we check if consent has been explicitly denied by the user.
            DeviceAccessStatus accessStatus = DeviceAccessInformation.CreateFromId(devInfo.Id).CurrentStatus;

            if (accessStatus != DeviceAccessStatus.Allowed)
            {
                System.Diagnostics.Debug.WriteLine("Access State: " + accessStatus);
                System.Diagnostics.Debug.WriteLine("This app does not have access to connect to the remote device (please grant access in Settings > Privacy > Other Devices");
                //return;
            }

            // TODO: Maybe automatic pairing?

            try {
                bluetoothDevice = await BluetoothDevice.FromIdAsync(devInfo.Id);
            } catch (Exception ex) {
                System.Diagnostics.Debug.WriteLine("Error: Couldn't get BluetoothDevice");
                return;
            }

            if (bluetoothDevice == null)
            {
                System.Diagnostics.Debug.WriteLine("Bluetooth Device returned null. Access Status = " + accessStatus.ToString());
            }

            // This should return a list of uncached Bluetooth services (so if the server was not active when paired, it will still be detected by this call
            var rfcommServices = await bluetoothDevice.GetRfcommServicesForIdAsync(
                RfcommServiceId.FromUuid(Constants.RfcommChatServiceUuid), BluetoothCacheMode.Uncached); // Maybe change to cached???

            if (rfcommServices.Services.Count > 0)
            {
                service = rfcommServices.Services[0];
            }
            else
            {
                System.Diagnostics.Debug.WriteLine("Error: Could not discover the chat service on the remote device");
                System.Diagnostics.Debug.WriteLine("Paired: " + devInfo.Pairing.IsPaired);
                System.Diagnostics.Debug.WriteLine("Connection Status: " + bluetoothDevice.ConnectionStatus);
                return;
            }

            // Do various checks of the SDP record to make sure you are talking to a device that actually supports the Bluetooth Rfcomm Chat Service
            var attributes = await service.GetSdpRawAttributesAsync();

            if (!attributes.ContainsKey(Constants.SdpServiceNameAttributeId))
            {
                System.Diagnostics.Debug.WriteLine(
                    "The service is not advertising the Service Name attribute (attribute id=0x100).");
                return;
            }
            var attributeReader = DataReader.FromBuffer(attributes[Constants.SdpServiceNameAttributeId]);
            var attributeType   = attributeReader.ReadByte();

            if (attributeType != Constants.SdpServiceNameAttributeType)
            {
                System.Diagnostics.Debug.WriteLine(
                    "The Chat service is using an unexpected format for the Service Name attribute. ");
                return;
            }
            var serviceNameLength = attributeReader.ReadByte();

            // The Service Name attribute requires UTF-8 encoding.
            attributeReader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;

            StopWatcher();

            lock (this) {
                socket = new StreamSocket();
            }
            try {
                await socket.ConnectAsync(service.ConnectionHostName, service.ConnectionServiceName);

                writer = new DataWriter(socket.OutputStream);
                reader = new DataReader(socket.InputStream);

                System.Diagnostics.Debug.WriteLine("Connected to Server");
                isConnected = true;
                OnConnected();

                mainLoop();
            } catch (Exception ex) when((uint)ex.HResult == 0x80070490)   // ERROR_ELEMENT_NOT_FOUND
            {
                System.Diagnostics.Debug.WriteLine("Please verify that you are running the BluetoothRfcommChat server.");
            } catch (Exception ex) when((uint)ex.HResult == 0x80072740)    // WSAEADDRINUSE
            {
                System.Diagnostics.Debug.WriteLine("Please verify that there is no other RFCOMM connection to the same device.");
            }
        }
        //---------------------------------------------------------------------
        // Methods for device connection after discovery. Enumerate services
        // on each discovered device and add supported devices to a dictionary
        // that maps devices to their link-local IPv6 addresses.
        //---------------------------------------------------------------------

        // Connects to each found device and enumerates available GATT
        // services, then only adds devices to the list that support both the
        // IPSSS and our IPv6ToBle packet writing service. This method is
        // called after the initial device discovery phase.
        public async Task PopulateSupportedDevices()
        {
            //
            // Step 1
            // Check for empty list in case we couldn't find anything
            //
            if (foundDevices.Count == 0)
            {
                return;
            }

            //
            // Step 2
            // Connect to each previously found device and enumerate its
            // services. If it supports both IPSS and IPv6ToBle Packet Writing
            // Service, add it to the list.
            //
            foreach (DeviceInformation deviceInfo in foundDevices)
            {
                BluetoothLEDevice  currentDevice = null;
                GattDeviceService  ipv6ToBlePacketProcessingService = null;
                GattCharacteristic ipv6AddressCharacteristic        = null;
                IPAddress          ipv6Address = null;

                bool hasInternetProtocolSupportService = false;
                bool hasIPv6ToBlePacketWriteService    = false;

                try
                {
                    // Connect. This is recommended to do on a UI thread
                    // normally because it may prompt for consent, but for our
                    // purposes in this application it will auto-accept and we
                    // don't have to use a UI thread.
                    currentDevice = await BluetoothLEDevice.FromIdAsync(deviceInfo.Id);

                    if (currentDevice == null)
                    {
                        Debug.WriteLine($"Failed to connect to device {deviceInfo.Id}");
                    }
                }
                catch (Exception e) when(e.HResult == Constants.E_DEVICE_NOT_AVAILABLE)
                {
                    Debug.WriteLine("Bluetooth radio is not on.");
                }

                // Enumerate the GATT services with GetGattServicesAsync
                if (currentDevice != null)
                {
                    // Retrieve the list of services from the device (uncached)
                    GattDeviceServicesResult servicesResult = await currentDevice.GetGattServicesAsync(BluetoothCacheMode.Uncached);

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

                        // 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 IPSS
                            ushort shortId = GattHelpers.ConvertUuidToShortId(uuid);
                            if (shortId == (ushort)GattHelpers.SigAssignedGattNativeUuid.InternetProtocolSupport)
                            {
                                hasInternetProtocolSupportService = true;
                                continue;
                            }

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

                // Query the device's IP address - enumerate characteristics
                // for the IPv6ToBlePacketProcessingService and read from the
                // IPv6 address characteristic to map devices to their
                // addresses
                if (hasInternetProtocolSupportService &&
                    hasIPv6ToBlePacketWriteService &&
                    ipv6ToBlePacketProcessingService != null)
                {
                    IReadOnlyList <GattCharacteristic> characteristics = null;

                    try
                    {
                        // Verify we can access the device's packet processing 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)
                            {
                                characteristics = characteristicsResult.Characteristics;
                            }
                            else
                            {
                                Debug.WriteLine("Could not access the packet" +
                                                " processing service."
                                                );
                                // On error, act as if there were no characteristics
                                characteristics = new List <GattCharacteristic>();
                            }
                        }
                        else
                        {
                            // Not granted access
                            Debug.WriteLine("Could not access the packet" +
                                            "processing service."
                                            );
                            // On error, act as if there were no characteristics
                            characteristics = new List <GattCharacteristic>();
                        }
                    }
                    catch (Exception e)
                    {
                        Debug.WriteLine("Could not read characteristics due to" +
                                        " permissions issues. " + e.Message
                                        );
                        // On error, act as if there were no characteristics
                        characteristics = new List <GattCharacteristic>();
                    }

                    // Find the IPv6 address characteristic
                    foreach (GattCharacteristic characteristic in characteristics)
                    {
                        if (characteristic.Uuid == Constants.IPv6ToBleIPv6AddressCharacteristicUuid)
                        {
                            ipv6AddressCharacteristic = characteristic;
                            break;
                        }
                    }

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

                        if (readResult.Status == GattCommunicationStatus.Success)
                        {
                            ipv6Address = new IPAddress(GattHelpers.ConvertBufferToByteArray(readResult.Value));
                        }
                    }

                    // Finally, add the deviceInfo/IP address pair to the
                    // dictionary
                    if (ipv6Address != null)
                    {
                        supportedBleDevices.Add(ipv6Address, deviceInfo);
                    }
                }

                // 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 disconnect
                // them first. But we didn't do that here, so no need.

                ipv6ToBlePacketProcessingService?.Dispose();
                currentDevice?.Dispose();
                currentDevice = null;
                GC.Collect();
            }
        }
Example #19
0
        private async void ConnectGenericDevice()
        {
            if (ChosenDevice != null)
            {
                await CheckBluetoothStatus(true);     // check bluetooth status and activate it if is turned off

                if (!IsBluetoothEnabled)
                {
                    AddLog("Can not connect with bluetooth disabled. Turn on the Bluetooth and try again.", AppLog.LogCategory.Warning);
                    return;
                }

                // request access to the selected device
                BluetoothDevice = await BluetoothLEDevice.FromIdAsync(ChosenDevice.Id);

                DeviceAccessStatus accessStatus = await BluetoothDevice.RequestAccessAsync();

                // log
                AddLog("[Connection: " + accessStatus.ToString() + "]" + " Connecting to " + BluetoothDevice.Name + "...", AppLog.LogCategory.Debug);
                AddLog("Connecting to " + BluetoothDevice.Name + "...", AppLog.LogCategory.Info);

                GattCharacteristicsResult hrGattCHaracteristics = null;

                // try to read the device charateristics
                try {
                    var gattDeviceServicesResult = await BluetoothDevice.GetGattServicesForUuidAsync(HRserviceGuid);        // get services with the HR service GUID

                    // for each service withe the given GUID try to read get
                    foreach (GattDeviceService service in gattDeviceServicesResult.Services)
                    {
                        AddLog("[" + ChosenDevice.Name + "] Found service. " +
                               "\n - Handle: " + service.AttributeHandle.ToString() +
                               "\n - UUID: " + service.Uuid.ToString(), AppLog.LogCategory.Debug);    // log

                        if (await service.GetCharacteristicsForUuidAsync(HRCharacteristicGuid) != null)
                        {
                            hrGattCHaracteristics = await service.GetCharacteristicsForUuidAsync(HRCharacteristicGuid);

                            HRReaderService = service;
                            break;
                        }
                    }
                } catch {
                    AddLog("Device \"" + ChosenDevice.Name + "\" does not support HR service." +
                           "\nSelect another one from the devices list.", AppLog.LogCategory.Warning);

                    return;
                }

                // get the HR reader characteristic
                if (hrGattCHaracteristics != null)
                {
                    foreach (GattCharacteristic characteristic in hrGattCHaracteristics.Characteristics.Where(c => c.Uuid.Equals(HRCharacteristicGuid)))
                    {
                        HRReaderCharacteristic = characteristic;
                    }
                }
                else
                {
                    // log something
                    return;
                }

                // if HR characteristic can't be found, show an error and return
                if (HRReaderCharacteristic == null)
                {
                    AddLog("Heart rate monitor characteristic NOT found.", AppLog.LogCategory.Debug);
                    AddLog("Could not connect to Heart Rate service of the device \"" + ChosenDevice.Name + "\".", AppLog.LogCategory.Warning);
                    return;
                }
                // if HR characteristic have been found, then start reading process
                else
                {
                    AddLog("Heart rate monitor characteristic found [Handle: " +
                           HRReaderCharacteristic.AttributeHandle.ToString() + "]", AppLog.LogCategory.Debug);

                    BeginBluetoothReadProcess();

                    SwitchConnectButtonToDisconnectButton();
                }
            }
            else
            {
                AddLog("The button should be disabled. Kowalski analisis.", AppLog.LogCategory.Debug);
                return;
            }
        }
Example #20
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;
            }
        }
Example #21
0
        //Connect to the chosen device
        private async void ConnectDevice()
        {
            if (DeviceInterfacesOutputLst.SelectedItem != null)
            {
                string DeviceID = "";                                                                                             //Device ID
                foreach (var device in devices.Where(device => device.Name == DeviceInterfacesOutputLst.SelectedItem.ToString())) //selext the chosen device from the listview
                {
                    DeviceID = device.Id;
                }
                BluetoothDevice = await BluetoothLEDevice.FromIdAsync(DeviceID);   //request access to the Device

                DeviceAccessStatus x = await BluetoothDevice.RequestAccessAsync(); //wait for the permission

                OutputList.Items.Insert(0, "Connection: " + x.ToString() + " - BluetoothLE Device is " + BluetoothDevice.Name);
                //Create the service and characteristic values to fill with the chosen device information
                GattDeviceService         HRservice         = null;
                GattCharacteristicsResult HRcharacteristics = null;

                try //read the device characteristics, if the characteristics are not found, an exception get thrown
                {
                    HRservice         = BluetoothDevice.GetGattService(HRserviceGuid);
                    HRcharacteristics = await HRservice.GetCharacteristicsAsync();
                }
                catch
                {
                    OutputList.Items.Insert(0, "Chosen device does not support HR service, choose another one");
                    return;
                }
                //TFind the characteristics UUID and assign them to the variable
                foreach (GattCharacteristic caratteristica in HRcharacteristics.Characteristics.Where(caratteristica => caratteristica.Uuid.Equals(HRMeasurement)))
                {
                    HRreader = caratteristica; //assegno la caratteristica ad HRreader
                    OutputList.Items.Insert(0, "Heart Rate Monitor characteristic found - Handle: " + HRreader.AttributeHandle.ToString());
                }

                //check the server port data
                try
                {
                    int serverPortInt;
                    serverPortInt = Int32.Parse(tcpPortText.Text);
                    serverPort    = tcpPortText.Text;
                }
                catch
                {
                    OutputList.Items.Insert(0, "Invalid TCP Port, using 13000");
                    tcpPortText.Text = "13000";
                    serverPort       = tcpPortText.Text;
                }

                if (HRreader == null)//if the HR characteristic in not found, show an error
                {
                    OutputList.Items.Insert(0, "Heart Rate Monitor characteristic not found");
                }
                else //If the characteristic have been found, start the readings
                {
                    //Requesting notify
                    //NOTE: we are not allowed to read the value on request, we have to ask the device to be notified when the HR value change
                    GattCommunicationStatus status = GattCommunicationStatus.ProtocolError; //setting the status as "protocol error", just in case...
                    OutputList.Items.Insert(0, "Waiting for notify handshake...");

                    try
                    {
                        status = await HRreader.WriteClientCharacteristicConfigurationDescriptorAsync(
                            GattClientCharacteristicConfigurationDescriptorValue.Notify);
                    }
                    catch
                    {
                        //f**k, i don't know
                    }

                    //We are now ready to receive the informations and send them via TCP
                    if (status == GattCommunicationStatus.Success)
                    {
                        OutputList.Items.Insert(0, "Notify Activated");
                        OutputList.Items.Insert(0, "Now reading... give me a few seconds");
                        deviceConnectionState = true;
                        serverPort            = tcpPortText.Text;
                        OutputList.Items.Insert(0, "Connecting to port " + serverPort);

                        DispatcherTimerSetup();
                        read();
                    }
                    else
                    {
                        if (status == GattCommunicationStatus.ProtocolError)
                        {
                            OutputList.Items.Insert(0, "Notify Failed - Protocol Error");
                        }
                        if (status == GattCommunicationStatus.Unreachable)
                        {
                            OutputList.Items.Insert(0, "Notify Failed - Unreachable");
                        }
                        if (status == GattCommunicationStatus.AccessDenied)
                        {
                            OutputList.Items.Insert(0, "Notify Failed - Access Denied");
                        }
                        OutputList.Items.Insert(0, "Sorry, I'm far from perfect");
                    }
                }
            }
            else
            {
                OutputList.Items.Insert(0, "Select a device from the list"); //nel caso in cui non venga selezionato un dispositivo dalla lista
            }
        }