c# Android - BluetoothServerSocket.Accept gives no result - c#

I am trying to listen at incoming Bluetooth connection thanks to this code based on this documentation:
public void WaitForConnection()
{
BluetoothServerSocket serverSocket = null;
BluetoothAdapter adapter = BluetoothAdapter.DefaultAdapter;
if (adapter == null)
throw new Exception("No Bluetooth adapter found");
if (!adapter.IsEnabled)
throw new Exception("Bluetooth adapter is not enabled");
// Create a new listening server socket
try
{
serverSocket = adapter.ListenUsingRfcommWithServiceRecord("MindCam", UUID.FromString(Ev3UUID));
}
catch (Java.IO.IOException e)
{
Console.WriteLine("Error listening connection: " + e.Message);
}
Task t = Task.Factory.StartNew(() =>
{
while (true)
{
try
{
_socket = serverSocket.Accept();
}
catch (IOException e)
{
Console.WriteLine("Socket's accept() method failed");
break;
}
if (_socket != null)
{
// A connection was accepted.
serverSocket.Close();
Console.WriteLine("Connection accepted");
break;
}
}
});
}
I call this method at the beginning of an activity. I debug that, and it seems that the code is executed until "serverSocket.Accept()", and even if it is not awaited, the code is no more executed. Afterwards, even when I attempt to make a connection from a Bluetooth device (a Mindstorms brick) to the Android device, it is not detected and this thread doesn't continue...
Why doesn't this work ?
Thanks in advance.

Related

Xamarin.Forms (Android) Bluetooth intermittently working

