Beispiel #1
0
        /// <summary>
        /// 连接到指定的蓝牙设备的RFComm服务
        /// </summary>
        /// <param name="BL">要连接到的设备</param>
        /// <returns>主机对象的规范名称</returns>
        public async Task <string> ConnectToRfcommServiceAsync(BluetoothDeivceData BL)
        {
            if (BL == null)
            {
                throw new ArgumentNullException(nameof(BL), "Parameter could not be null");
            }

            try
            {
                using (Windows.Devices.Bluetooth.BluetoothDevice Device = await Windows.Devices.Bluetooth.BluetoothDevice.FromIdAsync(BL.Id))
                {
                    RfcommDeviceServicesResult Services = await Device.GetRfcommServicesForIdAsync(RfcommServiceId.ObexObjectPush);

                    if (Services.Services.Any())
                    {
                        return(Services.Services.Select((Service) => Service.ConnectionHostName?.CanonicalName).Where((Name) => !string.IsNullOrEmpty(Name)).FirstOrDefault());
                    }
                    else
                    {
                        throw new Exception(Globalization.GetString("BluetoothUI_Tips_Text_3"));
                    }
                }
            }
            catch
            {
                throw new Exception(Globalization.GetString("BluetoothUI_Tips_Text_2"));
            }
        }
Beispiel #2
0
        private async void Button_Click_GetRfcommServices(object sender, RoutedEventArgs e)
        {
            BluetoothDevice bt = await BluetoothDevice.FromIdAsync(ViewModel.SelectedDevice.Id);

            RfcommDeviceServicesResult result = await bt.GetRfcommServicesAsync();

            foreach (var b in bt.SdpRecords)
            {
                Debug.WriteLine(Encoding.UTF8.GetString(b.ToArray()));
            }
            foreach (var service in result.Services)
            {
                Debug.WriteLine(service.ServiceId.AsString() + "    " + service.ConnectionHostName + "    " + service.ConnectionServiceName);
            }
        }
Beispiel #3
0
        private async void logRfTypes(RfcommDeviceServicesResult rfResultList)
        {
            try
            {
                string fileName = "BtServices.log";

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

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

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

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

                    DeviceAccessStatus serviceAccessStatus = await rf.RequestAccessAsync();

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

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

                await FileIO.WriteLinesAsync(logFile, lines);

                lines.Clear();
            }
            catch (Exception exc)
            {
                System.Diagnostics.Debug.WriteLine(exc.ToString());
                System.Diagnostics.Debugger.Break();
            }
        }
