Excuse me, quick question:
I have this hardware setup:
Same machine: "Com3" -> USB -> To Serial -> To USB -> "Com4"
And I followed MSDN SerialPort Class and MSDN SerialPort.ReadLine() to build this routine:
SerialPort SendSerialPort = new SerialPort("Com3", 9600);
SerialPort ReceiveSerialPort = new SerialPort("Com4", 9600);
SendSerialPort.Open();
ReceiveSerialPort.Open();
SendSerialPort.WriteLine("Test");
var message = ReceiveSerialPort.ReadLine(); // control stops here
SendSerialPort.Close();
ReceiveSerialPort.Close();
Console.WriteLine(message);
However, when I tend to ReadLine(), my control stops and just waits. I did not expect that.
I am expecting to receive the string Test and assign it to my var message. Could you please tell me what am I doing wrong here?
EDIT:
I tested my hardware using the Serial Port Utility Application and it worked just fine.
I've altered from the example you linked:
To actually have both ports running to read and write back and forth you will actually need to implement threading for reading and writing for both.
It can be a good idea to use a timer.
public static void Main()
{
SerialPort SendSerialPort = new SerialPort("Com3", 9600);
SerialPort ReceiveSerialPort = new SerialPort("Com4", 9600);
StringComparer stringComparer = StringComparer.OrdinalIgnoreCase;
Thread readThread = new Thread(Read);
// Set the read/write timeouts
_serialPort.ReadTimeout = 500;
_serialPort.WriteTimeout = 500;
SendSerialPort.Open();
ReceiveSerialPort.Open();
bool _continue = true;
readThread.Start();
Console.Write("Name: ");
name = Console.ReadLine();
Console.WriteLine("Type QUIT to exit");
while (_continue)
{
message = Console.ReadLine();
if (stringComparer.Equals("quit", message))
_continue = false;
else
SendSerialPort.WriteLine(String.Format("<{0}>: {1}", name, message));
}
readThread.Join();
SendSerialPort.Close();
}
public static void Read()
{
while (_continue)
{
try
{
string message = ReceiveSerialPort.ReadLine();
Console.WriteLine(message);
}
catch (TimeoutException) { }
}
}
Usually there will be a beginning and end value within the written data to tell the other port that the message is finished and also for the ports to validate that they are reading data they should be, usually with commands of what to do with that data. (out of scope for this question).
Also lacking and important is the intialisation of your ports.
I prefer to use the default constructor (preference only)
SerialPort Constructor ()
And then set any values like so:
_serialPort.BaudRate = SetPortBaudRate(_serialPort.BaudRate);
_serialPort.Parity = SetPortParity(_serialPort.Parity);
_serialPort.DataBits = SetPortDataBits(_serialPort.DataBits);
_serialPort.StopBits = SetPortStopBits(_serialPort.StopBits);
_serialPort.Handshake = SetPortHandshake(_serialPort.Handshake);
All the constructors will give these values:
This constructor uses default property values when none are specified. For example, the DataBits property defaults to 8, the Parity property defaults to the None enumeration value, the StopBits property defaults to 1, and a default port name of COM1.
Even the handshake has a default value. If you look at the source code.
private const Handshake defaultHandshake = Handshake.None;
The problem with your code is in this line
var message = ReceiveSerialPort.ReadLine();
You block your code to wait for a line, if the line never arrives it will remain here forever or the value set to ReadTimeout
So why does the line never arrive?
The problem can be an error in WriteLine("Test");, you should handle errors, or it can be that your in are blocking your code ReadLine() before the WriteLine("Test") manage to come through, you could insert a Thread.Sleep(100) between, but this is not really improving the code.
Note: Your code will also work as is sometimes, depending on these race conditions.
This synchronized / blocking reading from serial ports seems simple in code just one line; but it creates a lot of negative side effects in your communication protocol's.
A much better solution (considering that you like to Read / Write data from a microcontroller) is to either use a thread as Yvette suggested or use asynchronously reading Stream.BeginRead (Byte[], Int32, Int32, AsyncCallback, Object) which I would prefer.
The asynchronously reading will throw an event when something is incoming on the serial port. The basic idea of this programming strategy is to not do step programming but expecting what ever result and then handle it correctly.
In communications protocol with asynchronously reading the AutoResetEvent is very useful, hence you send something, then you start the AutoResetEvent, if asynchronously the expected result is arriving you will set this event and your code can continue, if it does not arrive the AutoResetEvent will timeout and you can handle this.
It cannot block when there is data available. What you sent either got stuck in the transmit buffer, got lost due to a wiring mistake, triggered an error or was ignored. If it works with another program then a wiring mistake can't be the problem.
Do keep in mind that just setting the Baudrate is not enough, you must also use set the DataBits, Parity and Stopbits properties to match the device settings. A mismatch can trigger an error, the kind you can only see when you write an event handler for the ErrorReceived event. Never skip that event, confounding problems can occur if you never check.
And above all the Handshake property must be set correctly. The proper value depends on how the ports are wired together, it is too common to not connect them. Start by setting it to Handshake.None so a wrong state for the DSR and CTS signals can't block reception and a wrong state for the DTR and RTS signals can't block transmission. Beware that it is common for another program to enable hardware handshaking, a mismatch is guaranteed to cause communications to stall.
If you use synchronous reads instead of the DataReceived event then you should in general deal with the possibility that a device is not responding. Either because it is powered off, not connected at all or malfunctioning. Use the ReadTimeout property for that so your program cannot hang. Aim high, 10000 milliseconds is a reasonable choice.
Beware the randomness of this problem, putzing around with another program can easily get the port configured correctly and now it will suddenly work. And beware that starting a thread accomplishes nothing, it will now be that thread that gets stuck and the Join() call will deadlock.
I'm trying to send and receive data with a GSM modem attached to a COM port.
Here is the essential part of my code:
SerialPort sp = new SerialPort();
sp.PortName = "COM1";
sp.BaudRate = 9600;
sp.DataBits = 8;
sp.Parity = Parity.None;
sp.StopBits = StopBits.One;
sp.ReadTimeout = 5000;
sp.Open();
if (sp.IsOpen)
{
Console.WriteLine(sp.PortName + " is open");
Console.WriteLine("Trying to write data");
sp.Write("AT");
Console.WriteLine("Data has been sent");
Console.WriteLine("Trying to read data");
char[] read = new char[200];
sp.Read(read, 0, 20);
foreach (char chr in read)
{
Console.Write(chr);
}
Console.WriteLine();
}
I don't get any errors but the GSM device is just sending me back whatever I send him. In this case AT. If I send "BOO" he sends back "BOO" (although sometimes I only get the first letter, I think this is because of the way I'm reading the data, should be in a seperate thread no? I can do this easily later).
I'm expecting him to send me back "OK" when I send him "AT".
What explanation could there be for the device sending me back whatever I'm sending him. I was thinking it could maybe be that the port communication is not set up properly and I'm actually not getting to the device, just sending it back to myself?
Have you communicated to it with PuTTY? You should first try to send and receive data from a terminal application (PuTTY Download Link) to rule out any issues with the modem itself, then move on to writing an application to communicate.
As for the code, you should be using sp.WriteLine instead of sp.Write... The modem needs to see a newline character to know your command is finished. You can set the newline character by using sp.NewLine so that it matches what the modem needs to see. Alternatively, you can just append '\r' to any AT command you are writing.
The GSM modems I have used all have echo on by default, you can disable echo by sending 'ATE0' to it. While echo is on, the modem will first echo anything you send it, then it will send it's response. I suspect you are seeing the echo come back but not the response, due to the way you are reading the data. Try this method for reading the data:
//add this just before opening the port
sp.DataReceived += new
SerialDataReceivedEventHandler(port_DataReceived);
Add the following method outside the method you are setting up the port:
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Console.WriteLine(port.ReadExisting());
}
Goodday everybody,
My problem is the following:
I am communicating with serialport to a zigbee like apparatus and this is working however when i send the following in the C# app:
(string is "0023000D6F000076CF27431e" (in picture send twice)
I get a part of the answer from the apparatus(read window from picture):
However when i send "0023000D6F000076CF27431e" direct to the port by terminal i get the apparatus to answer this:
This is the complete en correct answer.
And of course i need the last line (with the 0024 part in it).
I think (i am not very good in programming yet) this part recieve's the data:
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{// Event for receiving data
string txt = port.ReadExisting();
Thread.Sleep(10);
List<PlugwiseMessage> msg = reader.Read(Regex.Split(txt, "\r\n"));
DataReceived(sender, new System.EventArgs(), msg);
I googled about ReadExisting but it seem that this is te correct way to go????
Or is it not ??
Can someone explain this behaviour to me ?
This is by design. ReadExisting() does what it says, it only returns characters that exist in the serial port read buffer. Serial ports are very slow devices, you normally only get a couple of characters for each ReadExisting() call. This is especially tricky when you use a debugger, that slows your program down a lot, giving the serial port driver time to receive additional characters.
You can use ReadLine() instead, you'll get one line of text from the serial terminal output for each call. That works because the device is sending a linefeed as a line terminator (0x0a in the hex dump). Remove the Sleep() call, that only makes things worse.
I've been fighting with this issue for a day and I can't find answer for it.
I am trying to read data from GPS device trough COM port in Compact Framework C#. I am using SerialPort class (actually my own ComPort class boxing SerialPort, but it adds only two fields I need, nothing special).
Anyway, I am running while loop in a separate thread which reads line from the port, analyze NMEA data, print them, catch all exceptions and then I Sleep(200) the thread, because I need CPU for other threads... Without Sleep it works fine, but uses 100% CPU.. When I don't use Sleep after few minutes the output from COM port looks like this:
GPGSA,A,3,09,12,22,17,15,27,,,,,,,2.6,1.6,2.1*3F
GSA,A,3,09,12,22,17,15,27,,,,,,,2.6,1.6,2.1*3F
A,A,3,09,12,22,17,15,27,,,,,,,2.6,1.6,2.1*3F
,18,12,271,24,24,05,020,24,14,04,326,25,11,03,023,*76
A,3,09,12,22,17,15,27,,,,,,,2.6,1.6,2.1*3F
3,09,12,22,17,15,27,,,,,,,2.6,1.6,2.1*3F
09,12,22,17,15,27,,,,,,,2.6,1.6,2.1*3F
,12,22,17,15,27,,,,,,,2.6,1.6,2.1*3F
as you can see the same message is read few times but cut.
I wonder what I'm doing wrong...
My port configuration:
port.ReadBufferSize = 4096;
port.BaudRate = 4800;
port.DataBits = 8;
port.Parity = Parity.None;
port.StopBits = StopBits.One;
port.NewLine = "\r\n";
port.ReadTimeout = 1000;
port.ReceivedBytesThreshold = 100000;
And my reading function:
private void processGps(){
while (!closing)
{
//reconnect if needed
try
{
string sentence = port.ReadLine();
//here print the sentence
//analyze the sentence (this takes some time 50-100ms)
}
catch (TimeoutException)
{
Thread.Sleep(0);
}
catch (IOException ioex)
{
//handling IO exception (some info on the screen)
}
Thread.Sleep(200);
}
}
There is some more stuff in this function like reconnection if the device is lost etc., but it is not called when the GPS is connected properly. I was trying
port.DiscardInBuffer();
after some blocks of code (in TimeoutException, after read.)
Did anyone had similar problem? I really dont know what I'm doing wrong.. The only way to get rig of it is removing the last Sleep.
For all those who have similar problem. The first issue was about overflowing the buffer. I had 4096 size of buffer and the data was just flowing trough it so I was reading corrupted sentences. Now I read all buffer at once and analyze it. First sentence is sometimes corrupted, but the rest is ok.
The second thing was the device issue. Tom Tom MkII sometimes loses connection with the device. I had to restart the GPS and find it again in Bt devices list.
Regards
There's nothing in your post to say how you are doing handshaking.
Normally you would use software (XON/XOFF) or hardware (e.g. RTS/CTS) handshaking so that the serial port will tell the transmitting to stop when it is unable to receive more data. The handshaking configuration must (of course) match the configuration of the transmitting device.
If you fail to configure handshaking correctly, you may get away with it as long as you are processing the data fast enough - but when you have a Sleep, data may be lost.
I am trying to read data from a scale RS232 interface. It sends a continuous ASCII string stream through the Serial Port which I am having trouble getting. I just want to get one line of the data that it is sending out. I guess I assumed that I would use Readline to get the data, but it just locks up the PC when I run it. I think it is trying to get all of the data and won't stop until the data stops? Here is the code I'm using:
private void button1_Click(object sender, EventArgs e)
{
serialPort1.PortName = "COM4";
serialPort1.BaudRate = 9600;
serialPort1.DataBits = 8;
serialPort1.Parity = Parity.None;
serialPort1.StopBits = StopBits.One;
//opening the serial port
serialPort1.Open();
string str = serialPort1.ReadLine();
MessageBox.Show(str);
serialPort1.Close();
}
Can you help me to determine how to get just one line of the output data and close the connection?
SerialPort.ReadLine is defined to block "up to the first occurrence of a NewLine value", where NewLine defaults to a line feed. Are you sending a linefeed in your stream? Note that a linefeed character (ASCII 0x0A) is different that a carriage return (ASCII 0x0D) that you might be sending.
You can redefine the NewLine if needed, or if a line ending doesn't feel right, you can read up to a given string with SerialPort.ReadTo. You can also set a read timeout.
You might prefer to read a given number of bytes from the port, rather than a line, with one of the SerialPort.Read overloads.
If none of this applies, make sure that you're actually sending data where you think you are - bring up HyperTerminal/TeraTerm/your favorite serial terminal, configure it with the same serial port settings as you've used above, and make sure you see the data you expect to see.
An ideal solution would be to spawn a worker thread to actually read from the serial port (thus, the thread can be blocked all day long without impeding on your main application thread). Once data has been received, it can broadcast an event noting that data has been received and what that data is. The thread would communicate with the main application thread through the event.