TimeOutException и SerialPort в Delphi Prism - PullRequest
       40

TimeOutException и SerialPort в Delphi Prism

0 голосов
/ 23 августа 2011

Мне нужна моя программа для перехвата TimeOutException каждый раз, когда время ожидания SerialPort истекло, но это не удается. Фактически, программа прерывается, когда идет на чтение, и выдает это исключение, "Операция ввода-вывода была прервана из-за выхода из потока или запроса приложения."

Вот как реализован SerialPort:

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;

Вот как создается нить:

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

Вот настройки SerialPort:

   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;

Вот мой поток, который обрабатывает 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;

Вот событие для чтения байтов из последовательного порта:

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;

Что я делаю не так? Мне нужно перехватить SerialPort.Read TimeOuts и предпринять соответствующие действия.

Ответы [ 3 ]

1 голос
/ 24 августа 2011

Кажется, вы используете последовательный порт в качестве компонента формы, но делаете чтение / запись в фоновом потоке?

Или, как я понял, вы пишете в фоновом потоке, а затемчитать о каком-то другом, случайном потоке (который вызывает событие, на которое вы реагируете).

Это проблема, потому что фоновый поток тогда (внутренне) хочет обновить последовательный порт 'Control',что не разрешено из фоновых потоков.Проблема также может заключаться в том, что ожидающий чтения поток прерывается другим потоком, который пишет в бесконечном цикле, и, таким образом, вызывает исключение ввода-вывода.Здесь нужно немного гадать.

Первый выстрел: вы должны либо создать последовательный порт динамически (т.е. не помещать его в форму, а создать и настроить его с помощью кода), чтобы предотвратить это, либо (настоятельно не рекомендуется), установите для System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls значение false.

Второй снимок: С другой стороны, я настоятельно рекомендую убедиться, что с последовательным портом работает только один поток.Не писать в одной теме, а читать из другой.Делайте все, что связано с этим последовательным вводом / выводом, в одном потоке.Читай ИЛИ пиши, но не пытайся делать оба одновременно из разных потоков.

0 голосов
/ 31 августа 2011

Я полагаю, что проблема заключается в том, что я пишу в последовательный порт в своем собственном потоке или в пользовательском потоке и читаю из последовательного порта в другом.Я думаю, что полученное событие является частью основного потока программы.

Как указал Себастьян, имеет смысл, что запись и чтение из одного потока должны решить мою проблему последовательной связи.Действительно, похоже, надо было решить мою последовательную связь, хотя она составляет чуть менее 100%.Это проблема времени, так как моя программа зависит от фиксированных временных задержек.

Шаги: Внутри моего потока я пишу в последовательный порт и жду некоторое время, чтобы прочитать ответ из последовательного порта.Похоже, что это значительно улучшило связь, но теперь я не жду, когда сработает событие приема данных, когда оно увидит что-то во входном буфере.

Исправьте меня, если я ошибаюсь в своих мыслях или рассуждениях.

0 голосов
/ 24 августа 2011

Вместо: SerialPort1.Read (RXMsg, 0,5);

Есть ли в Delphi последовательная функция, которая возвращает количество символов, полученных и ожидающих чтения? * Например, 1003 *

(вероятно, в плохом псевдокоде):

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