docs: function(ip, options) {
      var modbus = this;
      modbus.ip = ip;
      modbus.openFlag = false;
      modbus.callback = null;
      modbus._transactionIdWrite = 1;
  
      // options
      if (typeof options === "undefined") options = {};
      modbus.port = options.port || MODBUS_PORT;
  
      // internal buffer
      modbus._buffer = Buffer.alloc(0);
  
      // handle callback - call a callback function only once, for the first event
      // it will triger
      var handleCallback = function(had_error) {
          if (modbus.callback) {
              modbus.callback(had_error);
              modbus.callback = null;
          }
      };
  
      // create a socket
      modbus._client = new net.Socket();
      if (options.timeout) this._client.setTimeout(options.timeout);
  
      // register the port data event
      modbus._client.on("data", function onData(data) {
          // add data to buffer
          modbus._buffer = Buffer.concat([modbus._buffer, data]);
  
          modbusSerialDebug({
              action: "receive tcp rtu buffered port",
              data: data,
              buffer: modbus._buffer
          });
  
          // check if buffer include a complete modbus answer
          var bufferLength = modbus._buffer.length;
  
          // check data length
          if (bufferLength < MIN_MBAP_LENGTH) return;
  
          // check buffer size for MAX_BUFFER_SIZE
          if (bufferLength > MAX_BUFFER_LENGTH) {
              modbus._buffer = modbus._buffer.slice(-MAX_BUFFER_LENGTH);
              bufferLength = MAX_BUFFER_LENGTH;
          }
  
          // check data length
          if (bufferLength < MIN_MBAP_LENGTH + EXCEPTION_LENGTH) return;
  
          // loop and check length-sized buffer chunks
          var maxOffset = bufferLength - MIN_MBAP_LENGTH;
          for (var i = 0; i <= maxOffset; i++) {
              modbus._transactionIdRead = modbus._buffer.readUInt16BE(i);
              var protocolID = modbus._buffer.readUInt16BE(i + 2);
              var msgLength = modbus._buffer.readUInt16BE(i + 4);
              var cmd = modbus._buffer[i + 7];
  
              modbusSerialDebug({
                  protocolID: protocolID,
                  msgLength: msgLength,
                  bufferLength: bufferLength,
                  cmd: cmd
              });
  
              if (
                  protocolID === 0 &&
                  cmd !== 0 &&
                  msgLength >= EXCEPTION_LENGTH &&
                  i + MIN_MBAP_LENGTH + msgLength <= bufferLength
              ) {
                  // add crc and emit
                  modbus._emitData(i + MIN_MBAP_LENGTH, msgLength);
                  return;
              }
          }
      });
  
      this._client.on("connect", function() {
          modbus.openFlag = true;
          handleCallback();
      });
  
      this._client.on("close", function(had_error) {
          modbus.openFlag = false;
          handleCallback(had_error);
      });
  
      this._client.on("error", function(had_error) {
          modbus.openFlag = false;
          handleCallback(had_error);
      });
  
      this._client.on("timeout", function() {
          // modbus.openFlag is left in its current state as it reflects two types of timeouts,
          // i.e. 'false' for "TCP connection timeout" and 'true' for "Modbus response timeout"
          // (this allows to continue Modbus request re-tries without reconnecting TCP).
          modbusSerialDebug("TcpRTUBufferedPort port: TimedOut");
          handleCallback(new Error("TcpRTUBufferedPort Connection Timed Out"));
      });
  
      /**
       * Check if port is open.
       *
       * @returns {boolean}
       */
      Object.defineProperty(this, "isOpen", {
          enumerable: true,
          get: function() {
              return this.openFlag;
          }
      });
  
      EventEmitter.call(this);
  }