Scenario:
I am building an Android app using Xamarin.Forms that will be deployed to a group of devices. All but one of the devices will be doing some data collection, and the remaining device will be the "hub" to aggregate all of the data and do some reporting. I am using Bluetooth for the device-to-device communication. The 'hub', labelled the master, acts as the client, and all of the collectors act as the server. I have a prototype working with a single server and client...almost.
Occasionally the client/master will be unable to read from the server/collector. I am struggling to find the reason for why this is and would appreciate any help.
Symptoms:
The client's call to .Read() from the InputStream will occasionally block indefinitely, even though the server has written to the output stream. I've added a timeout to this call to prevent the app from getting stuck entirely.
This happens intermittently, but I've found some pattern to when it works and when it doesn't
It seems to be related to the 'server' app, and not the client. The client can remain open, running, and initiate the request to connect to the server as often as needed.
It always works the first time the 'server' app is launched and connected to. It ususally works the second time. By the third connection, .Read() will consistently block/timeout. Closing and reopening the app on the server "cleans the slate" so to speak and it will work again.
Once it starts failing, it seems to be 'stuck' in a failed state.
Removing the app from the foreground (but not closing/killing it) seems to correct the faulted state, and the connection/read will happen successfully as long as the app/UI remains in the background. Once restored to the foreground, it starts failing again.
Code:
All of the bluetooth handling is done by a single class/service that I'm injecting using Xamarin.Forms DependencyService. All of the devices will, on startup (via the constructor of this class), loop indefinitely on a background thread, waiting for connections and repeating. Much of this bluetooth code is based on the Bluetooth Chat example, as well as some other online resources I've found (some android native/java, some Xamarin/C#)
The master will, on demand (triggered by press of a button in the UI), attempt to connect to any collectors (via bonded bluetooth devices) and read data from them. There is also a simple UI component which essentially serves as a console log.
Here is the service class in its entirety.
public class GameDataSyncService : IGameDataSyncService
{
private const string UUID = "8e99f5f1-4a07-4268-9686-3a288326e0a2";
private static Task acceptLoopTask;
private static Task syncDataTask;
private static readonly object locker = new object();
private static bool running = false;
public event EventHandler<DataSyncMessage> MessageBroadcast;
public GameDataSyncService()
{
// Every device will listen and accept incoming connections. The master will make the connections.
lock (locker)
{
if (acceptLoopTask == null)
{
acceptLoopTask = Task.Factory.StartNew(AcceptLoopWorker, TaskCreationOptions.LongRunning);
}
}
}
public void SyncData()
{
lock (locker)
{
if (running)
{
BroadcastMessage("Previous data sync is still running.", DataSyncMessageType.Warning);
return;
}
else
{
running = true;
syncDataTask = Task.Factory.StartNew(SyncDataWorker);
}
}
}
private void BroadcastMessage(string message, DataSyncMessageType type = DataSyncMessageType.Info)
{
MessageBroadcast?.Invoke(this, new DataSyncMessage { Text = message, Type = type });
}
private async Task AcceptLoopWorker()
{
int count = 0;
while (true)
{
BluetoothServerSocket serverSocket = null;
BluetoothSocket clientSocket = null;
try
{
BroadcastMessage($"Listening for incoming connection...", DataSyncMessageType.Debug);
serverSocket = BluetoothAdapter.DefaultAdapter.ListenUsingRfcommWithServiceRecord(nameof(GameDataSyncService), Java.Util.UUID.FromString(UUID));
clientSocket = serverSocket.Accept(); // This call blocks until a connection is established.
BroadcastMessage($"Connection received from {clientSocket.RemoteDevice.Name}. Sending data...", DataSyncMessageType.Info);
var bytes = Encoding.UTF8.GetBytes($"Hello World - {string.Join(" ", Enumerable.Repeat(Guid.NewGuid(), ++count))}");
await clientSocket.OutputStream.WriteAsync(bytes, 0, bytes.Length);
clientSocket.OutputStream.Flush();
// Give the master some time to close the connection from their end
await Task.Delay(1000*3);
}
catch (Exception ex)
{
BroadcastMessage($"{ex.GetType().FullName}: {ex.Message}", DataSyncMessageType.Debug);
}
finally
{
try { clientSocket?.InputStream?.Close(); } catch { }
try { clientSocket?.InputStream?.Dispose(); } catch { }
try { clientSocket?.OutputStream?.Close(); } catch { }
try { clientSocket?.OutputStream?.Dispose(); } catch { }
try { clientSocket?.Close(); } catch { }
try { clientSocket?.Dispose(); } catch { }
try { serverSocket?.Close(); } catch { }
try { serverSocket?.Dispose(); } catch { }
BroadcastMessage($"Connection closed.", DataSyncMessageType.Debug);
}
}
}
private async Task SyncDataWorker()
{
BroadcastMessage($"Beginning data sync...");
foreach (var bondedDevice in BluetoothAdapter.DefaultAdapter.BondedDevices.OrderBy(d => d.Name))
{
BluetoothSocket clientSocket = null;
try
{
clientSocket = bondedDevice.CreateRfcommSocketToServiceRecord(Java.Util.UUID.FromString(UUID));
BroadcastMessage($"Connecting to {bondedDevice.Name}...");
try
{
clientSocket.Connect();
}
catch
{
BroadcastMessage($"Connection to {bondedDevice.Name} failed.", DataSyncMessageType.Error);
}
while (clientSocket.IsConnected)
{
byte[] buffer = new byte[1024];
var readTask = clientSocket.InputStream.ReadAsync(buffer, 0, buffer.Length);
if (await Task.WhenAny(readTask, Task.Delay(1000)) != readTask)
{
BroadcastMessage($"Read timeout...", DataSyncMessageType.Error);
break;
}
int bytes = readTask.Result;
BroadcastMessage($"Read {bytes} bytes.", DataSyncMessageType.Success);
if (bytes > 0)
{
var text = Encoding.UTF8.GetString(buffer.Take(bytes).ToArray());
BroadcastMessage(text, DataSyncMessageType.Success);
break;
}
}
}
catch (Exception ex)
{
BroadcastMessage($"{ex.GetType().FullName}: {ex.Message}", DataSyncMessageType.Debug);
}
finally
{
try { clientSocket?.InputStream?.Close(); } catch { }
try { clientSocket?.InputStream?.Dispose(); } catch { }
try { clientSocket?.OutputStream?.Close(); } catch { }
try { clientSocket?.OutputStream?.Dispose(); } catch { }
try { clientSocket?.Close(); } catch { }
try { clientSocket?.Dispose(); } catch { }
}
}
await Task.Delay(1000 * 3);
BroadcastMessage($"Data sync complete!");
lock (locker)
{
running = false;
}
}
}
What I've tried (nothing below has had any effect):
Most of these were from 'solutions' from other stackoverflow posts.
Adding arbitrary delays into the mix
Making sure to explicitly close/dispose everything, in order, including the streams
Tried replacing the socket handling with their 'Insecure' counterparts.
Adjusting my read timeout to something arbitrarily long, in case a second wasn't enough.
Disabling/Re-enabling bluetooth on the server/collector before .Accept() ing a new connection (resorted to trying random stuff by this point)
Video:
I took a video of this happening.
The tablet in the back is the collector/server The tablet in the foreground is the master/client. When the video starts, the client is displaying some previous attempts, and the server app is in the background (but running). I demonstrate that the .Read works when the collector/server app is in the background, but not the foreground. Each request to begin data sync has a corresponding entry to the "console" (or a warning if I pressed it too soon)
https://youtu.be/NGuGa7upCU4
Summary:
To the best of my knowledge, my code is correct. I have no idea what else to change/fix to get this working more reliably. The actual connection seems like it is successful (based on logs from the server/collector, unfortunately not shown in the video), but the issue lies somewhere in the .Write (or .Read). ANy help, suggestions, or insight would be awesome.
Try the following, changed all to using:
private async Task AcceptLoopWorker()
{
int count = 0;
while (true)
{
try
{
BroadcastMessage("Listening for incoming connection...", DataSyncMessageType.Debug);
using (var serverSocket = BluetoothAdapter.DefaultAdapter.ListenUsingRfcommWithServiceRecord(nameof(GameDataSyncService), Java.Util.UUID.FromString(UUID)))
using (var clientSocket = serverSocket.Accept()) // This call blocks until a connection is established.
{
BroadcastMessage(string.Format("Connection received from {0}. Sending data...", clientSocket.RemoteDevice.Name), DataSyncMessageType.Info);
var bytes = System.Text.Encoding.UTF8.GetBytes(string.Format("Hello World - {0}", string.Join(" ", Enumerable.Repeat(Guid.NewGuid(), ++count))));
await clientSocket.OutputStream.WriteAsync(bytes, 0, bytes.Length);
}
await Task.Delay(1000 * 3); // Give the master some time to close the connection from their end
}
catch (Java.IO.IOException ex)
{
BroadcastMessage(string.Format("IOException {0}: {1}", ex.GetType().FullName, ex.Message), DataSyncMessageType.Debug);
}
catch (Java.Lang.Exception ex)
{
BroadcastMessage(string.Format("Exception {0}: {1}", ex.GetType().FullName, ex.Message), DataSyncMessageType.Debug);
}
}
}
private async Task SyncDataWorker()
{
BroadcastMessage("Beginning data sync...");
foreach (var bondedDevice in BluetoothAdapter.DefaultAdapter.BondedDevices.OrderBy(d => d.Name))
{
try
{
using (var clientSocket = bondedDevice.CreateRfcommSocketToServiceRecord(Java.Util.UUID.FromString(UUID)))
{
BroadcastMessage(string.Format("Connecting to {0}...", bondedDevice.Name));
if (!clientSocket.IsConnected)
{
clientSocket.Connect();
}
if (clientSocket.IsConnected)
{
byte[] buffer = new byte[1024];
var readTask = clientSocket.InputStream.ReadAsync(buffer, 0, buffer.Length);
if (await Task.WhenAny(readTask, Task.Delay(1000)) != readTask)
{
BroadcastMessage("Read timeout...", DataSyncMessageType.Error);
break;
}
int bytes = readTask.Result;
BroadcastMessage(string.Format("Read {0} bytes.", bytes), DataSyncMessageType.Success);
if (bytes > 0)
{
var text = System.Text.Encoding.UTF8.GetString(buffer.Take(bytes).ToArray());
BroadcastMessage(text, DataSyncMessageType.Success);
break;
}
}
else
{
BroadcastMessage("Not Connected...", DataSyncMessageType.Error);
}
}
}
catch (Java.IO.IOException ex)
{
BroadcastMessage(string.Format("IOException {0}: {1}", ex.GetType().FullName, ex.Message), DataSyncMessageType.Debug);
}
catch (Java.Lang.Exception ex)
{
BroadcastMessage(string.Format("Exception {0}: {1}", ex.GetType().FullName, ex.Message), DataSyncMessageType.Debug);
}
}
await Task.Delay(1000 * 3);
BroadcastMessage("Data sync complete!");
lock (locker)
{
running = false;
}
}

Exception after reset serial connection to a different Baud rate

In my application I'm using a 9600 baud rate serial connection and I want to use a 115200 baud rate connection for data transfer.
I've disconnected from the old connection and set it to be null value, and set my serial connection to new connection with different baud rate.
The connection is unstable and I sometimes get a System.ObjectDisposedException - what did I miss?
The connection code
public string startConnection()
{
if (serial != null)
{
serial.Dispose();
}
foreach (string portname in SerialPort.GetPortNames())
{
serial = new SerialPort(portname, 9600, Parity.None, 8, StopBits.One);
serial.ReadTimeout = 5000;
serial.WriteTimeout = 5000;
serial.Handshake = System.IO.Ports.Handshake.None;
serial.NewLine = "\n";
string received = "";
try
{
serial.Open();
serial.DiscardInBuffer();
serial.Write(":09;BATTERY;");
Thread.Sleep(500);
received = serial.ReadLine();
if (received.Contains(";BATTERY;V="))
{
status = SERIAL_CONNECTED;
return portname;
}
}
catch (Exception err)
{
try
{
serial.Close();
status = DISCONNECTED;
}
catch (Exception)
{
// throw;
}
}
}
throw new Exception("couldn't connect to coms");
//return "couldn't connect to coms";
//this.Close();
}
Disconnect function:
public void disconnect ()
{
if (serial == null || serial.IsOpen==false ||status == DISCONNECTED)
return;
status = DISCONNECTED;
serial.Close();
serial = null;
}
The main program is:
private async void BurnOFP_click(object sender, RoutedEventArgs e)
{
startConnection();
some actions.............
disconnect();
var t = new Task(() =>
{
try
{
myUswm.startModemConnection(); // same but with different baud rate
}
catch (Exception e2) { MessageBox.Show(e2.Message); }
});
t.Start();
t.Wait();
modem = new XMODEM_FullDotNET(myUswm.getSerialPort(), XMODEM_FullDotNET.Variants.XModemCRC);
buff = File.ReadAllBytes(softwareFilePath_Text.Text);
if (buff.Length < 1)
{
MessageBox.Show("ERROR : wrong OFP file");
return;
}
if (myUswm.prepareOFPBurning()) // sends u to start transfer
{
if (isBurning == false)
{
isBurning = true;
modem._ProgressSent = 0;
myProgBar = new myProgressBar(modem);
myProgBar.StartTransfer(modem, buff.Length);
myProgBar.Show(); // show window
// got the Exception here!!!!!!!!!!
var t3 = new Task(() =>
{
modem.Send(buff);
});
............
}
else
MessageBox.Show("burning in progress..");
}
}
catch (Exception e1)
{
MessageBox.Show(e1.Message);
}
}
Thanks for any help
RESOLVED
my problem was A bad timing caused by closing and reopen the same port.
I've found the information in MSDN Serial class:
The best practice for any application is to wait for some amount of time after calling the Close method before attempting to call the Open method, as the port may not be closed instantly.
my solution was keeping the connection alive and change the baud rate and update the connection status in my application manually.

