Package org.openhab.binding.modbus.internal

Source Code of org.openhab.binding.modbus.internal.ModbusSlave

/**
* Copyright (c) 2010-2014, openHAB.org and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.binding.modbus.internal;

import java.util.Collection;

import net.wimpi.modbus.io.ModbusTransaction;
import net.wimpi.modbus.msg.ModbusRequest;
import net.wimpi.modbus.msg.ModbusResponse;
import net.wimpi.modbus.msg.ReadCoilsRequest;
import net.wimpi.modbus.msg.ReadCoilsResponse;
import net.wimpi.modbus.msg.ReadInputDiscretesRequest;
import net.wimpi.modbus.msg.ReadInputDiscretesResponse;
import net.wimpi.modbus.msg.ReadInputRegistersRequest;
import net.wimpi.modbus.msg.ReadInputRegistersResponse;
import net.wimpi.modbus.msg.ReadMultipleRegistersRequest;
import net.wimpi.modbus.msg.ReadMultipleRegistersResponse;
import net.wimpi.modbus.msg.WriteCoilRequest;
import net.wimpi.modbus.msg.WriteMultipleRegistersRequest;
import net.wimpi.modbus.msg.WriteSingleRegisterRequest;
import net.wimpi.modbus.procimg.InputRegister;
import net.wimpi.modbus.procimg.Register;
import net.wimpi.modbus.util.BitVector;

import org.openhab.binding.modbus.ModbusBindingProvider;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.IncreaseDecreaseType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.OpenClosedType;
import org.openhab.core.library.types.UpDownType;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* ModbusSlave class is an abstract class that server as a base class for
* MobvusTCPSlave and ModbusSerialSlave instantiates physical Modbus slave.
* It is responsible for polling data from physical device using appropriate connection.
* It is also responsible for updating physical devices according to OpenHAB commands 
*
* @author Dmitry Krasnov
* @since 1.1.0
*/
public abstract class ModbusSlave implements ModbusSlaveConnection {

  private static final Logger logger = LoggerFactory.getLogger(ModbusSlave.class);

  /** name - slave name from cfg file, used for items binding */
  protected String name = null;
 
  private static boolean writeMultipleRegisters = false;
 
  public static void setWriteMultipleRegisters(boolean setwmr) {
    writeMultipleRegisters = setwmr;
  }

  /**
   * Type of data provided by the physical device
   * "coil" and "discrete" use boolean (bit) values
   * "input" and "holding" use byte values
   */
  private String type;

  /** Modbus slave id */
  private int id = 1;

  /** starting reference and number of item to fetch from the device */
  private int start = 0;

  private int length = 0;

  /**
   * How to interpret Modbus register values.
   * Examples:
   *   uint16 - one register - one unsigned integer value (default)
   *   int32  - every two registers will be interpreted as single 32-bit integer value
   *   bit    - every register will be interpreted as 16 independent 1-bit values 
   */
  private String valueType = ModbusBindingProvider.VALUE_TYPE_UINT16;

  private Object storage;
  protected ModbusTransaction transaction = null;



  /**
   * @param slave slave name from cfg file used for item binding
   */
  public ModbusSlave(String slave) {
    name = slave;
  }

  /**
   * writes data to Modbus device corresponding to OpenHAB command
   * works only with types "coil" and "holding"
   *
   * @param command OpenHAB command received
   * @param readRegister data from readRegister are used to define value to write to the device
   * @param writeRegister register address to write new data to
   */
  void executeCommand(Command command, int readRegister,
      int writeRegister) {
    if (ModbusBindingProvider.TYPE_COIL.equals(getType()) || ModbusBindingProvider.TYPE_DISCRETE.equals(getType())) {
      setCoil(command, readRegister, writeRegister);
    }
    if (ModbusBindingProvider.TYPE_HOLDING.equals(getType())) {
      setRegister(command, readRegister, getStart() + writeRegister);
    }
  }

