Skip to content
This repository has been archived by the owner on May 17, 2021. It is now read-only.

Modbus combined registers direct support #1383

Merged
merged 2 commits into from
Sep 7, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,20 @@ public interface ModbusBindingProvider extends BindingProvider {

static final String[] SLAVE_DATA_TYPES = { TYPE_COIL, TYPE_DISCRETE, TYPE_HOLDING, TYPE_INPUT };

/**
* Value type, primary for "input" type
*/
static final public String VALUE_TYPE_BIT = "bit";
static final public String VALUE_TYPE_INT8 = "int8";
static final public String VALUE_TYPE_UINT8 = "uint8";
static final public String VALUE_TYPE_INT16 = "int16";
static final public String VALUE_TYPE_UINT16 = "uint16";
static final public String VALUE_TYPE_INT32 = "int32";
static final public String VALUE_TYPE_UINT32 = "uint32";
static final public String VALUE_TYPE_FLOAT32 = "float32";

static final String[] VALUE_TYPES = { VALUE_TYPE_BIT, VALUE_TYPE_INT8, VALUE_TYPE_UINT8, VALUE_TYPE_INT16, VALUE_TYPE_UINT16, VALUE_TYPE_INT32, VALUE_TYPE_UINT32, VALUE_TYPE_FLOAT32 };

/**
* Returns Modbus item configuration
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import net.wimpi.modbus.procimg.InputRegister;
import net.wimpi.modbus.util.BitVector;
Expand Down Expand Up @@ -52,7 +55,7 @@ public class ModbusBinding extends AbstractActiveBinding<ModbusBindingProvider>
private static final String SERIAL_PREFIX = "serial";

private static final Pattern EXTRACT_MODBUS_CONFIG_PATTERN =
Pattern.compile("^("+TCP_PREFIX+"|"+SERIAL_PREFIX+"|)\\.(.*?)\\.(connection|id|pollInterval|start|length|type)$");
Pattern.compile("^("+TCP_PREFIX+"|"+SERIAL_PREFIX+"|)\\.(.*?)\\.(connection|id|pollInterval|start|length|type|valuetype)$");

/** Stores instances of all the slaves defined in cfg file */
private static Map<String, ModbusSlave> modbusSlaves = new ConcurrentHashMap<String, ModbusSlave>();
Expand Down Expand Up @@ -105,23 +108,63 @@ protected void internalUpdateItem(String slaveName, InputRegister[] registers,
if (provider.providesBindingFor(itemName)) {
ModbusBindingConfig config = provider.getConfig(itemName);
if (config.slaveName.equals(slaveName)) {
InputRegister value = registers[config.readRegister];
String slaveValueType = modbusSlaves.get(slaveName).getValueType();

State newState = extractStateFromRegisters(registers, config.readRegister, slaveValueType);
if (config.getItem() instanceof SwitchItem) {
if (value.getValue() == 0 && (provider.getConfig(itemName).getItemState() != OnOffType.OFF)) {
eventPublisher.postUpdate(itemName, OnOffType.OFF);
} else if (value.getValue() != 0 && (provider.getConfig(itemName).getItemState() != OnOffType.ON)) {
eventPublisher.postUpdate(itemName, OnOffType.ON);
}
} else {
DecimalType newState = new DecimalType(value.getValue());
if (!newState.equals(provider.getConfig(itemName).getItemState()))
eventPublisher.postUpdate(itemName, newState);
newState = newState.equals(DecimalType.ZERO) ? OnOffType.OFF : OnOffType.ON;
}

State currentState = config.getItemState();
if (! newState.equals(currentState))
eventPublisher.postUpdate(itemName, newState);
}
}
}
}

