I have a serial port app that read weighing machine.
public void Read()
{
while (Puerto.BytesToRead > 0)
{
try
{
string inputData = Puerto.ReadExisting();
dataReceived = inputData;
}
catch (TimeoutException) { }
}
}
the return string is like this
It has other extrange chars in it, how can i do to parse or get a clean data from it? all I need is 0.52lb
I have no idea what weighing machine is it and what the serial port specs on it but, if it is black box to you too then, check the following:
- check if you have a technical spec that explains what comes out of RS232 port
- do several (10?) samples with one sample weight and see if the number of bytes are delivered each time
- if you see the number of bytes being constant (barring discrepancy in the 0.52lb text changing to 0.5lb once in a while), it is likely that garbage following the weight is additional binary data.
- if not, and you see the weight (text) with exact offset each time, you just can scrape the output
this is complete reverse engineering, I suggest going after technical spec and doing more insightful data handling though.
This could be anything - a bug in the weighing machine, some sort of hardware issue, or a problem in how the serial port is configured. I would suspect a configuration problem. Make sure all the settings are correct (BaudRate, Handshake, Parity, StopBits). Also, try connecting to the same serial port device using another program (e.g. see http://helpdeskgeek.com/windows-7/windows-7-hyperterminal/ ) and see if you see the same garbage data.
Related
I am working on making GUI for a Smart Water flow meter whose communication protocol is RS485,
as per instructions from Communication Manual i am sending an inquiry packet and i am receiving proper response in serial port terminal. But when i am trying to do it on my C# app.
Things are happening oppositely.
string data = "[H201815000081]";
private void button1_Click(object sender, EventArgs e)
{
serialPort1.Write(data);
incoming_data = serialPort1.ReadExisting();
text_reciever.Text = incoming_data;
}
// text_reciver is the text box of my gui where i want to display the
// values from flow meter.Data Type of incoming_data is string
Here is the code, i am sending an inquiry code to the device and in return i am getting garbage values on my text box. Some times it is stream of Question mark symbol (?), some time it shows nothing.
But when i revert myself to serial port terminal (Real Term).
It is showing proper values as mentioned in communication manual.
Please assist in this regards.
After looking around i just found the answer to my question.
The point is previously i was communicating with serial port teminal, where everything was working fine, but when it comes to interacting with peripherals one need to make sure that Serialport.DTRProperty is enabled.
When opening the serial port one must enable the DTR property by:
serialPort1.DtrEnable = true;
Otherwise the windows form will read the garbage value.
the incoming data would be serial number of device (ASCII Format) and Water flow values
Question Withdrawn. I found out that I was sending incorrect ASCII patterns and THIS was my problem versus any problems with the receiver. Receiving a single character was merely the echo back of my wrong command
Summary:
C# form app. Serial 38400:N81 no flow control. Talking to a custom device.
If I use Teraterm, everything's fine.
The device I attach to gives simple, immediate responses:
Type 'v' you get a version string "v1.34 02-18-16 17:22" where the v in that is the local echo of the typed command. There are other status commands which are similar, once a character is received by the device, it replies immediately.
In my C# application I have pretty much exactly what you see in this guide under the example:
https://msdn.microsoft.com/en-us/library/system.io.ports.serialport.datareceived%28v=vs.110%29.aspx
Differences are that I'm at 38400 versus 9600 and I also do not set up the Handshake or the RtsEnable.
I've done this before so feeling stupid as to some obvious problem here. And I did do a bit of searching/following similar question links too.
Instead of receiving the version string, I receive one character '6'.
For a different command I also receive one character '8'. The notable thing here is that while '6' is part of my version string, '8' is never in the response for that other command.
Any suggestions on how I'd debug the ReadExisting() call?
I fully understand that a received string may arrive in fragments. The issue is that I always only ever receive the one character and nothing else. The event handler never sees any additional data. When I re-issue my version command I get the same '6' back I get before.
My event handler where I'm trying to test the receiver:
private void ReceiveData(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
Debug.WriteLine("Data Received: ");
Debug.Write(indata);
}
Under the debugger, indata.Length is 1.
Teraterm Port Settings:
I was suggested to look for errors and here's the code:
public event SerialErrorReceivedEventHandler ErrorReached;
protected virtual void OnReceiveError(SerialErrorReceivedEventArgs e)
{
SerialErrorReceivedEventHandler handler = ErrorReached;
if (handler != null)
{
handler(this, e);
}
Debug.WriteLine("Serial error");
}
I saw no errors.
Further comments were that the receiver needs to be run more than once. It is, when I issue a 'v' (just the v) I should see the version and 's' should give me status. Again, both work fine on Teraterm. I get 686868 if I issue vsvsvs or other matching patterns if I type like vvsss, I'll get 66888 in reply.
Other point is controlling this device if I issue r and s for run and stop, there is a LED on it which goes solid red (from intermittent flashing to indicate that it's running. I see it run and stop per my commands. So I know that I'm talking to the device in a proper/coherent fashion. Just still have troubles seeing valid receive data.
Some suggestions to try:
You're reading a string from the port, so if the data can't be readily interpreted as a string you may only get a fragment before it stops converting. Read into a byte array to be sure you are really seeing the data that you receive. Even if you think you should get a string, this lets you see what you are actually receiving.
Check your port settings. Symptoms of the wrong baud rate or encoding are frequently that you receive a reduced number of (possibly random, possibly repeatable) bytes of "garbage". This would be consistent with receiving characters that should not be in the response, and the string terminating early.
Remove all configuration options from your port, apart from setting the baud rate. Very few devices use anything other than 8n1 and attempting to set options can often screw the port up. If that doesn't work then start seeing additional options only if you have to.
Make sure you only open the port once and keep it open till you have finished talking to the device. (Repeatedly opening and closing the port I'd really five by accident, and would flush the data in it, interfering with your attempts to read)
I have an application that, among other things, uses the SerialPort to communicate with a Digi XBee coordinator radio.
The code for this works rock solid on the desktop under .NET.
Under Mono running on a Quark board and WindRiver Linux, I get about a 99% failure rate when attempting to receive and decode messages from other radios in the network due to checksum validation errors.
Things I have tested:
I'm using polling for the serial port, not events, since event-driven serial is not supported in Mono. So the problem is not event related.
The default USB Coordinator uses an FTDI chipset, but I swapped out to use a proto board and a Prolific USB to serial converter and I see the same failure rate. I think this eliminates the FTDI driver as the problem.
I changed the code to never try duplex communication. It's either sending or receiving. Same errors.
I changed the code to read one byte at a time instead of in blocks sized by the size identifier in the incoming packet. Same errors.
I see this with a variety of remote devices (smart plug, wall router, LTH), so it's not remote-device specific.
The error occurs with solicited or unsolicited messages coming from other devices.
I looked at some of the raw packets that fail a checksum and manual calculation gets the same result, so the checksum calculation itself is right.
Looking at the data I see what appear to be packet headers mid-packet (i.e. inside the length indicated in the packet header). This makes me think that I'm "missing" some bytes, causing subsequent packet data to be getting read into earlier packets.
Again, this works fine on the desktop, but for completeness, this is the core of the receiver code (with error checking removed for brevity):
do
{
byte[] buffer;
// find the packet start
byte #byte = 0;
do
{
#byte = (byte)m_port.ReadByte();
} while (#byte != PACKET_DELIMITER);
int read = 0;
while(read < 2)
{
read += m_port.Read(lengthBuffer, read, 2 - read);
}
var length = lengthBuffer.NetworkToHostUShort(0);
// get the packet data
buffer = new byte[length + 4];
buffer[0] = PACKET_DELIMITER;
buffer[1] = lengthBuffer[0];
buffer[2] = lengthBuffer[1];
do
{
read += m_port.Read(buffer, 3 + read, (buffer.Length - 3) - read);
} while (read < (length + 1));
m_frameQueue.Enqueue(buffer);
m_frameReadyEvent.Set();
} while (m_port.BytesToRead > 0);
I can only think of two places where the failure might be happening - the Mono SerialPort implementation or the WindRiver serial port driver that's sitting above the USB stack. I'm inclined to think that WindRiver has a good driver.
To add to the confusion, we're running Modbus Serial on the same device (in a different application) via Mono and that works fine for days, which somewhat vindicates Mono.
Has anyone else got any experience with the Mono SerialPort? Is it solid? Flaky? Any ideas on what could be going on here?
m_port.Read(lengthBuffer, 0, 2);
That's a bug, you have no guarantee whatsoever that you'll actually read two bytes. Getting just one is very common, serial ports are slow. You must use the return value of Read() to check. Note how you did it right in your second usage. Beyond looping, the simple alternative is to just call ReadByte() twice.
I have a USB to RS232 adapter and I was using it to get a long input (28 chars) from a barcode reader.
Everything works fine in my computer.
I installed my c# application on other computer that has RS232 Serial Port connected to its PCI-E and when I'm receiving the input from the barcode reader, it splits it into two parts!
How do I know that? Because I have an event handler for DataReceived on my c# application, and it's being called 2 times, and each time I get a part of the input.
The RS232 PCI-E ports are manufacturer by Oxford Semiconductor Inc.
OS is Windows 7.
I'm assuming it's a hardware issue and not a problem in my application.. Maybe some settings to change, a buffer size or something like that but I could't find something like that.
Thanks in advanced!
No, it is your application. You shouldn't expect all of the data to be immediately available; you were getting lucky on the first machine. You need to call Read() until you get everything you expect.
Differences in the UARTs, drivers, etc. can cause windows to raise that event multiple times, depending on timing and other factors.
Something along these lines:
char buf[28];
int offset = 0;
int nread;
while (offset < buf.Length) {
nread = comPort.Read(buf, offset, buf.Length - offset);
offset += nread;
}
what should i do to wait until all the data sent to serial port
to test this condition assume the code bellow:
Console.WriteLine("Baud is:" + SerialPortObj.BaudRate);
Console.WriteLine(DateTime.Now.Millisecond);
string tmpStr="";
for (int i = 0; i < 100; i++)
{
tmpStr += "A";
}
SerialPortObj.Write(tmpStr.ToCharArray(),0,99);
Console.WriteLine(DateTime.Now.Millisecond);
example output is:
Baud is:300
97
97
And it indicate that .Net is not waiting until all chars to be send!
just to mention the code below does not work:
Console.WriteLine("Baud is:" + SerialPortObj.BaudRate);
Console.WriteLine(DateTime.Now.Millisecond);
string tmpStr="";
for (int i = 0; i < 100; i++)
{
tmpStr += "A";
}
SerialPortObj.Write(tmpStr.ToCharArray(),0,99);
while (SerialPortObj.BytesToWrite>0)
{
Thread.Sleep(1);
Console.WriteLine(SerialPortObj.BytesToWrite);
};
Console.WriteLine(DateTime.Now.Millisecond);
example output is:
Baud is:300
97
97
i am working on an special protocol that is depends on baud rate change over and use some thing like the follow:
->[Send Some Bytes (Baud300)]
<-[Receive Another Bytes (Baud9600)]
so i want to send some chars by write method and wait until it finish and right after finishing i try to change baud , so i could understand the received bytes
is there any idea?
In the first place the serial port is stateless. So you can never really by sure when the right point in time is reached for a baud rate change. Due to the fact that you are going to implement your own special protocol you must have control of both sides of the communication (sender/receiver). So in that case i strongly recommend to also set the Handshake property to RequestToSend and checking of the DtrEnable property.
Also you should use two buffers (received/outgoing) on each site of the communication which are watched by their own task/thread. If you push something into the outgoing buffer, the task check if sending is possible (CtsHolding, DsrHolding) and if yes, change the baudrate and push that data onto the wire. Wait till the holding properties are set back and then change the baudrate to the other value. The incoming thread is quite simple in this case. It simply waits for the DataReceived event cause the change of the baudrate is done by the outgoing task.
If you use hardware handshake (which i strongly recommend in your case), then be sure that your serial port supports it correctly. Most of the USB-to-Serial-Adapters don't work very well with anything else then 19200-8-N-1. So before you think you didn't code it right or the SerialPort class is buggy try to find two machines with a real serial port (or one machine with two ports for testing).
Try to store your data in a variable and when a specific condition apear (can be set by you), send the value of the variable to the serial port
Do it in hardware?
You might try to use two serial adaptors, configured as 300/9600. Tx on one and rx on the other. You would need a 'funny cable' with pins 2/3 split out to different D-types, but that should work.