  /**
   * Calculates boolean value that will be written to the device as a result of OpenHAB command
   * Used with item bound to "coil" type slaves
   *
   * @param command OpenHAB command received by the item
   * @return new boolean value to be written to the device
   */
  protected static boolean translateCommand2Boolean(Command command) {
    if (command.equals(OnOffType.ON))
      return true;
    if (command.equals(OnOffType.OFF))
      return false;
    if (command.equals(OpenClosedType.OPEN))
      return true;
    if (command.equals(OpenClosedType.CLOSED))
      return false;
    throw new IllegalArgumentException("command not supported");
  }

  /**
   * Performs physical write to device when slave type is "coil"
   * @param command command received from OpenHAB
   * @param readRegister reference to the register that stores current value
   * @param writeRegister register reference to write data to
   */
  private void setCoil(Command command, int readRegister,
      int writeRegister) {
    synchronized (storage) {
      boolean b = translateCommand2Boolean(command);
      if (((BitVector)storage).getBit(readRegister) != b) {
        if (b) {
          doSetCoil(getStart() + writeRegister, true);
        } else {
          doSetCoil(getStart() + writeRegister, readRegister == writeRegister ? false : true);
        }
      }
    }
  }


  /**
   * Performs physical write to device when slave type is "holding" using Modbus FC06 function
   * @param command command received from OpenHAB
   * @param readRegister reference to the register that stores current value
   * @param writeRegister register reference to write data to
   */
  protected void setRegister(Command command, int readRegister, int writeRegister) {
   
    if (!isConnected()) {
      return;
    }

    Register newValue = null;
    synchronized (storage) {
      newValue = (Register) ((InputRegister[])storage)[readRegister];
    }

    if (command instanceof IncreaseDecreaseType) {
      if (command.equals(IncreaseDecreaseType.INCREASE))
        newValue.setValue(newValue.getValue() + 1);
      else if (command.equals(IncreaseDecreaseType.DECREASE))
        newValue.setValue(newValue.getValue() - 1);
    } else if (command instanceof UpDownType) {
      if (command.equals(UpDownType.UP))
        newValue.setValue(newValue.getValue() + 1);
      else if (command.equals(UpDownType.DOWN))
        newValue.setValue(newValue.getValue() - 1);
    } else if (command instanceof DecimalType) {
      newValue.setValue(((DecimalType)command).intValue());
    } else if (command instanceof OnOffType) {
      if (command.equals(OnOffType.ON))
        newValue.setValue(1);
      else if (command.equals(OnOffType.OFF))
        newValue.setValue(0);
    }

   
    ModbusRequest request = null;
    if (writeMultipleRegisters) {
      Register [] regs = new Register[1];
      regs[0] = newValue;
      request = new WriteMultipleRegistersRequest(writeRegister, regs);     
    } else {
      request = new WriteSingleRegisterRequest(writeRegister, newValue);
    }
    request.setUnitID(getId());
    transaction.setRequest(request);

    try {
      logger.debug("ModbusSlave: FC" +request.getFunctionCode()+" ref=" + writeRegister + " value=" + newValue.getValue());       
      transaction.execute();
    } catch (Exception e) {
      logger.debug("ModbusSlave:" + e.getMessage());
      return;
    }
  }

  /**
   * @return slave name from cfg file
   */
  public String getName() {
    return name;
  }

  /**
   * Sends boolean (bit) data to the device using Modbus FC05 function
   * @param writeRegister
   * @param b
   */
  public void doSetCoil(int writeRegister, boolean b) {
    if (!connect()) {
      logger.info("ModbusSlave not connected");
      return;
    }
    ModbusRequest request = new WriteCoilRequest(writeRegister, b);
    request.setUnitID(getId());
    transaction.setRequest(request);
    try {
      logger.debug("ModbusSlave: FC05 ref=" + writeRegister + " value=" + b);       
      transaction.execute();
    } catch (Exception e) {
      logger.debug("ModbusSlave:" + e.getMessage());
      return;
    }
  }

