IO.Ports exception throw and retry loop - c#

I've been lurking here for a while, and have learned a ton just poking through questions. I'm pretty stumped on something, though. I'm using C#, and I'm trying to use IO.Ports to communicate with a USB device.
I've got code working that assumes the correct serial port, but sometimes my device winds up on a different port when plugged in, and I'd like to be able to run my code without having to change one variable and recompile. So, I want the code to poll the user for a port number, try to open the port, catch IOException when the port name's wrong, and re-poll until a valid port is given.
This is what I have so far:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
namespace USBDev1
{
class Program
{
static void Main(string[] args)
{
String portname = "COM";
SerialPort port = new SerialPort();
port.BaudRate = 9600;
bool loopthing = true;
while (loopthing == true)
{
Console.WriteLine("Which port?");
portname = "COM" + Console.ReadLine();
try
{
port.PortName = portname;
port.Open();
loopthing = false;
}
catch (System.IO.IOException e)
{
Console.WriteLine("Didn't work, yo");
throw (e);
}
}
// Body code
}
}
}

I am not sure what you are asking, but I think you should list the available ports before choosing one. The following code may work; it compiles, but it is not tested.
This is also not a good way to do it. A better way would be to list the ports before you plug in your device, then list the ports again to see the new port that showed up after you plugged in the device.
SerialPort port;
bool isCorrectPortFound = false;
// Try different ports until a device reacts when a character is written to it
while (!isCorrectPortFound)
{
// Get all open ports
string[] ports = SerialPort.GetPortNames();
// Menu choice for a port to select
char portSelect = '0';
// Write the port names to the screen
foreach (string s in ports)
{
portSelect++;
Console.Write(portSelect);
Console.Write(". ");
Console.WriteLine(s);
}
Console.WriteLine();
Console.Write("Select from port 1 to " + portSelect.ToString() + " > ");
int selectedPort = (Console.Read()) - '0'; // Character value of 1 to ...
try
{
// Assume selectedPort is a valid integer, set baud, etc. as per your choice.
port = new SerialPort(ports[selectedPort] /* COMportBaudRate,
COMportParity,
COMportDataBits,
COMportStopBits */);
// OK, port is open, write to the device. The device
// must respond visually, blinking a LED or something.
port.Write("A");
Console.WriteLine();
Console.Write("Did the device get your message? (y n) > ");
int a = (Console.Read()) - 'a';
if (a + 'a' == 'y')
isCorrectPortFound = true;
else
{
port.Close();
port = null;
}
}
catch (Exception ex)
{
// Display a message box, exit, etc.
}
}
// Do other stuff

Related

Why SerialPort only works after button pressed

