<commit_before>var StreamStack = require('stream-stack').StreamStack;
var Put = require('put');
var BufferList = require('bufferlist').BufferList;
var Binary = require('bufferlist/binary').Binary;
var inherits = require('util').inherits;
var client = require('./client');
var server = require('./server');
var slice = Array.prototype.slice;

// The length of the "MODBUS Application Protocol" header.
const MBAP_LENGTH = 7;

exports.EXCEPTION_CODES = {
  1 : 'Illegal Function',
  2 : 'Illegal Data Address',
  3 : 'Illegal Data Value',
  4 : 'Slave Device Failure',
  5 : 'Acknowledge',
  6 : 'Slave Device Busy',
  8 : 'Memory Parity Error',
  10: 'Gateway Path Unavailable',
  11: 'Gateway Target Path Failed to Respond'
};

exports.FUNCTION_CODES = {
  READ_COILS:               1,
  READ_DISCRETE_INPUTS:     2,
  READ_HOLDING_REGISTERS:   3,
  READ_INPUT_REGISTERS:     4,
  WRITE_SINGLE_COIL:        5,
  WRITE_SINGLE_REGISTER:    6,
  READ_EXCEPTION_STATUS:    7, // Serial Line only
  DIAGNOSTICS:              8, // Serial Line only
  PROGRAM_484:              9,
  POLL_484:                 10,
  GET_COMM_EVENT_COUNTER:   11,// Serial Line only
  GET_COMM_EVENT_LOG:       12,// Serial Line only
  PROGRAM_CONTROLLER:       13,
  POLL_CONTROLLER:          14,
  WRITE_MULTIPLE_COILS:     15,
  WRITE_MULTIPLE_REGISTERS: 16,
  REPORT_SLAVE_ID:          17,// Serial Line only
  PROGRAM_884_M84:          18,
  RESET_COMM_LINK:          19,
  READ_FILE_RECORD:         20,
  WRITE_FILE_RECORD:        21,
  MASK_WRITE_REGISTER:      22,
  READ_WRITE_MULTIPLE_REGISTERS:23,
  READ_FIFO_QUEUE:          24,
  ENCAPSULATED_INFERFACE_TRANSPORT:43
};

function ModbusRequestStack(stream) {
  StreamStack.call(this, stream);
  this.bufferlist = new BufferList();
  this.stream.on('data', this._onData.bind(this));
  this._reqNum = 1;
}
inherits(ModbusRequestStack, StreamStack);
exports.ModbusRequestStack = ModbusRequestStack;

// The 'version' of the MODBUS protocol. Only version 0 is defined.
ModbusRequestStack.prototype.protocolVersion = 0;

// The unit identifier to request. This is usually used in over serial lines, not so much over TCP.
ModbusRequestStack.prototype.unitIdentifier = 1;

// Make a MODBUS request for a given 'function code'.
ModbusRequestStack.prototype.request = function(functionCode) {
  this.functionCode = functionCode;
  var argsLen = arguments.length;
  if (argsLen > 1) {
    var callback = arguments[argsLen-1];
    if (typeof(callback) == 'function') {
      this.on('error', function(e) {
        callback(e);
      });
      this.once('response', function(res) {
        callback(null, res);
      });
    }
  }
  var args = slice.call(arguments, 1, argsLen-(callback?1:0));
  var pdu = client.REQUESTS[functionCode].apply(this, args);
  return Put()
    .word16be(this._reqNum++)
    .word16be(this.protocolVersion)
    .word16be(pdu.length+1)
    .word8(this.unitIdentifier)
    .put(pdu)
    .write(this.stream);
}

ModbusRequestStack.prototype._onData = function(chunk) {
  if (chunk) this.bufferlist.push(chunk);
  if (!this.responseHeader && this.bufferlist.length >= MBAP_LENGTH) {
    this.responseHeader = readMBAP(this.bufferlist);
    // Re-check the bufferlist to see if we have the rest of the response already
    this._onData();
  } else if (this.bufferlist.length >= (this.responseHeader.length-1)) {
    // We have the complete response.
    var response = client.RESPONSES[this.functionCode](this.bufferlist);
    this.bufferlist.advance(this.responseHeader.length-1);
    this.emit('response', response);
    // Modbus request/response complete!
  }
}



function ModbusResponseStack(stream) {
  StreamStack.call(this, stream);
  this.bufferlist = new BufferList();
  this._bindedOnData = this._onData.bind(this);
  this.stream.on('data', this._bindedOnData);
}
inherits(ModbusResponseStack, StreamStack);
exports.ModbusResponseStack = ModbusResponseStack;