  /**
   * Reads data from the connected device and updates items with the new data
   *
   * @param binding ModbusBindig that stores providers information
   */
  public void update(ModbusBinding binding) {
    if (!connect()) {
      resetConnection();
      logger.info("ModbusSlave not connected");
      return;
    }
   
    try {

    Object local = null;


      if (ModbusBindingProvider.TYPE_COIL.equals(getType())) {
        ModbusRequest request = new ReadCoilsRequest(getStart(), getLength());
        if (this instanceof ModbusSerialSlave) {
          request.setHeadless();
        }
        request.setUnitID(id);
        ReadCoilsResponse responce = (ReadCoilsResponse) getModbusData(request);
        local = responce.getCoils();
      } else if (ModbusBindingProvider.TYPE_DISCRETE.equals(getType())) {
        ModbusRequest request = new ReadInputDiscretesRequest(getStart(), getLength());
        ReadInputDiscretesResponse responce = (ReadInputDiscretesResponse) getModbusData(request);
        local = responce.getDiscretes();
      } else if (ModbusBindingProvider.TYPE_HOLDING.equals(getType())) {
        ModbusRequest request = new ReadMultipleRegistersRequest(getStart(), getLength());
        ReadMultipleRegistersResponse responce = (ReadMultipleRegistersResponse) getModbusData(request);
        local = responce.getRegisters();
      } else if (ModbusBindingProvider.TYPE_INPUT.equals(getType())) {
        ModbusRequest request = new ReadInputRegistersRequest(getStart(), getLength());
        ReadInputRegistersResponse responce = (ReadInputRegistersResponse) getModbusData(request);
        local = responce.getRegisters();
      }
      if (storage == null)
        storage = local;
      else {
        synchronized(storage) {
          storage = local;
        }
      }
      Collection<String> items = binding.getItemNames();
      for (String item : items) {
        updateItem(binding, item);
      }
    } catch (Exception e) {
      resetConnection();
      logger.info("ModbusSlave error getting responce from slave");
    }

  }

  /**
   * Updates OpenHAB item with data read from slave device
   * works only for type "coil" and "holding"
   * @param binding ModbusBinding
   * @param item item to update
   */
  private void updateItem(ModbusBinding binding, String item) {
    if (ModbusBindingProvider.TYPE_COIL.equals(getType()) || ModbusBindingProvider.TYPE_DISCRETE.equals(getType())) {
      binding.internalUpdateItem(name, (BitVector)storage,  item);
    }
    if (ModbusBindingProvider.TYPE_HOLDING.equals(getType()) || ModbusBindingProvider.TYPE_INPUT.equals(getType())) {
      binding.internalUpdateItem(name, (InputRegister[])storage, item);
    }
  }

  /**
   * Executes Modbus transaction that reads data from the device and returns response data
   * @param request describes what data are requested from the device
   * @return response data
   */
  private ModbusResponse getModbusData(ModbusRequest request) {
    request.setUnitID(getId());
    transaction.setRequest(request);

    try {
      transaction.execute();
    } catch (Exception e) {
      logger.debug("ModbusSlave:" + e.getMessage());
      return null;
    }

    ModbusResponse r = transaction.getResponse();
    if ((r.getTransactionID() != transaction.getTransactionID()) && !r.isHeadless()) {
      return null;
    }

    return r;
  }

  int getStart() {
    return start;
  }

  void setStart(int start) {
    this.start = start;
  }

  int getLength() {
    return length;
  }

  void setLength(int length) {
    this.length = length;
  }

  int getId() {
    return id;
  }

  void setId(int id) {
    this.id = id;
  }

  String getType() {
    return type;
  }

  void setType(String type) {
    this.type = type;
  }

  String getValueType() {
    return valueType;
  }

  void setValueType(String valueType) {
    this.valueType = valueType;
  }

}
TOP

Related Classes of org.openhab.binding.modbus.internal.ModbusSlave

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.