我需要在Xamarin.Android/iOS/Mono上通過藍牙使用SPP。這是我想對Xamarin.Android的代碼,但該行爲是相同的,如果我去到iOS和Mono在Linux/Mac上:如何通過藍牙使用Xamarin.Android/iOS/Mono和SPP?
using System;
using System.Collections.Generic;
using System.Text;
using Android.Bluetooth;
using Java.Util;
using System.IO;
using System.Threading;
using PI.SDK.Devices.BC.Responses;
using System.Threading.Tasks;
namespace PI.SDK.Devices.BC
{
public class BluetoothDeviceConnectionChannel : IBCDeviceConnectionChannel
{
private Queue<ResponseBase> _dispatcher;
private bool _abort = false;
private BluetoothAdapter _adapter;
private BluetoothSocket _socket;
private BluetoothDevice _device;
private static UUID _uuid = UUID.FromString("00001101-0000-1000-8000-00805F9B34FB");
private StreamReader _reader;
private StreamWriter _writer;
private string _deviceAddress;
public event Action<string> Notify;
public bool IsOpen { get { return _socket.IsConnected; } }
public BluetoothDeviceConnectionChannel(string deviceAddress)
{
_adapter = BluetoothAdapter.DefaultAdapter;
if (_adapter == null)
throw new PIDeviceManagerException("Bluetooth is not supported on this Android device");
_deviceAddress = deviceAddress;
}
public BluetoothDeviceConnectionChannel(BluetoothDevice device) : this(device.Address) { }
public void Close()
{
_socket.Close();
}
public bool Open()
{
if (!_adapter.IsEnabled)
{
throw new PIDeviceManagerException("Bluetooth is not enabled");
}
_adapter.CancelDiscovery();
_device = _adapter.GetRemoteDevice(_deviceAddress);
_socket = _device.CreateRfcommSocketToServiceRecord(_uuid);
_socket.Connect();
if (_socket.IsConnected)
{
_reader = new StreamReader(_socket.InputStream, Encoding.GetEncoding("Windows-1252"));
_writer = new StreamWriter(_socket.OutputStream, Encoding.GetEncoding("Windows-1252"));
_dispatcher = new Queue<ResponseBase>();
Task.Factory.StartNew(() => ReceiveData());
return true;
}
return false;
}
public void ReceiveData()
{
while (_socket != null && _socket.IsConnected)
{
var data = _reader.ReadToEnd();
if (string.IsNullOrWhiteSpace(data))
continue;
var dataBuffer = data.ToCharArray();
var synBuilder = new StringBuilder();
foreach (var c in dataBuffer)
{
switch (c)
{
case ControlChars.NACK:
case ControlChars.EOT:
#if DEBUG
System.Diagnostics.Debug.WriteLine($"[PINPAD -> APP] {c.ToString().Dump()}");
#endif
_abort = true;
return;
case ControlChars.ACK:
#if DEBUG
System.Diagnostics.Debug.WriteLine($"[PINPAD -> APP] {c.ToString().Dump()}");
#endif
continue;
case ControlChars.SYN:
synBuilder.Append(c);
break;
case ControlChars.ETB:
synBuilder.Append(c);
var cmdResponse = synBuilder.ToString();
#if DEBUG
System.Diagnostics.Debug.WriteLine($"[PINPAD -> APP] {cmdResponse.Dump()}");
#endif
var response = CommandResponseParser.Parse(cmdResponse);
if (response != null)
{
_dispatcher.Enqueue(response);
}
return;
default:
synBuilder.Append(c);
break;
}
}
}
}
public ResponseBase SendData(string data)
{
_abort = false;
try
{
_writer.Write(data);
}
catch
{
throw new PIException("Unable to send data to device");
}
#if DEBUG
System.Diagnostics.Debug.WriteLine($"[APP -> PINPAD] {data.Dump()}");
#endif
if (data[0] == ControlChars.CAN)
{
Thread.Sleep(100);
return null;
}
while (!_abort)
{
if (_dispatcher.Count > 0)
{
var response = _dispatcher.Dequeue();
if (response != null)
{
if (response is PPNotifyResponse)
{
if (Notify != null && Notify.GetInvocationList().Length > 0)
Notify(response.Message);
continue;
}
return response;
}
}
}
throw new InvalidOperationException("invalidData");
}
public ResponseBase SendData(CommandBase data)
{
var cmd = data.ToBCCommandString();
return SendData(cmd);
}
}
}
我想要實現的代碼波紋管用於Windows的他相同的行爲使用SerialPort類和一個COMxxx端口,這個端口只不過是一個串口藍牙COM與目標設備。
using PI.SDK.Devices.BC.Responses;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Text;
using System.Threading;
namespace PI.SDK.Devices.BC
{
public class SerialDeviceConnectionChannel : IBCDeviceConnectionChannel
{
private SerialPort _port;
private Queue<ResponseBase> _dispatcher;
private bool _abort = false;
public event Action<string> Notify;
public bool IsOpen { get { return _port.IsOpen; } }
public SerialDeviceConnectionChannel(string port)
{
_port = new SerialPort(port, 19200, Parity.None, 8, StopBits.One);
_port.ReadTimeout = 3 * 1000;
_port.WriteTimeout = 3 * 1000;
_port.Encoding = Encoding.GetEncoding(1252);
_port.DataReceived += DataReceived;
}
public void Close()
{
_port.Close();
}
public bool Open()
{
while (true)
{
try
{
_port.Open();
_port.DiscardInBuffer();
_port.DiscardInBuffer();
break;
}
catch { Console.WriteLine($"Trying to connect to {_port}"); }
}
_dispatcher = new Queue<ResponseBase>();
return _port.IsOpen;
}
private void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
var data = _port.ReadExisting();
var dataBuffer = data.ToCharArray();
var synBuilder = new StringBuilder();
foreach (var c in dataBuffer)
{
switch (c)
{
case ControlChars.NACK:
case ControlChars.EOT:
#if DEBUG
Console.WriteLine($"[PINPAD -> APP] {c.ToString().Dump()}");
#endif
_abort = true;
return;
case ControlChars.ACK:
#if DEBUG
Console.WriteLine($"[PINPAD -> APP] {c.ToString().Dump()}");
#endif
continue;
case ControlChars.SYN:
synBuilder.Append(c);
break;
case ControlChars.ETB:
synBuilder.Append(c);
var cmdResponse = synBuilder.ToString();
#if DEBUG
Console.WriteLine($"[PINPAD -> APP] {cmdResponse.Dump()}");
#endif
var response = CommandResponseParser.Parse(cmdResponse);
if (response != null)
{
_dispatcher.Enqueue(response);
}
return;
default:
synBuilder.Append(c);
break;
}
}
}
public ResponseBase SendData(string data)
{
_abort = false;
try
{
_port.Write(data);
}
catch
{
throw new PIException("Unable to send data to device");
}
#if DEBUG
Console.WriteLine($"[APP -> PINPAD] {data.Dump()}");
#endif
if (data[0] == ControlChars.CAN)
{
Thread.Sleep(100);
return null;
}
while (!_abort)
{
if (_dispatcher.Count > 0)
{
var response = _dispatcher.Dequeue();
if (response != null)
{
if (response is PPNotifyResponse)
{
if (Notify != null && Notify.GetInvocationList().Length > 0)
Notify(response.Message);
continue;
}
return response;
}
}
}
throw new InvalidOperationException("invalidData");
}
public ResponseBase SendData(CommandBase data)
{
var cmd = data.ToBCCommandString();
return SendData(cmd);
}
}
}
此代碼在調用_reader.ReadToEnd()時掛起。除Windows以外的所有其他平臺上。看起來我沒有得到迴應。
請注意,Android/iOS/Mono版本必須遵守Windows classe ctor上所述的串行連接配置,以及消息和串行通信的編碼必須爲Windows-1252。
任何幫助指出的錯誤或如何讓它的工作方式與在Windows上相同的方式將不勝感激,因爲沒有SerialPort類,我有點在這些設備上丟失,看起來像藍牙通信是晦澀的時說話關於Xamarin /移動設備。
謝謝!
最好的問候, Gutemberg