libIEC61850 also provides a client API for MMS. This API is in no way specific to IEC 61850 but provides a generic MMS client API. In the future I plan to create an IEC 61850 specific client API that is at a higher layer of abstraction and relies on the MMS API yet provided.
A simple MMS client example
The main object of the MMS client API is the MmsConnection class. This class handles the complete MMS stack.
#include "mms_client_connection.h" int main(int argc, char** argv) { MmsConnection con = MmsConnection_create(); MmsIndication indication = MmsConnection_connect(con, "localhost", 102); if (indication == MMS_OK) { // add application code here } MmsConnection_destroy(con); }
In line 5 a new MmsConnection object is created.
In line 7 and 8 the connect-method is invoked on the newly created MmsConnection instance. The first parameter is a string that contains either a hostname or an IP address of the MMS server to connect. The second parameter is the TCP port of the server. This is usually 102 for MMS. The return value is of the enumeration type MmsIndication. The value will be either MMS_OK if the connection attempt was successful or MMS_ERROR if the connection attempt fails.
After the application has finished its purpose the MmsConnection should be closed. This is done by invoking the destroy-method as can be seen in Line 14. The destroy method will disconnect from the server and release all allocated resources of the MMS client stack.
Getting information about the server
The MMS protocol provides services to collect informations about the data model implemented in a server.
The following code line requests the list of Logical Devices from the server:
LinkedList nameList = MmsConnection_getDomainNames(con);
To get the variables list of a specific Logical Device (in this example “SampleIEDDevice1”) you need to invoke the code as following:
nameList = MmsConnection_getDomainVariableNames(con, "SampleIEDDevice1");
If you want to know the list of data sets you use the following function invokation:
LinkedList nameList = MmsConnection_getDomainVariableListNames(con, "SampleIEDDevice1");
The result is of type “LinkedList”. The following code snippet shows how to iterate the list:
LinkedList element = nameList; while ((element = LinkedList_getNext(element)) != NULL) { char* str = (char*) (element->data); printf("%s\n", str); }
Mapping MMS variable names to IEC 61850 object references.
MMXU2$MX$TotW is equal to MMXU2.TotW in IEC 61850 semantics. Be aware that the MMS mapping of an IEC object contains the Functional Constraint directly after the Logical Node name.
You can get type information for server variables with the MmsConnection_getVariableAccessAttributes() function:
MmsConnection_getVariableAccessAttributes(con, "SampleIEDDevice1", "MMXU2$MX$TotW");
Reading data from the server
To get data from the server you have to use the MmsConnection_readVariable() function.
MmsValue* value = MmsConnection_readVariable(con, "SampleIEDDevice1", "MMXU2$MX$TotW$mag$f");
This reads the value for the variable “MMXU2.TotW.mag.f” from the logical device “SampleIEDDevice1”. Be aware that you have to use the MMS variable name instead of the IEC object reference.
Handling MmsValue objects
The MmsValue objects are responsable for dealing with MMS values of any type at the client and the server side. The also contain information about the type of the value. To determine the type of a value you can use the getType() method.
MmsType type = MmsValue_getType(value);
MmsType is an enumeration type that can hold the following values:
- MMS_ARRAY
- MMS_STRUCTURE
- MMS_BOOLEAN
- MMS_BIT_STRING
- MMS_INTEGER
- MMS_UNSIGNED
- MMS_FLOAT
- MMS_OCTET_STRING
- MMS_VISIBLE_STRING
- MMS_GENERALIZED_TIME
- MMS_BINARY_TIME
- MMS_UTC_TIME
A MmsValue object can be of a simple type like MMS_INTEGER and MMS_FLOAT or of a complex type (MMS_STRUCTURE and MMS_ARRAY).
Create new instances
There are methods to create new instances of MmsValue:
MmsValue_newIntegerFromInt32(int32_t integer);
MmsValue_newFloat(float variable);
There are other methods of this kind to create new instances of simple values. You can find them in mms_value.h. To create a complex value you can use:
MmsValue_newStructure(MmsTypeSpecification* typeSpec);
This creates a tree of MmsValue objects according to the provided MmsTypeSpecification object.
A client can retrieve a MmsTypeSpecification object with the getVariableAccessAttributes() method of MmsConnection:
MmsConnection_getVariableAccessAttributes(MmsConnection self, char* domainId, char* itemId);
Dealing with data sets
You can create, read and delete data sets with the MMS client API. IEC 61850 data sets are mapped to MMS Named Variable Lists. To create a data set on the server you can use the defineNamedVariableList() method.
MmsConnection_defineNamedVariableList(MmsConnection self, char* domainId, char* listName, LinkedList variableNames);
Here is a source-code snippet to ilustrate the usage of this function:
LinkedList items = LinkedList_create(); LinkedList_add(items, "LLN0$intvar1"); LinkedList_add(items, "LLN0$floatvar1"); MmsIndication indication = MmsConnection_defineNamedVariableList(con, "device1", "LLN0$DataSet1", items); LinkedList_destroyStatic(items);
To delete a data set you should use the deleteNamedVariableList() method:
MmsIndication
MmsConnection_deleteNamedVariableList(MmsConnection self, char* domainId, char* listName)
Both functions are returning MMS_OK on success or MMS_ERROR if the operation failed. Usually you can only delete those data sets that you also created.
To read the values of a data set you have to use the readNamedVariableListValues() method:
MmsValue* MmsConnection_readNamedVariableListValues(MmsConnection self, char* domainId, char* listName, bool specWithResult)
The first parameters should be self-explaining. The last parameter specWithResult is required to instruct the client to request the server to inculde the Variable Access Specification into the response. You should set this to true since IEC 61850-8-1 mandates this.
If you want to deal with data sets that you did not create by yourself and you don’t know the list of variables available in this data set you can use the readNamedVariableListDirectory() method:
LinkedList MmsConnection_readNamedVariableListDirectory(MmsConnection self, char* domainId, char* listName, bool* deletable)
The result is a list of strings with the variable names of the variable list. Be aware that deletable is also a return value. You should provide a pointer to a bool variable here. It indicates if the data set is deletable or permanent. If you are not interested in this information you can simply provide a NULL pointer here.