public async Task <bool> ConnectDevice(SensorDevice sensorDevice, CancellationTokenSource tokenSource, int slotIndex = -1) { _isBusy = true; // Cannot connect to an already connected device or devices that is neither master or slave. if (sensorDevice.IsConnected || sensorDevice.Type == DeviceType.None) { return(false); } _log.Info("Connecting to a device."); if (_deviceSlotService.AllSlotsAreFull) { _userDialogs.Alert(new AlertConfig { Message = $"The device list is full. Please disconnect a device before attempting to connect another one." }); _isBusy = false; return(false); } DeviceSlot emptySlot; if (slotIndex > -1) { emptySlot = _deviceSlotService.DeviceSlots[slotIndex]; } else { emptySlot = _deviceSlotService.GetEmptySlot(sensorDevice.Type); } if (emptySlot == null) { _userDialogs.Alert(new AlertConfig { Message = $"Cannot connect to more devices of this type." }); _isBusy = false; return(false); } _log.Debug($"Connecting to {sensorDevice.Type}"); // Attempt to connect to device. int timeout = 4000; // 4 second timeout var task = _adapter.ConnectToDeviceAsync(device: sensorDevice.Device, cancellationToken: tokenSource.Token); try { if (await Task.WhenAny(task, Task.Delay(timeout)) != task) { tokenSource.Cancel(); _userDialogs.Alert(new AlertConfig { Message = $"Connection to {sensorDevice.Name} timed out." }); _isBusy = false; return(false); } } catch (DeviceConnectionException) { _userDialogs.Alert(new AlertConfig { Message = $"Could not connect to {sensorDevice.Name}." }); _isBusy = false; return(false); } // Clear the Last active output data types list. _sensorDataService.RecentOutputAdditions.Clear(); try { // TODO: Add file service for sensor data logging. sensorDevice.Characteristics = await GetAvailableCharacteristics(sensorDevice); _log.Debug($"New {sensorDevice.Type} Device Address: " + sensorDevice.Id); if (sensorDevice.Characteristics.Count == 0) { _userDialogs.Alert(new AlertConfig { Message = $"Error: No valid characteristics were detected for {sensorDevice.Name}. Disconnecting from the device." }); await DisconnectDevice(sensorDevice); _isBusy = false; return(false); } // Subscribe to data characteristics foreach (var characteristic in sensorDevice.Characteristics) { if (characteristic.Uuid == CMD_CHARACTERISTIC) { sensorDevice.CommandCharacteristic = characteristic; } else if (characteristic.Uuid == DATA_CHARACTERISTIC) { sensorDevice.DownloadDataCharacteristic = characteristic; await sensorDevice.DownloadDataCharacteristic.StartUpdatesAsync(); } else if (characteristic.Uuid == INFO_CHARACTERISTIC) { sensorDevice.InfoCharacteristic = characteristic; await sensorDevice.InfoCharacteristic.StartUpdatesAsync(); } else if (characteristic.Uuid == BATTERY_UUID) { sensorDevice.BatteryCharacteristic = characteristic; byte[] battery_pkg = await sensorDevice.BatteryCharacteristic.ReadAsync(); _deviceSlotService.UpdateBatteryStatus(emptySlot.Index, battery_pkg[0]); await sensorDevice.BatteryCharacteristic.StartUpdatesAsync(); } else if (characteristic.CanUpdate) { var datatype = _dataTypeForCharacteristicUUID[characteristic.Uuid]; DataType tempDataType = datatype; // Necessary temp conversion due to DataType clash in different chest and limb devices. if (datatype == DataType.temp) { if (sensorDevice.Type == DeviceType.Chest) { tempDataType = DataType.chest_temp; } else if (sensorDevice.Type == DeviceType.Limb) { tempDataType = DataType.foot_temp; } } if (!_dataTypeToOutputType.ContainsKey(tempDataType)) { continue; } foreach (var outputType in _dataTypeToOutputType[tempDataType]) { var outputTuple = Tuple.Create(emptySlot.Index, outputType); int outputID = outputTuple.GetHashCode(); OutputData.Add(outputID); emptySlot.OutputDataIDs.Add(outputID); _sensorDataService.AddToDataBuffer(outputID); SubscribedCharacteristicsList.Add(outputType); _sensorDataService.RecentOutputAdditions.Add(outputTuple); } var func = new EventHandler <CharacteristicUpdatedEventArgs>((sender, args) => CharacteristicOnValueUpdated(sender, args, sensorDevice)); _characteristicEventAggregator.TryAdd(characteristic, func); // Cleanup previous event handler. characteristic.ValueUpdated -= func; // Attach event handler to characteristic value update. characteristic.ValueUpdated += func; // Start Getting Sensor Data. await characteristic.StartUpdatesAsync(); } } _deviceSlotService.AddDeviceToSlot(emptySlot.Index, sensorDevice); } catch (Exception e) { _log.Debug(e.Message); } _isBusy = false; return(true); }