Beispiel #4
0
        /// <summary>Get extra info for connection and other not gathered at discovery to save time</summary>
        /// <param name="deviceInfo">The device information data model to populate</param>
        /// <param name="forceRetrieve">Force re-reading of all extra information</param>
        /// <returns>An asynchronous task result</returns>
        private async Task GetExtraInfo(BTDeviceInfo deviceInfo, bool forceRetrieve)
        {
            this.log.InfoEntry("GetExtraInfo");

            // 0 length remote host name indicates that we require more information for connection
            if (deviceInfo.RemoteHostName.Length == 0 || forceRetrieve)
            {
                this.log.Info("GetExtraInfo", () => string.Format("Getting info to fill in host name for address:{0}", deviceInfo.Address));

                using (BluetoothDevice device = await BluetoothDevice.FromIdAsync(deviceInfo.Address)) {
                    // TODO - defer this to before connection or info request
                    // SDP records only after services
                    // Must use uncached
                    RfcommDeviceServicesResult serviceResult = await device.GetRfcommServicesAsync(BluetoothCacheMode.Uncached);

                    this.log.Info("GetExtraInfo", () => string.Format("Success. Number of services:{0}", serviceResult.Services.Count));

                    //WrapErr.ChkTrue(serviceResult.Services.Count > 0, 9999, () => string.Format("No services for BT:{0}", deviceInfo.Name));
                    if (serviceResult.Services.Count == 0)
                    {
                        throw new Exception(string.Format("No services for BT:{0}", deviceInfo.Name));
                    }


                    if (serviceResult.Error == BluetoothError.Success)
                    {
                        foreach (var service in serviceResult.Services)
                        {
                            BT_ServiceType serviceType = BT_ParseHelpers.GetServiceType(service.ConnectionServiceName);
                            this.log.Info("GetExtraInfo", () => string.Format("Device {0} Connection host name {1} Service name {2} Type {3}",
                                                                              deviceInfo.Name,
                                                                              service.ConnectionHostName,
                                                                              service.ConnectionServiceName,
                                                                              serviceType.ToString()));
                            if (serviceType == BT_ServiceType.SerialPort)
                            {
                                // TODO get extra info on attributes
                                //var sdpAttr = await service.GetSdpRawAttributesAsync(BluetoothCacheMode.Uncached);
                                //foreach (var attr in sdpAttr) {
                                //    this.log.Info("HarvestInfo", () => string.Format("             SDP Attribute:{0} Capacity:{1} Length:{2}", attr.Key, attr.Value.Capacity, attr.Value.Length));
                                //}
                                // Sample output. See: https://www.bluetooth.com/specifications/assigned-numbers/service-discovery/
                                //SDP Attribute id | Capacity | Length | Description(?)
                                //    256               7           7
                                //      0               5           5
                                //      6              11          11
                                //      4              14          14
                                //      1               5           5      (service class ID list
                                deviceInfo.ServiceType       = BT_ServiceType.SerialPort;
                                deviceInfo.RemoteHostName    = service.ConnectionHostName.ToString();
                                deviceInfo.RemoteServiceName = service.ConnectionServiceName;
                                // TODO info on access
                                //service.DeviceAccessInformation.CurrentStatus == DeviceAccessStatus.Allowed
                                this.log.Info("****", () => string.Format("Device:{0} Host Name:{1} Service:{2}",
                                                                          deviceInfo.Name, deviceInfo.RemoteHostName, deviceInfo.RemoteServiceName));
                            }
                            else
                            {
                                // Not used.
                            }
                        }
                    }
                    else
                    {
                        this.log.Error(9999, () => string.Format("Get Service result:{0}", serviceResult.Error.ToString()));
                    }
                }
            }
        }
        public async Task <bool> ConnectSpp()
        {
            bool result = await ObtainBtDevice();

            Log($"ConnectSpp({BleID}, ObtainBtDevice={result})");

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

            if (BtDevice.DeviceAccessInformation.CurrentStatus == DeviceAccessStatus.DeniedByUser)
            {
                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

            RfcommDeviceServicesResult rfcommServices =
                await BtDevice.GetRfcommServicesForIdAsync(
                    RfcommServiceId.SerialPort,
                    BluetoothCacheMode.Uncached);

            Log($"{rfcommServices.Services.Count} Services found");

            foreach (RfcommDeviceService service in rfcommServices.Services)
            {
                Log($"{service.ConnectionServiceName}");
                Log($"\tHostName: {service.ConnectionHostName}");
                Log($"\tServiceId: {service.ServiceId.AsString()}");
                Log($"\tProtectionLevel: {service.ProtectionLevel}");
                Log($"\tDeviceAccessInformation: {service.DeviceAccessInformation.CurrentStatus}");
            }

            if (rfcommServices.Services.Count > 0)
            {
                SppService = rfcommServices.Services[0];
            }
            else
            {
                return(false);
            }

            Log($"Connecting to {SppService.ServiceId.AsString()}");

            // Do various checks of the SDP record to make sure you are talking to a device that actually supports the Bluetooth Rfcomm Chat Service

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

                SppServiceWriter = new DataWriter(SppServiceSocket.OutputStream);
                SppServiceReader = new DataReader(SppServiceSocket.InputStream);
                SppServiceReader.InputStreamOptions = InputStreamOptions.ReadAhead;
            }
            catch (Exception ex)
            {
                Log($"{ex.Message}");
                Log($"{ex.StackTrace}");
                return(false);
            }

            return(true);
        }
        /// <summary>Get extra info for connection and other not gathered at discovery to save time</summary>
        /// <param name="deviceInfo">The device information data model to populate</param>
        /// <param name="forceRetrieve">Force re-reading of all extra information</param>
        /// <returns>An asynchronous task result</returns>
        private async Task GetExtraInfo(BTDeviceInfo deviceInfo, bool forceRetrieve, bool display)
        {
            try {
                this.log.InfoEntry("GetExtraInfo");

                // TODO Cannot call this after the services have already been retrieved. So do not force

                // 0 length remote host name indicates that we require more information for connection
                if (deviceInfo.RemoteHostName.Length == 0 || forceRetrieve)
                {
                    this.log.Info("GetExtraInfo", () => string.Format("Getting info to fill in host name for address:{0}", deviceInfo.Address));

                    using (BluetoothDevice device = await BluetoothDevice.FromIdAsync(deviceInfo.Address)) {
                        // TODO - defer this to before connection or info request
                        // SDP records only after services
                        // Must use uncached
                        RfcommDeviceServicesResult serviceResult = await device.GetRfcommServicesAsync(BluetoothCacheMode.Uncached);

                        this.log.Info("GetExtraInfo", () => string.Format("Success. Number of services:{0}", serviceResult.Services.Count));

                        //WrapErr.ChkTrue(serviceResult.Services.Count > 0, 9999, () => string.Format("No services for BT:{0}", deviceInfo.Name));
                        if (serviceResult.Services.Count == 0)
                        {
                            throw new Exception(string.Format("No services for BT:{0}", deviceInfo.Name));
                        }


                        if (serviceResult.Error == BluetoothError.Success)
                        {
                            foreach (var service in serviceResult.Services)
                            {
                                BT_ServiceType serviceType = BT_ParseHelpers.GetServiceType(service.ServiceId.AsShortId());
                                this.log.Info("GetExtraInfo", () => string.Format("Device {0} Connection host name {1} Service name {2} Type {3}",
                                                                                  deviceInfo.Name,
                                                                                  service.ConnectionHostName,
                                                                                  service.ConnectionServiceName,
                                                                                  serviceType.ToString()));
                                if (serviceType == BT_ServiceType.SerialPort)
                                {
                                    //await this.GetListSDPAttributes(service);
                                    deviceInfo.ServiceType       = serviceType;
                                    deviceInfo.RemoteHostName    = service.ConnectionHostName.ToString();
                                    deviceInfo.RemoteServiceName = service.ConnectionServiceName;
                                    deviceInfo.ServiceClassName  = serviceType.ToString().CamelCaseToSpaces();
                                    deviceInfo.ServiceClassInt   = (int)service.ServiceId.AsShortId();

                                    // TODO info on access
                                    //service.DeviceAccessInformation.CurrentStatus == DeviceAccessStatus.Allowed

                                    this.log.Info("****", () => string.Format("Device:{0} Host Name:{1} Service:{2}",
                                                                              deviceInfo.Name, deviceInfo.RemoteHostName, deviceInfo.RemoteServiceName));



                                    //deviceInfo.Strength = 0;
                                    this.ListDeviceInfoProperties(device);

                                    this.log.Info("****", () => string.Format("device.BluetoothAddress: {0}", device.BluetoothAddress));
                                    this.log.Info("****", () => string.Format("device.BluetoothDeviceId.id: {0}", device.BluetoothDeviceId.Id));
                                    this.log.Info("****", () => string.Format("device.DeviceId: {0}", device.DeviceId));
                                    this.log.Info("****", () => string.Format("device.DeviceInformation.Id: {0}", device.DeviceInformation.Id));
                                    this.log.Info("****", () => string.Format("device.ClassOfDevice: {0}", device.ClassOfDevice.RawValue));
                                    //this.log.Info("****", () => string.Format(":{0}", ));
                                    //this.log.Info("****", () => string.Format(":{0}", ));

                                    // Experimental. See the note on the method
                                    //await this.GetRadioInfo(device, deviceInfo, service.ConnectionServiceName);
                                    //await this.GetRadioInfo(device, deviceInfo, deviceInfo.RemoteHostName);

                                    // List of radios available on current device
                                    //await this.ListRadios();

                                    if (display)
                                    {
                                        this.BT_DeviceInfoGathered?.Invoke(this, deviceInfo);
                                    }
                                }
                                else
                                {
                                    //Not used.
                                }
                                service.Dispose();
                            }
                        }
                        else
                        {
                            this.log.Error(9999, () => string.Format("Get Service result:{0}", serviceResult.Error.ToString()));
                        }
                    }
                }
                else if (deviceInfo.RemoteHostName.Length > 0 && display)
                {
                    this.BT_DeviceInfoGathered?.Invoke(this, deviceInfo);
                }
            }
            catch (Exception e) {
                this.log.Exception(9999, "GetExtraInfo", "", e);
            }
        }
Beispiel #7
0
        public async Task <bool> BtConnect(string deviceID)
        {
            try
            {
                //System.Diagnostics.Debug.Assert(Thread.CurrentThread.IsBackground, "SerialComm:BtConnect() cannot be called from the UI thread.");

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

                    return(false);
                }

                BluetoothDevice device = await BluetoothDevice.FromIdAsync(deviceID);

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

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

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

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

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

                    logRfTypes(rfResultList);

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

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

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


            return(IsOpen());
        }
        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
            {
            }
        }