Search code examples
c#linuxubuntubluetoothdbus

Bluetooth RFComm on a C# program running on Linux


I haven't found a NuGet package that allows me to do Bluetooth RFComm in a C# program running under Linux.

In addition, I would like to provide a Stream object to the API that will use the bluetooth port.

Linux.Bluetooth (uses Tmds.DBus to access D-Bus) supports only BLE and InTheHand.Net doesn't have GNU/Linux support.

Can anyone suggest a simple strategy for implementing this feature ? To access the D-Bus, I can use Tmds.DBus, but how do I create the Stream object ?

Update : I think it's better to use a C++/Qt (or a Python) program to handle this part and use a TCP socket to communicate between the C# program and the other having access to

Update 2 : I found this article and I don't know if I can create the same type of sockets on a C# program : https://people.csail.mit.edu/albert/bluez-intro/c404.html => No, when compiling the client program, I needed to install this Ubuntu packet : libbluetooth-dev and to link the program to libbluetooth. I can try importing C libraries into the C# program...


Solution

  • A simple solution is to use a virtual serial device to communicate with a Bluetooth device.

    I'm sharing with you a quick and dirty example of how to use the bluetooth port in a C# program running under Ubuntu.

    The program must be launched with the sudo command since SerialPort is unable to open /dev/rfcomm1 (the virtual serial port created with the command rfcomm bind) without root privileges but I think there's an easy workaround to fix that.

    //using InTheHand.Net;
    //using InTheHand.Net.Bluetooth;
    //using InTheHand.Net.Sockets;
    using System;
    using System.Diagnostics;
    using System.IO.Ports;
    using System.Net.Mail;
    using System.Text;
    
    namespace QuickBTTest
    {
        internal class Program
        {
            static void Main(string[] args)
            {
                byte[] outBuffer = new byte[12];
                byte[] inBuffer = new byte[6];
    
                outBuffer[0] = (byte)'$';
                outBuffer[1] = (byte)'P';
                outBuffer[2] = (byte)'R';
                outBuffer[3] = 12;
                outBuffer[4] = 0;
                outBuffer[5] = 100;
                outBuffer[6] = 0;
                outBuffer[7] = 50;
                outBuffer[8] = 0;
                outBuffer[9] = 200;
                ushort cs = 0;
                for (int i = 1; i < 10; i++)
                {
                    cs = (ushort)(cs + outBuffer[i]);
                }
                outBuffer[10] = (byte)(cs >> 8);
                outBuffer[11] = (byte)cs;
    
                string address = "88:6B:0F:84:64:1C";
    
                string devicePath = "/dev/rfcomm0";
                int port = 1;
    
                if (!File.Exists(devicePath))
                {
                    try
                    {
                        Process rfcommProcess = new Process();
                        rfcommProcess.StartInfo.FileName = "sudo";
                        rfcommProcess.StartInfo.Arguments = $"/usr/bin/rfcomm bind {devicePath} {address} {port}";
                        rfcommProcess.StartInfo.UseShellExecute = false;
                        rfcommProcess.StartInfo.RedirectStandardOutput = true;
                        rfcommProcess.StartInfo.RedirectStandardError = true;
                        rfcommProcess.Start();
    
                        /*string error = rfcommProcess.StandardError.ReadToEnd();
    
                        if (!string.IsNullOrWhiteSpace(error))
                        {
                            Console.WriteLine($"Bluetooth bind error : {error}");
                            return;
                        }*/
    
                        rfcommProcess.WaitForExit(3000);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine($"Bluetooth bind error : {e.Message}");
                        return;
                    }
                }
    
                if (File.Exists(devicePath))
                {
                    SerialPort serialPort = new SerialPort();
                    serialPort.PortName = devicePath;
                    serialPort.BaudRate = 115200;
                    serialPort.ReadTimeout = 5000;
    
                    serialPort.Open();
    
                    if (serialPort.IsOpen)
                    {
                        serialPort.Write(outBuffer, 0, outBuffer.Length);
    
                        Console.WriteLine("Wait for response... press enter");
                        Console.ReadLine();
    
                        int ret = serialPort.Read(inBuffer, 0, inBuffer.Length);
                        if (ret > 0)
                        {
                            Console.WriteLine("Rcvd response :");
                            for (int i = 0; i < ret; i++)
                            {
                                Console.Write(inBuffer[i] + ", ");
                            }
                            Console.WriteLine();
                        }
                    }
    
                    serialPort.Close();
    
                    Process tCmd = new Process();
                    tCmd.StartInfo.FileName = "sudo";
                    tCmd.StartInfo.Arguments = $"/usr/bin/rfcomm release {devicePath}";
                    tCmd.StartInfo.UseShellExecute = false;
                    tCmd.StartInfo.RedirectStandardOutput = true;
                    tCmd.StartInfo.RedirectStandardError = true;
                    tCmd.Start();
    
                    string output = tCmd.StandardOutput.ReadToEnd();
                    string err = tCmd.StandardError.ReadToEnd();
    
                    tCmd.WaitForExit(5000);
                }
            }
        }
    }