/*
* 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.iec61850;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.openmuc.framework.config.ArgumentSyntaxException;
import org.openmuc.framework.config.DriverInfo;
import org.openmuc.framework.config.ScanException;
import org.openmuc.framework.config.ScanInterruptedException;
import org.openmuc.framework.driver.spi.Connection;
import org.openmuc.framework.driver.spi.ConnectionException;
import org.openmuc.framework.driver.spi.DriverDeviceScanListener;
import org.openmuc.framework.driver.spi.DriverService;
import org.openmuc.openiec61850.ClientAssociation;
import org.openmuc.openiec61850.ClientSap;
import org.openmuc.openiec61850.ServerModel;
import org.openmuc.openiec61850.ServiceError;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component
public final class Iec61850Driver implements DriverService {
private final static Logger logger = LoggerFactory.getLogger(Iec61850Driver.class);
private final static DriverInfo info = new DriverInfo("iec61850", // id
// description
"This driver can be used to access IEC 61850 MMS devices",
// device address
"Synopsis: <host>[:<port>]\nThe default port is 102.",
// parameters
"Synopsis: [-a <authentication_parameter>] [-lt <local_t-selector>] [-rt <remote_t-selector>]",
// channel address
"Synopsis: <bda_reference>:<fc>",
// device scan settings
"N.A.");
@Override
public DriverInfo getInfo() {
return info;
}
@Override
public void scanForDevices(String settings, DriverDeviceScanListener listener)
throws UnsupportedOperationException, ArgumentSyntaxException, ScanException, ScanInterruptedException {
throw new UnsupportedOperationException();
}
@Override
public void interruptDeviceScan() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public Connection connect(String deviceAddress, String settings)
throws ArgumentSyntaxException, ConnectionException {
String[] deviceAddresses = deviceAddress.split(":");
if (deviceAddresses.length < 1 || deviceAddresses.length > 2) {
throw new ArgumentSyntaxException("Invalid device address syntax.");
}
String remoteHost = deviceAddresses[0];
InetAddress address;
try {
address = InetAddress.getByName(remoteHost);
} catch (UnknownHostException e) {
throw new ConnectionException("Unknown host: " + remoteHost, e);
}
int remotePort = 102;
if (deviceAddresses.length == 2) {
try {
remotePort = Integer.parseInt(deviceAddresses[1]);
} catch (NumberFormatException e) {
throw new ArgumentSyntaxException("The specified port is not an integer");
}
}
ClientSap clientSap = new ClientSap();
String authentication = null;
if (!settings.isEmpty()) {
String[] args = settings.split("\\s+", 0);
if (args.length > 6) {
throw new ArgumentSyntaxException(
"Less than one or more than four arguments in the settings are not allowed.");
}
for (int i = 0; i < args.length; i++) {
if (args[i].equals("-a")) {
i++;
if (i == args.length) {
throw new ArgumentSyntaxException(
"No authentication parameter was specified after the -a parameter");
}
authentication = args[i];
}
else if (args[i].equals("-lt")) {
if (i == (args.length - 1) || args[i + 1].startsWith("-")) {
clientSap.setTSelLocal(new byte[0]);
}
else {
i++;
byte[] tSelLocal = new byte[args[i].length()];
for (int j = 0; j < args[i].length(); j++) {
tSelLocal[j] = (byte) args[i].charAt(j);
}
clientSap.setTSelLocal(tSelLocal);
}
}
else if (args[i].equals("-rt")) {
if (i == (args.length - 1) || args[i + 1].startsWith("-")) {
clientSap.setTSelRemote(new byte[0]);
}
else {
i++;
byte[] tSelRemote = new byte[args[i].length()];
for (int j = 0; j < args[i].length(); j++) {
tSelRemote[j] = (byte) args[i].charAt(j);
}
clientSap.setTSelRemote(tSelRemote);
}
}
else {
throw new ArgumentSyntaxException("Unexpected argument: " + args[i]);
}
}
}
ClientAssociation clientAssociation;
try {
clientAssociation = clientSap.associate(address, remotePort, authentication, null);
} catch (IOException e) {
throw new ConnectionException(e);
}
ServerModel serverModel;
try {
serverModel = clientAssociation.retrieveModel();
} catch (ServiceError e) {
clientAssociation.close();
throw new ConnectionException("Service error retrieving server model" + e.getMessage(), e);
} catch (IOException e) {
clientAssociation.close();
throw new ConnectionException("IOException retrieving server model: " + e.getMessage(), e);
}
return new Iec61850Connection(clientAssociation, serverModel);
}
}