user3272241
user3272241

Reputation: 67

Recovering from ComPort drop-out

D5-pro: Using TurboPower APro and the ComPort and Terminal Components with USB Arduino Nano for a very basic Comms-Terminal. All works fine until I unplug the USB to simulate losing the Port. It all just hangs and will not restart without closing and restarting.

I cannot find an Event or process that is monitoring the Port status so I can gracefully shut the Port. I am able to prevent the Port being opened if it doesn't exist, but once opened and data streaming in, I seem to lose all access to it.

I also tried TComPort and Terminal by Dejan Crnila and it also does not stop gracefully either. It actually crashes and I have to use TaskManager to shut it all down.

Can someone please guide me with some code snippets that might give an indication that the port has gone missing. Or is there a better free Component for doing this.

Upvotes: 0

Views: 396

Answers (1)

Helen Downs
Helen Downs

Reputation: 390

Some modifications in the AwUser unit are required.

  1. Add a new event for I/O errors.

    TPortIOErrorEvent = procedure(CP : TObject; Error : Cardinal) of object; property OnPortIOError: TPortIOErrorEvent read FOnPortIOError write FOnPortIOError;

  2. Modify the TComThread.Execute method in the AwUser unit.

          {Release time slice until we get a communications event}
      if not WaitComEvent(CurrentEvent, @ComOL) then begin
        if GetLastError = ERROR_IO_PENDING then begin
          if GetOverLappedResult(CidEx,
                                 ComOL,
                                 Junk,
                                 True) then begin
    
            {WIN32 bug workaround: Apro gets the modem status bits
            with a call (later) to GetCommModemStatus. Unfortunately,
            that routine never seems to return either RI or TERI.
            So, we note either EV_RING or EV_RINGTE here and later
            manually merge the TERI bit into ModemStatus.}
            if ((CurrentEvent and EV_RINGTE) <> 0) or
               ((CurrentEvent and EV_RING) <> 0) then
              RingFlag := True;
    
            {Read complete, reset event}
            ResetEvent(ComOL.hEvent);
          end else begin
            {Port closed or other fatal condition, just exit the thread}
            SetEvent(GeneralEvent);
            CloseHandle(ComOL.hEvent);
            H.ThreadGone(Self);
            Exit;
          end;
        end else begin
          Err := GetLastError; {!!! added code}
          { If we get an ERROR_INVALID_PARAMETER, we assume it's our }
          { use of ev_RingTe -- clear the flag and try again }
          if (GetLastError = ERROR_INVALID_PARAMETER) and
             (LastMask and EV_RINGTE <> 0) then begin
            LastMask := DefEventMask and not EV_RINGTE;
            SetCommMask(CidEx, LastMask);
          end;
          {!!! added code begin}
          if (Err <> ERROR_INVALID_PARAMETER) and (Err>0) and Assigned(FOnPortIOError) then
           FOnPortIOError(H.fOwner, Err)
          {!!! added code end}
        end;
      end;
    
  3. Add the similar code to "ProcessOutputEvent".

  4. In the new event handler analyze the I/O error and close/re-open the port.

Upvotes: 0

Related Questions