I've recently started a new job and been drafted on to a project that's running late. My task was initially to add Bluetooth connectivity to a C# app, but at the request of a more senior colleague I've had to write a standalone executable to open up two Bluetooth connections and forward any data sent/received from the Bluetooth devices over two TCP connections. The Code also listens to the TCP connections and forwards messages on to the Bluetooth device.
When the Network connection is closed by the client the Bluetooth connection also dies, this was requested behaviour.
The code works as it's required to from the tests that I've done, but I don't have much experience with C# or Bluetooth. The implementation I have written spawns a few threads which I would ideally reduce, and I'm looking for ways to possibly improve reliability - although it's worked in testing I'd like to make this a bullet-proof as possible as it seems like it's going to form the crux of the product we're making.
I should add that the code uses the 32feet.Net library to find and connect to Bluetooth devices.
Main Method
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace BluetoothManager
{
class Program
{
static void Main(string[] args)
{
BTManager rover_btm = new BTManager();
BTManager base_btm = new BTManager();
base_btm.Port = 0xba5e;
rover_btm.Port = 17825;
base_btm.Name = "Base";
rover_btm.Name = "Rover";
base_btm.match = (args.Length >= 1 && args[0] != "") ? args[0] : "baseBT";
rover_btm.match = (args.Length >= 2 && args[1] != "") ? args[1] : "roverBT";
if (rover_btm.match == base_btm.match)
{
Console.WriteLine("WARNING: The rover and base names are the same, this can be problematic");
}
Console.WriteLine("Base Station match: " + base_btm.match);
Console.WriteLine("Rover match: " + rover_btm.match);
Thread Base = new Thread(new ThreadStart(base_btm.HandleThread));
Thread Rover = new Thread(new ThreadStart(rover_btm.HandleThread));
Base.Start();
Rover.Start();
Base.Join();
Rover.Join();
Console.Read();
}
}
}
Bluetooth Manager
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using InTheHand.Net.Bluetooth;
using InTheHand.Net.Ports;
using InTheHand.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using Microsoft.Win32;
using System.IO;
namespace BluetoothManager
{
class BTManager
{
private static BluetoothDeviceInfo[] peers;
private BluetoothClient client;
private bool _isConnected = false;
private string _match;
private const string defpin = "0000";
private TcpListener tcpListener;
private int _port;
private string _name = "Not Named";
private NetworkStream networkStream;
private Stream bluetoothStream;
private byte[] fromNetwork = new byte[1024];
private byte[] fromBluetooth = new byte[1024];
private ManualResetEvent bluetoothRecievedEvent = new ManualResetEvent(false);
private TcpClient TcpClient;
public string Name
{
get { return _name; }
set { _name = value; }
}
public int Port
{
get { return _port; }
set { _port = value; }
}
public bool IsConnected
{
get { return _isConnected; }
private set { _isConnected = value; }
}
public string match
{
get { return _match; }
set { _match = value; }
}
public BTManager()
{
}
private void nullEverything()
{
if (client != null)
{
client = null;
}
if (TcpClient != null)
{
TcpClient.Close();
TcpClient = null;
}
if (tcpListener != null)
{
tcpListener.Stop();
tcpListener = null;
}
if (networkStream != null)
{
networkStream.Flush();
networkStream.Close();
networkStream = null;
}
if (bluetoothStream != null)
{
bluetoothStream.Flush();
bluetoothStream.Close();
bluetoothStream = null;
}
}
public void HandleThread()
{
nullEverything();
client = new BluetoothClient();
//client.Close();
BluetoothDeviceInfo device;
while (!this.findDevice(out device)) ;
Console.WriteLine("About to pair");
int count = 0;
int max = 5;
while ((!(BluetoothSecurity.PairRequest(device.DeviceAddress, defpin))) && count < max)
{
Console.WriteLine("Pairing Failed, retrying");
count++;
Thread.Sleep(100);
}
if (count == max)
{
HandleThread();
}
else
{
Console.WriteLine("Paired..Beginning connect");
client.BeginConnect(device.DeviceAddress, BluetoothService.SerialPort, this.callback, client);
}
}
private void callback(IAsyncResult result)
{
client.EndConnect(result);
this.tcpListener = new TcpListener(IPAddress.Loopback, _port);
this.tcpListener.Start();
this.TcpClient = this.tcpListener.AcceptTcpClient();
this.networkStream = TcpClient.GetStream();
this.bluetoothStream = client.GetStream();
this.bluetoothStream.ReadTimeout = 10000;
while (client.Connected && TcpClient.Connected)
{
try
{
if (networkStream.CanRead)
{
Array.Clear(this.fromNetwork, 0, 1024);
if (networkStream.DataAvailable)
{
networkStream.Read(this.fromNetwork, 0, 1024);
Console.WriteLine(Encoding.ASCII.GetString(fromNetwork));
}
bluetoothStream.Write(fromNetwork, 0, 1024);
bluetoothStream.Flush();
Array.Clear(fromBluetooth, 0, 1024);
bluetoothRecievedEvent.Reset();
this.bluetoothStream.BeginRead(this.fromBluetooth, 0, 1024, this.bluetoothReceived, this.bluetoothStream);
if (!bluetoothRecievedEvent.WaitOne(new TimeSpan(0, 0, 0, 10)))
{
Console.WriteLine("Bluetooth Timeout Reached");
break;
}
}
}
catch (Exception e)
{
Console.WriteLine("Either Network Connection cancelled or Bluetooth failed");
Console.WriteLine(e.Message);
}
}
client.Close();
TcpClient.Close();
tcpListener.Stop();
this.HandleThread();
}
private void bluetoothReceived(IAsyncResult result)
{
try
{
networkStream.Write(fromBluetooth, 0, 1024);
networkStream.Flush();
Array.Clear(fromBluetooth, 0, 1024);
bluetoothRecievedEvent.Set();
}
catch (Exception e)
{
Console.WriteLine("Network write operation failed");
Console.WriteLine(e.Message);
}
}
private bool findDevice(out BluetoothDeviceInfo device)
{
peers = client.DiscoverDevicesInRange();
device = Array.Find(peers, element => element.DeviceName == match);
foreach (BluetoothDeviceInfo btdi in peers)
{
Console.WriteLine(btdi.DeviceName);
}
if (device == null)
{
Console.WriteLine(Name +": Not Found");
return false;
}
else
{
Console.WriteLine(Name +": Found");
return true;
}
}
}
}