ClientAssociation
is
* obtained using ClientSap
. An association object can be used to execute the IEC 61850 ACSI services. Note
* that not all ACSI services have a corresponding function in this API. For example all GetDirectory and GetDefinition
* services are covered by retrieveModel()
. The control services can be executed by using getDataValues and
* setDataValues on the control objects in the data model.
*
*/
public final class ClientAssociation {
private static final Integer16 version = new Integer16(new byte[] { (byte) 0x01, (byte) 0x01 });
private static final ParameterSupportOptions proposedParameterCbbBitString = new ParameterSupportOptions(
new byte[] { 0x03, 0x05, (byte) 0xf1, 0x00 });
private AcseAssociation acseAssociation = null;
private final ClientReceiver clientReceiver;
private final BlockingQueueretrieveModel
in order to get the server model that is needed to call the other ACSI services.
*
* @param sclFilePath
* the path to the SCL file that is to be parsed.
* @return The ServerNode that is the root node of the complete server model.
* @throws SclParseException
* if any kind of fatal error occurs in the parsing process.
*/
public ServerModel getModelFromSclFile(String sclFilePath) throws SclParseException {
ListServiceError
will be thrown.
*
* @param modelNode
* the functionally constrained model node that is to be read.
* @throws ServiceError
* if a ServiceError is returned by the server.
* @throws IOException
* if a fatal association error occurs. The association object will be closed and can no longer be used
* after this exception is thrown.
*/
public void getDataValues(FcModelNode modelNode) throws ServiceError, IOException {
ConfirmedServiceRequest serviceRequest = constructGetDataValuesRequest(modelNode);
ConfirmedServiceResponse confirmedServiceResponse = encodeWriteReadDecode(serviceRequest);
decodeGetDataValuesResponse(confirmedServiceResponse, modelNode);
}
/**
* Will update all data inside the model except for control variables (those that have FC=CO). Control variables are
* not meant to be read. Update is done by calling getDataValues on the FCDOs below the Logical Nodes.
*
* @throws ServiceError
* if a ServiceError is returned by the server.
* @throws IOException
* if a fatal association error occurs. The association object will be closed and can no longer be used
* after this exception is thrown.
*/
public void getAllDataValues() throws ServiceError, IOException {
for (ModelNode logicalDevice : serverModel.getChildren()) {
for (ModelNode logicalNode : logicalDevice.getChildren()) {
for (ModelNode dataObject : logicalNode.getChildren()) {
FcModelNode fcdo = (FcModelNode) dataObject;
if (fcdo.getFc() != Fc.CO && fcdo.getFc() != Fc.SE) {
try {
getDataValues(fcdo);
} catch (ServiceError e) {
throw new ServiceError(e.getErrorCode(), "service error retrieving " + fcdo.getReference()
+ "[" + fcdo.getFc() + "]" + ", " + e.getMessage(), e);
}
}
}
}
}
}
private ConfirmedServiceRequest constructGetDataValuesRequest(FcModelNode modelNode) {
VariableAccessSpecification varAccessSpec = constructVariableAccessSpecification(modelNode);
ReadRequest readRequest = new ReadRequest();
readRequest.setVariableAccessSpecification(varAccessSpec);
ConfirmedServiceRequest confirmedServiceRequest = new ConfirmedServiceRequest();
confirmedServiceRequest.setRead(readRequest);
return confirmedServiceRequest;
}
private void decodeGetDataValuesResponse(ConfirmedServiceResponse confirmedServiceResponse, ModelNode modelNode)
throws ServiceError {
if (confirmedServiceResponse.getRead() == null) {
throw new ServiceError(ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT,
"Error decoding GetDataValuesReponsePdu");
}
ListServiceError
will be thrown. In this case
* it is not possible to find out which of several Basic Data Attributes could not be written.
*
* @param modelNode
* the functionally constrained model node that is to be written.
* @throws ServiceError
* if a ServiceError is returned by the server.
* @throws IOException
* if a fatal association error occurs. The association object will be closed and can no longer be used
* after this exception is thrown.
*/
public void setDataValues(FcModelNode modelNode) throws ServiceError, IOException {
ConfirmedServiceRequest serviceRequest = constructSetDataValuesRequest(modelNode);
ConfirmedServiceResponse confirmedServiceResponse = encodeWriteReadDecode(serviceRequest);
decodeSetDataValuesResponse(confirmedServiceResponse);
}
private ConfirmedServiceRequest constructSetDataValuesRequest(FcModelNode modelNode) throws ServiceError {
VariableAccessSpecification variableAccessSpecification = constructVariableAccessSpecification(modelNode);
ListOfData listOfData = new ListOfData();
List dataList = listOfData.getData();
dataList.add(modelNode.getMmsDataObj());
WriteRequest writeRequest = new WriteRequest();
writeRequest.setListOfData(listOfData);
writeRequest.setVariableAccessSpecification(variableAccessSpecification);
ConfirmedServiceRequest confirmedServiceRequest = new ConfirmedServiceRequest();
confirmedServiceRequest.setWrite(writeRequest);
return confirmedServiceRequest;
}
private VariableAccessSpecification constructVariableAccessSpecification(FcModelNode modelNode) {
VariableDefs listOfVariable = new VariableDefs();
Listnull
if reading was successful and a ServiceError if reading of this
* member failed.
*
* @param dataSet
* the DataSet that is to be read.
* @return a list indicating ServiceErrors that may have occurred.
* @throws IOException
* if a fatal IO error occurs. The association object will be closed and can no longer be used after
* this exception is thrown.
*/
public List* The data set reference as it is set in an RCB must contain a dollar sign instead of a dot to separate the logical * node from the data set name, e.g.: 'LDevice1/LNode$DataSetName'. Therefore his method will check the reference * for a dot and if necessary convert it to a '$' sign before sending the request to the server. *
* The parameters PurgeBuf, EntryId are only applicable if the given rcb is of type BRCB.
*
*
* @param rcb
* the report control block
* @param setRptId
* whether to set the report ID
* @param setDatSet
* whether to set the data set
* @param setOptFlds
* whether to set the optional fields
* @param setBufTm
* whether to set the buffer time
* @param setTrgOps
* whether to set the trigger options
* @param setIntgPd
* whether to set the integrity period
* @param setPurgeBuf
* whether to set purge buffer
* @param setEntryId
* whether to set the entry ID
* @return a list indicating ServiceErrors that may have occurred.
* @throws IOException
* if a fatal IO error occurs. The association object will be closed and can no longer be used after
* this exception is thrown.
*/
public List
*
*
* @param controlDataObject
* needs to be a controllable Data Object that contains a Data Attribute named "SBO".
* @return false if the selection/reservation was not successful (because it is already selected by another client).
* Otherwise true is returned.
* @throws ServiceError
* if a ServiceError is returned by the server.
* @throws IOException
* if a fatal IO error occurs. The association object will be closed and can no longer be used after
* this exception is thrown.
*/
public boolean select(FcModelNode controlDataObject) throws ServiceError, IOException {
BdaVisibleString sbo;
try {
sbo = (BdaVisibleString) controlDataObject.getChild("SBO");
} catch (Exception e) {
throw new IllegalArgumentException("ModelNode needs to conain a child node named SBO in order to select");
}
getDataValues(sbo);
if (sbo.getValue().length == 0) {
return false;
}
return true;
}
/**
* Executes the Operate ACSI Service on the given controllable Data Object (DO). The following subnodes of the given
* control DO should be set according your needs before calling this function. (Note that you can probably leave
* most attributes with their default value):
*
*
*
* All other operate parameters are automatically handled by this function.
*
* @param controlDataObject
* needs to be a controllable Data Object that contains a Data Attribute named "Oper".
* @throws ServiceError
* if a ServiceError is returned by the server
* @throws IOException
* if a fatal IO error occurs. The association object will be closed and can no longer be used after
* this exception is thrown.
*/
public void operate(FcModelNode controlDataObject) throws ServiceError, IOException {
ConstructedDataAttribute oper;
try {
oper = (ConstructedDataAttribute) controlDataObject.getChild("Oper");
} catch (Exception e) {
throw new IllegalArgumentException("ModelNode needs to conain a child node named \"Oper\".");
}
((BdaInt8U) oper.getChild("ctlNum")).setValue((short) 1);
((BdaTimestamp) oper.getChild("T")).setDate(new Date(System.currentTimeMillis()));
setDataValues(oper);
}
/**
* Will close the connection simply by closing the TCP socket.
*/
public void close() {
clientReceiver.close(new IOException("Connection closed by client"));
}
/**
* Will send a disconnect request first and then close the TCP socket.
*/
public void disconnect() {
clientReceiver.disconnect();
}
}