0

I need my program to catch TimeOutException every time SerialPort Read Times out, but it fails to do that. In fact, the program breaks when it goes to read and throws this exceptions, "The I/O operation has been aborted because of either a thread exit or an application request."

Here is how SerialPort Instantiated:

dxComm = class(System.Windows.Forms.Form)
private
protected
public
    constructor;
    serialPort1:System.IO.Ports.SerialPort;
    thr:Thread;
    method mythread;
end;

constructor DXComm;
begin
  //
  // Required for Windows Form Designer support
  //
  InitializeComponent();

  //
  // TODO: Add any constructor code after InitializeComponent call
  //
  SerialPort1 := new System.Io.Ports.SerialPort();
  thr:=nil;
end;

Here is how thread is created:

          thr:= new Thread(@mythread);
          thr.Start;

Here is the SerialPort settings:

   case TypeDXCard.SelectedIndex of

    0:
      begin
        DXProtocol := TDXProtocol.tDxTwo;
        msglen := 6;
        rmsglen := 5;
      end;
    1:
      begin
        DXProtocol := TDXProtocol.tDxExpress;
        msglen:=0;
        rmsglen:=0;
      end;

    else
      begin
        DXProtocol := TDXProtocol.tDxTwo;
        msglen := 6;
        rmsglen := 5;
      end;
  end;

  dx := ord(DXProtocol);

  if (SerialPort1 <> nil) then
  begin
      case CommPort.SelectedIndex of
        0: SerialPort1.PortName := 'COM1';
        1: SerialPort1.PortName := 'COM2';
        2: SerialPort1.portName := 'COM3';
        3: SerialPort1.PortName := 'COM4';
      end;    

       case BaudRate.SelectedIndex of
         0: SerialPort1.BaudRate := 1200;
         1: SerialPort1.BaudRate := 2400;
         2: SerialPort1.BaudRate := 4800;
         3: SerialPort1.BaudRate := 9600;
         4: SerialPort1.BaudRate := 19200;
         5: SerialPort1.BaudRate := 38400;
         6: SerialPort1.BaudRate := 57600;
         7: SerialPort1.BaudRate := 115200;
      end;

      if (EvenParity.Checked) then
        SerialPort1.Parity := System.IO.Ports.Parity.Even
      else
        SerialPort1.Parity := System.IO.Ports.Parity.None;
  end;

  with SerialPort1 do
  begin
    SerialPort1.DataBits:=8;
    SerialPort1.DtrEnable:=true;
    SerialPort1.ReadBufferSize:= 4096;
    SerialPort1.ReadTimeout:=TimeOutDelay*2;
    SerialPort1.RtsEnable:=true;
    SerialPort1.StopBits:=System.IO.Ports.StopBits.One;
    SerialPort1.WriteTimeout:=1000;
    SerialPort1.Handshake := HandShake.None;
    SerialPort1.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(@MySerialData);
  end;

Here is my Thread that handles the SerialPort.Write:

method DXcomm.mythread;
var x,y:Integer;
begin
    while true do
    begin        
        Thread.Sleep(ScanTime);
        SerialPort1.RtsEnable:=true;
        SerialPort1.DiscardOutBuffer;
        SendMessage;   <---------Assembles the bytes and sends it out
        while SerialPort1.BytesToWrite>0 do;
        thread.Sleep(4);
        SerialPort1.DiscardInBuffer;
        SerialPort1.RtsEnable:=false;

        if (stopthread) then
            break;
    end;
end;

Here is the event for reading bytes from the serialport:

method DXComm.MySerialData(sender: System.Object; e:SerialDataReceivedEventArgs);
begin
    if not SerialPort1.IsOpen then Exit;   

    try
        SerialPort1.Read(RXMsg,0,5); <------Here is Where my program throws that exception when I check on TimeOutException down below.

          if changeFlag then
          begin
               changeList.IncRxCnt;
               FixUpChangeList;
          end
          else
              ActiveUnit.Retreive;       
    except on ex: TimeOutException do <----This line of code fails.
    //except on ex: Exception do      <----This line of code works fine, but executes all the time instead of just only when there is an exception.
    begin
        //TimeOut Exception
        ActiveUnit.Timeout;
        SerialPort1.DiscardInBuffer;
        SerialPort1.DiscardOutBuffer;
    end;
    end;
end;

What am I doing wrong? I need to catch SerialPort.Read TimeOuts and take appropriate action.

3 Answers 3

1

It seems you're using the Serial port as a component on a form but doing the reading / writing in a background thread?

Or, as I got it, you write in a background thread and then read on some other, random, thread (the one that is calling the Event you react on).

That is a problem, because the background thread then (internally) want's to update the Serial Port 'Control', which isn't allowed from Background threads. The problem could also be that the thread waiting to read is interrupted by the other thread that is writing in the infinite loop and thus causes the I/O exception. It's a bit of guessing involved here.

First shot: You have to either create the Serial Port dynamically (i.e. not putting it on your form but instanciating and configuring it by code) to prevent that or (strongly discouraged though), set System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls to false.

Second shot: On the other hand I would strongly suggest to make definetly sure that only one thread at all is working with the serial port. Not writing in one thread and reading from another. Do everything that is related to this serial I/O in one single thread. Read OR write, but do not try to do both at the same time from different threads.

Sign up to request clarification or add additional context in comments.

5 Comments

@ Sebastian, SerialPort is dynamically created within the Winform class not placed on the form as a control. I believe I only have one thread that directly deals with SerialPort communication.
I suggest debugging and checking the Thread ID right before the Read line, the Thread ID on every sending and the Thread ID of the occuring exception. I would really wonder if all are always the same.
@ Sebastian, you are correct in that the thread is switching its ID every so often or after number of cycle, but there is only one thread. Is this because method MySerialData part of the dxCommWin window form?
@ Sebastian, I am seeing more interesting things while debugging the thread. It seems that after every cycle of serial communication a new thread is spun or created but they are either in sleep or wait or join state.
Then you really have a threading problem. You should make sure that everything runs in the same thread, or, as stated, set CheckForIllegalCrossThreadCallsto false, but this is globally for the application and can cause other problems.
0

Instead of: SerialPort1.Read(RXMsg,0,5);

Does Delphi have a serial function that returns the number of characters received and waiting to be read?

For example(in probably poor pseudo code):

while (Not Timeout)
{
    if (serialport1.characterswaiting)
    {
        SerialPort1.Read(RXMsg,0,5);
    }
}

1 Comment

This is Delphi Prism and hence pure .Net.
0

I believe the problem lies in the fact that I am writing to the serialport in my own thread or user-defined thread and reading from the serialport in another. The event datareceived is part of the main thread of the program, I think.

As pointed out by Sebastian, it makes sense that writing and reading from the same thread should solve my serial communication problem. Indeed, it seems have to solved my serial communication, although it is little less than 100%. That's a timing issue, since my program depends on fixed time delays.

The steps: Within my thread, I write to the serial port and wait for sometime to read the response from the serialport. This seems to have greatly improved the communication, but now I don't wait for the datareceived event to fire once it sees something in the input buffer.

Correct me if I am wrong in my thinking or reasoning.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.