/**
  * @generate serialEvent.xml
  * @webref serial:events
  * @usage web_application
  * @param event the port where new data is available
  */
 public void serialEvent(SerialPortEvent event) {
   if (event.getEventType() == SerialPortEvent.RXCHAR) {
     int toRead;
     try {
       while (0 < (toRead = port.getInputBufferBytesCount())) {
         // this method can be called from the context of another thread
         synchronized (buffer) {
           // read one byte at a time if the sketch is using serialEvent
           if (serialEventMethod != null) {
             toRead = 1;
           }
           // enlarge buffer if necessary
           if (buffer.length < inBuffer + toRead) {
             byte temp[] = new byte[buffer.length << 1];
             System.arraycopy(buffer, 0, temp, 0, inBuffer);
             buffer = temp;
           }
           // read an array of bytes and copy it into our buffer
           byte[] read = port.readBytes(toRead);
           System.arraycopy(read, 0, buffer, inBuffer, read.length);
           inBuffer += read.length;
         }
         if (serialEventMethod != null) {
           if ((0 < bufferUntilSize && bufferUntilSize <= inBuffer - readOffset)
               || (0 == bufferUntilSize && bufferUntilByte == buffer[inBuffer - 1])) {
             try {
               // serialEvent() is invoked in the context of the current (serial) thread
               // which means that serialization and atomic variables need to be used to
               // guarantee reliable operation (and better not draw() etc..)
               // serialAvailable() does not provide any real benefits over using
               // available() and read() inside draw - but this function has no
               // thread-safety issues since it's being invoked during pre in the context
               // of the Processing applet
               serialEventMethod.invoke(parent, this);
             } catch (Exception e) {
               System.err.println("Error, disabling serialEvent() for " + port.getPortName());
               System.err.println(e.getLocalizedMessage());
               serialEventMethod = null;
             }
           }
         }
         invokeSerialAvailable = true;
       }
     } catch (SerialPortException e) {
       throw new RuntimeException(
           "Error reading from serial port " + e.getPortName() + ": " + e.getExceptionType());
     }
   }
 }
  /**
   * @generate Serial_readBytesUntil.xml
   * @webref serial:serial
   * @usage web_application
   * @param inByte character designated to mark the end of the data
   */
  public byte[] readBytesUntil(int inByte) {
    if (inBuffer == readOffset) {
      return null;
    }

    synchronized (buffer) {
      // look for needle in buffer
      int found = -1;
      for (int i = readOffset; i < inBuffer; i++) {
        if (buffer[i] == (byte) inByte) {
          found = i;
          break;
        }
      }
      if (found == -1) {
        return null;
      }

      int toCopy = found - readOffset + 1;
      byte[] dest = new byte[toCopy];
      System.arraycopy(buffer, readOffset, dest, 0, toCopy);
      readOffset += toCopy;
      if (inBuffer == readOffset) {
        inBuffer = 0;
        readOffset = 0;
      }
      return dest;
    }
  }
  /**
   * @generate Serial_readBytes.xml
   * @webref serial:serial
   * @usage web_application
   */
  public byte[] readBytes() {
    if (inBuffer == readOffset) {
      return null;
    }

    synchronized (buffer) {
      byte[] ret = new byte[inBuffer - readOffset];
      System.arraycopy(buffer, readOffset, ret, 0, ret.length);
      inBuffer = 0;
      readOffset = 0;
      return ret;
    }
  }
  /**
   *
   *
   * <h3>Advanced</h3>
   *
   * Grab whatever is in the serial buffer, and stuff it into a byte buffer passed in by the user.
   * This is more memory/time efficient than readBytes() returning a byte[] array.
   *
   * <p>Returns an int for how many bytes were read. If more bytes are available than can fit into
   * the byte array, only those that will fit are read.
   */
  public int readBytes(byte[] dest) {
    if (inBuffer == readOffset) {
      return 0;
    }

    synchronized (buffer) {
      int toCopy = inBuffer - readOffset;
      if (dest.length < toCopy) {
        toCopy = dest.length;
      }
      System.arraycopy(buffer, readOffset, dest, 0, toCopy);
      readOffset += toCopy;
      if (inBuffer == readOffset) {
        inBuffer = 0;
        readOffset = 0;
      }
      return toCopy;
    }
  }
  /**
   *
   *
   * <h3>Advanced</h3>
   *
   * Return a byte array of anything that's in the serial buffer up to the specified maximum number
   * of bytes. Not particularly memory/speed efficient, because it creates a byte array on each
   * read, but it's easier to use than readBytes(byte b[]) (see below).
   *
   * @param max the maximum number of bytes to read
   */
  public byte[] readBytes(int max) {
    if (inBuffer == readOffset) {
      return null;
    }

    synchronized (buffer) {
      int length = inBuffer - readOffset;
      if (length > max) length = max;
      byte[] ret = new byte[length];
      System.arraycopy(buffer, readOffset, ret, 0, length);

      readOffset += length;
      if (inBuffer == readOffset) {
        inBuffer = 0;
        readOffset = 0;
      }
      return ret;
    }
  }
  /**
   *
   *
   * <h3>Advanced</h3>
   *
   * If dest[] is not big enough, then -1 is returned, and an error message is printed on the
   * console. If nothing is in the buffer, zero is returned. If 'interesting' byte is not in the
   * buffer, then 0 is returned.
   *
   * @param dest passed in byte array to be altered
   */
  public int readBytesUntil(int inByte, byte[] dest) {
    if (inBuffer == readOffset) {
      return 0;
    }

    synchronized (buffer) {
      // look for needle in buffer
      int found = -1;
      for (int i = readOffset; i < inBuffer; i++) {
        if (buffer[i] == (byte) inByte) {
          found = i;
          break;
        }
      }
      if (found == -1) {
        return 0;
      }

      // check if bytes to copy fit in dest
      int toCopy = found - readOffset + 1;
      if (dest.length < toCopy) {
        System.err.println(
            "The buffer passed to readBytesUntil() is to small "
                + "to contain "
                + toCopy
                + " bytes up to and including "
                + "char "
                + (byte) inByte);
        return -1;
      }
      System.arraycopy(buffer, readOffset, dest, 0, toCopy);
      readOffset += toCopy;
      if (inBuffer == readOffset) {
        inBuffer = 0;
        readOffset = 0;
      }
      return toCopy;
    }
  }