//--------------------------------------------------------------------- // Constructor //--------------------------------------------------------------------- public IPv6ToBleIPv6AddressCharacteristic( GattLocalCharacteristic characteristic, GenericGattService service, IPAddress address ) : base(characteristic, service) { Ipv6Address = address; Value = GattHelpers.ConvertByteArrayToBuffer(Ipv6Address.GetAddressBytes()); }
//--------------------------------------------------------------------- // 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; } }
/// <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> /// Awaits the reception of a packet on the packet write characteristic /// of the packet write service of the local GATT server. /// /// This is so a server can know when a packet has been received and /// deal with it accordingly. /// </summary> /// <param name="sender"></param> /// <param name="eventArgs"></param> private async void WatchForPacketReception( object sender, PropertyChangedEventArgs eventArgs ) { if (sender == localPacketWriteCharacteristic) { if (eventArgs.PropertyName == "Value") { // Get the received packet Packet = GattHelpers.ConvertBufferToByteArray(localPacketWriteCharacteristic.Value); // Get the other two characteristics' info for decompressing // the packet DataReader reader = DataReader.FromBuffer(localCompressedHeaderLengthCharacteristic.Value); CompressedHeaderLength = reader.ReadInt32(); reader = DataReader.FromBuffer(localPayloadLengthCharacteristic.Value); PayloadLength = reader.ReadInt32(); Debug.WriteLine("Received this packet over " + "Bluetooth: " + Utilities.BytesToString(packet)); // TESTING: Start the timer for header decompression to time // total transmission/reception time bleReceptionTimer.Start(); // Decompress the packet try { headerCompression.UncompressHeaderIphc(packet, compressedHeaderLength, payloadLength ); } catch (Exception e) { Debug.WriteLine("Exception occurred during header " + "decompression. Message: " + e.Message ); bleReceptionTimer.Stop(); return; } bleReceptionTimer.Stop(); Debug.WriteLine($"Header decompression took {bleReceptionTimer.ElapsedMilliseconds} milliseconds."); // Only send it back out if this device is not the destination; // in other words, if this device is a middle router in the // subnet IPAddress destinationAddress = GetDestinationAddressFromPacket( packet ); // Check if the packet is NOT for this device bool packetIsForThisDevice = false; packetIsForThisDevice = IPAddress.Equals(destinationAddress, generatedLocalIPv6AddressForNode); if (!packetIsForThisDevice) { // Check if the message is in the local message cache or not if (messageCache.Contains(packet)) { Debug.WriteLine("This packet is not for this device and" + " has been seen before." ); return; } // If this message has not been seen before, add it to the // message queue and remove the oldest if there would now // be more than 10 if (messageCache.Count < 10) { messageCache.Enqueue(packet); } else { messageCache.Dequeue(); messageCache.Enqueue(packet); } await SendPacketOverBluetoothLE(packet, destinationAddress ); } else { // It's for this device. Check if it has been seen before // or not. // Check if the message is in the local message cache or not if (messageCache.Contains(packet)) { Debug.WriteLine("This packet is for this device, but " + "has been seen before." ); return; } // If this message has not been seen before, add it to the // message queue and remove the oldest if there would now // be more than 10 if (messageCache.Count < 10) { messageCache.Enqueue(packet); } else { messageCache.Dequeue(); messageCache.Enqueue(packet); } // Send the packet to the driver for inbound injection SendPacketToDriverForInboundInjection(packet); } } } }
/// <summary> /// Awaits the reception of a packet on the packet write characteristic /// of the packet write service of the local GATT server. /// /// This is so a server can know when a packet has been received and /// deal with it accordingly. /// </summary> /// <param name="sender"></param> /// <param name="eventArgs"></param> private async void WatchForPacketReception( object sender, PropertyChangedEventArgs eventArgs ) { if (sender == localPacketWriteCharacteristic) { if (eventArgs.PropertyName == "Value") { // Set the packet byte array to the received value for others to // read or retrieve Packet = GattHelpers.ConvertBufferToByteArray(localPacketWriteCharacteristic.Value); Debug.WriteLine("Received this packet over " + "Bluetooth: " + Utilities.BytesToString(packet)); // Only send it back out if this device is not the destination; // in other words, if this device is a middle router in the // subnet IPAddress destinationAddress = GetDestinationAddressFromPacket( packet ); // Check if the packet is NOT for this device bool packetIsForThisDevice = false; packetIsForThisDevice = IPAddress.Equals(destinationAddress, generatedLocalIPv6AddressForNode); if (!packetIsForThisDevice) { // Check if the message is in the local message cache or not if (messageCache.Contains(packet)) { Debug.WriteLine("This packet is not for this device and" + " has been seen before." ); return; } // If this message has not been seen before, add it to the // message queue and remove the oldest if there would now // be more than 10 if (messageCache.Count < 10) { messageCache.Enqueue(packet); } else { messageCache.Dequeue(); messageCache.Enqueue(packet); } await SendPacketOverBluetoothLE(packet, destinationAddress ); } else { // It's for this device. Check if it has been seen before // or not. // Check if the message is in the local message cache or not if (messageCache.Contains(packet)) { Debug.WriteLine("This packet is for this device, but " + "has been seen before." ); return; } // If this message has not been seen before, add it to the // message queue and remove the oldest if there would now // be more than 10 if (messageCache.Count < 10) { messageCache.Enqueue(packet); } else { messageCache.Dequeue(); messageCache.Enqueue(packet); } // Send the packet to the driver for inbound injection SendPacketToDriverForInboundInjection(packet); } } } }
//--------------------------------------------------------------------- // 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(); } }
//--------------------------------------------------------------------- // Asynchronous initialization //--------------------------------------------------------------------- public override async Task InitAsync() { await CreateServiceProvider(Constants.IPv6ToBlePacketProcessingServiceUuid); GattLocalCharacteristicResult characteristicResult = null; // // Step 1 // Create the packet write characteristic // GattLocalCharacteristic createdPacketWriteCharacteristic = null; characteristicResult = await ServiceProvider.Service.CreateCharacteristicAsync( Constants.IPv6ToBlePacketWriteCharacteristicUuid, GattHelpers.packetWriteParameters ); // // Step 2 // Assign the created packet write characteristic to this service's internal one // GattHelpers.GetCharacteristicFromResult(characteristicResult, ref createdPacketWriteCharacteristic ); if (createdPacketWriteCharacteristic != null) { PacketWriteCharacteristic = new IPv6ToBlePacketWriteCharacteristic( createdPacketWriteCharacteristic, this ); } characteristicResult = null; // // Step 3 // Create the compressed header length characteristic // GattLocalCharacteristic createdCompressedHeaderLengthCharacteristic = null; characteristicResult = await ServiceProvider.Service.CreateCharacteristicAsync( Constants.IPv6ToBleCompressedHeaderLengthCharacteristicUuid, GattHelpers.packetWriteParameters ); // // Step 4 // Assign the created compressed header length characteristic to this service's internal one // GattHelpers.GetCharacteristicFromResult(characteristicResult, ref createdCompressedHeaderLengthCharacteristic ); if (createdCompressedHeaderLengthCharacteristic != null) { CompressedHeaderLengthCharacteristic = new CompressedHeaderLengthCharacteristic( createdCompressedHeaderLengthCharacteristic, this ); } characteristicResult = null; // // Step 5 // Create the payload length characteristic // GattLocalCharacteristic createdPayloadLengthCharacteristic = null; characteristicResult = await ServiceProvider.Service.CreateCharacteristicAsync( Constants.IPv6ToBlePayloadLengthCharacteristicUuid, GattHelpers.packetWriteParameters ); // // Step 6 // Assign the created payload length characteristic to this service's internal one // GattHelpers.GetCharacteristicFromResult(characteristicResult, ref createdPayloadLengthCharacteristic ); if (createdPayloadLengthCharacteristic != null) { PayloadLengthCharacteristic = new PayloadLengthCharacteristic( createdPayloadLengthCharacteristic, this ); } characteristicResult = null; // // Step 7 // Create the IPv6 address read characteristic // // Generate the device's link-local IPv6 address IPAddress address = await StatelessAddressConfiguration.GenerateLinkLocalAddressFromBlThRadioIdAsync(2); if (address == null) { Debug.WriteLine("Could not generate a link-local IPv6 address" + " from the Bluetooth address." ); return; } // Create the characteristic GattLocalCharacteristic createdIPv6AddressReadCharacteristic = null; characteristicResult = await ServiceProvider.Service.CreateCharacteristicAsync( Constants.IPv6ToBleIPv6AddressCharacteristicUuid, GattHelpers.ipv6AddressReadParameters ); // // Step 8 // Assign the created IPv6 address read characteristic to this service's internal one // GattHelpers.GetCharacteristicFromResult(characteristicResult, ref createdIPv6AddressReadCharacteristic ); if (createdIPv6AddressReadCharacteristic != null) { IPv6AddressCharacteristic = new IPv6ToBleIPv6AddressCharacteristic( createdIPv6AddressReadCharacteristic, this, address ); } }