I Have created some code for communicating with a device over the serialport. By sending certain command with serialPort1.WriteLine I should receive answer with serialPort1.ReadExisting(). Well I'm able to detect the device but I need to read some other information but to get this information correct I only get it when I place the code in a button_Click function. The funny thing is that All is written in a function and I wish to get the information after the device is detected immediately. When I call the function after the device has been detected it doesn't work and when I call the function after the button is pressed I get the correct information. I do not understand why this is so.
The function for detecting the device is like this:
private void detectVM25ToolStripMenuItem_Click(object sender, EventArgs e)
{
// Detect VM25 and show connection is established
String device;
//Search all portnames
String[] ports = SerialPort.GetPortNames();
int totalPorts = ports.Length;
int count = 0 ;
//Test which enabled port is the VM25.
foreach (string port in ports)
{
count = count + 1;
serialPort1.PortName = port;
serialPort1.Open();
if (serialPort1.IsOpen)
{
serialPort1.WriteLine("#S" + Environment.NewLine);
answer = serialPort1.ReadExisting();
if (answer != "")
{
device = answer.Substring(0, 4);
if (device == "VM25")
{
getRecordings();
statusLblDevice.ForeColor = Color.LawnGreen;
statusLblDevice.Text = port + " - " + device + " - Connected";
VM25Port = port;
}
}
else if (answer == "")
{
serialPort1.Close();
if (count == totalPorts)
{
MessageBox.Show("No device found");
}
}
}
}
}
The function getRecordings() should give me data. If I place this function in my form and get called after a button is pressed I get the correct info but when it is inside the above function it doesn't do anything.
private void getRecordings()
{
if (serialPort1.IsOpen)
{
serialPort1.WriteLine("#H" + Environment.NewLine);
memoryInfo = serialPort1.ReadExisting();
label1.Text = memoryInfo;
}
}
Does anybody knows why this is the case? I would like not to have press a button and get this information after it has detected the device. I also tried to create a delay with `Task.Delay()' unfortunately this did not help
It's surely because you have no synchronization whatsoever. .ReadExisting() does not get an entire response, it gets only what's already been received. So calling it right after .WriteLine(...)... well your data hasn't even reached the device yet, so there definitely won't be an answer ready to read.
Since you know the length of your expected answer (or at least the prefix you're interested in), set the read timeout and then call .Read() (or better, .BaseStream.ReadAsync()) with that length.
Even that is only going to mostly work when the port is freshly opened... for subsequent commands you risk getting data in your buffer from the tail end of a reply to an earlier command. Correct use of a serial port really requires the two ends to agree on some sort of framing, whether that is "a message contains only ASCII and ends with CR+LF" or "a message starts with the length of its payload" or some less common scheme.
with the point out of #Ben Voigt I discovered I should tackle this issue different.
I have use the method serialPort1.ReadTo() because I know that each message end with "/a".
therefore I fixed the function as follows
private void detectVM25ToolStripMenuItem_Click(object sender, EventArgs e)
{
// Detect VM25 and show connection is established
String device;
//Search all portnames
String[] ports = SerialPort.GetPortNames();
int totalPorts = ports.Length;
int count = 0 ;
//Test which enabled port is the VM25.
foreach (string port in ports)
{
count = count + 1;
serialPort1.PortName = port;
serialPort1.Open();
if (serialPort1.IsOpen)
{
serialPort1.WriteLine("#S" + Environment.NewLine);
answer = serialPort1.ReadExisting();
if (answer != "")
{
device = answer.Substring(0, 4);
if (device == "VM25")
{
statusLblDevice.ForeColor = Color.LawnGreen;
statusLblDevice.Text = port + " - " + device + " - Connected";
VM25Port = port;
serialPort1.WriteLine("#H" + Environment.NewLine);
string input = serialPort1.ReadTo("/a");
label1.Text = input;
string totalMeasurements = input.Substring(0, 11);
string totalFFT = input.Substring(11, 11);
statusLblMeas.Text = totalMeasurements;
statusLblFFT.Text = totalFFT;
}
}
else if (answer == "")
{
serialPort1.Close();
if (count == totalPorts)
{
MessageBox.Show("No device found");
}
}
}
}
}
Note the changes of reading the serialport where I stated that it should read up to "/a"

C # Serial.read is reading the characters correctly, even with the wrong BaudRate

I'm creating a software in C # that must read the serial port and when recognizing a String (String already known sent by the arduino with BaudRate 38400) it must inform the baudRate used in the reading.
My problem is that no matter what value I put in C # BaudRate, it still recognizes the data correctly.
I tried to change the baudRate on the Arduino, but the result is always the same.
For example, the arduino sends the word "Hello" to a baudRate of 38400. The C # should read the serial port and when recognizing the word Hello (which should only appear with the correct BaudRate) it should display the used baudRate and end the function . However, even setting the baud rate to 1200, 2400 ... etc, ... C # always reads the word "Hello".
On the arduino serial monitor, when I change the speed, the characters are scrambled when I select a different speed than the one configured (as it should happen in C #).
I need C # to receive the scrambled serial data when the baudRate is incorrect.
Snippet of C# code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.IO.Ports;
namespace Baud
{
public partial class frmSerial : Form
{
public static System.IO.Ports.SerialPort serialPort1;
//private delegate void LineReceivedEvent(string line);
public frmSerial()
{
InitializeComponent();
}
private void btnConnect_Click(object sender, EventArgs e)
{
Int32[] lista_bauds = new Int32[] { 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200 };
Boolean connected = false;
System.ComponentModel.IContainer components = new System.ComponentModel.Container();
serialPort1 = new System.IO.Ports.SerialPort(components); // Creating the new object.
for (int i = 0; i < lista_bauds.Length & connected == false; i++)
{
Console.WriteLine(lista_bauds[i]);
string ReceivedData = "";
serialPort1.PortName = "COM" + numCom.Value.ToString(); // Setting what port number.
serialPort1.BaudRate = 1200; // Setting baudrate.
serialPort1.ReadTimeout = 4000;
//serialPort1.DtrEnable = true; // Enable the Data Terminal Ready
serialPort1.Open(); // Open the port for use.
try
{
if (serialPort1.IsOpen == true)
{
ReceivedData = serialPort1.ReadExisting();
Console.WriteLine(ReceivedData);
if (ReceivedData.Equals("Hello") == true)
{
txtDatasend.Text = "Conectado com BaudRate de" + lista_bauds[i]; ;
Console.WriteLine(ReceivedData);
connected = true;
btnConnect.Text = "Conectar";
serialPort1.Close();
}
else
{
serialPort1.Close();
}
}
}
catch (Exception)
{
throw;
}
}
numCom.Enabled = false;
}
private void btnSend_Click(object sender, EventArgs e)
{
// Sends the text as a byte.
serialPort1.Write(new byte[] { Convert.ToByte(txtDatasend.Text) }, 0, 1);
}
}
}
Heres the arduino code:
int LED_Pin = 13; // LED connected to digital pin 13
void setup()
{
Serial.begin(38400); // Configure the baudrate and data format for serial transmission
pinMode(LED_Pin,OUTPUT); // Pin13 as Output
digitalWrite(LED_Pin,LOW); // Pin13 LED OFF
}
void loop()
{
Serial.println("Autenticar"); // Send the String,Use Serial.println() because we have used SerialPort.ReadLine() on C# side
// SerialPort.ReadLine() on C# side will return only after receiving '/n' character
Blink_LED(); // Blink LED to indicate transmission
}
//Function to Blink LED 13
void Blink_LED()
{
digitalWrite(LED_Pin,HIGH);
delay(100);
digitalWrite(LED_Pin,LOW);
delay(100);
}

Interfacing Arduino with pc GUI using 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

Accessing Bluetooth data via Serialport in C#

So I'm working in Unity3D, programming in C#, and I heard that one can read data from a Bluetooth adaptor via SerialPort. I have several Bluetooth USB adaptors that I've tried to connect on my PC using this method. However, when I try to open the SerialPort, I get an error message that says port does not exist. I only included the code relevant to the question, but portI is a string ("COM11" or "COM12") and PortIn is of type SerialPort.
void OnGUI() {
GUI.Label(new Rect(btnX, btnY, btnW, btnH), "PortIn = " + portI);
if(!connected) {
for (int i = 0; i<ports.Length; i++) {
if(GUI.Button(new Rect(btnX, btnY + btnH + (btnH * i), btnW, btnH), ports[i])) {
portI = ports[i];
}
}
}
if(GUI.Button(new Rect(btnX + (btnW * 2 + 20), btnY, btnW, btnH), "Connect")) {
portIn = new SerialPort(portI, 9600);
portIn.ReadTimeout = 1000;
if (!portIn.IsOpen) {
portIn.Open();
}
connected = true;
}
}
}
Here is some code I'm working on and it gets data from the bluetooth connection to a standalone pc build (or in the editor) as long as the COM port (in my case COM9) is the same as the bluetooth device when you pair it.
After you pair it go to Bluetooth Settings > COM Ports and see what port is there with the name of your device. It might say COM8 or COM9 or whatever. If the device is paired and the COM Port is the same in the code as it is in your Bluetooth Settings, AND the timeout number and baud rate are the same as in the application you are sending the data from... then you will get something from this code when you run it. This is just meant to help make a connection to the serial over bluetooth connection.
Hope it helps someone. I've gotten a lot of great advice from reading these forums ;)
using System.Collections;
using System.IO.Ports;
public class checker : MonoBehaviour {
public static SerialPort sp = new SerialPort("COM9", 9600, Parity.None, 8, StopBits.One);
public string message, message1;
public string message2;
void Start() {
OpenConnection();
}
void Update() {
message2 = sp.ReadLine();
}
void OnGUI() {
GUI.Label(new Rect(10, 180, 100, 220), "Sensor1: " + message2);
}
public void OpenConnection() {
if (sp != null)
{
if (sp.IsOpen)
{
sp.Close();
message = "Closing port, because it was already open!";
}
else
{
sp.Open();
sp.ReadTimeout = 1000;
message = "Port Opened!";
}
}
else
{
if (sp.IsOpen)
{
print("Port is already open");
}
else
{
print("Port == null");
}
}
}
void OnApplicationQuit() {
sp.Close();
}
}
It should be possible. The bluetooth rfcomm/spp services emulate a serial port. A COM port if it's on Windows. Baudrate doesn't matter in this emulation, it will always go as fast as possible.
You need to have the devices paired and connected though.
To what device are you connecting? Try to make a connection first with Putty or some terminal application.

List available COM ports

I have a very small code that shows available COM ports.
My question is:
Is there an easy way to have the program to run in the tray and only popup when a new COM port is available and is it possible to add the name for the COM port that you can see in device manager ec "USB serial port"?
I often add/remove a USB->RS232 comverter and find it a pain in the ass because I must go into the device manger to see what COM port it is assigned to. It's not the same each time
Maybe there already is a small app that can do this but I havent found it on Google yet
using System;
using System.Windows.Forms;
using System.IO.Ports;
namespace Available_COMports
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//show list of valid com ports
foreach (string s in SerialPort.GetPortNames())
{
listBox1.Items.Add(s);
}
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
}
}
}
public static void Main()
{
// Get a list of serial port names.
string[] ports = SerialPort.GetPortNames();
Console.WriteLine("The following serial ports were found:");
// Display each port name to the console.
foreach(string port in ports)
{
Console.WriteLine(port);
}
Console.ReadLine();
}
Take a look at this question. It uses WMI to find available COM ports. You could keep track of what COM ports exist, and only notify about new ones.
To find out when devices are hot-plugged, you want to handle WM_DEVICECHANGE. Call RegisterDeviceNotification to enable delivery of these notifications.
The code to get the COM number of certain device.
List<USBDeviceInfo> devices = new List<USBDeviceInfo>();
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("root\\CIMV2",
"SELECT * FROM Win32_PnPEntity");
foreach (ManagementObject queryObj in searcher.Get())
{
devices.Add(new USBDeviceInfo(
(string)queryObj["DeviceID"],
(string)queryObj["PNPDeviceID"],
(string)queryObj["Name"]
));
}
foreach (USBDeviceInfo usbDevice in devices)
{
if (usbDevice.Description != null)
{
if (usbDevice.Description.Contains("NAME OF Device You are Looking for")) //use your own device's name
{
int i = usbDevice.Description.IndexOf("COM");
char[] arr = usbDevice.Description.ToCharArray();
str = "COM" + arr[i + 3];
if (arr[i + 4] != ')')
{
str += arr[i + 4];
}
break;
}
}
}
mySerialPort = new SerialPort(str);

Categories

Resources