C# GUI gets Error But Arduino Connects Perfectly

Hi,

I have been creating a GUI in C# to interface with a MC I have. I've had success doing just this using one computer but when I switch it to a laptop I get the error:

"The port selected is not a COM/com port, or does not resolve to a valid serial port.
Parameter name: portName"

I'm not 100% what the problem is. The Arduino interface works fine using the laptop, but only when I use my GUI on the laptop does it not work.

I have been using the following code:

string[] ports = System.IO.Ports.SerialPort.GetPortNames();

//Check ports to find the one that board is connected to
foreach (var port in ports)
{
timeoutcheck = 0;
try
{
usb.BaudRate = 38400;
usb.PortName = port;
//usb.PortName = "COM10:";
MessageBox.Show(port,port,MessageBoxButtons.OK);

usb.Open();

Now what confuses me is that It works perfectly on another computer I am using, and the arduino interface has no problem connecting on the laptop.

The Board seems to connect on "COM10" on the laptop. I've read on other forums that my printer drivers may be blocking the port. If thats so is there an easy way to either create a completely new and unused port that the laptoc can detect when I plug in my board, OR bypass the blockage?

Any thoughts on the subject would be a great help.

Thanks

It may be caused by the fact that one computer has more serial ports than the other. If one computer has only one serial port then the loop you are using would only iterate once. The other computer may have more than one (even if it physically only has one the registry may still list old virtual devices). This would cause the loop to run more than once and it looks like you aren't closing the port that you're opening, and you're not waiting for the port to close. The port does not close instantly so you'll need to have it wait. see this article: SerialPort.Open Method (System.IO.Ports) | Microsoft Learn
Also I note that you are casting "port in ports" as a var... you will have better luck with the debugger if you cast it as a string as port.getPortNames() returns an array of strings.

Hi ,

Thanks for the Response,

I actually close the port later in my code. Heres the full snippet

tring[] ports = System.IO.Ports.SerialPort.GetPortNames();

//Check ports to find the one that board is connected to
foreach (var port in ports)
{
timeoutcheck = 0;
try
{
usb.BaudRate = 38400;
usb.PortName = port;

//MessageBox.Show(port,port,MessageBoxButtons.OK);

usb.Open();
usb.Write("A");

usb.ReadTimeout = 3000;
usb.Read(check, 0, 1);

}

catch (TimeoutException)
{
timeoutcheck = 1;
usb.Close();
}

if (timeoutcheck == 0)
{
break;
}

}

So basically i'm sniffing for which port the board is connected to because I have it send back data which breaks the loop.

You may be right about the laptop having less ports, but if thats so, how do I get my GUI to interface the same way the arduino enviornment does, because it has no problem on the laptop.
What really bothers me is that when I look at the details of the exception. it says an ArgumentException is thrown. I should be using the portnames that are returned from string[] ports = System.IO.Ports.SerialPort.GetPortNames()

which should be COM1 and upwards, so i find this exception confusing.

could it be that no COM ports are open and so it is trying to open a null string?

Also I should mention i am relatively new to C# so your advice about the port.getPortNames(), are you suggesting I do string[] port = pot.getPortNames(). Which will give me an array of strings I an check against? or is my syntax for this wrong?

Thanks again for the help

I accidentally cut off the s at the beggining of my code,

It should say

string

I'm looking over your code here a bit more, but as a quick clarification what I mean about the cast is this:

Instead of -
foreach (var port in ports)

I would have used
foreach (string port in ports)

now you can check to see if port == "" and you "shouldn't" have to worry about nulls like you would with var.

Can you post the output of the exception? Also, note from my last post that you should probably do a thread.sleep() immediately after calling port.close() because it doesn't close immediately. There was a linked article you may find interesting.

Another thing you probably don't have to do, but might solve your problem would be to dispose the port object after calling close() and then instantiate a new port object at the beginning of the loop. This would help if its a problem with cleanup or object state between passes. As long as you declare the "usb" variable in the global scope it should still be accessible after your loop exits.

--==PLEASE NOTE=--
Please post the solution to your problem once you find it for other people to learn from :slight_smile:

Hi,

Ok so you were correct about either checking the null string, or the delay, OR both. I'm inclined to think both. I'm getting better results.
I changed the code to the following:

//Check ports to find the one that board is connected to
foreach (string port in ports)
{

if(port == ""){
MessageBox.Show("No PORTS OPEN","NO PORTS", MessageBoxButtons.OK);

break;
}

else{

timeoutcheck = 0;
try
{
usb.BaudRate = 38400;
usb.PortName = port;
MessageBox.Show(port,port,MessageBoxButtons.OK);

usb.Open();
usb.Write("A");

usb.ReadTimeout = 3000;
usb.Read(check, 0, 1);

}

catch (TimeoutException)
{
timeoutcheck = 1;
usb.Close();
Thread.Sleep(100);
}

if (timeoutcheck == 0)
{
break;
}

}}

When I run this code, I get "COM8" and then "COM9" in a message box before I receive the error (thats good progress!). lesson learned - always delay after a _serial.close()

the error I receive after is the following:

************** Exception Text **************

System.ArgumentException: The given port name does not start with COM/com or does not resolve to a valid serial port.

Parameter name: portName

at System.IO.Ports.SerialStream..ctor(String portName, Int32 baudRate, Parity parity, Int32 dataBits, StopBits stopBits, Int32 readTimeout, Int32 writeTimeout, Handshake handshake, Boolean dtrEnable, Boolean rtsEnable, Boolean discardNull, Byte parityReplace)

at System.IO.Ports.SerialPort.Open()

at WindowsFormsApplication1.mainform.calibrate_button_Click(Object sender, EventArgs e)

at System.Windows.Forms.Control.OnClick(EventArgs e)

at System.Windows.Forms.Button.OnClick(EventArgs e)

at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)

at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)

