SerialPort.Read truncates received data

Hi everybody. I am having problems reading serial data that includes 0x02 and 0x03 ‘characteres’ (STX and ETX).

SerialPort.Read truncates the data at the 0x02 position and I only get the data before the 0x02. I verified that using a Y serial cable connected to my G80 COM3 and to Hyperterminal in parallel. Hyperterm shows all the data, but SerialRead stops reading when it finds a 0x02. If I check for data using SerialPort.BytesToRead after that, it says there is no further data to read.

This is the code:

public static SerialPort COM3 = new SerialPort("COM3");
...
public static void COM3_init() {
	COM3.BaudRate=2400;
	COM3.ReadTimeout = 0;
	COM3.Handshake = Handshake.None;
	COM3.Open();
}
...

public static void Thread_Read_COM3() {
	while(true) {
		if (COM3.BytesToRead > 0)
		{
			Thread.Sleep(my_wait);	// I've tried even with my_wait=3000 to give it time
			msg3len = COM3.BytesToRead;
			COM3.Read(bCOM3rcv, 0, COM3.BytesToRead);
			// At this point I get only the bytes BEFORE the 0x02

			// I added this to check again in case the rest of the data is available after reading the first part
			Thread.Sleep(my_wait);   
			if (COM3.BytesToRead > 0) {
				// I check for more bytes to read, but there are no more.
			}
			...
		}
		Thread.Sleep(100);	
	}
}

Thanks a lot for your help.

JCP

i belive this code could help you
https://www.ghielectronics.com/docs/15/uart-serial

i am also using TinyCLR ports 0.5.0 and have no problem with handle of this two bytes with [RDM6300 RFID CODE] (https://github.com/valoni/TinyCLR_Drivers/tree/master/TinyCLR%20Os%20Examples/RDM6300/)

1 Like

Thanks a lot for sharing your code and . There must be something I’m doing wrong. I’ll look at your code and try to figure out where my mistakes are.

Have a look at this code. It is running quite happily in many installations of our system in EU hospitals environments.

using System.IO.Ports;
using System.Threading;

namespace PPlusApplicatorID
{
internal class InterfaceIO
{
private readonly SerialPort port;
private readonly byte[] inBuffer = new byte[32];
private readonly byte[] outBuffer = new byte[32];
private readonly Globals g;
private int i;
private int inByte;

    private int waitLoop = 100;

    private const byte Enq = 0x05;
    private const byte Stx = 0x02;
    private const byte Etx = 0x03;

    public enum Commands : byte
    {
        GetStatus = 0,
        ClearStatusCodes
    }

    public InterfaceIO(Globals value)
    {
        this.g = value;

        // Instance IO and open the port
        this.port = new SerialPort("COM1");
        this.port.BaudRate = 9600;
        this.port.Parity = Parity.None;
        this.port.DataBits = 8;
        this.port.StopBits = StopBits.One;
        this.port.Handshake = Handshake.None;
        this.port.ReadTimeout = Timeout.Infinite;
        this.port.Open();

        // Clear the buffers down
        this.ClearBytes(inBuffer);
        this.ClearBytes(outBuffer);
    }

    public void ClearBytes(byte[] bytes)
    {
        for (i = 0; i < bytes.Length; i++)		    // Clear the byte block
        {
            bytes[i] = 0;
        }
    }

    public void PerformIo()
    {
        while (true)
        {
            this.ClearBytes(inBuffer);
            this.port.DiscardInBuffer();

            inByte = this.port.ReadByte();
            g.Led.Flash();
            switch (inByte)
            {
                case Enq:   // Get current status
                    this.ClearBytes(outBuffer);

                    // Command
                    this.outBuffer[0] = (byte)Commands.GetStatus;

                    // Temperature
                    this.outBuffer[1] = (byte)(this.g.Temperature & 0xFF);

                    // Applicator 1
                    this.outBuffer[2] = (byte)(this.g.Applicator1 & 0xFF);

                    // Applicator 2
                    this.outBuffer[3] = (byte)(this.g.Applicator2 & 0xFF);

                    // Filter
                    this.outBuffer[4] = (byte)(this.g.Filter & 0xFF);

                    // Status
                    this.outBuffer[5] = (byte)(this.g.Status);

                    // Versions
                    this.outBuffer[6] = this.g.VerMajor;
                    this.outBuffer[7] = this.g.VerMinor;

                    // CRC8
                    this.outBuffer[8] = this.g.Crc8.DoCrc8(this.outBuffer, 8);

                    this.port.WriteByte(Stx);
                    this.port.Write(this.outBuffer, 0, 9);
                    this.port.WriteByte(Etx);
                    break;

                case Stx:   // Start a command
                    this.port.Read(this.inBuffer, 0, 1);
                    this.ProcessCommand(inBuffer[0]);
                    break;

                default:    // Ignore all else
                    break;
            }

            Thread.Sleep(10);
        }
    }

    private void ProcessCommand(byte p)
    {
        waitLoop = 100; // 100 * 10ms = 1 second
        switch (p)
        {
            case (byte)Commands.ClearStatusCodes:
                while (this.port.BytesToRead < 3 && --waitLoop > 0)
                {
                    Thread.Sleep(10);
                }

                if (waitLoop > 0)
                {
                    try
                    {
                        this.port.Read(this.inBuffer, 1, 3);
                        if (this.g.Crc8.CrcCheck(this.inBuffer, 2) && (this.inBuffer[3] == Etx))    // Command was well formed
                        {
                            this.g.Status = ErrorFlags.NoError;

                            this.ClearBytes(outBuffer);
                            this.outBuffer[0] = (byte)Commands.ClearStatusCodes;
                            this.outBuffer[1] = (byte)(this.g.Status);
                            this.outBuffer[2] = this.g.Crc8.DoCrc8(this.outBuffer, 2);

                            this.port.WriteByte(Stx);
                            this.port.Write(this.outBuffer, 0, 3);
                            this.port.WriteByte(Etx);
                        }
                    }
                    catch
                    {
                    /* ignore the whole command */ 
                    }
                }
                break;

            default:
                // Ignore the command
                break;
        }
    }
}

}

1 Like

Perhaps it’s the ReadTimeOut = 0;

The read time-out value was originally set at 500 milliseconds in the Win32 Communications API. This property allows you to set this value. The time-out can be set to any value greater than zero, or set to InfiniteTimeout, in which case no time-out occurs.InfiniteTimeout is the default.

1 Like

Thank you RoSchmi and Ariane_Medical. I try ReadTimeout=Timeout.Infinite;

Regards, JCP

To avoid characters to be interpreted as control characters you can wrap your file or data as base64 string:

            byte[] textAsBytes = encoding.GetBytes(text);
            encodedText = Convert.ToBase64String(textAsBytes);
2 Likes