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.
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");
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.
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 piece of hardware that I'm connecting to using the .NET SerialPort class over RS232.
According to its documentation it doesn't support any type of flow control.
I can write queries and commands to the device, for the queries it'll respond immediately to a read, and if echo is on for the device and I have to do a read after writing a command then the command writes work fine too. The commands and responses are a maximum of 7 characters.
However if echo is off and I write 2 commands in quick succession the second one isn't carried out, unless I put in a Thread.Sleep(15) between the writes, presumably replicating the time it takes to do the ReadLine when echo is on.
I can't necessarily guarantee that echo will be on, and explicitly turning it on isn't really an option either, so I basically need to handle the behaviour as I find it.
The SerialPort is set up as follows:
SerialPort _serialPort = new SerialPort
{
PortName = "COM1",
BaudRate = 9600,
Parity = Parity.None,
DataBits = 8,
ReadTimeout = 5000,
WriteTimeout = 5000,
NewLine = "\x0D"
};
And I'm using WriteLine and ReadLine to communicate with it.
Sleeping the thread feels like a hack, and I haven't found an alternative with all my googling.
So, have I missed something, is there some way I can check when the next command write to a serialport can be carried out or is Thread.Sleep pretty much my lot?
http://msmvps.com/blogs/coad/archive/2005/03/23/SerialPort-_2800_RS_2D00_232-Serial-COM-Port_2900_-in-C_2300_-.NET.aspx
Set handshake property to RTSCTS and handle the PinChanged event when CTS becomes true?
Lines marked ‘Output’ in the table can be set by the serial port to a high or low state (True or > > False) and the ‘Input’ lines can be read as high or low. You can use the PinChanged event to be > > notified when one of the input pins changes. The Handshake property can be set to use RTS/CTS > > > (uses hardware control lines) or XON/XOFF (uses software) or both.
Control Line Name DB9 Pin SerialPort Property I/O
DTR Data Terminal Ready 4 DtrEnable Output
RTS Request to Send 7 RtsEnable Output
CTS Clear to Send 8 CtsHolding Input
DSR Data Set Ready 6 DsrHolding Input
CD (or DCD) Data Carrier Detect 1 CDHolding Input
Unfortunately due to the lack of support in my system for flow control Thread.Sleep seems to be the solution.
I've set up my code so that it checks to see if echo is on and then if it is it just uses the ReadLine, and if it's off then it uses a Thread.Sleep(15).
It feels nasty, but it works reliably, so I'm just having to go with that.
I was just having a similar problem. Using a low baud rate I was attempting to write commands to the port too fast (apparently the "write" command returns before the write is finished).
I solved this by modifying the "Serial Port Ready?" function I call before each command. I added a while loop to sleep for 5ms while the "BytesToWrite" property was greater than zero. Worked fine after that.
NetFoss requires you to run it with a command line similar to this:
nf.bat /n[#] /h[#] [command line]
where /n[#] is a node number and /h[#] is an OS socket handle.
I want to write something in C# very similar to what a telnet BBS would do when it runs door games. It should accept the client socket, gather a bit of information passed into it from the client, then pass the socket over to NetFoss to be used to run a DOS based application that supports communications via a fossil driver.
I honestly was just guessing about how to go about this, and here's what I came up with:
class Program
{
const int BACKLOG_SIZE = 20;
static void Main(string[] args)
{
Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
server.Bind(new IPEndPoint(IPAddress.Any, 3102));
server.Listen(BACKLOG_SIZE);
while (true)
{
Socket socket = server.Accept();
Process p = new Process();
p.EnableRaisingEvents = false;
p.StartInfo.FileName = #"c:\netfoss\nf.bat";
p.StartInfo.Arguments = #"/n1 /h" + socket.Handle + #" c:\game\game.bat 1";
p.StartInfo.WorkingDirectory = "c:\netfoss";
p.StartInfo.UseShellExecute = false;
p.Start();
}
}
}
Interestingly enough, the application that NetFoss is running via game.bat is being output to the C# application's console window but not the telnet client, and even more interesting is that the telnet client DOES receive the initial NetFoss message that shows it is able to communicate with the socket. So, why is the application that is passed to NetFoss outputting to my console window instead of the telnet client?
Anyone know what I'm missing?
EDIT:
I forgot to mention that I also tried setting UseShellExecute to TRUE, and this throws a NetFoss error saying that it is an invalid handle. From my understanding, I would have to duplicate the handle in some way so that the unmanaged application can access it? Is there any way to accomplish what I'm trying to do using C#?
Thanks,
Marc
It is normal that the DOS application outputs to your console window, but it should also output to the telnet client.
Since you are seeing the initial NetFoss version message in your telnet client, we know that the socket handle is being sucesfully passed to NetFoss... So it sounds like the problem is that your DOS application is not FOSSIL aware, or is not currently configured to use a FOSSIL or an INT14h communications method.
Regards, Mike
NetFoss developer