/*
* Copyright 2011-16 Fraunhofer ISE
*
* This file is part of OpenMUC.
* For more information visit http://www.openmuc.org
*
* OpenMUC is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenMUC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenMUC. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openmuc.framework.driver.modbus;
import java.util.ArrayList;
import java.util.List;
import org.openmuc.framework.data.BooleanValue;
import org.openmuc.framework.data.Record;
import org.openmuc.framework.data.Value;
import org.openmuc.framework.driver.spi.ChannelRecordContainer;
import net.wimpi.modbus.procimg.InputRegister;
import net.wimpi.modbus.util.BitVector;
/**
* Represents a group of channels which is used for a multiple read request
*/
public class ModbusChannelGroup {
private static final int INVALID = -1;
private EPrimaryTable primaryTable;
private final ArrayList<ModbusChannel> channels;
/** Start address to read from */
private int startAddress;
/** Number of Registers/Coils to be read from startAddress */
private int count;
private int unitId;
private EFunctionCode functionCode;
private final String samplingGroup;
public ModbusChannelGroup(String samplingGroup, ArrayList<ModbusChannel> channels) {
this.samplingGroup = samplingGroup;
this.channels = channels;
setPrimaryTable();
setUnitId();
setStartAddress();
setCount();
setFunctionCode();
}
public String getInfo() {
String info = "SamplingGroup: '" + samplingGroup + "' Channels: ";
for (ModbusChannel channel : channels) {
info += channel.getStartAddress() + ":" + channel.getDatatype() + ", ";
}
return info;
}
private void setFunctionCode() {
boolean init = false;
EFunctionCode tempFunctionCode = null;
for (ModbusChannel channel : channels) {
if (!init) {
tempFunctionCode = channel.getFunctionCode();
init = true;
}
else {
if (!tempFunctionCode.equals(channel.getFunctionCode())) {
throw new RuntimeException("FunctionCodes of all channels within the samplingGroup '"
+ samplingGroup + "' are not equal! Change your openmuc config.");
}
}
}
functionCode = tempFunctionCode;
}
/**
* Checks if the primary table of all channels of the sampling group is equal and sets the value for the channel
* group.
*/
private void setPrimaryTable() {
boolean init = false;
EPrimaryTable tempPrimaryTable = null;
for (ModbusChannel channel : channels) {
if (!init) {
tempPrimaryTable = channel.getPrimaryTable();
init = true;
}
else {
if (!tempPrimaryTable.equals(channel.getPrimaryTable())) {
throw new RuntimeException("Primary tables of all channels within the samplingGroup '"
+ samplingGroup + "' are not equal! Change your openmuc config.");
}
}
}
primaryTable = tempPrimaryTable;
}
private void setUnitId() {
int idOfFirstChannel = INVALID;
for (ModbusChannel channel : channels) {
if (idOfFirstChannel == INVALID) {
idOfFirstChannel = channel.getUnitId();
}
else {
if (channel.getUnitId() != idOfFirstChannel) {
// TODO ???
// channel 1 device 1 = unitId 1
// channel 1 device 2 = unitId 2
// Does openmuc calls the read method for channels of different devices?
// If so, then the check for UnitID has to be modified. Only channels of the same device
// need to have the same unitId...
throw new RuntimeException("UnitIds of all channels within the samplingGroup '" + samplingGroup
+ "' are not equal! Change your openmuc config.");
}
}
}
unitId = idOfFirstChannel;
}
/**
* StartAddress is the smallest channel address of the group
*/
private void setStartAddress() {
startAddress = INVALID;
for (ModbusChannel channel : channels) {
if (startAddress == INVALID) {
startAddress = channel.getStartAddress();
}
else {
startAddress = Math.min(startAddress, channel.getStartAddress());
}
}
}
/**
*
*/
private void setCount() {
int maximumAddress = startAddress;
for (ModbusChannel channel : channels) {
maximumAddress = Math.max(maximumAddress, channel.getStartAddress() + channel.getCount());
}
count = maximumAddress - startAddress;
}
public void setChannelValues(InputRegister[] inputRegisters, List<ChannelRecordContainer> containers) {
for (ModbusChannel channel : channels) {
// determine start index of the registers which contain the values of the channel
int registerIndex = channel.getStartAddress() - getStartAddress();
// create a temporary register array
InputRegister[] registers = new InputRegister[channel.getCount()];
// copy relevant registers for the channel
System.arraycopy(inputRegisters, registerIndex, registers, 0, channel.getCount());
// now we have a register array which contains the value of the channel
ChannelRecordContainer container = searchContainer(channel.getChannelAddress(), containers);
ModbusDriverUtil util = new ModbusDriverUtil();
long receiveTime = System.currentTimeMillis();
Value value = util.getRegistersValue(registers, channel.getDatatype());
// logger.debug("got value: " + value + " for channel: " + channel.getChannelAddress());
container.setRecord(new Record(value, receiveTime));
}
}
public void setChannelValues(BitVector bitVector, List<ChannelRecordContainer> containers) {
for (ModbusChannel channel : channels) {
long receiveTime = System.currentTimeMillis();
// determine start index of the registers which contain the values of the channel
int index = channel.getStartAddress() - getStartAddress();
BooleanValue value = new BooleanValue(bitVector.getBit(index));
ChannelRecordContainer container = searchContainer(channel.getChannelAddress(), containers);
container.setRecord(new Record(value, receiveTime));
}
}
private ChannelRecordContainer searchContainer(String channelAddress, List<ChannelRecordContainer> containers) {
for (ChannelRecordContainer container : containers) {
if (container.getChannelAddress().toUpperCase().equals(channelAddress.toUpperCase())) {
return container;
}
}
throw new RuntimeException("No ChannelRecordContainer found for channelAddress " + channelAddress);
}
public boolean isEmpty() {
boolean result = true;
if (channels.size() != 0) {
result = false;
}
return result;
}
public EPrimaryTable getPrimaryTable() {
return primaryTable;
}
public int getStartAddress() {
return startAddress;
}
public int getCount() {
return count;
}
public int getUnitId() {
return unitId;
}
public EFunctionCode getFunctionCode() {
return functionCode;
}
public ArrayList<ModbusChannel> getChannels() {
return channels;
}
}