I have a WPF/C# app that is launched as part of the "Startup" group on a Windows Embedded Standard machine. One of the first things the app does (in its static App() method) is create a new SerialPort object for COM1. COM1 is a hardwired serial port, not a USB virtual port or anything like that.
My problem is that every so often (maybe 1 out of 12) on startup, I get an exception:
System.UnauthorizedAccessException: Access to the port 'COM1' is denied.
There are no other applications using this port. Also, when I relaunch the app following this error, it grabs the port just fine. It's as if the com port isn't ready/set up for my app sometimes.
I'm clueless on this one! Any insight is appreciated!
UPDATE: I added a call to SerialPort.GetPortNames() and printout all available ports before attempting to open the port. In the failure case COM1 is indeed THERE! So, it's not that the port isn't ready. It looks like something in Windows is actually grabbing the port temporarily and blocking me.
A few responders at Microsoft seem to think that the kernel grabs COM1 temporarily at startup for debug reasons. They say the best approach is to essentially work around the issue... catch the exception and try again. Boooo.
I modified my code to retry opening the port a few times before giving up, which seems to work around this issue.
Old code:
_port = new SerialPort(port, 9600, Parity.None, 8, StopBits.One);
_port.Open(); // This can throw an exception
New code:
const int PORT_OPEN_MAX_ATTEMPTS = 10;
bool portOpened = false;
int portOpenAttempts = 0;
_port = new SerialPort(port, 9600, Parity.None, 8, StopBits.One);
while (!portOpened)
{
try
{
_port.Open();
portOpened = true; // Only get here if no exception
}
catch (UnauthorizedAccessException ex)
{
// Log, close, then try again
if (portOpenAttempts++ < PORT_OPEN_MAX_ATTEMPTS)
{
_logger.Debug("Port UnauthorizedAccessException. Attempt - " + portOpenAttempts);
Thread.Sleep(100);
_port.Close();
}
else
{
throw(ex);
}
}
}
Related
Good afternoon.
In Windows 10 Enterprise, I have a COM1 device.
To send and receive data, I use the following code:
using (var serialPort = new SerialPort(SerialPort.GetPortNames()[0])
{
BaudRate = 9600,
Parity = Parity.None,
StopBits = StopBits.One,
DataBits = 8,
Handshake = Handshake.None,
ReadTimeout = 50000
})
{
serialPort.Open();
var inputBuffer = new byte[] { 1, 3, 8, 10, 4 };
var outputBuffer = new byte[inputBuffer.Length];
serialPort.Write(inputBuffer, 0, inputBuffer.Length);
serialPort.Read(outputBuffer, 0, inputBuffer.Length);
}
However, after reaching 50 seconds, a timeout error occurs in the "Read" method.
Questions:
What settings do I need to make for SerialPort so that the "Read" method receives data that was written using the "Write" method?
How to check that the data was successfully written as a result of executing the "Write" method?
Maybe you need to make some settings in the KOM at the OS level, or there are problems with rights, or something else?
P.S.
Never worked with COM before.
There is no API that allows the Windows serial port to have a loopback function.
One of the following is possible.
Find and use device drivers and/or hardware that informally support the loopback feature.
Set the loopback connector that physically connects the TxD pin and RxD pin to the serial port.
Prepare another PC at the end of the serial cable, or prepare two serial ports on one PC and run a program that echoes back the data read at that connection destination.
I recently purchased a modem, which attaches via USB and appears to the operating system as a serial port device: COM19
To ensure the modem was OK, I first tried using PuTTY in serial mode. From there, I have no problem issuing AT commands and receiving responses from the modem. According to PuTTY configuration, my default options for controlling local serial lines are (at the time):
Speed (baud): 9600
Data bits: 8
Stop bits: 1
Parity: None
Flow control: XON/XOFF
Here's what I see in PuTTY (when I type the AT command):
AT
OK
^BOOT:30645964,0,0,0,75
However, when I try to access the same COM port from .NET (not at the same time as running PuTTY) I never receive the "OK" responses. I do still receive (what appears to be) echo, and the occasional unsolicited message from the modem, so I can see that I'm connected to the correct device. Sometimes the modem will respond to a malformed command with "ERROR", but never "OK". Here's the C# snippet where I initialize the COM port:
var commandPort = new SerialPort(portName, 9600, Parity.None, 8, StopBits.One);
commandPort.DataReceived += CommandPort_DataReceived;
commandPort.Handshake = Handshake.XOnXOff;
commandPort.Open();
commandPort.Write("AT\n");
for (var i = 0; i < 30; i++)
{
Thread.Sleep(1000);
}
And this is the event handler:
private static void CommandPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Console.Write(((SerialPort)sender).ReadExisting());
}
This is what's printed back to the console of the C# application (note that I'm not explicitly writing the command to the console, it's added by the CommandPort_DataReceived event handler):
AT
^BOOT:30645964,0,0,0,75
None of the AT commands issued by the .NET application perform any action, though their equivalents in PuTTY are able to query modem state, place calls, etc. What am I doing wrong?
Use the SerialPort class's NewLine property. By default it's set to "\n". This needs to be "\r", then you can use the WriteLine(...) method to send AT commands.
commandPort.NewLine = "\r";
commandPort.Open();
commandPort.WriteLine("AT");
so I have an C# WinForm that use
SerialPort SerialPort1 = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
SerialPort1.Open()
SerialPort1.DataReceived += new SerialDataReceivedEventHandler(...)
to listen on several Virtual COM Ports that Created by other Software(I can't control it)
So generally it goes well except When the other Software is dead or gone, the Virtual COM port it created is also gone or missing
So my WinForm App fail because there is no COM1 to listen to
Question: How should I handle this error when there is no COM port to listen
Thank you so much for your reply
Put it in a try - catch statement and print a message to the user if something bad happened.
try
{
SerialPort SerialPort1 = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
SerialPort1.Open()
SerialPort1.DataReceived += new SerialDataReceivedEventHandler(...)
}
catch(Exception e)
{
//Print error to user
}
For finer granularity on the exception, see the msdn documentation of the serial port here.
Well, no, virtual serial ports are emulated by software. If that software fails then of course there's no functional serial port anymore. Nothing you can do about that other than finding better software.
If this is the common failure mode, jerking out the connector of a USB device while a program is talking to it then just don't bother. Whomever does that needs to be learned the Hard Way that using the Windows "Safely Remove Hardware" tray icon option is not optional. It tends to take a bit of reinforcement to get them to realize what "Unsafely Remove Hardware" does. Albeit, oddly, that it tends to be programmers that do this, rarely regular users. Could be site bias and regular users just tend to figure out by themselves that doing this isn't a good idea. It isn't, these drivers count on humans being cooperative. Necessary since serial ports are not plug & play devices, there's no way for the driver to deliver a "device is gone, stop using" notification. Well, other than hard-crashing your program intentionally.
If the only problem is that the number of the port is unpredictable you could detect all the available ports as shown below and the try them one at a time. I once had this problem when a usb device sometimes showed up as COM1 and other times as COM5
string[] availablePorts = SerialPort.GetPortNames();
foreach (string strPortName in availablePorts)
{
try
{
SerialPort SerialPort1 = new SerialPort(strPortName, 9600, Parity.None, 8, StopBits.One);
SerialPort1.Open();
}
catch (Exception e)
{
//Print error to user
}
}
I have a C# code which communicates with three different COM ports. The COM ports are actually three serial port to USB converters.
The code each time switches 'off' and 'on' the devices to which it is communicating, then initializes the three com ports, tries to send and read data and then closes the com port. This keeps continuing for a pre-defined number of loops.
My problem is that after about 8 or 9 iterations, the COM port communication stops working. Sometime it throws an error saying the port is closed, sometime it does not throw any exception but it is actually not reading or writing anything from the com port. Some point it was only writing but not reading back the data.
What might be the reason and any tips to debug this problem?
EDIT:
The port abruptly closes or stops working even in the middle of the program as shown below:
SerialPort.Write("ss");
SerialPort.Read("ss"); // FAILS!!
Some part of the code I am using
public string Read(string readCommand)
{
string str = "";
_port.WriteLine("\r");
_port.WriteLine(readCommand + "\r");
Thread.Sleep(0x3e8);
str = _port.ReadExisting();
return str;
}
public void Write(string command)
{
_port.WriteLine(command + "\r");
Thread.Sleep(100);
if (_port.ReadExisting() == string.Empty)
{
throw new IOException("Error writing to COM");
}
}
public void Initialize()
{
if (_port == null)
{
_port = new SerialPort(this.PortName.ToString(), this.BaudRate, this.Parity, this.DataBits, this.StopBits);
_port.Handshake = this.Handshake;
}
try
{
if (!_port.IsOpen)
{
_port.Open();
if (Read("") == string.Empty)
{
throw new IOException("Device not connected or powered on");
}
}
}
catch (Exception)
{
this.Close();
}
}
Thanks...
_port.WriteLine(command + "\r");
Thread.Sleep(100);
if (_port.ReadExisting() == string.Empty)
{
throw new IOException("Error writing to COM");
}
That's evil code and bound to throw sooner or later. Windows cannot provide a service guarantee like that. Or for that matter the device itself, especially when you power it on and off. Use SerialPort.ReadTimeout, set it to at least 2 seconds. And make a blocking call, like ReadLine().
catch (Exception)
{
this.Close();
}
That's tops the previous snippet. You have no idea what's going wrong when that runs. And your code will try to use a closed port. Just delete the statements, it does nothing but harm.
Do not close the ports until your program ends. SerialPort uses a background thread to watch for events on the port, that thread needs to shutdown after the Close() call before you can open the port again. How long it takes to shutdown is unpredictable, it could be seconds worst case. There's no point in closing the port, it isn't going to be useful to anything else.
You need to use SetCommTimeouts (not sure what the .NET wrapper is, I gave up on the .NET serial classes long ago and call the Win32 API directly) to force the USB/serial converter to send the data back to your program.
By default it may try to collect a block equal in size to a USB transfer block, for efficiency.
Its tough to tell exactly what the problem might be without see some of the code. My guess would be that you are not waiting long enough for the COM port to close after reopening it. Note from the SerialPort.Close page, that:
The best practice for any application is to wait for some amount of time after calling the Close method before attempting to call the Open method, as the port may not be closed instantly.
Can you just open the COM ports and leave them open until you are done? For example from this post:
using (SerialPort serialPort = new SerialPort("COM1", 9600))
{
serialPort.Open();
while (true)
{
Thread.Sleep(1000);
// serialPort.Write();
Thread.Sleep(1000);
// serialPort.Read();
// break at some point to end
}
serialPort.Close();
}
I'm trying to send a sms via a Nokia phone over serial which is easy enough via putty. The commands from the nokia documentation works fine.
However, trying to send the same commands from a c# application fails miserably. I've run Sysinternals PortMon and can see the commands come through OK, the only difference I can see is in the way it connects but I am having trouble finding the commands that would iron out those differences.
The code I'm running looks a little bit like this
using (SerialPort port = new SerialPort(comPort, 9600, Parity.None, 8, StopBits.One))
{
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
port.ErrorReceived += new SerialErrorReceivedEventHandler(port_ErrorReceived);
//port.ReceivedBytesThreshold = 1;
port.DtrEnable = true;
port.RtsEnable = true;
port.ReadTimeout = 1;
port.Handshake = Handshake.XOnXOff;
try
{
port.Open();
port.WriteLine("AT");
port.WriteLine("AT+CMGF=1");
port.WriteLine("AT+CMGS=\"" + number + "\"");
port.WriteLine(message);
port.Write(new byte[] { (byte)26 }, 0, 1);
}
finally
{
if (port.IsOpen)
{
port.Close();
}
}
The differences I'm seeing in the trace from the serial port are
At the start
0.00001844 aspnet_wp.exe IOCTL_SERIAL_SET_HANDFLOW USBSER001 SUCCESS Shake:1 Replace:43 XonLimit:4096 XoffLimit:4096
And at the very end
0.00061153 aspnet_wp.exe IOCTL_SERIAL_PURGE USBSER001 SUCCESS Purge: RXABORT RXCLEAR
0.00004442 aspnet_wp.exe IOCTL_SERIAL_PURGE USBSER001 SUCCESS Purge: TXABORT TXCLEAR
Has anyone got any tips on how to iron out these issues? I also notice that the phone is not responding back to the application with any acknowledgement when I issue a command so I suspect the problem is with the connection, not those messages at the end.
Try to see if you can read out the serial communication from the phone. After you send 'AT', the phone should respond with 'OK'. It might be a good idea to verify that the serial communication is working before taking on the SMS bit.
From what I remember, I think that after AT+CMGS the message should be entered and followed by ctrl-z, and no newline is needed. Could you try changing the WriteLine(message) to Write(message)?
Hope this helps!
You need to wait for the ">" before writing out the message. Also, don't terminate the message with a CR/LF (WriteLine).