Interfacing Arduino with pc GUI using C# - c#

I am just a beginner in c#. I am now trying to interface arduino with a GUI application. And i need a small function to automatically detect the port which I have connected Arduino. I tried using nested "try and catch" blocks but it failed. can anyone suggest a good way to automatic select the port in which arduino is connected and open that port such that we can move directly to coding other switches that do different functions in that arduino.

Recently i had the same situation and i wrote this method to check for our device, all you need to set your device to send specific Pattern on Specific input. In this example if you send 0x33 then your device have to send 0x8A to identify itself.
public enum SerialSignal
{
SendSync = 0x33,
ReceiveSync = 0x8A,
}
private static SerialPort _arduinoSerialPort ;
/// <summary>
/// Polls all serial port and check for our device connected or not
/// </summary>
/// <returns>True: if our device is connected</returns>
public static bool Initialize()
{
var serialPortNames = SerialPort.GetPortNames();
foreach (var serialPortName in serialPortNames)
{
try
{
_arduinoSerialPort = new SerialPort(serialPortName) { BaudRate = 9600 };
_arduinoSerialPort.Open();
_arduinoSerialPort.DiscardInBuffer();
_arduinoSerialPort.Write(new byte[] { (int)SerialSignal.SendSync }, 0, 1);
var readBuffer = new byte[1];
Thread.Sleep(500);
_arduinoSerialPort.ReadTimeout = 5000;
_arduinoSerialPort.WriteTimeout = 5000;
_arduinoSerialPort.Read(readBuffer, 0, 1);
// Check if it is our device or Not;
if (readBuffer[0] == (byte)SerialSignal.ReceiveSync){
return true;
}
}
catch (Exception ex)
{
Debug.WriteLine("Exception at Serial Port:" + serialPortName + Environment.NewLine +
"Additional Message: " + ex.Message);
}
// if the send Sync repply not received just release resourceses
if (_arduinoSerialPort != null) _arduinoSerialPort.Dispose();
}
return false;
}

public partial class Form1 : Form
{
SerialPort serial = new SerialPort();
static SerialPort cport;
public Form1()
{
InitializeComponent();
button1.Enabled = true;
button2.Enabled = false;
button3.Enabled = false;
}
private void button1_Click(object sender, EventArgs e)
{
int i;
try
{
string[] ports = SerialPort.GetPortNames();
foreach(string newport in ports)
{
cport = new SerialPort(newport, 9600);
cport.Open();
cport.WriteLine("A");
int intReturnASCII = serial.ReadByte();
char returnMessage = Convert.ToChar(intReturnASCII);
if (returnMessage == 'B')
{
button2.Enabled = true;
break;
}
else
{
cport.Close();
}
}
}
catch (Exception )
{
Console.WriteLine("No COM ports found");
}
}

I undertand that I'm a bit late, But I have created a simple and free C# NuGet library that allows for interaction between the host PC and an Arduino board!
Examples in the ReadMe.txt file.
ArduinoFace - NuGet

Related

Reading Serial Data from Arduino in Windows Forms Application

I am currently trying to build a windows forms app that gets sensor data from an arduino via the serial com.
when checking in the arduino IDE the data gets writen into the serial port correctly.
But i can't figure out how to read the data via c#.
class Program
{
static SerialPort SP;
static void Main(string[] args)
{
SP = new SerialPort();
SP.PortName = "COM7";
SP.BaudRate = 9600;
SP.Handshake = System.IO.Ports.Handshake.RequestToSend;
SP.Open();
while (true)
{
Console.WriteLine(DateTime.Now.ToString() + " : " + SP.ReadLine());
}
}
}
My guess is that the Port is not properly set up, but i have no idea what i am missing.
The Goal is just to receive strings from the arduino, i do not necessarily need to send any data to the arduino.
edit: i am working with an arduino micro
Did you close Arduino IDE?
You need to add a wait code before reading from the port
Below is a working example:
private SerialPort _currentPort = new SerialPort("COM7", 9600);
private readonly object _sync = new object();
public bool Open()
{
_currentPort.Encoding = Encoding.UTF8;
_currentPort.DtrEnable = true;
_currentPort.ReadTimeout = 2000;
try
{
if (!_currentPort.IsOpen)
lock (_sync)
{
if (_currentPort.IsOpen)
return true;
_currentPort.Open();
System.Threading.Thread.Sleep(1500);
}
}
catch (Exception e)
{
//_localLogger?.Error($"{_currentPort.PortName}, {e.Message}", e);
return false;
}
return _currentPort.IsOpen;
}
public bool Subscribe()
{
try
{
if (Open())
{
_currentPort.DataReceived += CurrentPortOnDataReceived;
return true;
}
return false;
}
catch (Exception e)
{
//_localLogger?.Error($"{_currentPort.PortName}, {e.Message}", e);
return false;
}
}
private void CurrentPortOnDataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (!_currentPort.IsOpen)
{
//_localLogger.Info($"{_currentPort} is closed");
Open();
}
Console.WriteLine(_currentPort.ReadExisting());
}