ModbusResponseStack.prototype._onData = function(chunk) {
  if (chunk) this.bufferlist.push(chunk);
  if (!this.requestHeader && this.bufferlist.length >= MBAP_LENGTH) {
    this.requestHeader = readMBAP(this.bufferlist);
    //console.log(this.requestHeader);
    // Re-check the bufferlist to see if we have the rest of the request
    // already (we probably do, it's usually sent in the same packet).
    this._onData();
  } else if (!this.functionCode && this.requestHeader && this.bufferlist.length >= 1) {
    // Get the function code
    this.functionCode = this.bufferlist.take(1).charCodeAt(0);
    //console.log(this.functionCode);
    // Don't advance the bufferlist, since the server.REQUEST function should
    // parse the 'functionCode' as a property.
    //this.bufferlist.advance(1);
    this._onData();
  } else if (this.requestHeader && this.bufferlist.length >= (this.requestHeader.length-2)) {
    // We have the complete request.
    this.request = server.REQUESTS[this.functionCode](this.bufferlist);
    this.request.functionCode = this.functionCode;
    delete this.request.length; // Questionable...
    for (var key in this.requestHeader) {
      this.request[key] = this.requestHeader[key];
    }
    this.bufferlist.advance(this.requestHeader.length-1);
    //console.log('bufferlist.length: ' + this.bufferlist.length);
    this._gotRequest = true;
    this.stream.removeListener('data', this._bindedOnData);
    this.emit('request', this.request);
  }
}

// Sends back the response after receiving a request.
ModbusResponseStack.prototype.writeResponse = function() {
  if (!this._gotRequest) throw new Error('Can\'t call "writeResponse" until after the "request" event');
  
  var pdu = server.RESPONSES[this.functionCode].apply(this, arguments);
  return Put()
    .word16be(this.request.transactionId)
    .word16be(this.request.protocolVersion)
    .word16be(pdu.length+1)
    .word8(this.request.unitIdentifier)
    .put(pdu)
    .write(this.stream);
}


// Reads the "MODBUS Application Protocol" header from the given bufferlist,
// and return a object with 'transactionId', 'protocolVersion', 'length', and
// 'unitIdentifier' properties (standard for both client and server).
function readMBAP(bufferlist) {
  var mbap = Binary(bufferlist)
    .getWord16be('transactionId')
    .getWord16be('protocolVersion')
    .getWord16be('length')
    .getWord8('unitIdentifier')
    .end().vars;
  bufferlist.advance(MBAP_LENGTH);
  return mbap;
}
exports.readMBAP = readMBAP;<commit_msg>A few changes; see below:<commit_after>var StreamStack = require('stream-stack').StreamStack;
var Put = require('put');
var BufferList = require('bufferlist').BufferList;
var Binary = require('bufferlist/binary').Binary;
var inherits = require('util').inherits;
var client = require('./client');
var server = require('./server');
var slice = Array.prototype.slice;

// The length of the "MODBUS Application Protocol" header.
const MBAP_LENGTH = 7;

exports.EXCEPTION_CODES = {
  1 : 'Illegal Function',
  2 : 'Illegal Data Address',
  3 : 'Illegal Data Value',
  4 : 'Slave Device Failure',
  5 : 'Acknowledge',
  6 : 'Slave Device Busy',
  8 : 'Memory Parity Error',
  10: 'Gateway Path Unavailable',
  11: 'Gateway Target Path Failed to Respond'
};

exports.FUNCTION_CODES = {
  READ_COILS:               1,
  READ_DISCRETE_INPUTS:     2,
  READ_HOLDING_REGISTERS:   3,
  READ_INPUT_REGISTERS:     4,
  WRITE_SINGLE_COIL:        5,
  WRITE_SINGLE_REGISTER:    6,
  READ_EXCEPTION_STATUS:    7, // Serial Line only
  DIAGNOSTICS:              8, // Serial Line only
  PROGRAM_484:              9,
  POLL_484:                 10,
  GET_COMM_EVENT_COUNTER:   11,// Serial Line only
  GET_COMM_EVENT_LOG:       12,// Serial Line only
  PROGRAM_CONTROLLER:       13,
  POLL_CONTROLLER:          14,
  WRITE_MULTIPLE_COILS:     15,
  WRITE_MULTIPLE_REGISTERS: 16,
  REPORT_SLAVE_ID:          17,// Serial Line only
  PROGRAM_884_M84:          18,
  RESET_COMM_LINK:          19,
  READ_FILE_RECORD:         20,
  WRITE_FILE_RECORD:        21,
  MASK_WRITE_REGISTER:      22,
  READ_WRITE_MULTIPLE_REGISTERS:23,
  READ_FIFO_QUEUE:          24,
  ENCAPSULATED_INFERFACE_TRANSPORT:43,
  TRS_GET_CONFIG:           60,// Proprietary
  TRS_SET_CONFIG:           76 // Proprietary
};

function ModbusRequestStack(stream) {
  StreamStack.call(this, stream);
  this.bufferlist = new BufferList();
  this._bindedOnData = this._onData.bind(this);
  this.stream.on('data', this._bindedOnData);
  if (this.stream._reqNum) {
    this.stream._reqNum++;
  } else {
    this.stream._reqNum = 1;
  }
}
inherits(ModbusRequestStack, StreamStack);
exports.ModbusRequestStack = ModbusRequestStack;

