package org.openmuc.openiec61850.app; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import javax.swing.JCheckBox; import javax.swing.JTextField; import org.openmuc.openiec61850.BdaFloat32; import org.openmuc.openiec61850.BdaBoolean; import org.openmuc.openiec61850.BdaTriggerConditions; import org.openmuc.openiec61850.Brcb; import org.openmuc.openiec61850.ClientAssociation; import org.openmuc.openiec61850.ClientEventListener; import org.openmuc.openiec61850.ClientSap; import org.openmuc.openiec61850.DataSet; import org.openmuc.openiec61850.Fc; import org.openmuc.openiec61850.FcModelNode; import org.openmuc.openiec61850.ModelNode; import org.openmuc.openiec61850.Report; import org.openmuc.openiec61850.SclParseException; import org.openmuc.openiec61850.ServerModel; import org.openmuc.openiec61850.ServiceError; import org.openmuc.openiec61850.Urcb; import org.openmuc.openiec61850.clientgui.BasicDataBind; import org.openmuc.openiec61850.internal.cli.Action; import org.openmuc.openiec61850.internal.cli.ActionException; import org.openmuc.openiec61850.internal.cli.ActionListener; import org.openmuc.openiec61850.internal.cli.ActionProcessor; import org.openmuc.openiec61850.internal.cli.CliParameter; import org.openmuc.openiec61850.internal.cli.CliParameterBuilder; import org.openmuc.openiec61850.internal.cli.CliParseException; import org.openmuc.openiec61850.internal.cli.CliParser; import org.openmuc.openiec61850.internal.cli.FatalActionException; import org.openmuc.openiec61850.internal.cli.IntCliParameter; import org.openmuc.openiec61850.internal.cli.StringCliParameter; import org.openmuc.openiec61850.clientgui.databind.BooleanDataBind; import org.openmuc.openiec61850.clientgui.databind.Float32DataBind; /** * * @author Stefan Feuerhahn * */ public class ConsoleClient { private static final String PRINT_MODEL_KEY = "m"; private static final String PRINT_MODEL_KEY_DESCRIPTION = "print model"; private static final String GET_DATA_VALUES_KEY = "g"; private static final String GET_DATA_VALUES_KEY_DESCRIPTION = "send GetDataValues request"; private static final String READ_ALL_DATA_KEY = "ga"; private static final String READ_ALL_DATA_KEY_DESCRIPTION = "update all data in the model"; private static final String CREATE_DATA_SET_KEY = "cds"; private static final String CREATE_DATA_SET_KEY_DESCRIPTION = "create data set"; private static final String DELETE_DATA_SET_KEY = "dds"; private static final String DELETE_DATA_SET_KEY_DESCRIPTION = "delete data set"; private static final String REPORTING_KEY = "r"; private static final String REPORTING_KEY_DESCRIPTION = "configure reporting"; private static final StringCliParameter hostParam = new CliParameterBuilder("-h") .setDescription("The IP/domain address of the server you want to access.") .setMandatory() .buildStringParameter("host"); private static final IntCliParameter portParam = new CliParameterBuilder("-p") .setDescription("The port to connect to.") .buildIntParameter("port", 102); private static final StringCliParameter modelFileParam = new CliParameterBuilder("-m").setDescription( "The file name of the SCL file to read the model from. If this parameter is omitted the model will be read from the server device after connection.") .buildStringParameter("model-file"); private static volatile ClientAssociation association; private static ServerModel serverModel; private static final ActionProcessor actionProcessor = new ActionProcessor(new ActionExecutor()); private static class EventListener implements ClientEventListener { @Override public void newReport(Report report) { System.out.println("\n----------------"); System.out.println("Received report: "); System.err.println(report); System.out.println("------------------"); } @Override public void associationClosed(IOException e) { System.out.print("Received connection closed signal. Reason: "); if (!e.getMessage().isEmpty()) { System.out.println(e.getMessage()); } else { System.out.println("unknown"); } actionProcessor.close(); } } private static class ActionExecutor implements ActionListener { @Override public void actionCalled(String actionKey) throws ActionException, FatalActionException { try { switch (actionKey) { case PRINT_MODEL_KEY: System.out.println(serverModel); break; case READ_ALL_DATA_KEY: System.out.print("Reading all data..."); try { association.getAllDataValues(); } catch (ServiceError e) { System.err.println("Service error: " + e.getMessage()); } System.out.println("done"); break; case GET_DATA_VALUES_KEY: { if (serverModel == null) { System.out.println("You have to retrieve the model before reading data."); return; } FcModelNode fcModelNode = askForFcModelNode(); System.out.println("Sending SetDataValues request..."); try { BasicDataBind data = new Float32DataBind((BdaFloat32)fcModelNode); JTextField tf_t = (JTextField)data.getValueField(); tf_t.setText("12.0"); data.write(); association.setDataValues(fcModelNode); } catch (ServiceError e) { System.out.println("Service error: " + e.getMessage()); return; } catch (IOException e) { System.out.println("Fatal error: " + e.getMessage()); return; } System.out.println("Successfully write data."); System.out.println("Sending GetDataValues request..."); try { association.getDataValues(fcModelNode); } catch (ServiceError e) { System.out.println("Service error: " + e.getMessage()); return; } catch (IOException e) { System.out.println("Fatal error: " + e.getMessage()); return; } System.out.println("Successfully read data."); BasicDataBind data = new Float32DataBind((BdaFloat32)fcModelNode); JTextField tf_t = (JTextField)data.getValueField(); System.out.println("The read data is:" + tf_t.getText()); //System.out.println(fcModelNode); break; } case CREATE_DATA_SET_KEY: { System.out.println("Enter the reference of the data set to create (e.g. myld/MYLN0.dataset1): "); String reference = actionProcessor.getReader().readLine(); System.out.println("How many entries shall the data set have: "); String numberOfEntriesString = actionProcessor.getReader().readLine(); int numDataSetEntries = Integer.parseInt(numberOfEntriesString); List dataSetMembers = new ArrayList<>(); for (int i = 0; i < numDataSetEntries; i++) { dataSetMembers.add(askForFcModelNode()); } DataSet dataSet = new DataSet(reference, dataSetMembers); System.out.print("Creating data set.."); association.createDataSet(dataSet); System.out.println("done"); break; } case DELETE_DATA_SET_KEY: { System.out.println("Enter the reference of the data set to delete (e.g. myld/MYLN0.dataset1): "); String reference = actionProcessor.getReader().readLine(); DataSet dataSet = serverModel.getDataSet(reference); if (dataSet == null) { throw new ActionException("Unable to find data set with the given reference."); } System.out.print("Deleting data set.."); association.deleteDataSet(dataSet); System.out.println("done"); break; } case REPORTING_KEY: { System.out.println("Enter the URCB reference: "); String reference = actionProcessor.getReader().readLine(); Urcb urcb = serverModel.getUrcb(reference); if (urcb == null) { Brcb brcb = serverModel.getBrcb(reference); if (brcb != null) { throw new ActionException( "Though buffered reporting is supported by the library it is not yet supported by the console application."); } throw new ActionException("Unable to find RCB with the given reference."); } while (true) { association.getRcbValues(urcb); System.out.println(); System.out.println(urcb); System.out.println(); System.out.println("What do you want to configure?"); System.out.println("1 - reserve"); System.out.println("2 - cancel reservation"); System.out.println("3 - enable"); System.out.println("4 - disable"); System.out.println("5 - set data set"); System.out.println("6 - set trigger options"); System.out.println("7 - set integrity period"); System.out.println("8 - send general interrogation"); System.out.println("0 - quit"); try { int rcbAction = Integer.parseInt(actionProcessor.getReader().readLine()); switch (rcbAction) { case 0: return; case 1: System.out.print("Reserving RCB.."); association.reserveUrcb(urcb); System.out.println("done"); break; case 2: System.out.print("Canceling RCB reservation.."); association.cancelUrcbReservation(urcb); System.out.println("done"); break; case 3: System.out.print("Enabling reporting.."); association.enableReporting(urcb); System.out.println("done"); break; case 4: System.out.print("Disabling reporting.."); association.disableReporting(urcb); System.out.println("done"); break; case 5: { System.out.print("Set data set reference:"); String dataSetReference = actionProcessor.getReader().readLine(); urcb.getDatSet().setValue(dataSetReference); List serviceErrors = association.setRcbValues(urcb, false, true, false, false, false, false, false, false); if (serviceErrors.get(0) != null) { throw serviceErrors.get(0); } System.out.println("done"); break; } case 6: { System.out.print( "Set the trigger options (data change, data update, quality change, interity, GI):"); String triggerOptionsString = actionProcessor.getReader().readLine(); String[] triggerOptionsStrings = triggerOptionsString.split(","); BdaTriggerConditions triggerOptions = urcb.getTrgOps(); triggerOptions.setDataChange(Boolean.parseBoolean(triggerOptionsStrings[0])); triggerOptions.setDataUpdate(Boolean.parseBoolean(triggerOptionsStrings[1])); triggerOptions.setQualityChange(Boolean.parseBoolean(triggerOptionsStrings[2])); triggerOptions.setIntegrity(Boolean.parseBoolean(triggerOptionsStrings[3])); triggerOptions.setGeneralInterrogation(Boolean.parseBoolean(triggerOptionsStrings[4])); List serviceErrors = association.setRcbValues(urcb, false, false, false, false, true, false, false, false); if (serviceErrors.get(0) != null) { throw serviceErrors.get(0); } System.out.println("done"); break; } case 7: { System.out.print("Specify integrity period in ms:"); String integrityPeriodString = actionProcessor.getReader().readLine(); urcb.getIntgPd().setValue(Long.parseLong(integrityPeriodString)); List serviceErrors = association.setRcbValues(urcb, false, false, false, false, false, true, false, false); if (serviceErrors.get(0) != null) { throw serviceErrors.get(0); } System.out.println("done"); break; } case 8: System.out.print("Sending GI.."); association.startGi(urcb); System.out.println("done"); break; default: System.err.println("Unknown option."); break; } } catch (ServiceError e) { System.err.println("Service error: " + e.getMessage()); } catch (NumberFormatException e) { System.err.println("Cannot parse number: " + e.getMessage()); } } } default: break; } } catch (Exception e) { throw new ActionException(e); } } private FcModelNode askForFcModelNode() throws IOException, ActionException { System.out.println("Enter reference (e.g. myld/MYLN0.do.da.bda): "); String reference = actionProcessor.getReader().readLine(); System.out.println("Enter functional constraint of referenced node: "); String fcString = actionProcessor.getReader().readLine(); Fc fc = Fc.fromString(fcString); if (fc == null) { throw new ActionException("Unknown functional constraint."); } ModelNode modelNode = serverModel.findModelNode(reference, Fc.fromString(fcString)); if (modelNode == null) { throw new ActionException( "A model node with the given reference and functional constraint could not be found."); } if (!(modelNode instanceof FcModelNode)) { throw new ActionException("The given model node is not a functionally constraint model node."); } FcModelNode fcModelNode = (FcModelNode) modelNode; return fcModelNode; } @Override public void quit() { System.out.println("** Closing connection."); association.close(); return; } } public static void writeNodeData(String reference, String fc_str) { FcModelNode fcModelNode = (FcModelNode)serverModel.findModelNode(reference, Fc.fromString(fc_str)); if(null == fcModelNode) { System.err.println("error, no modenode was found....."); return; } System.out.println("Sending SetDataValues request..."); try { /* BasicDataBind data = new Float32DataBind((BdaFloat32)fcModelNode); JTextField tf_t = (JTextField)data.getValueField(); tf_t.setText("12.0"); */ BasicDataBind data = new BooleanDataBind((BdaBoolean)fcModelNode.getChild("ctlVal")); JCheckBox ckb_t = (JCheckBox)data.getValueField(); ckb_t.setSelected(false); data.write(); association.setDataValues(fcModelNode); } catch (ServiceError e) { System.out.println("Service error: " + e.getMessage()); return; } catch (IOException e) { System.out.println("Fatal error: " + e.getMessage()); return; } System.out.println("Successfully write data."); } public static void readNodeData(String reference, String fc_str) { FcModelNode fcModelNode = (FcModelNode)serverModel.findModelNode(reference, Fc.fromString(fc_str)); if(null == fcModelNode) { System.err.println("error, no modenode was found....."); return; } System.out.println("Sending GetDataValues request..."); try { association.getDataValues(fcModelNode); } catch (ServiceError e) { System.out.println("Service error: " + e.getMessage()); return; } catch (IOException e) { System.out.println("Fatal error: " + e.getMessage()); return; } System.out.println("Successfully read data."); /* BasicDataBind data = new Float32DataBind((BdaFloat32)fcModelNode); JTextField tf_t = (JTextField)data.getValueField(); System.out.println("The modelnode is:" + fcModelNode.getReference() + ", the value is: " + tf_t.getText()); */ BasicDataBind data = new BooleanDataBind((BdaBoolean)fcModelNode.getChild("ctlVal")); JCheckBox ckb_t = (JCheckBox)data.getValueField(); System.out.println("The modelnode is:" + fcModelNode.getChild("ctlVal").getReference() + ", the value is: " + ckb_t.isSelected()); } public static void main(String[] args) { List cliParameters = new ArrayList<>(); cliParameters.add(hostParam); cliParameters.add(portParam); cliParameters.add(modelFileParam); CliParser cliParser = new CliParser("openiec61850-console-client", "A client application to access IEC 61850 MMS servers."); cliParser.addParameters(cliParameters); try { cliParser.parseArguments(args); } catch (CliParseException e1) { System.err.println("Error parsing command line parameters: " + e1.getMessage()); System.out.println(cliParser.getUsageString()); System.exit(1); } InetAddress address; try { address = InetAddress.getByName(hostParam.getValue()); } catch (UnknownHostException e) { System.out.println("Unknown host: " + hostParam.getValue()); return; } ClientSap clientSap = new ClientSap(); try { association = clientSap.associate(address, portParam.getValue(), null, new EventListener()); } catch (IOException e) { System.out.println("Unable to connect to remote host."); return; } Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { association.close(); } }); System.out.println("successfully connected"); if (modelFileParam.isSelected()) { System.out.println("reading model from file..."); try { serverModel = association.getModelFromSclFile(modelFileParam.getValue()); } catch (SclParseException e1) { System.out.println("Error parsing SCL file: " + e1.getMessage()); return; } System.out.println("successfully read model"); } else { System.out.println("retrieving model..."); try { serverModel = association.retrieveModel(); } catch (ServiceError e) { System.out.println("Service error: " + e.getMessage()); return; } catch (IOException e) { System.out.println("Fatal error: " + e.getMessage()); return; } System.out.println("successfully read model"); } actionProcessor.addAction(new Action(PRINT_MODEL_KEY, PRINT_MODEL_KEY_DESCRIPTION)); actionProcessor.addAction(new Action(GET_DATA_VALUES_KEY, GET_DATA_VALUES_KEY_DESCRIPTION)); actionProcessor.addAction(new Action(READ_ALL_DATA_KEY, READ_ALL_DATA_KEY_DESCRIPTION)); actionProcessor.addAction(new Action(CREATE_DATA_SET_KEY, CREATE_DATA_SET_KEY_DESCRIPTION)); actionProcessor.addAction(new Action(DELETE_DATA_SET_KEY, DELETE_DATA_SET_KEY_DESCRIPTION)); actionProcessor.addAction(new Action(REPORTING_KEY, REPORTING_KEY_DESCRIPTION)); actionProcessor.start(); /* writeNodeData("ZJDYBTSE/ncdGGIO1.Para6.setMag.f", "SP"); readNodeData("ZJDYBTSE/ncdGGIO1.Para6.setMag.f", "SP"); writeNodeData("ZJDYBTSE/ncdGGIO1.SPCSO1.Oper", "CO"); readNodeData("ZJDYBTSE/ncdGGIO1.SPCSO1.Oper", "CO");*/ } }