<commit_before>/* tslint:disable:no-bitwise prefer-for-of */
import { isBoolean, isInteger, isString } from "container.ts/lib/validate";
import { fromEvent, merge, Observable, Subscriber } from "rxjs";
import { take, takeUntil, timeout } from "rxjs/operators";
import * as SerialPort from "serialport";
import * as adu from "../adu";
import * as pdu from "../pdu";
import * as rtu from "./Rtu";

/** Modbus RTU master data bits options. */
export type IMasterDataBits = 8 | 7 | 6 | 5;

/** Modbus RTU master stop bits options. */
export type IMasterStopBits = 1 | 2;

/** Modbus RTU master parity options. */
export enum EMasterParity {
  None,
  Even,
  Odd
}
export type IRtuMasterParity = "none" | "even" | "odd";
export const RTU_MASTER_PARITY = ["none", "even", "odd"];

export type IMasterRequestOptions = adu.IMasterRequestOptions<rtu.Request, rtu.Response, rtu.Exception>;

/** Modbus RTU master options */
export interface IMasterOptions extends IMasterRequestOptions {
  path: string;
  baudRate?: number;
  dataBits?: IMasterDataBits;
  stopBits?: IMasterStopBits;
  parity?: EMasterParity;
  rtscts?: boolean;
  slaveAddress?: number;
  inactivityTimeout?: number;
}

/** Modbus RTU master. */
export class Master extends adu.Master<rtu.Request, rtu.Response, rtu.Exception> {
  /** Default values. */
  public static DEFAULT = Object.assign(
    {
      BAUDRATE: 19200,
      DATA_BITS: 8,
      STOP_BITS: 1,
      PARITY: EMasterParity.Even,
      RTSCTS: true,
      SLAVE_ADDRESS: 1
    },
    adu.Master.DEFAULT
  );

  public readonly path: string;
  public readonly baudRate: number;
  public readonly dataBits: IMasterDataBits;
  public readonly stopBits: IMasterStopBits;
  public readonly parity: EMasterParity;
  public readonly rtscts: boolean;
  public readonly slaveAddress: number;
  public readonly inactivityTimeout: number;

  protected port: SerialPort | null = null;

  protected get openOptions(): SerialPort.OpenOptions {
    const parity: IRtuMasterParity = RTU_MASTER_PARITY[this.parity] as any;
    return {
      baudRate: this.baudRate,
      dataBits: this.dataBits,
      stopBits: this.stopBits,
      parity,
      rtscts: this.rtscts
    };
  }

  public constructor(options: IMasterOptions) {
    super(options);

    this.path = isString(options.path);
    this.baudRate = isInteger(String(options.baudRate || Master.DEFAULT.BAUDRATE));
    this.dataBits = isInteger(String(options.dataBits || Master.DEFAULT.DATA_BITS)) as IMasterDataBits;
    this.stopBits = isInteger(String(options.stopBits || Master.DEFAULT.STOP_BITS), {
      min: 1,
      max: 2
    }) as IMasterStopBits;
    this.parity = options.parity || Master.DEFAULT.PARITY;
    this.rtscts = isBoolean(String(options.rtscts || Master.DEFAULT.RTSCTS));
    this.slaveAddress = isInteger(String(options.slaveAddress || Master.DEFAULT.SLAVE_ADDRESS), {
      min: 0,
      max: 0xff
    });
    this.inactivityTimeout = this.isTimeout(options.inactivityTimeout);
  }

