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); }
/// <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); } }
/// <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"); } }
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"); } } } }
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(); } }
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(); } }
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 { } }
/// <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); }
/// <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); }
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); } }
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."); } }
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()); }
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(); } }
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; } }
//--------------------------------------------------------------------- // 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; } }
//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 } }