Through testing, I have discovered two laptops that refuse to communicate through a .Net SerialPort object. I should probably start off by saying that the application is using .Net 4.0. This is the setup:
Both laptops communicate using these serial ports with Tera Term
There is no communication on either the internal serial port on the motherboard or any USB serial port emulators
The ports being tested were not already in use.
No exceptions are being triggered
The software can open the COM ports, but not transmit any data
The ErrorReceived event handler is not being called
Here is how the object is initialized prior to use:
serialPort = new SerialPort();
serialPort.PortName = SelectSerialPort.GetSerialPort();
serialPort.BaudRate = 9600;
serialPort.Parity = Parity.None;
serialPort.DataBits = 8;
serialPort.StopBits = StopBits.One;
serialPort.Handshake = Handshake.RequestToSend;
serialPort.ReadTimeout = 10000;
serialPort.WriteTimeout = 1000;
serialPort.ErrorReceived += OnSerialError;
This setup has been tested on at least twenty other computers and it works just fine. To write to the port I am simply calling:
serialPort.Write(packet, 0, nBytes);
Where packet is a byte[] and nBytes is the length of the data to be sent. It seems like the write timeout is being triggered because the software will open the serial port and after a delay the port closes without transmitting any data.
I was able to capture the following logs with a serial port monitor. The first log is what I expect to see, the COM port is opened and configured then the data is sent. The second log is from one of the laptops. You can see the port opens but the port just closes without transmitting anything.
I noticed that there are two main differences in the log files. The log from the laptops contains RTS off and the good log does not. Also, the log from the laptops seems to be setting the write timeout to zero. In the good log:
Set timeouts: ReadInterval=-1, ReadTotalTimeoutMultiplier=-1, ReadTotalTimeoutConstant=10000, WriteTotalTimeoutMultiplier=0, WriteTotalTimeoutConstant=1000
And the log from the laptops:
Set timeouts: ReadInterval=-1, ReadTotalTimeoutMultiplier=-1, ReadTotalTimeoutConstant=-2, WriteTotalTimeoutMultiplier=0, WriteTotalTimeoutConstant=0
What could be causing this issue, and what can i do to stop it?
It seems like i have found the solution to this problem while I was doing some research for a different project. I stumbled on a post in the Arduino forum where someone was having a similar issue with an Atmega32U4 (which has a proper USART).
It would seem that there were two properties of the SerialPort that I overlooked - SerialPort.DtrEnable, and SerialPort.RtsEnable.
The winning combination seems to be the following configuration:
serialPort = new SerialPort();
serialPort.PortName = SelectSerialPort.GetSerialPort();
serialPort.BaudRate = 9600;
serialPort.Parity = Parity.None;
serialPort.DataBits = 8;
serialPort.StopBits = StopBits.One;
serialPort.Handshake = Handshake.None;
serialPort.DtrEnable = true;
serialPort.RtsEnable = true;
serialPort.ReadTimeout = 10000;
serialPort.WriteTimeout = 1000;
serialPort.ErrorReceived += OnSerialError;
Once these two properties were set to true, communication with no handshaking started working. However, the executable had to be run as Administrator otherwise I would receive an access denied message.
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 have a 'honeypot' that I am developing in C# that listens on a series of ports (user inputted). It is a large project/windows service that functions as expected for almost any port entered and will not listen on ports that currently have something listening already. The problem is that when I test the service using telnet or netcat, opening a connection on port 23 is not caught by my service and therefore establishes the connection.
I open the ports in the firewall by doing the following:
for (int i = 0; i < ports.Length; i++)
{
string arg = "advfirewall firewall add rule name=\"PeepHole Open" + "\" dir=in action=allow protocol=TCP localport=" + ports[i];
string arg1 = "advfirewall firewall add rule name=\"PeepHole Open" + "\" dir=in action=allow protocol=UDP localport=" + ports[i];
ProcessStartInfo procStartInfo = new ProcessStartInfo("netsh", arg);
ProcessStartInfo procStartInfo1 = new ProcessStartInfo("netsh", arg1);
procStartInfo.RedirectStandardOutput = true;
procStartInfo1.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
procStartInfo1.UseShellExecute = false;
procStartInfo.CreateNoWindow = true;
procStartInfo1.CreateNoWindow = true;
Process.Start(procStartInfo1);
Process.Start(procStartInfo);
}
And I start the listeners by:
IPEndPoint Ep = new IPEndPoint(IPAddress.Parse("0.0.0.0"), current_port);
//TcpListener tempListener = new TcpListener(hostIP, current_port);
TcpListener tempListener = new TcpListener(Ep);
TCP_Listener listen = new TCP_Listener(); //my defined tcplistener struct
listen.listener = tempListener; //set the Listener's TcpListener field
listen.port = current_port; //set the Listener's Port field
listen.listener.Start(); //start this particular TcpListener
tcp_listener_list.Add(listen); //add the struct to the list of Listeners
And accept the TCP connection by:
for (int i = 0; i < tcp_listener_list.Count - 1; i++)
{
if (tcp_listener_list[i].listener.Pending())
{
TcpClient client = tcp_listener_list[i].listener.AcceptTcpClient();
int clientPort = tcp_listener_list[i].port;
IPEndPoint ep = client.Client.RemoteEndPoint as IPEndPoint;
ThreadPool.QueueUserWorkItem(LogTCP, new object[] { client, clientPort, ep });
}
}
And in LogTCP I close the connection by (where client is a TcpClient object):
NetworkStream networkStream = client.GetStream();
networkStream.Close();
client.Close(); //close the connection, all the data is gleaned from the attacker already
Now the problem is that when I run telnet or netcat to test the closing and logging of the port, my code is never executed and the connection is established because the port is opened; the TCP connection never is .Pending() and if I remove that, the issue is persistent. Also, I have the same issue if I set up the listeners to use IPAddress.Any and if I reconfigure my accept method to AcceptSocket with or without the .Pending() if statement. Does windows treat certain ports differently on a low level with certain programs?
I am running a windows service from Windows 8.1 and sending TCP connections through telnet on putty (on the machine that the service is installed on) and telnet and netcat on a Linux VM. Both Telnet Client and Telnet Server are disabled on the 'host' machine.
I have tried many different variations of closing the sockets and connections that I found during my researching.
client.Client.Close() produces an ObjectDisposedException
client.Client.Shutdown(SocketShutdown.Both) makes all previously 'working' ports hang connections with CLOSE_WAIT
I think the key here, is you mention as an aside that you have created your own struct. Structs are very tricky. You might think that the below code will end up with a TCP_Listener instance that has your tempListener and current_port. But if you set a breakpoint you'll probably notice otherwise. Every modification you do on a struct actually returns a brand new struct, so you can't assign fields one at a time like you do with a class.
TCP_Listener listen = new TCP_Listener(); //my defined tcplistener struct
listen.listener = tempListener; //set the Listener's TcpListener field
listen.port = current_port; //set the Listener's Port field
listen.listener.Start();
I would recommend, rather than a struct, you use a class. Or you initialize your struct as new TCP_Listener(tempListener, current_port), then Start it.
That is at least part of your problem. Once you fix that, let us know if it's still not working and we can look at the next issue.
Pending is never needed. Just continually accept on all listeners. Start one task per listener to do that:
while (true) {
ProcessConnectionAsync(await listener.AcceptAsync());
}
Something like this.
And here is an off-by-one bug: tcp_listener_list.Count - 1. But that bug goes away when you do it as explained above.
Regarding closing, why not just client.Dispose();? This is the normal way to do resource management in .NET. Nothing else is required.
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.
The objectve is to find which Serial port is phyisically connected to other machine. I want to Search my system to find the available serial ports and send a test message using all the ports and wait for the response. And get the port numbers of Which ever ports get a response is connected to the other machine. How to do?? Thanks.
The SerialPort.GetPortNames() method returns an array of the COM port names of all available serial ports. You could iterate it and try to Open() them. Expect failure, the port might already be opened by another program.
You don't want to send something to a device that doesn't expect it. Using the DsrHolding property is a reasonable test to see if a device is attached that's powered up.
Your ultimate nemesis is going to be the Baudrate property. You cannot guess the proper value. Serial ports are way too primitive to support plug-and-play style device discovery. Avoid using something that cannot work reliably, allow you user to configure your program with the settings you need. It is the normal practice.
Use System.IO.Ports.
public static void OnSerialDataReceived(object sender,
SerialDataReceivedEventArgs args)
{
string data = ComPort.ReadExisting();
Console.Write(data.Replace("\r", "\n"));
}
private static void InitializeComPort(string port, int baud)
{
ComPort = new SerialPort(port, baud);
// ComPort.PortName = port;
// ComPort.BaudRate = baud;
ComPort.Parity = Parity.None;
ComPort.StopBits = StopBits.One;
ComPort.DataBits = 8;
ComPort.Handshake = Handshake.None;
ComPort.DataReceived += OnSerialDataReceived;
ComPort.Open();
}
more on Mark Michaelis' blog
SerialPort.GetPortNames() method is static methods for SerialPort .Do you sure communication between them have flow control?
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).