  public open(options: IMasterRequestOptions = {}): Observable<void> {
    // TODO(M): Timeout/retry support.
    return new Observable((subscriber: Subscriber<void>) => {
      // Ensure master closed and in known state.
      this.close();
      this.onOpen();

      // (Re)create serial port, add error listener.
      this.port = new SerialPort(this.path, this.openOptions);
      this.port.on("error", (error: any) => {
        subscriber.error(new adu.MasterError(error.code, error));
      });

      // If port closes, call close and complete observable.<commit_msg>fixed processing options<commit_after>/* tslint:disable:no-bitwise prefer-for-of */
import { isBoolean, isInteger, isString } from "container.ts/lib/validate";
import { fromEvent, merge, Observable, Subscriber } from "rxjs";
import { take, takeUntil, timeout } from "rxjs/operators";
import * as SerialPort from "serialport";
import * as adu from "../adu";
import * as pdu from "../pdu";
import * as rtu from "./Rtu";

/** Modbus RTU master data bits options. */
export type IMasterDataBits = 8 | 7 | 6 | 5;

/** Modbus RTU master stop bits options. */
export type IMasterStopBits = 1 | 2;

/** Modbus RTU master parity options. */
export enum EMasterParity {
  None,
  Even,
  Odd
}
export type IRtuMasterParity = "none" | "even" | "odd";
export const RTU_MASTER_PARITY = ["none", "even", "odd"];

export type IMasterRequestOptions = adu.IMasterRequestOptions<rtu.Request, rtu.Response, rtu.Exception>;

/** Modbus RTU master options */
export interface IMasterOptions extends IMasterRequestOptions {
  path: string;
  baudRate?: number;
  dataBits?: IMasterDataBits;
  stopBits?: IMasterStopBits;
  parity?: EMasterParity;
  rtscts?: boolean;
  slaveAddress?: number;
  inactivityTimeout?: number;
}

/** Modbus RTU master. */
export class Master extends adu.Master<rtu.Request, rtu.Response, rtu.Exception> {
  /** Default values. */
  public static DEFAULT = Object.assign(
    {
      BAUDRATE: 19200,
      DATA_BITS: 8,
      STOP_BITS: 1,
      PARITY: EMasterParity.Even,
      RTSCTS: true,
      SLAVE_ADDRESS: 1
    },
    adu.Master.DEFAULT
  );

  public readonly path: string;
  public readonly baudRate: number;
  public readonly dataBits: IMasterDataBits;
  public readonly stopBits: IMasterStopBits;
  public readonly parity: EMasterParity;
  public readonly rtscts: boolean;
  public readonly slaveAddress: number;
  public readonly inactivityTimeout: number;

  protected port: SerialPort | null = null;

  protected get openOptions(): SerialPort.OpenOptions {
    const parity: IRtuMasterParity = RTU_MASTER_PARITY[this.parity] as any;
    return {
      baudRate: this.baudRate,
      dataBits: this.dataBits,
      stopBits: this.stopBits,
      parity,
      rtscts: this.rtscts
    };
  }

  public constructor(options: IMasterOptions) {
    super(options);

    this.path = isString(options.path);
    this.baudRate = isInteger(String(options.baudRate || Master.DEFAULT.BAUDRATE));
    this.dataBits = isInteger(String(options.dataBits || Master.DEFAULT.DATA_BITS)) as IMasterDataBits;
    this.stopBits = isInteger(String(options.stopBits || Master.DEFAULT.STOP_BITS), {
      min: 1,
      max: 2
    }) as IMasterStopBits;
    this.parity = (options.parity != null) ? options.parity : Master.DEFAULT.PARITY;
    this.rtscts = (options.rtscts != null) ? isBoolean(String(options.rtscts)) : Master.DEFAULT.RTSCTS;
    this.slaveAddress = isInteger(String(options.slaveAddress || Master.DEFAULT.SLAVE_ADDRESS), {
      min: 0,
      max: 0xff
    });
    this.inactivityTimeout = this.isTimeout(options.inactivityTimeout);
  }

  public open(options: IMasterRequestOptions = {}): Observable<void> {
    // TODO(M): Timeout/retry support.
    return new Observable((subscriber: Subscriber<void>) => {
      // Ensure master closed and in known state.
      this.close();
      this.onOpen();

      // (Re)create serial port, add error listener.
      this.port = new SerialPort(this.path, this.openOptions);
      this.port.on("error", (error: any) => {
        subscriber.error(new adu.MasterError(error.code, error));
      });

      // If port closes, call close and complete observable.
{'fraction_non_alphanumeric': 0.11964858457676754, 'fraction_numerical': 0.005020220331892344, 'mean_word_length': 3.642071197411003, 'pattern_counts': {'":': 0, '<': 11, '<?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': '1631228', 'n_tokens_mistral': 2303, 'n_tokens_neox': 2242, 'n_words': 581}