Read data from StreamSocketListener on RFComm bluetooth connected device C#

I'm developing an universal application Win8.1 / WP8.1
I'm able to discover and connect to the paired bluetooth devices (Stick readers - Rfid)
This is how I'm connecting
Variables
private IAsyncOperation<RfcommDeviceService> connectService;
private IAsyncAction connectAction;
private RfcommDeviceService rfcommService;
private RfcommServiceProvider rfcommProvider;
private StreamSocketListener listener;
private DataReader reader;
private DataWriter writer;
//Connection
public async Task ConnectToServiceAsync(string name)
{
DeviceInformation serviceInfo = null;
foreach (var device in devices)
{
if(device.Name == name)
{
serviceInfo = device;
break;
}
}
if (serviceInfo != null)
{
this.State = BluetoothConnectionState.Connecting;
try
{
// Initialize the target Bluetooth RFCOMM device service
connectService = RfcommDeviceService.FromIdAsync(serviceInfo.Id);
rfcommService = await connectService;
if (rfcommService != null)
{
rfcommProvider = await RfcommServiceProvider.CreateAsync(rfcommService.ServiceId);
// Create a socket and connect to the target
listener = new StreamSocketListener();
listener.ConnectionReceived += Listener_ConnectionReceived;
connectAction = listener.BindServiceNameAsync(rfcommService.ServiceId.AsString(), SocketProtectionLevel.BluetoothEncryptionAllowNullAuthentication);
await connectAction;//to make it cancellable
writer = new DataWriter(socket.OutputStream);
reader = new DataReader(socket.InputStream);
this.State = BluetoothConnectionState.Connected;
}
else
OnExceptionOccuredEvent(this, new Exception("Unable to create service.\nMake sure that the 'bluetooth.rfcomm' capability is declared with a function of type 'name:serialPort' in Package.appxmanifest."));
}
catch (TaskCanceledException)
{
this.State = BluetoothConnectionState.Disconnected;
}
catch (Exception ex)
{
this.State = BluetoothConnectionState.Disconnected;
OnExceptionOccuredEvent(this, ex);
}
}
}
//Then wait for a connection over the listener
private async void Listener_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
{
DataReader inputreader = new DataReader(args.Socket.InputStream);
while (true)
{
try
{
inputreader.InputStreamOptions = InputStreamOptions.Partial;
// Read first byte (length of the subsequent message, 255 or less).
uint sizeFieldCount = await inputreader.LoadAsync(1);
if (sizeFieldCount != 1)
{
// The underlying socket was closed before we were able to read the whole data.
return;
}
// Read the message.
uint messageLength = inputreader.ReadByte();
uint actualMessageLength = await inputreader.LoadAsync(messageLength);
if (messageLength != actualMessageLength)
{
// The underlying socket was closed before we were able to read the whole data.
return;
}
// Read the message and process it.
string message = inputreader.ReadString(actualMessageLength);
OnMessageReceivedEvent(this, message);
}
catch (Exception ex)
{
if (inputreader != null)
OnExceptionOccuredEvent(this, ex);
}
}
}
The problem is that the Bluetooth Stick Reader never send a connection request, it just read the rfid device ID and sends it over the serial port.
So, I'm able to connect to the device but I don't know how to actively listen or read the incoming data.
Any help will be appreciated.
RFCOMM communication is Client/Server model. You need to define a server to broadcast the service and a client connected to the service.
As I saw from the code you post, it only includes the server side code which provides the service but there was no client connecting to service. Only when the client connected to the service, the ConnectionReceived event will be fired.
I have written a sample which host the RFCOMM service in a console application and consume the service in Windows Runtime App before (Code Sample).
The client code is as following:
rfcommServiceInfoCollection = await DeviceInformation.FindAllAsync(
RfcommDeviceService.GetDeviceSelector(RfcommServiceId.ObexObjectPush));
var count = rfcommServiceInfoCollection.Count;
Debug.WriteLine("Count of RFCOMM Service: " + count);
if(count > 0)
{
lock (this)
{
streamSocket = new StreamSocket();
}
var defaultSvcInfo = rfcommServiceInfoCollection.FirstOrDefault();
rfcommDeviceService = await RfcommDeviceService.FromIdAsync(defaultSvcInfo.Id);
if(rfcommDeviceService == null)
{
Debug.WriteLine("Rfcomm Device Service is NULL, ID = {0}", defaultSvcInfo.Id);
return;
}
Debug.WriteLine("ConnectionHostName: {0}, ConnectionServiceName: {1}", rfcommDeviceService.ConnectionHostName, rfcommDeviceService.ConnectionServiceName);
await streamSocket.ConnectAsync(rfcommDeviceService.ConnectionHostName, rfcommDeviceService.ConnectionServiceName);
By the way, do not forget to add the RFCOMM capabilities in your appxmanifest.
For example:
<m2:DeviceCapability Name="bluetooth.rfcomm">
<m2:Device Id="any">
<m2:Function Type="name:obexObjectPush" />
</m2:Device>
</m2:DeviceCapability
As Jeffrey said, this is a client/Server model, but in my case the client doesn't have any logic, and is not capable to request any connection.
Thank you for your samples, It helped a lot.
After trying several things I got some code working, and a "server" running and listening in the rfcomm service:
public async Task ConnectToServiceAsync(string name)
{
lock(this.interlock)
{
readBuffer = String.Empty;
}
DeviceInformation serviceInfo = null;
foreach (var device in devices)
{
if(device.Name == name)
{
serviceInfo = device;
break;
}
}
if (serviceInfo != null)
{
DeviceName = serviceInfo.Name;
this.State = BluetoothConnectionState.Connecting;
try
{
// Initialize the target Bluetooth RFCOMM device service
connectService = RfcommDeviceService.FromIdAsync(serviceInfo.Id);
rfcommService = await connectService;
if (rfcommService != null)
{
// Create a socket and connect to the target
socket = new StreamSocket();
connectAction = socket.ConnectAsync(rfcommService.ConnectionHostName, rfcommService.ConnectionServiceName, SocketProtectionLevel.BluetoothEncryptionAllowNullAuthentication);
await connectAction;//to make it cancellable
writer = new DataWriter(socket.OutputStream);
reader = new DataReader(socket.InputStream);
State = BluetoothConnectionState.Connected;
Task taskReceive = Task.Run(async () => { ListenForMessagesAsync(socket); });
taskReceive.ConfigureAwait(false);
}
else
OnExceptionOccuredEvent(this, new Exception("Unable to create service.\nMake sure that the 'bluetooth.rfcomm' capability is declared with a function of type 'name:serialPort' in Package.appxmanifest."));
}
catch (TaskCanceledException)
{
this.State = BluetoothConnectionState.Disconnected;
}
catch (Exception ex)
{
this.State = BluetoothConnectionState.Disconnected;
OnExceptionOccuredEvent(this, ex);
}
}
}
And the listener in
private async Task ListenForMessagesAsync(StreamSocket localsocket)
{
while (socket != null)
{
try
{
string message = String.Empty;
DataReader dataReader = new DataReader(localsocket.InputStream);
dataReader.InputStreamOptions = InputStreamOptions.Partial;
// Read the message and process it.
lock (this.interlock)
{
if (!message.Contains("\r\n"))
readBuffer = readBuffer + message;
else
{
var data = message.Split('\r');
readBuffer = readBuffer + data[0];
}
if (readBuffer.Length == 15)
{
readBuffer = readBuffer.Replace("\r\n", "");
OnMessageReceivedEvent(this, readBuffer);
readBuffer = String.Empty;
}
if (readBuffer.Length > 15 || (readBuffer.Length < 15 && readBuffer.Contains("\r\n")))
readBuffer = String.Empty;
}
}
catch (Exception ex)
{
if (socket != null)
OnExceptionOccuredEvent(this, ex);
}
}
}

socket.isConnected returns false

I am writing a pc & phone communication app. The pc code is written in C#. When I connect my phone (which is paired with pc) to my pc, the phone connects however the logs say, the socket is not connected i-e; socket.isConnected() returns false on my phone. I have tried to run this app on multiple phones and the problem persists.
I think the issue is with my C# code as I don't know C# well.
Following is the c# code:
BluetoothListener blueListener = new BluetoothListener(mUUID);
blueListener.Start();
BluetoothClient conn = blueListener.AcceptBluetoothClient();
if(conn.Connected)
updateUI("Mobile connected");
Stream mStream = conn.GetStream();
while (true)
{
try
{
byte[] received = new byte[1024];
mStream.Read(received, 0, received.Length);
//.....
}
catch() {}
}
I am using 32feet library in C#.
Following is my Android code:
BluetoothSocket socket = selectedDevice.createRfcommSocketToServiceRecord(deviceUUID);
try
{
socket = openSocketForSendingData();
try
{
BluetoothAdapter bAdapter = BluetoothAdapter.getDefaultAdapter();
bAdapter.cancelDiscovery();
socket.connect();
Log.e("NP socket", "No Exception");
}
catch(Exception e)
{
Log.e("NP socket Exception", e.toString());
}
if(socket == null)
Log.e("Socket NULL", "socket is null");
if(!socket.isConnected())
{
Log.e("NP socket", "socket not cconnected");
try
{
socket.close();
}
catch(Exception e)
{
Log.e("Socket CLOSE",e.toString());
}
}
else
Log.e("NP socket", "socket cconnected");
if(socket.getOutputStream() == null)
Log.e("Soccket Outupt", "output stream null");
dos = new DataOutputStream(socket.getOutputStream());
dos.writeChars("Hello World I am android");
}
catch(Exception e)
{
Log.e("NP writing socket", e.toString());
}
The UUID in both codes is same.
Can you guide me what mistake am I making?
PS: Before asking this question, I have already spent all day searching the solution on internet, but it was no good.
Regards

Issue with opening and closing serial port

I am currently working on C# application which requires to read serial port. In UI, there is a ON/OFF button which enables user click on it to start and stop reading data from serial port. If I continuously click on the button on and off. It threw an exception - Access to COM3 is denied or even said "The device is not connected". Can anyone suggest a better way to implement the serial port function which is able to resolve the situation as described above? Here is the code I use:
**// Start reading data from serial port**
public override void StartReading(string portname)
{
try
{
int k = int.Parse(portname.Replace("COM", ""));
if (startThread != null)
{
startThread.Abort();
startThread = null;
}
startThread = new Thread(new ThreadStart(delegate
{
isActive = true;
try
{
using (SerialPort sp = new SerialPort(portname))
{
if (!isActive)
{
DisposeBT(sp);
return;
}
sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
if (!isActive)
{
DisposeBT(sp);
return;
}
if (!isActive)
{
DisposeBT(sp);
return;
}
else
{
Thread.Sleep(6500);
try
{
if (sp != null && !sp.IsOpen)
{
sp.Open();
}
}
catch (Exception ex)
{
Logger.Warn("Failed to open the serial port for HRM once. Try it again.");
Logger.Error(ex);
////////////////////// new added below
if(sp !=null && sp.IsOpen)
{
sp.Dispose();
}
Thread.Sleep(6500);
if (IsPortAvailable(k))
{
try
{
if (sp != null && !sp.IsOpen)
{
sp.Open();
}
}
catch (Exception ex1)
{
////////////////////// new added below
if (sp != null && sp.IsOpen)
{
sp.Dispose();
}
Logger.Warn("Failed to open the serial for HRM twice.");
Logger.Error(ex1);
// return;
}
}
}
}
while (true)
{
if (!isActive)
{
DisposeBT(sp);
break;
}
}
if (!isActive)
{
DisposeBT(sp);
return;
}
DisposeBT(sp);
}
}
catch (Exception ex)
{
Logger.Warn("Exception thrown for HRM.");
Logger.Error(ex);
}
}));
startThread.IsBackground = true;
startThread.Priority = ThreadPriority.Highest;
startThread.Start();
}
catch (Exception ex)
{
Logger.Warn("Failed to start reading for HRM02I3A1 bluetooth device.");
Logger.Error(ex);
}
}
// Stop reading data from serial port
public override void StopReading()
{
try
{
isActive = false;
}
catch { }
}
// event handler for the serial port to read data from sp.
void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (isActive)// && startThread.IsAlive
{
SerialPort sp1 = (SerialPort)sender;
try
{
sp1.Read(data, 0, 8);
decoder.Decode(data);
}
catch(Exception ex)
{
Logger.Warn("------data received from Serial Port error for HRM-------");
Logger.Error(ex);
};
}
}
first make background worker thread that accept the cancel event.
in the DoWork method you can write something like that
void DoWork{
// init com port
while(no body cancelled the background worker){
// if there any waiting data receive and process it. do not use event handlers
}
// close the serial port so you can open it again later.
}
Also if you want to cancel the background work it would be a piece of cake
// send cancel command.
// wait till it is canceled.
Try adding startThread.Join() directly after the call to startThread.Abort().
Take a look at the msdn documentation on Thread.Abort and perhaps you also should check what join does.

Categories