// The 'version' of the MODBUS protocol. Only version 0 is defined.
ModbusRequestStack.prototype.protocolVersion = 0;

// The unit identifier to request. This is usually important for
// serial lines, not so much over TCP.
ModbusRequestStack.prototype.unitIdentifier = 1;

// Make a MODBUS request for a given 'function code'.
ModbusRequestStack.prototype.request = function(functionCode) {
  this.functionCode = functionCode;
  var argsLen = arguments.length;
  if (argsLen > 1) {
    var callback = arguments[argsLen-1];
    if (typeof(callback) == 'function') {
      this.on('error', callback);
      this.on('response', function(res) {
        callback(null, res);
      });
    }
  }
  var args = slice.call(arguments, 1, argsLen-(callback?1:0));
  var pdu = client.REQUESTS[functionCode].apply(this, args);
  return Put()
    .word16be(this.stream._reqNum)
    .word16be(this.protocolVersion)
    .word16be(pdu.length+1)
    .word8(this.unitIdentifier)
    .put(pdu)
    .write(this.stream);
}

ModbusRequestStack.prototype._onData = function(chunk) {
  //console.log(chunk);
  if (chunk) this.bufferlist.push(chunk);
  if (!this.responseHeader && this.bufferlist.length >= MBAP_LENGTH) {
    this.responseHeader = readMBAP(this.bufferlist);
    // Re-check the bufferlist to see if we have the rest of the response already
    this._onData();
  } else if (this.bufferlist.length >= (this.responseHeader.length-1)) {
    // We have the complete response.
    var response = client.RESPONSES[this.functionCode].call(this, this.bufferlist);
    this.bufferlist.advance(this.responseHeader.length-1);
    this.stream.removeListener('data', this._bindedOnData);
    this.emit('response', response);
    // Modbus request/response complete!
  }
}



function ModbusResponseStack(stream) {
  StreamStack.call(this, stream);
  this.bufferlist = new BufferList();
  this._bindedOnData = this._onData.bind(this);
  this.stream.on('data', this._bindedOnData);
}
inherits(ModbusResponseStack, StreamStack);
exports.ModbusResponseStack = ModbusResponseStack;

ModbusResponseStack.prototype._onData = function(chunk) {
  if (chunk) this.bufferlist.push(chunk);
  if (!this.requestHeader && this.bufferlist.length >= MBAP_LENGTH) {
    this.requestHeader = readMBAP(this.bufferlist);
    //console.log(this.requestHeader);
    // Re-check the bufferlist to see if we have the rest of the request
    // already (we probably do, it's usually sent in the same packet).
    this._onData();
  } else if (!this.functionCode && this.requestHeader && this.bufferlist.length >= 1) {
    // Get the function code
    this.functionCode = this.bufferlist.take(1).charCodeAt(0);
    //console.log(this.functionCode);
    // Don't advance the bufferlist, since the server.REQUEST function should
    // parse the 'functionCode' as a property.
    //this.bufferlist.advance(1);
    this._onData();
  } else if (this.requestHeader && this.bufferlist.length >= (this.requestHeader.length-2)) {
    // We have the complete request.
    this.request = server.REQUESTS[this.functionCode].call(this, this.bufferlist);
    this.request.functionCode = this.functionCode;
    delete this.request.length; // Questionable...
    for (var key in this.requestHeader) {
      this.request[key] = this.requestHeader[key];
    }
    this.bufferlist.advance(this.requestHeader.length-1);
    //console.log('bufferlist.length: ' + this.bufferlist.length);
    this._gotRequest = true;
    this.stream.removeListener('data', this._bindedOnData);
    this.emit('request', this.request);
  }
}

// Sends back the response after receiving a request.
ModbusResponseStack.prototype.writeResponse = function() {
  if (!this._gotRequest) throw new Error('Can\'t call "writeResponse" until after the "request" event');
  
  var pdu = server.RESPONSES[this.functionCode].apply(this, arguments);
  return Put()
    .word16be(this.request.transactionId)
    .word16be(this.request.protocolVersion)
    .word16be(pdu.length+1)
    .word8(this.request.unitIdentifier)
    .put(pdu)
    .write(this.stream);
}


// Reads the "MODBUS Application Protocol" header from the given bufferlist,
// and return a object with 'transactionId', 'protocolVersion', 'length', and
// 'unitIdentifier' properties (standard for both client and server).
function readMBAP(bufferlist) {
  var mbap = Binary(bufferlist)
    .getWord16be('transactionId')
    .getWord16be('protocolVersion')
    .getWord16be('length')
    .getWord8('unitIdentifier')
    .end().vars;
  bufferlist.advance(MBAP_LENGTH);
  return mbap;
}
exports.readMBAP = readMBAP;

{'fraction_non_alphanumeric': 0.12354011830729561, 'fraction_numerical': 0.01607765812225087, 'mean_word_length': 3.633520730850316, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3263199', 'n_tokens_mistral': 4341, 'n_tokens_neox': 4201, 'n_words': 954}