private DecimalType extractStateFromRegisters(InputRegister[] registers, int index, String type) {
if (type.equals(ModbusBindingProvider.VALUE_TYPE_BIT)) {
return new DecimalType((registers[index / 16].toUnsignedShort() >> (index % 16)) & 1);
}
else if (type.equals(ModbusBindingProvider.VALUE_TYPE_INT8)) {
return new DecimalType(registers[index / 2].toBytes()[1 - (index % 2)]);
}
else if (type.equals(ModbusBindingProvider.VALUE_TYPE_UINT8)) {
return new DecimalType((registers[index / 2].toUnsignedShort() >> (8 * (index % 2))) & 0xff);
}
else if (type.equals(ModbusBindingProvider.VALUE_TYPE_INT16)) {
ByteBuffer buff = ByteBuffer.allocate(2);
buff.put(registers[index].toBytes());
return new DecimalType(buff.order(ByteOrder.BIG_ENDIAN).getShort(0));
}
else if (type.equals(ModbusBindingProvider.VALUE_TYPE_UINT16)) {
return new DecimalType(registers[index].toUnsignedShort());
}
else if (type.equals(ModbusBindingProvider.VALUE_TYPE_INT32)) {
ByteBuffer buff = ByteBuffer.allocate(4);
buff.put(registers[index * 2 + 0].toBytes());
buff.put(registers[index * 2 + 1].toBytes());
return new DecimalType(buff.order(ByteOrder.BIG_ENDIAN).getInt(0));
}
else if (type.equals(ModbusBindingProvider.VALUE_TYPE_UINT32)) {
ByteBuffer buff = ByteBuffer.allocate(8);
buff.position(4);
buff.put(registers[index * 2 + 0].toBytes());
buff.put(registers[index * 2 + 1].toBytes());
return new DecimalType(buff.order(ByteOrder.BIG_ENDIAN).getLong(0));
}
else if (type.equals(ModbusBindingProvider.VALUE_TYPE_FLOAT32)) {
ByteBuffer buff = ByteBuffer.allocate(4);
buff.put(registers[index * 2 + 0].toBytes());
buff.put(registers[index * 2 + 1].toBytes());
return new DecimalType(buff.order(ByteOrder.BIG_ENDIAN).getFloat(0));
}
else {
throw new IllegalArgumentException();
}
}

/**
* Posts update event to OpenHAB bus for "coil" type slaves
* @param binding ModbusBinding to get item configuration from BindingProviding
Expand Down Expand Up @@ -253,6 +296,12 @@ public void updated(Dictionary<String, ?> config) throws ConfigurationException
} else {
throw new ConfigurationException(configKey, "the given slave type '" + value + "' is invalid");
}
} else if ("valuetype".equals(configKey)) {
if (ArrayUtils.contains(ModbusBindingProvider.VALUE_TYPES, value)) {
modbusSlave.setValueType(value);
} else {
throw new ConfigurationException(configKey, "the given value type '" + value + "' is invalid");
}
} else {
throw new ConfigurationException(configKey,
"the given configKey '" + configKey + "' is unknown");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public static void setWriteMultipleRegisters(boolean setwmr) {
}

/**
* Type of data porived by the physical device
* Type of data provided by the physical device
* "coil" and "discrete" use boolean (bit) values
* "input" and "holding" use byte values
*/
Expand All @@ -75,6 +75,15 @@ public static void setWriteMultipleRegisters(boolean setwmr) {

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;

Expand Down Expand Up @@ -358,4 +367,12 @@ void setType(String type) {
this.type = type;
}

String getValueType() {
return valueType;
}

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

}
5 changes: 5 additions & 0 deletions distribution/openhabhome/configurations/openhab_default.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,11 @@ ntp:hostname=ptbtime1.ptb.de
# (optional, defaults to '0' - but set it to something meaningful)
#modbus:slave1.length=

# Value type, required for combined registers (details: http://www.simplymodbus.ca/FAQ.htm#Types)
# Can be "bit", "int8", "uint8", "int16", "uint16", "int32", "uint32", "float32"
# (optional, defaults to 'uint16')
#modbus:slave1.valuetype=

############################### PLC Bus Binding #######################################
#
# PLCBus adapter serial port
Expand Down