at System.Windows.Forms.Control.WndProc(Message& m)

at System.Windows.Forms.ButtonBase.WndProc(Message& m)

at System.Windows.Forms.Button.WndProc(Message& m)

at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)

at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)

at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

I'm unsure how to fix this.
The com port that should be read in is "COM11". That seems to be the port that windows is assigning to my board. I am unsure of why this error is occurring.

Thanks for the help so far!

Ok, this is just a stab in the dark, but could that serial port already be marked as open? This seems like it would be the wrong exception, but sometimes the CLR is not exactly forthcoming about managed resources. I would try to open one of the other ports using a program like realterm and see if you get the same error when trying to open com 8 or 9.

Realterm is a fantastic free program, by the way, for dealing with serial communications. You might also try installing COM0COM which is a serial null-modem pair emulator, it's a great way to emulate devices for testing. Be sure to name your ports starting with COM though or .NET won't be able to access them.

I just noticed that theres a Virtual Serial Port Emulator On the Laptop. (this laptop isn't mine)

Could that be conflicting with port name that is being read in?

I've seen the very exception you're getting when there is a serial port in the system that doesn't start with COM. You can theoretically name a serial port pretty much anything in Windows, but .NET doesn't like it. For instance you can call an emulator CNC0 instead of COM1... Windows will let you access it but .NET can't connect to it. You could put a condition in you loop that only lets you try to access ports that have names that fit the COM## naming scheme. It would be easy to grab just the first three characters and compare them to "COM" or use a regular expression to validate it.
I'd say that it is pretty likely this is your problem.

Why not just add a catch block for the exception, and handle (i.e. ignore) it?

PaulS: You can certainly do that. It is, however, not considered best practice to catch an exception to ignore it. I understand this is probably not production software, but you really aught to try to avoid and handle situations that cause common exceptions first, catch exceptions that are unlikely but possible and handle them second and then gracefully catch and handle the unexpected exception last. This gives you the best possibility to feed back to the user the situation that can cause an exception (without using the term "exception" that a user won't understand) and allow them to correct it before continuing with execution.

An example here would be that you could notify (or log) the user that a serial port cannot be accessed because of its name. Otherwise they may have an inaccessible port and not know why... If you simply ignore the exception there is absolutely no way they will even know there is a problem except that their port won't show up.

I do a lot of coding around library stuff where you can't predict, in advance, whether a call will be successful.

What I do in those cases is to catch the exception, and print out why it occurred. If it is something that is reasonable to ignore, I quit printing the message. If possible, I'll code a workaround.

But, the problem the OP was having dealt with an unhandled exception. I was merely suggesting that OP handle it. Ignoring it, when it is a matter of a name that isn't what the function can handle isn't unreasonable.

What's unreasonable is Microsoft's code not being able to open the port that it put in the list of ports that could be opened.

I tried to catch and ignore the exception.

I am now getting an error saying the port isn't Open.

What I find stranger is if I change the COM port of my board to say COM3 or COM4,

these Ports are never shown through the message box, meaning its not being picked up by

string[] ports = System.IO.Ports.SerialPort.GetPortNames();

I'm currently looking into the Virtual Serial Ports that are on this laptop. In reality there is only 1 serial port. The virtual ports are put on by a blackberry driver. I have been reading issues with these ports and people not being able to access their modem after installation.

I'm currently going under the assumption that this is the main reason why nothing is working.

How are you changing the COM port that the board is connected to? The port is assigned when the board is plugged in.

try @"\.\COM10" (without the trailing colon) instead.

COM1 through COM9 are aliases to \.\COM1 through \.\COM9 for the purposes of the underlying Posix system. (remember dos days, where you could

type filename.txt >> com9

even when in Windows?

Microsoft didn't alias all of the com ports thought(1-255) - just the ones DOS did for backwards compatibility.

see
http://support.microsoft.com/kb/115831
and

Your assumption is likely correct. Remember that you are iterating through a list that may not be presented in the same order each time you request it. The reason you are getting the "port is not open" error is because your try-catch block isn't including all calls to the port after the point at which you are "ignoring" the exception. This is precisely why ignoring exceptions will cause you more pain than good.

I agree that .NET does have some drawbacks in this regard, but that is somewhat the price you pay for JIT code, if you really want to avoid this kind of problem, write in C++ and avoid .NET. I'm no Microsoft Fanboy (I'm writing this on one my three MACs, hehe) but I write A LOT of C# code, and we use it for long-running, mission critical processes communicating via serial over our comm satellites.

My bet is that the blackberry driver makes a port with a nonstandard identifier to hide it from other applications and to move it where they want it in the device manager.

Since the problem with oddly named ports is a known-issue I would do a quick check for problem names, notify the user, and skip them when executing any code against the ports.

I've SOLVED IT!!!! and i feel like an idiot for not solving it sooner, but I blame it on the fact that this isn't my computer so I do not know what is on it.

If anyone out there has a RIM Virtual Serial Port on their computer (i'm assuming one would have this if they interface their Black berry with their computer), You must disable all virtual ports made in your devices manager under the ports section. I'm not 100% sure why, but it seems it blocks all other ports from being opened, and if you try to use the virtual ones you get an exception saying "port does not exist"

Thanks a ton for your help. I think the bits I added from you helped to make better code.

I'm assuming that most other things that take up your COM ports could end up blocking them as well. So if anyone in the future is having problems, try disabling all other devices on port before trying to interface with your arduino board as a quick fix. Now I need to find a way to disable those virtual ports via my GUI before sending and I'll be in business.

Any thoughts?

You can Change the COM port by going into:

control pane
-System
-hardware tab
-Devices Manager
-Ports
-Right Click On desired port
-properties
-Port Settings

  • Advance
    And then just change the COM port