views:

2067

answers:

3

I'm very new to sending data over a serial port through .net and I've noticed after implementing a TCP counterpart that I wouldn't get it that easy with serial!

So to start at the top, I am nearly there with my serial bi-directional communication implementation I am just getting stuck on a few things: -

  1. My reads are being split across multiple messages or received as a fragmented response over the COM port and I don't know what settings I might need, or how I should write the code differently to fix this. What could cause this? I am inspecting the message at a breakpoint on SerialPort_DataReceived.

Basically the data should be sent as:

01: LS|DA090521|TI111043|q
02: PS|RN102|PTC|TA1040000|P#0|DA090521|TI111429|j

but it is being split (at random positions on each requested read)

01: LS|DA090521|TI111
02: 043|q
03: PS|RN102|PTC|TA1
04: 0000|P#0|DA090521|TI111429|j

- Question 1 has been answered, thanks Chris W. and others! I now have the message I expect being built from fragments progressively (looking out for STX, {msg body}, ETX) and then an action performed when message has been completely built, and got it going with a thread-safe Queue, very happy.

. 2. I am receiving a "|" symbol through my read nearly every cycle, is this due to a command I have set wrongly somehow, an artifact of Serial communication, or something the device is sending me? (I don't think so though, as Hyperterminal connectivity reveals this character is not being sent continuously.)

. 3. Can you confirm I am reading and writing data correctly in the respective methods.

Thanks guys for looking at my other two questions too.

Relevant code as follows:

...
    //                          COM3,    9600,     None,   8,        One
    SerialPort = new SerialPort(comPort, baudRate, parity, dataBits, stopBits);
    if (SerialPort.IsOpen) SerialPort.Close();
    // SerialPort.RtsEnable = true; // Request-to-send
    // SerialPort.DtrEnable = true; // Data-terminal-ready
    SerialPort.ReadTimeout = 150; // tried this, but didn't help
    SerialPort.WriteTimeout = 150; // tried this, but didn't help
    SerialPort.Open();

    SerialPort.DataReceived += new SerialDataReceivedEventHandler(SerialPort_DataReceived);
}

void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    // Process received data
    SerialPort sp = (SerialPort)sender;
    byte[] buffer = new byte[sp.BytesToRead];
    int bytesRead = sp.Read(buffer, 0, buffer.Length);

    // message has successfully been received
    message = Encoding.ASCII.GetString(buffer, 0, bytesRead);
}

public bool SendMessage(string text)
{
    // Only send message if a client is connected
    if (SerialPort != null && SerialPort.IsOpen)
    {
        byte[] buffer = Encoding.ASCII.GetBytes(text);
        SerialPort.Write(buffer, 0, buffer.Length);
    }
}
+1  A: 

My reads are being split across multiple messages

This is normal, expected, inevitable behaviour. It can happen with data-over-TCP as well. To the serial interface it's just an endless stream of bytes. It's your application's responsibility to repackage those bytes into packets.

If the location of packet boundaries is important, and if you can't tell where the packet boundaries are supposed to be from looking at the received data, then you may need to rethink the format of the data so that you can tell where the packet boundaries are.

I am receiving a "|" symbol through my read nearly every cycle

What's the hex value of that character? See whether setting the Handshake property to XOnXOff or RequestToSendXOnXOff improves the situation.

ChrisW
Thanks for the reply Chris, appreciate it. Ok, perhaps I am trying to put this in too much of a box, if what you are saying is we almost need to do our own 'packet management', which, shamefully (I didn't realise) is probably the basis behind serial transport, then I might need to interrogate the start of msg/end of msg characters, package it up, clean and rinse and repeat.
GONeale
'|' equals 124 btw.
GONeale
I don't know then; the default XON/XOFF values are 0x13 and 0x11 :- http://en.wikipedia.org/wiki/XON
ChrisW
Thanks for your suggestions Chris! I now have the message being built progressively (looking out for STX, {msg body}, ETX) and then an action performed when message has been completely built, and got it going with a thread-safe Queue<T>, very happy.
GONeale
That souds like the right way, and I am reassured that you understand words like "ETX". There's also a useful property named ReadIntervalTimeout in the COMMTIMEOUTS structure passed to the Win32 SetCommTimeouts function, which might suit you if the DCE sends entire packets with little delay between each byte and some delay between each packet; but the .NET API doesn't apparently include this function/property.
ChrisW
No problem. Thanks.
GONeale
+1  A: 

At the lower level the serial port can decide when to trigger the data received event. It might decide to do that before the "full" packet has arrived. But, it looks like you have a terminator character in your expected data set. If so you can do the following (note I have changed your SerialPort assignment to avoid syntax confusion:

        p = new SerialPort(PortName, BaudRate, Prty, DataBits, SBits);
        p.NewLine = Terminator;

where Terminator is a string containing your termination character(s). Then you can use SerialPort.ReadLine() (and SerialPort.WriteLine() if that applies). This might at least help with your first issue.

Thanks reading the hint on "NewLine" tends to make sense, I was too used to TCP and the idea of packets being created and handled for you. I just assumed I can "send messages" and then receive them. :)
GONeale
As you can see my NewLine character I believe should be 0x03, well, actually 0x03 + "j". We have no idea why it prints a random alpha character at the end, right now it tends to always be "j". I don't know if this is correlating, and I should understand NewLine as the character/s I wish to split the data received into?
GONeale
p.NewLine can be a string with any number of characters. I've only ever worked with devices where it's "\n" or "\r\n" but anything would do. What's the last character on the first line of your packet example?
Well, 0x03 (which is ). But I will need to check 0x03 + the random character, which I've since learnt is a BCC (block check character).
GONeale
Sorry, I was using an older browser which rendered the 0x03 weirdly. Anyway, yes you can set p.Terminator = "\x03", then use p.ReadLine(), and probably remove the delegate in the bargain. On another note, .NET has properties p.ReadTimeout and p.WriteTimout, both specified in integer milliseconds. Hope this info is still useful to you!
+1  A: 

I have done a lot of Win32 serial port programming, but just a little with .NET, so take my advice with some salt.

My reads are being split across multiple messages or received as a fragmented response over the COM port and I don't know what settings I might need, or how I should write the code differently to fix this.

As others have said, this is perfectly normally. Depending on what type of equipment is on the DCE side, you may have to do repacking yourself. I'm not sure what type of equipment you're hooked up to so I cannot really say much more.

If you want to get more data, you can try:

  • adjusting the System.Int32 ReceivedBytesThreshold property
  • using synchronous I/O and specifying a fixed number of bytes to read rather than event-based reception

I am receiving a "|" symbol through my read nearly every cycle, is this due to a command I have set wrongly somehow, an artifact of Serial communication, or something the device is sending me? (I don't think so though, as Hyperterminal connectivity reveals this character is not being sent continuously.)

If you're curious about what is going over the line, check out PortMon from SysInternals, a free app that will snoop your com port while you're transferring data over the line. It seems technical, but really you just have to look at the IRP_MJ_WRITE and IRP_MJ_READ commands, and on the line you'll see the length in bytes and the data sent over the wire. With this you should be able to tell if the problem is the .NET SerialPort object or if the device is actually sending "|" over the line.

Can you confirm I am reading and writing data correctly in the respective methods.

It looks proper for the event-based method of receiving data.

Dr. Watson
Great, really insightful, especially the PortMon tool. That should let me know where it is originating from.. I am now handling my packet manually, which is working well, I will update my post for point 1.
GONeale