Closing a USB serial port leaves the port unavailable

My app uses USB based serial ports to connect to physical hardware devices. I can open any valid USB port and communicate with the external devices. However, when I close the connection, the USB port is left in some sort of indeterminate state for some time, and during that time further attempts to reconnect result in the "Access to port "COM--" is denied" error. However, after some few seconds, attempting to reconnect is successful. How can I determine WHEN the USB port will again support a new connection?
The code looks like this:
private void Setup(string Port)
{
bool ValidPort = false;
int CloseSleep = 10;
_PortName = Port;
_PortType = this;
string[] AvailablePorts = SerialPort.GetPortNames();
foreach(string aPort in AvailablePorts)
{
if (aPort == _PortName)
{
// The required port is listed in the list of available ports)
ValidPort = true;
break;
}
}
if (ValidPort)
{
try
{
if (_ThePort != null)
{
_ThePort.Close();
_ThePort.DataReceived -= ReceivedDataEventHandler;
while(CloseSleep-- > 0)
System.Threading.Thread.Sleep(100);
_ThePort.Dispose();
_ThePort = null;
}
}
catch (Exception ex)
{
EMS_Config_Tool.ModalDialog md = new EMS_Config_Tool.ModalDialog("Closing Port: " + ex.Message, "System Exception");
md.ShowDialog();
}
System.IO.Ports.SerialPort TheNewPort = new System.IO.Ports.SerialPort(Port, 38400);
// Setup the event handlers from Tx and Rx
Handler.DataOutEvent += CommsSender;
TheNewPort.DataReceived += ReceivedDataEventHandler;
TheNewPort.DataBits = 8;
TheNewPort.Parity = Parity.None;
TheNewPort.Handshake = System.IO.Ports.Handshake.None;
TheNewPort.StopBits = System.IO.Ports.StopBits.One;
// We will try 3 times to open the port, and report an error if we fail to open the port
try
{
TheNewPort.Open();
}
catch (Exception)
{
System.Threading.Thread.Sleep(1000);
try
{
TheNewPort.Open();
}
catch (Exception)
{
System.Threading.Thread.Sleep(1000);
try
{
TheNewPort.Open();
}
catch (Exception ex)
{
EMS_Config_Tool.ModalDialog md = new EMS_Config_Tool.ModalDialog("Opening Port: " + ex.Message, "System Exception");
return;
}
}
}
The final catch statement is where the error about Access being denied is issued. Note my attempt to retry opening the port 3 times doesn't really help. If I leave the port alone for about 5 to 10 seconds and retry calling the Setup method it succeeds immediately.
As #Neil said, there are many issues. The best thing to do, in my point of view, is to put the search in a loop, and as soon as the port can be opened, it will be.
I used to do like this :
public Task WaitingPort()
{
while (port is null)
{
port = CheckPort();
}
}
private SerialPort CheckPort()
{
string[] listPort = SerialPort.GetPortNames();
foreach(string namePort in listPort)
{
SerialPort port = new SerialPort(namePort, 9600);
if (!port.IsOpen)
{
try
{
port.Open();
port.ReadTimeout = 1500;
string data = port.Readline();
// I programmed my device to send an "A" until it receives
// "777" to be able to recognize it once opened
if (data.Substring(0, 1) == "A")
{
port.ReadTimeout = 200;
port.Write("777"); // to make it stop sending "A"
return port;
}
else
{
port.Close();
}
}
catch (Exception e1)
{
port.Close();
}
}
}
return null;
}
Of course, this is just some kind of a template which you have to reshape to your use
I have amended my code to use a constrained loop to give it a better chance to work, which it usually does. I was hoping that there was a better way to do it, as I tend to have pretty impatient users who will be posting defect reports if they have to wait 5 or 10 seconds to make a connection....
// We will try several times to open the port, upto 10 times over 5 seconds, and report an error if we finally fail to open the port
try
{
TheNewPort.Open();
}
catch (Exception ex)
{
RetryOpenTimer.Interval = 500;
RetryCount = 10;
RetryOpenTimer.Elapsed += new System.Timers.ElapsedEventHandler(RetryOpenTimer_Elapsed);
WaitForOpen = true;
RetryOpenTimer.Start();
while (WaitForOpen && RetryCount > 0)
{
System.Threading.Thread.Sleep(500);
}
if (WaitForOpen)
{
EMS_Config_Tool.ModalDialog md = new EMS_Config_Tool.ModalDialog("Opening Port: " + ex.Message, "System Exception");
return;
}
}
...
void RetryOpenTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
RetryOpenTimer.Stop();
RetryOpenTimer.Elapsed -= RetryOpenTimer_Elapsed;
try
{
if (RetryCount-- > 0)
{
TheNewPort.Open();
WaitForOpen = false;
}
else
return;
}
catch (Exception)
{
RetryOpenTimer.Start();
RetryOpenTimer.Elapsed += RetryOpenTimer_Elapsed;
}
}

Bluetooth connection getting read failed, socket might closed or timeout, read ret: -1

I am creating an app in Xamarin(Android app), that allows user to send data on his phone via bluetooth connection to another phone. When I click the button it should run the bluetooth getAllPairedDevices and then openConnection, but when it tries to connect it goes into throw exception.
This string sets data variable:
private string data = null;
This is my call button, that checks if any devices are paired:
Button btConnect = FindViewById<Button>(Resource.Id.connect);
btConnect.Click += (sender, e) =>
{
BluetoothManager manager = new BluetoothManager();
if (manager.getAllPairedDevices() != false)
{
System.Threading.Thread thread = new System.Threading.Thread(() =>
{
while (true)
{
data = manager.getDataFromDevice();
}
});
thread.IsBackground = true;
thread.Start();
}
};
And then this is my bluetooth class:
public class BluetoothManager
{
// Unique ID for connecting
private const string UuidUniverseProfile = "00001101-0000-1000-8000-00805f9b34fb";
// Incoming bluetooth data from UART
private BluetoothDevice result;
// Input/Output stream of this communication
private BluetoothSocket mSocket;
// Convert byte[] to strings
private BufferedReader reader;
private System.IO.Stream mStream;
private InputStreamReader mReader;
public BluetoothManager()
{
reader = null;
}
private UUID getUUIDfromString()
{
return UUID.FromString(UuidUniverseProfile);
}
private void close(IDisposable connectedObject)
{
if (connectedObject == null) return;
try
{
connectedObject.Dispose();
}
catch (Exception ex)
{
throw ex;
}
connectedObject = null;
}
private void openDeviceConnection(BluetoothDevice btDevice)
{
try
{
// Getting socket from specific device
mSocket = btDevice.CreateRfcommSocketToServiceRecord(getUUIDfromString());
mSocket.Connect();
// Input stream
mStream = mSocket.InputStream;
// Output stream
//mStream.OutputStream;
mReader = new InputStreamReader(mStream);
reader = new BufferedReader(mReader);
System.Threading.Thread.Sleep(1000);
mSocket.Close();
}
catch (IOException ex)
{
close(mSocket);
close(mStream);
close(mReader);
throw ex;
}
}
public String getDataFromDevice()
{
return reader.ReadLine();
}
public bool getAllPairedDevices()
{
// Default android phone bluetooth
BluetoothAdapter btAdapter = BluetoothAdapter.DefaultAdapter;
var devices = btAdapter.BondedDevices;
if (devices != null && devices.Count > 0)
{
// All paired devices
foreach (BluetoothDevice mDevice in devices)
{
openDeviceConnection(mDevice);
}
return true;
}
else
{
return false;
}
}
}
Since I am new to Bluetooth communication I am not exactly sure where the problem is, I already checked multiple answers, and android.library but it is so complicated, so no luck.
Also a subquestion, how would you send a simple string via this setup?

Broadcast from bluetooth server to multiple bluetooth clients with 32feet

I have an issue about the server-client communication.
I googled around but I did not find a solution to this.
Right now I am using 32feet in order to get in touch 2 or more (till 7) BT clients to 1 BT server.
I need to broadcast a message from the server to every device in the same time, but I don't know how to do it.
The only way I figured out was to use the list of connection in order to send the message one per time, but it means a delay between each message sent (around 100 ms per device). Unfortunately it means to have a large delay on the last one.
Can someone please give me an advice on how to solve this problem?
Is there a way to broadcast the message to all devices in the same time?
If it can be helpfull, here there is the handle of connection and reading from devices.
Thanks for your help
private void btnStartServer_Click(object sender, EventArgs e)
{
btnStartClient.Enabled = false;
ConnectAsServer();
}
private void ConnectAsServer()
{
connessioniServer = new List<BluetoothClient>();
// thread handshake
Thread bluetoothConnectionControlThread = new Thread(new ThreadStart(ServerControlThread));
bluetoothConnectionControlThread.IsBackground = true;
bluetoothConnectionControlThread.Start();
// thread connessione
Thread bluetoothServerThread = new Thread(new ThreadStart(ServerConnectThread));
bluetoothServerThread.IsBackground = true;
bluetoothServerThread.Start();
}
private void ServerControlThread()
{
while (true)
{
foreach (BluetoothClient cc in connessioniServer)
{
if (!cc.Connected)
{
connessioniServer.Remove(cc);
break;
}
}
updateConnList();
Thread.Sleep(0);
}
}
Guid mUUID = new Guid("fc5ffc49-00e3-4c8b-9cf1-6b72aad1001a");
private void ServerConnectThread()
{
updateUI("server started");
BluetoothListener blueListener = new BluetoothListener(mUUID);
blueListener.Start();
while (true)
{
BluetoothClient conn = blueListener.AcceptBluetoothClient();
connessioniServer.Add(conn);
Thread appoggio = new Thread(new ParameterizedThreadStart(ThreadAscoltoClient));
appoggio.IsBackground = true;
appoggio.Start(conn);
updateUI(conn.RemoteMachineName+" has connected");
}
}
private void ThreadAscoltoClient(object obj)
{
BluetoothClient clientServer = (BluetoothClient)obj;
Stream streamServer = clientServer.GetStream();
streamServer.ReadTimeout=1000;
while (clientServer.Connected)
{
try
{
int bytesDaLeggere = clientServer.Available;
if (bytesDaLeggere > 0)
{
byte[] bytesLetti = new byte[bytesDaLeggere];
int byteLetti = 0;
while (bytesDaLeggere > 0)
{
int bytesDavveroLetti = streamServer.Read(bytesLetti, byteLetti, bytesDaLeggere);
bytesDaLeggere -= bytesDavveroLetti;
byteLetti += bytesDavveroLetti;
}
updateUI("message sent from "+clientServer.RemoteMachineName+": " + System.Text.Encoding.Default.GetString(bytesLetti));
}
}
catch { }
Thread.Sleep(0);
}
updateUI(clientServer.RemoteMachineName + " has gone");
}
private void updateUI(string message)
{
Func<int> del = delegate()
{
textBox1.AppendText(message + System.Environment.NewLine);
return 0;
};
Invoke(del);
}
private void updateConnList()
{
Func<int> del = delegate()
{
listaSensori.Items.Clear();
foreach (BluetoothClient d in connessioniServer)
{
listaSensori.Items.Add(d.RemoteMachineName);
}
return 0;
};
try
{
Invoke(del);
}
catch { }
}
I don't exactly understand how you do it right now (the italian names are not helping...) but maybe my solution can help you.
first of all, bluetooth classic does not support broadcast. so you have to deliver at one at a time.
i do connect to 7 serial port devices at a time, using 7 threads. then i tell every thread to send data. this is very close to same time, but of course not exactly.
let me know if that helps or if you need a code example.

Appending strings received within a subscriber method?

In the code below, the strings received within myReceivedLines appear when connecting with my serial port (when connecttodevice is true). However they disapear when I launch another command (when homeall is true).
I added the field called myReceivedLines within the class so that I could use the method String.Add() to all the feedback received and commands sent (having like a console within the program).
Why does the feedback dispear when a command is sent and how can I make sure all the strings stay in the variable myReceivedLines? Is the string going to myReceivedLine disapearing because they happen within a subscriber method? How do I solve that?
NB: GH_DataAccess.SetDataList(Int32, IEnumerable) is a method from the Kernel a software called Grasshopper to assign values to an output (it has to be used within the GH_Component.SolveInstance() method which is also from this Kernel), I am using this to visualise myReceivedLines.
code:
public class SendToPrintComponent : GH_Component
{
//Fields
List<string> myReceivedLines = new List<string>();
SerialPort port;
//subscriber method for the port.DataReceived Event
private void DataReceivedHandler(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
while (sp.BytesToRead > 0)
{
try
{
myReceivedLines.Add(sp.ReadLine());
}
catch (TimeoutException)
{
break;
}
}
}
protected override void SolveInstance(IGH_DataAccess DA)
{
//Opening the port
if (port == null)
{
string selectedportname = default(string);
DA.GetData(1, ref selectedportname);
int selectedbaudrate = default(int);
DA.GetData(2, ref selectedbaudrate);
//Assigning an object to the field within the SolveInstance method()
port = new SerialPort(selectedportname, selectedbaudrate, Parity.None, 8, StopBits.One);
//Enables the data terminal ready (dtr) signal during serial communication (handshaking)
port.DtrEnable = true;
port.WriteTimeout = 500;
port.ReadTimeout = 500;
}
//Event Handling Method
bool connecttodevice = default(bool);
DA.GetData(3, ref connecttodevice);
**if (connecttodevice == true)**
{
if (!port.IsOpen)
{
port.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
DA.SetDataList(0, myReceivedLines);
port.Open();
}
}
else
if (port.IsOpen)
{
port.DataReceived -= new SerialDataReceivedEventHandler(DataReceivedHandler);
port.Close();
}
if (port.IsOpen)
{
DA.SetData(1, "Port Open");
}
//If the port is open do all the rest
if (port.IsOpen)
{
bool homeall = default(bool);
DA.GetData(5, ref homeall);
//Home all sends all the axis to the origin
**if (homeall == true)**
{
port.Write("G28" + "\n");
myReceivedLines.Add("G28" + "\n");
DA.SetDataList(2, myReceivedLines);
}
}
else
{
DA.SetData(1, "Port Closed");
}
}
}
If you are trying to append to a string, I would reccomend a StringBuilder object.
Or the less cleaner resolution, use the += operator,
string s = "abcd";
s+="efgh";
Console.WriteLine(s); //s prints abcdefgh
First of all your variables (myReceivedLines and port) are not static. I'm not sure if you want them to be static because I can't see how your using SendToPrintComponent class.
And could you explain DA.SetDataList(0, myReceivedLines); or better yet include the code because the problem could be there...

Categories

Resources