protected async override void OnNavigatedTo(NavigationEventArgs args) { DI = args.Parameter as DeviceInformationWrapper; ParentStatusHandler?.SetStatusActive(true); uiTerminalControl.ParentTerminal = this; uiTerminalControl.DoSendData = this; uiTerminalControl.DI = DI; uiTerminalControl.UpdateShortcutButtons(); TerminalAdapter = new BluetoothCommTerminalAdapter(this, DI); await TerminalAdapter.InitAsync(); ParentStatusHandler?.SetStatusActive(false); }
protected override void OnNavigatedTo(NavigationEventArgs args) { di = args.Parameter as DeviceInformationWrapper; // When will this be null? When we've created a page generically instead of for a particular device. // This happens when you do a beacon search. if (di.BleAdvert != null) { di.BleAdvert.UpdatedBleAdvertisement += BleAdvert_UpdatedBleAdvertisement; } BleAdvertisementWrapper.UpdatedUniversalBleAdvertisement += BleAdvert_UpdatedUniversalBleAdvertisement; if (di.BleAdvert == null) { // Don't let the user switch off the track all. uiTrackAll.Visibility = Visibility.Collapsed; uiTrackAll.IsChecked = true; // belt and suspenders } }
public static (string name, string id, string description) GetBleName(DeviceInformationWrapper wrapper, BluetoothLEAdvertisementReceivedEventArgs bleAdvert) { string name = "???"; string id = "??-??"; string description = "??--??"; if (bleAdvert == null || (wrapper != null && wrapper.BleAdvert == null)) { return(name, id, description); } name = bleAdvert.Advertisement.LocalName; id = BluetoothAddress.AsString(bleAdvert.BluetoothAddress); if (EmptyOrAllNull(name)) { // BAD: There's a device where the LocalName is 13 NUL chars! name = id; } name = CustomizeWrapperFromAdvertisement(wrapper, bleAdvert, name); description = AsDescription(bleAdvert); return(name, id, description); }
/// <summary> /// Warning: in addition to its normal function, this function ALSO triggers events. Yes, it's gross, and yes, I'm sorry. This only happens when wrapper is non-null /// </summary> /// <param name="wrapper"></param> /// <param name="ble"></param> /// <param name="name"></param> /// <returns></returns> private static string CustomizeWrapperFromAdvertisement(DeviceInformationWrapper wrapper, BluetoothLEAdvertisementReceivedEventArgs ble, string name) { // Lets's see if it's an Eddystone beacon... // https://github.com/google/eddystone // https://github.com/google/eddystone/blob/master/protocol-specification.md foreach (var section in ble.Advertisement.DataSections) { switch (section.DataType) { case 0x16: // 22=service data var dr = DataReader.FromBuffer(section.Data); dr.ByteOrder = ByteOrder.LittleEndian; var Service = dr.ReadUInt16(); // https://github.com/google/eddystone if (Service == 0xFEAA) // An Eddystone type { //EddystoneFrameType = (byte)(0x0F & (dr.ReadByte() >> 4)); var EddystoneFrameType = dr.ReadByte(); const int TypeUID = 0x00; const int TypeURL = 0x10; const int TypeTLM = 0x20; const int TypeEID = 0x40; switch (EddystoneFrameType) { case TypeUID: wrapper?.BleAdvert.Event("UID: <data>"); break; case TypeTLM: wrapper?.BleAdvert.Event("TLM: <data>"); break; case TypeEID: wrapper?.BleAdvert.Event("EID: <data>"); break; case TypeURL: // 0x10: An Eddystone-URL // https://github.com/google/eddystone/tree/master/eddystone-url var result = BluetoothDeviceController.Beacons.Eddystone.ParseEddystoneUrlArgs(section.Data); name = result.Success ? result.Url : "Invalid eddystone!"; if (wrapper != null) { wrapper.BleAdvert.EddystoneUrl = name; } if (result.Success && result.Url.StartsWith("https://ruu.vi/#")) { //foundValues.Add(AdvertisementType.RuuviTag); var ruuvi = BluetoothDeviceController.Beacons.RuuviTag.ParseRuuviTag(result.Url); ruuvi.Data.EventTime = DateTime.Now; if (ruuvi.Success) { name = ruuvi.ToString(); // Make a new user-friendly string } if (wrapper != null) { wrapper.BleAdvert.AdvertisementType = BleAdvertisementWrapper.BleAdvertisementType.RuuviTag; } // TODO: this is actually weird; it should be done somewhere else. // This function is all about setting up the wrapper, not actually // triggering events! wrapper?.BleAdvert.Event(ruuvi.Data); } else { if (wrapper != null) { wrapper.BleAdvert.AdvertisementType = BleAdvertisementWrapper.BleAdvertisementType.Eddystone; } name = $"Eddystone {result.Url}"; // TODO: this is actually weird; it should be done somewhere else. // This function is all about setting up the wrapper, not actually // triggering events! wrapper?.BleAdvert.Event(result.Url); } break; } } break; } } return(name); }
private async Task DisplayBluetooth(NameDevice knownDevice, DeviceInformationWrapper di, BluetoothLEDevice ble) { var jsonFormat = Newtonsoft.Json.Formatting.Indented; var jsonSettings = new Newtonsoft.Json.JsonSerializerSettings() { DefaultValueHandling = Newtonsoft.Json.DefaultValueHandling.Ignore, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore, ContractResolver = IgnoreEmptyEnumerableResolver.Instance, }; var wireAllDevices = new NameAllBleDevices(); WireDevice = new NameDevice(); WireDevice.Name = di.di.Name; WireDevice.Details += $"Id:{di.di.Id}\nCanPair:{di.di.Pairing.CanPair} IsPaired:{di.di.Pairing.IsPaired}"; wireAllDevices.AllDevices.Add(WireDevice); WireDevice.ClassModifiers = knownDevice.ClassModifiers; WireDevice.ClassName = knownDevice.ClassName; WireDevice.Description = knownDevice.Description; uiRawData.Text = Newtonsoft.Json.JsonConvert.SerializeObject(WireDevice, jsonFormat); string raw = null; if (ble == null) { // Happens if another program is trying to use the device! raw = $"BLE: ERROR: Another app is using this device.\n"; } else { // TODO: remove this code which is only here while I investigate the WESCALE scale #if NEVER_EVER_DEFINED { // WESCALE: no gatt services var services = ble.GattServices; var count = services.Count; var devacc = ble.DeviceAccessInformation; var devaccstatus = devacc.CurrentStatus; foreach (var service in services) { var chars = service.GetAllCharacteristics(); } try { var guid = Guid.Parse("0000fff0-0000-1000-8000-00805f9b34fb"); var request = await ble.RequestAccessAsync(); var allservice = await ble.GetGattServicesForUuidAsync(guid); var servicefff0 = ble.GetGattService(guid); var charsfff0 = servicefff0.GetAllCharacteristics(); var countfff0 = charsfff0.Count; foreach (var ch in charsfff0) { ; } } catch (Exception ex) { ; } } #endif var result = await ble.GetGattServicesAsync(); if (result.Status != GattCommunicationStatus.Success) { raw += GetStatusString(result.Status, result.ProtocolError); } else { var header = new BleDeviceHeaderControl(); await header.InitAsync(ble); int serviceCount = 0; foreach (var service in result.Services) { await header.AddServiceAsync(ble, service); var shouldDisplay = ServiceShouldBeEdited(service); var defaultService = knownDevice.GetService(service.Uuid.ToString("D")); var wireService = new NameService(service, defaultService, serviceCount++); WireDevice.Services.Add(wireService); try { var cresult = await service.GetCharacteristicsAsync(); if (cresult.Status != GattCommunicationStatus.Success) { raw += GetStatusString(cresult.Status, cresult.ProtocolError); } else { var characteristicCount = 0; foreach (var characteristic in cresult.Characteristics) { //The descriptors don't seem to be actually interesting. it's how we read and write. var descriptorStatus = await characteristic.GetDescriptorsAsync(); if (descriptorStatus.Status == GattCommunicationStatus.Success) { foreach (var descriptor in descriptorStatus.Descriptors) { ; } } var defaultCharacteristic = defaultService?.GetChacteristic(characteristic.Uuid.ToString("D")); var wireCharacteristic = new NameCharacteristic(characteristic, defaultCharacteristic, characteristicCount++); wireService.Characteristics.Add(wireCharacteristic); if (wireCharacteristic.Suppress) { continue; // don't show a UI for a supressed characteristic. } // // Here are each of the editor children items // var edit = new BleCharacteristicControl(knownDevice, service, characteristic); uiEditor.Children.Add(edit); var dc = DeviceCharacteristic.Create(characteristic); //NOTE: does any device have a presentation format? foreach (var format in characteristic.PresentationFormats) { raw += $" Fmt: Description:{format.Description} Namespace:{format.Namespace} Type:{format.FormatType} Unit: {format.Unit} Exp:{format.Exponent}\n"; } try { if (wireCharacteristic.IsRead) { var vresult = await characteristic.ReadValueAsync(); if (vresult.Status != GattCommunicationStatus.Success) { raw += GetStatusString(vresult.Status, vresult.ProtocolError); } else { var dt = BluetoothLEStandardServices.GetDisplayInfo(service, characteristic); var hexResults = dt.AsString(vresult.Value); wireCharacteristic.ExampleData.Add(hexResults); // And add as a converted value var NC = BleNames.Get(knownDevice, service, characteristic); var decode = NC?.Type; if (decode != null && !decode.StartsWith("BYTES|HEX")) { var decoded = ValueParser.Parse(vresult.Value, decode); wireCharacteristic.ExampleData.Add(decoded.UserString); } } } } catch (Exception e) { raw += $" Exception reading value: {e.HResult} {e.Message}\n"; } // Update the UI with the latest discovery // Later: or not. The raw data isn't super useful. //uiRawData.Text = Newtonsoft.Json.JsonConvert.SerializeObject(WireDevice, jsonFormat); } } } catch (Exception e) { raw += $" Exception reading characteristic: {e.HResult} {e.Message}\n"; } } } } JsonAsList = Newtonsoft.Json.JsonConvert.SerializeObject(wireAllDevices, jsonFormat, jsonSettings); JsonAsSingle = Newtonsoft.Json.JsonConvert.SerializeObject(WireDevice, jsonFormat, jsonSettings); uiProgress.IsActive = false; uiRawData.Text += raw; return; }
public BluetoothCommTerminalAdapter(ITerminal terminal, DeviceInformationWrapper input_di) { Terminal = terminal; di = input_di; }