Program: 74683
Project: 74683
Buggy source:
/** 
 * If input data is available at the serial port, read it and produce it as a byte array at the output port of this actor; if a token is available at the input port of this actor, consume it and send the bytes contained by this token to the serial port.  If <i>blocking</i> is true, then after writing the input data to the serial port, stall the calling thread until there are input data available at the serial port. The <i>minimumOutputSize</i> specifies the minimum number of bytes that must be available. <p> Before returning, if data is sent to the serial port, this method calls flush(). However, the flush() method does not wait for the hardware to complete the transmission, as this might take many milliseconds (roughly 1mS for every 10 bytes at 115200 baud). Consequently, the data will not have been completely produced on the serial port when this returns. <p> If data is still available on the serial port when this returns, then before returning it calls fireAtCurrentTime() on the director.
 * @exception IllegalActionException Not thrown in this base class.
 */
public synchronized void fire() throws IllegalActionException {
  super.fire();
  try {
    if ((dataToSend.getWidth() > 0) && dataToSend.hasToken(0)) {
      ArrayToken dataArrayToken=(ArrayToken)dataToSend.get(0);
      OutputStream out=_serialPort.getOutputStream();
      int inputLength=dataArrayToken.length();
      if (_debugging) {
        _debug("String_Node_Str" + inputLength);
      }
      for (int j=0; j < inputLength; j++) {
        UnsignedByteToken dataToken=(UnsignedByteToken)dataArrayToken.getElement(j);
        out.write(dataToken.byteValue());
      }
      out.flush();
    }
    InputStream in=_serialPort.getInputStream();
    int bytesAvailable=in.available();
    if (_debugging) {
      _debug("String_Node_Str" + bytesAvailable);
    }
    while ((bytesAvailable < _minimumOutputSize) && _blocking && !_stopRequested&& !_stopFireRequested) {
      try {
        if (_debugging) {
          _debug("String_Node_Str" + _minimumOutputSize);
        }
        wait();
        bytesAvailable=in.available();
        if (_debugging) {
          _debug("String_Node_Str" + bytesAvailable);
        }
      }
 catch (      InterruptedException ex) {
        throw new IllegalActionException(this,"String_Node_Str");
      }
    }
    if (bytesAvailable >= _minimumOutputSize) {
      if (_discardOldData && (bytesAvailable > _maximumOutputSize)) {
        int excess=bytesAvailable - _maximumOutputSize;
        if (_debugging) {
          _debug("String_Node_Str" + excess);
        }
        bytesAvailable-=(int)in.skip(excess);
      }
      int outputSize=bytesAvailable;
      if (outputSize > _maximumOutputSize) {
        outputSize=_maximumOutputSize;
      }
      byte[] dataBytes=new byte[outputSize];
      if (_debugging) {
        _debug("String_Node_Str" + outputSize);
      }
      int bytesRead=in.read(dataBytes,0,outputSize);
      if (bytesRead != outputSize) {
        throw new IllegalActionException(this,"String_Node_Str" + bytesRead + "String_Node_Str"+ outputSize+ "String_Node_Str");
      }
      Token[] dataTokens=new Token[outputSize];
      for (int j=0; j < outputSize; j++) {
        dataTokens[j]=new UnsignedByteToken(dataBytes[j]);
      }
      if (_debugging) {
        _debug("String_Node_Str");
      }
      dataReceived.broadcast(new ArrayToken(BaseType.UNSIGNED_BYTE,dataTokens));
      int available=in.available();
      if (available >= _minimumOutputSize) {
        if (_debugging) {
          _debug("String_Node_Str" + available);
        }
        getDirector().fireAtCurrentTime(this);
      }
    }
  }
 catch (  IOException ex) {
    throw new IllegalActionException(this,ex,"String_Node_Str");
  }
 finally {
    _directorFiredAtAlready=false;
  }
}

Fixed version (ground truth):
/** 
 * If input data is available at the serial port, read it and produce it as a byte array at the output port of this actor; if a token is available at the input port of this actor, consume it and send the bytes contained by this token to the serial port.  If <i>blocking</i> is true, then after writing the input data to the serial port, stall the calling thread until there are input data available at the serial port. The <i>minimumOutputSize</i> specifies the minimum number of bytes that must be available. <p> Before returning, if data is sent to the serial port, this method calls flush(). However, the flush() method does not wait for the hardware to complete the transmission, as this might take many milliseconds (roughly 1mS for every 10 bytes at 115200 baud). Consequently, the data will not have been completely produced on the serial port when this returns. <p> If data is still available on the serial port when this returns, then before returning it calls fireAtCurrentTime() on the director.
 * @exception IllegalActionException Not thrown in this base class.
 */
public synchronized void fire() throws IllegalActionException {
  super.fire();
  try {
    if ((dataToSend.getWidth() > 0) && dataToSend.hasToken(0)) {
      ArrayToken dataArrayToken=(ArrayToken)dataToSend.get(0);
      OutputStream out=_serialPort.getOutputStream();
      int inputLength=dataArrayToken.length();
      if (_debugging) {
        _debug("String_Node_Str" + inputLength);
      }
      for (int j=0; j < inputLength; j++) {
        UnsignedByteToken dataToken=(UnsignedByteToken)dataArrayToken.getElement(j);
        out.write(dataToken.byteValue());
      }
      out.flush();
    }
    InputStream in=_serialPort.getInputStream();
    int bytesAvailable=in.available();
    if (_debugging) {
      _debug("String_Node_Str" + bytesAvailable);
    }
    while ((bytesAvailable < _minimumOutputSize) && _blocking && !_stopRequested) {
      try {
        if (_debugging) {
          _debug("String_Node_Str" + _minimumOutputSize);
        }
        wait();
        bytesAvailable=in.available();
        if (_debugging) {
          _debug("String_Node_Str" + bytesAvailable);
        }
      }
 catch (      InterruptedException ex) {
        throw new IllegalActionException(this,"String_Node_Str");
      }
    }
    if (bytesAvailable >= _minimumOutputSize) {
      if (_discardOldData && (bytesAvailable > _maximumOutputSize)) {
        int excess=bytesAvailable - _maximumOutputSize;
        if (_debugging) {
          _debug("String_Node_Str" + excess);
        }
        bytesAvailable-=(int)in.skip(excess);
      }
      int outputSize=bytesAvailable;
      if (outputSize > _maximumOutputSize) {
        outputSize=_maximumOutputSize;
      }
      byte[] dataBytes=new byte[outputSize];
      if (_debugging) {
        _debug("String_Node_Str" + outputSize);
      }
      int bytesRead=in.read(dataBytes,0,outputSize);
      if (bytesRead != outputSize) {
        throw new IllegalActionException(this,"String_Node_Str" + bytesRead + "String_Node_Str"+ outputSize+ "String_Node_Str");
      }
      Token[] dataTokens=new Token[outputSize];
      for (int j=0; j < outputSize; j++) {
        dataTokens[j]=new UnsignedByteToken(dataBytes[j]);
      }
      if (_debugging) {
        _debug("String_Node_Str");
      }
      dataReceived.broadcast(new ArrayToken(BaseType.UNSIGNED_BYTE,dataTokens));
      int available=in.available();
      if (available >= _minimumOutputSize) {
        if (_debugging) {
          _debug("String_Node_Str" + available);
        }
        getDirector().fireAtCurrentTime(this);
      }
    }
  }
 catch (  IOException ex) {
    throw new IllegalActionException(this,ex,"String_Node_Str");
  }
 finally {
    _directorFiredAtAlready=false;
  }
}