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.
Related
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");
I'm using C# and .NET 4.5, with the Visual Studio 2012 compiler/IDE to open and interact with a serial port. My code is designed to connect to the QSB quadrature-to-USB converter from US Digital.
Here is the code that I'm using to open the port and connect.
this.Port = new SerialPort();
this.Port.BaudRate = 230400;
this.Port.PortName = "COM9";
this.Port.Parity = Parity.None;
this.Port.Handshake = Handshake.None;
this.Port.DataBits = 8;
this.Port.StopBits = StopBits.One;
this.Port.Open();
Setting a breakpoint immediately after this.Port.Open() allows me to verify that the serial port is indeed connected. In another section of code, the following is called in response to a button push:
this.Port.WriteLine("W168");
This command *should cause my hardware to spin a motor, and in fact it does if I send the command using Putty, or using a Python script that I wrote (both using exactly the same settings as the C# code does). Yet nothing happens. I can open the port in Putty or Python and execute the command with the expected results, and then run my C# code and nothing happens.
Am I missing something C# specific that prevents this from working?
For what it's worth, here is my working Python code:
ser = serial.Serial("COM9", 230400, timeout=1)
ser.write(b"W168\n")
Link to pySerial documentation: http://pyserial.sourceforge.net/pyserial_api.html#classes
Default values for fields mentioned in the C# code but not mentioned in the python call above are:
bytesize = 8
parity = none
stopbits = one
xonxoff = false
rtscts = false
dsrdtr = false
When working with Serial Ports in C# there is one thing to always remember when establishing a connection. If you set the handshake value to none like this:
this.Port.Handshake = Handshake.None;
Then you need to set a few more parameters as well for the connection to be completed, and they are:
this.Port.DtrEnable = true;
this.Port.RtsEnable = true;
The reaso is because the Dtrenable means this:
Data Terminal Ready (DTR) signal
MSDN explains what DTR means as this:
Data Terminal Ready (DTR) is typically enabled during XON/XOFF software handshaking and Request to Send/Clear to Send (RTS/CTS) hardware handshaking, and modem communications.
Rtsenable means this:
Request to Send (RTS) signal
MSDN explains what RTS means as this:
The Request to Transmit (RTS) signal is typically used in Request to Send/Clear to Send (RTS/CTS) hardware handshaking.
Together these two parameters handle the handshaking of the serial port communications without you having to define it between the master and slave.
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 am working out with serial com port.
I have insert this code in my program.
I able to send data to the devices and fail to read data from the devices.
In debug mode, i only able to get serialport.BytesToRead = 0.
May i know why this will happen??
while (serialport.BytesToRead > 0)
{
int byte_count = serialport.BytesToRead;
byte[] buffer = new byte[byte_count];
int read_count = serialport.Read(buffer, 0, byte_count);
string echo = ASCIIEncoding.ASCII.GetString(buffer, 0, read_count);
echo = System.Text.Encoding.UTF8.GetString(buffer);
Console.WriteLine(echo);
}
First use another program, like Putty or HyperTerminal to verify that the device and connection is in working order and to double-check that you are using the correct port, baudrate, parity, stopbits and databits. If you can't get anything out of the device with such a program then it won't work either using your own code.
Next focus on the handshaking. A common mistake is to leave it at none and then not turn on the DtrEnable and RtsEnable signals. A device won't send anything when it thinks that you're offline. SysInternals' PortMon utility can be handy, it shows you what's going on at the device driver level.
When to you read from the SerialPort? Are you trying to read right after you send? In that case you might try to read before there is actually anything to read from the port.
You should use the DataReceived event to read data.
Note that this event might trigger before all data is received, so you might have to retrieve the data over several calls of DataReceived until you get all the data you are supposed to.
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);
}
}
}