/*
* 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.ehz;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.openmuc.framework.config.ChannelScanInfo;
import org.openmuc.framework.data.ValueType;
import org.openmuc.framework.driver.spi.ChannelRecordContainer;
import org.openmuc.framework.driver.spi.ConnectionException;
import org.openmuc.jsml.structures.ASNObject;
import org.openmuc.jsml.structures.Integer16;
import org.openmuc.jsml.structures.Integer32;
import org.openmuc.jsml.structures.Integer64;
import org.openmuc.jsml.structures.Integer8;
import org.openmuc.jsml.structures.SML_File;
import org.openmuc.jsml.structures.SML_GetListRes;
import org.openmuc.jsml.structures.SML_ListEntry;
import org.openmuc.jsml.structures.SML_Message;
import org.openmuc.jsml.structures.SML_MessageBody;
import org.openmuc.jsml.structures.Unsigned16;
import org.openmuc.jsml.structures.Unsigned32;
import org.openmuc.jsml.structures.Unsigned64;
import org.openmuc.jsml.structures.Unsigned8;
import org.openmuc.jsml.tl.SML_SerialReceiver;
import gnu.io.PortInUseException;
import gnu.io.UnsupportedCommOperationException;
/**
* @author Frederic Robra
*
*/
public class SmlConnection extends GeneralConnection {
private final SML_SerialReceiver receiver;
private String serverID;
public SmlConnection(String deviceAddress) throws ConnectionException {
name = "SML - " + deviceAddress + " - ";
receiver = new SML_SerialReceiver();
try {
receiver.setupComPort(deviceAddress);
} catch (IOException e) {
throw new ConnectionException();
} catch (PortInUseException e) {
throw new ConnectionException("Port in use");
} catch (UnsupportedCommOperationException e) {
throw new ConnectionException("Unsupported comm operation");
}
}
/*
* (non-Javadoc)
*
* @see org.openmuc.framework.driver.ehz.Connection#close()
*/
@Override
public void close() {
try {
receiver.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* (non-Javadoc)
*
* @see org.openmuc.framework.driver.ehz.Connection#read(java.util.List, int)
*/
@Override
public void read(List<ChannelRecordContainer> containers, int timeout) throws ConnectionException {
logger.trace(name + "reading channels");
try {
long timestamp = System.currentTimeMillis();
SML_ListEntry[] list = getSML_ListEntries();
Map<String, Double> values = new LinkedHashMap<>();
for (SML_ListEntry entry : list) {
String address = getAddress(entry.getObjName().getOctetString());
double value = getValue(entry);
values.put(address, value);
logger.trace(name + address + " = " + value);
}
handleChannelRecordContainer(containers, values, timestamp);
} catch (IOException e) {
e.printStackTrace();
logger.error(name + "read failed");
close();
throw new ConnectionException(e);
}
}
/*
* (non-Javadoc)
*
* @see org.openmuc.framework.driver.ehz.Connection#listChannels(int)
*/
@Override
public List<ChannelScanInfo> listChannels(int timeout) {
List<ChannelScanInfo> channelInfos = new LinkedList<>();
logger.debug(name + "scanning channels");
try {
SML_ListEntry[] list = getSML_ListEntries();
for (SML_ListEntry entry : list) {
String channelAddress = getAddress(entry.getObjName().getOctetString());
String description = "Current value: " + getValue(entry); // TODO entry.getUnit();
ValueType valueType = ValueType.DOUBLE;
Integer valueTypeLength = null;
Boolean readable = true;
Boolean writable = false;
ChannelScanInfo channelInfo = new ChannelScanInfo(channelAddress, description, valueType,
valueTypeLength, readable, writable);
channelInfos.add(channelInfo);
}
} catch (IOException e) {
e.printStackTrace();
logger.error(name + "read failed");
}
return channelInfos;
}
/*
* (non-Javadoc)
*
* @see org.openmuc.framework.driver.ehz.Connection#isWorking()
*/
@Override
public boolean isWorking() {
try {
getSML_ListEntries();
return true;
} catch (IOException e) {
return false;
}
}
private SML_ListEntry[] getSML_ListEntries() throws IOException {
SML_File smlFile = receiver.getSMLFile();
List<SML_Message> messages = smlFile.getMessages();
SML_ListEntry[] list = null;
for (SML_Message message : messages) {
int tag = message.getMessageBody().getTag().getVal();
if (tag == SML_MessageBody.GetListResponse) {
SML_GetListRes resp = (SML_GetListRes) message.getMessageBody().getChoice();
if (serverID == null) {
serverID = "";
for (Byte b : resp.getServerId().getOctetString()) {
serverID += Integer.toString((b & 0xff) + 0x100, 16).substring(1);
}
serverID = serverID.toUpperCase();
}
list = resp.getValList().getValListEntry();
break;
}
}
return list;
}
private String getAddress(byte[] data) {
StringBuilder address = new StringBuilder(data.length * 2);
for (byte b : data) {
address.append(String.format("%x", b));
}
return address.toString();
}
// TODO return OpenMUC value
private double getValue(SML_ListEntry entry) {
double value = 0;
ASNObject obj = entry.getValue().getChoice();
if (obj.getClass().equals(Integer64.class)) {
Integer64 val = (Integer64) obj;
value = val.getVal();
}
else if (obj.getClass().equals(Integer32.class)) {
Integer32 val = (Integer32) obj;
value = val.getVal();
}
else if (obj.getClass().equals(Integer16.class)) {
Integer16 val = (Integer16) obj;
value = val.getVal();
}
else if (obj.getClass().equals(Integer8.class)) {
Integer8 val = (Integer8) obj;
value = val.getVal();
}
else if (obj.getClass().equals(Unsigned64.class)) {
Unsigned64 val = (Unsigned64) obj;
value = val.getVal();
}
else if (obj.getClass().equals(Unsigned32.class)) {
Unsigned32 val = (Unsigned32) obj;
value = val.getVal();
}
else if (obj.getClass().equals(Unsigned16.class)) {
Unsigned16 val = (Unsigned16) obj;
value = val.getVal();
}
else if (obj.getClass().equals(Unsigned8.class)) {
Unsigned8 val = (Unsigned8) obj;
value = val.getVal();
}
else {
return Double.NaN;
}
byte scaler = entry.getScaler().getVal();
return value * Math.pow(10, scaler);
}
}