- fixed problem with SqNum (INT8U/INT16U) in RCBs and reports

- started to implement sorting algorithm for getNameList
This commit is contained in:
Michael Zillgith 2015-10-23 17:50:25 +02:00
parent 3afba2c958
commit 947b4a0cd5
7 changed files with 391 additions and 13 deletions

View file

@ -182,10 +182,10 @@
#define CONFIG_IEC61850_CONTROL_SERVICE 0
#endif
/* support flatted named variable name space required by IEC 61850-8-1 MMS mapping */
/* support flat named variable name space required by IEC 61850-8-1 MMS mapping */
#define CONFIG_MMS_SUPPORT_FLATTED_NAME_SPACE 1
/* VMD scope named variables are not used by IEC 61850 */
/* VMD scope named variables are not used by IEC 61850 (one application is ICCP) */
#define CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES 0
#define CONFIG_INCLUDE_PLATFORM_SPECIFIC_HEADERS 0

View file

@ -25,6 +25,7 @@
#define STRING_UTILITIES_H_
#include "libiec61850_platform_includes.h"
#include "linked_list.h"
char*
copyString(const char* string);
@ -76,4 +77,34 @@ StringUtils_createBufferFromHexString(char* hexString, uint8_t* buffer);
bool
StringUtils_startsWith(char* string, char* prefix);
/**
* \brief Compare to characters using the collation order as defined in ISO 9506-2 7.5.2
*
* \param a the first string
* \param b the second string
*
* \returns 0 if a equals b; a positive number if b > a; a negative number if b < a
*/
int
StringUtils_compareChars(char a, char b);
/**
* \brief Compare to strings using the collation order as defined in ISO 9506-2 7.5.2
*
* \param a the first string
* \param b the second string
*
* \returns 0 if a equals b; a positive number if b > a; a negative number if b < a
*/
int
StringUtils_compareStrings(const char* a, const char* b);
/**
* \brief sort a list of strings alphabetically (according to the MMS identifier collation order)
*
* \param list a list that contains string elements
*/
void
StringUtils_sortList(LinkedList list);
#endif /* STRING_UTILITIES_H_ */

View file

@ -240,3 +240,129 @@ StringUtils_startsWith(char* string, char* prefix)
return false;
}
#define LT_MAX_CHARS 128
static int
getCharWeight(int c)
{
static bool initialized = false;
static char lookupTable[LT_MAX_CHARS + 1];
static char* charOrder = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz$_0123456789";
if (!initialized) {
int ltIndex;
int weight = 1;
for (ltIndex = 1; ltIndex < LT_MAX_CHARS; ltIndex++) {
if (strchr(charOrder, ltIndex)) continue;
lookupTable[ltIndex] = weight;
weight++;
}
int charIndex;
for (charIndex = 0; charOrder[charIndex]; charIndex++) {
lookupTable[(int)charOrder[charIndex]] = weight;
weight++;
}
initialized = true;
}
if ((c < 1) || (c > LT_MAX_CHARS))
return c;
else
return lookupTable[c];
}
int
StringUtils_compareChars(char a, char b)
{
return (getCharWeight(a) - getCharWeight(b));
}
int
StringUtils_compareStrings(const char* a, const char* b)
{
int diff = StringUtils_compareChars(*a, *b);
while (diff == 0) {
if ((*a == 0) || (*b == 0)) {
return b - a;
}
diff = StringUtils_compareChars(*++a, *++b);
}
return diff;
}
void
StringUtils_sortList(LinkedList list)
{
LinkedList firstElement = list->next;
LinkedList prevElement = NULL;
while (true) {
/* Check for end of list */
if (firstElement->next) {
char* str1 = (char*) LinkedList_getData(firstElement);
char* str2 = (char*) LinkedList_getData(firstElement->next);
/* Compare first element with next element */
if (StringUtils_compareStrings(str1, str2) > 0) {
LinkedList removedElement = firstElement;
if (firstElement == list->next)
list->next = firstElement->next;
else
prevElement->next = firstElement->next;
firstElement = firstElement->next;
/* search for place to insert */
LinkedList compareElement = removedElement->next->next;
LinkedList prevCompareElement = removedElement->next;
while (true) {
str2 = (char*) LinkedList_getData(compareElement);
if (StringUtils_compareStrings(str1, str2) < 0) {
/* insert element before */
prevCompareElement->next = removedElement;
removedElement->next = compareElement;
break;
}
prevCompareElement = compareElement;
compareElement = compareElement->next;
/* Are we at the end of the list? */
if (compareElement == NULL) {
/* Insert removed element at end of list */
prevCompareElement->next = removedElement;
removedElement->next = NULL;
break;
}
}
}
else {
prevElement = firstElement;
firstElement = firstElement->next;
}
}
else
break;
}
}

View file

@ -501,7 +501,6 @@ GOOSE_createGOOSEControlBlocks(MmsMapping* self, MmsDomain* domain,
"$GO$", gooseControlBlock->name);
if (gooseControlBlock->appId != NULL) {
// gcb->goID = copyString(gooseControlBlock->appId);
MmsValue* goID = MmsValue_getElement(gseValues, 1);
MmsValue_setVisibleString(goID, gooseControlBlock->appId);

View file

@ -432,7 +432,7 @@ sendReport(ReportControl* self, bool isIntegrity, bool isGI)
if (self->sqNum == 256)
self->sqNum = 0;
MmsValue_setUint8(sqNum, self->sqNum);
MmsValue_setUint16(sqNum, self->sqNum);
LinkedList_destroyDeep(deletableElements, (LinkedListValueDeleteFunction) MmsValue_delete);
LinkedList_destroyStatic(reportElements);
@ -1225,7 +1225,7 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme
MmsValue* sqNum = ReportControl_getRCBValue(rc, "SqNum");
MmsValue_setUint16(sqNum, 0U);
MmsValue_setUint32(sqNum, 0U);
retVal = DATA_ACCESS_ERROR_SUCCESS;
goto exit_function;
@ -2165,7 +2165,7 @@ sendNextReportEntry(ReportControl* self)
/* Increase sequence number */
self->sqNum++;
MmsValue_setUint16(sqNum, self->sqNum);
MmsValue_setUint32(sqNum, self->sqNum);
assert(self->reportBuffer->nextToTransmit != self->reportBuffer->nextToTransmit->next);

View file

@ -1,7 +1,7 @@
/*
* mms_get_namelist_service.c
*
* Copyright 2013, 2014 Michael Zillgith
* Copyright 2013, 2014, 2015 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -125,10 +125,12 @@ addSubNamedVaribleNamesToList(LinkedList nameList, char* prefix, MmsVariableSpec
return listElement;
}
#endif /* (CONFIG_MMS_SUPPORT_FLATTED_NAME_SPACE == 1) */
static LinkedList
getNameListDomainSpecific(MmsServerConnection connection, char* domainName) {
getNameListDomainSpecific(MmsServerConnection connection, char* domainName)
{
MmsDevice* device = MmsServer_getDevice(connection->server);
LinkedList nameList = NULL;
@ -157,6 +159,85 @@ getNameListDomainSpecific(MmsServerConnection connection, char* domainName) {
return nameList;
}
#if 0
typedef struct sGetNextListElementDomainSpecificState {
const char* continueAfter;
MmsVariableSpecification** variables;
int variablesCount;
} GetNextListElementDomainSpecificState;
static bool
getNextListElement_DomainSpecific_init(MmsServerConnection connection, char* domainName,
GetNextListElementDomainSpecificState* state, const char* continueAfter)
{
MmsDevice* device = MmsServer_getDevice(connection->server);
MmsDomain* domain = MmsDevice_getDomain(device, domainName);
state->continueAfter = continueAfter;
if (domain != NULL) {
state->variables = domain->namedVariables;
state->variablesCount = domain->namedVariablesCount;
}
}
static LinkedList
TEMP_addSubNamedVaribleNamesToList(LinkedList nameList, char* prefix, MmsVariableSpecification* variable)
{
LinkedList listElement = nameList;
if (variable->type == MMS_STRUCTURE) {
int i;
MmsVariableSpecification** variables = variable->typeSpec.structure.elements;
for (i = 0; i < variable->typeSpec.structure.elementCount; i++) {
char* variableName = appendMmsSubVariable(prefix, variables[i]->name);
listElement = LinkedList_insertAfter(listElement, variableName);
listElement = addSubNamedVaribleNamesToList(listElement, variableName, variables[i]);
}
}
return listElement;
}
// return NULL if no more elements are left
static char*
getNextListElement_DomainSpecific(void* stateParameter)
{
GetNextListElementDomainSpecificState* state = (GetNextListElementDomainSpecificState*) stateParameter;
= NULL;
int i;
LinkedList element = nameList;
for (i = 0; i < state->variablesCount; i++) {
element = LinkedList_insertAfter(element, copyString(state->variables[i]->name));
#if (CONFIG_MMS_SUPPORT_FLATTED_NAME_SPACE == 1)
char* prefix = state->variables[i]->name;
element = TEMP_addSubNamedVaribleNamesToList(element, prefix, state->variables[i]);
#endif
}
return nameList;
}
#endif
#if (MMS_DATA_SET_SERVICE == 1)
static LinkedList
@ -325,9 +406,125 @@ createNameListResponse(
response->size = bufPos;
if (DEBUG_MMS_SERVER)
printf("getNameList: encoded %i bytes\n", response->size);
printf("MMS_SERVER: getNameList: encoded %i bytes\n", response->size);
}
#if 0
static void
NEW_createNameListResponse(
MmsServerConnection connection,
int invokeId,
LinkedList nameList,
ByteBuffer* response,
char* continueAfter)
{
#if 0
//TODO move continueAfter handling in variable name generation code!
LinkedList startElement = NULL;
if (continueAfter != NULL) {
LinkedList element = nameList;
while ((element = LinkedList_getNext(element)) != NULL) {
if (strcmp((char*) (element->data), continueAfter) == 0) {
startElement = element;
break;
}
}
if (startElement == NULL) {
mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED);
return;
}
}
/* determine number of identifiers to include in response */
if (startElement == NULL)
startElement = nameList;
#endif
int nameCount = 0;
int estimatedMmsPduLength = 27; /* estimated overhead size of PDU encoding */
int maxPduSize = connection->maxPduSize;
bool moreFollows = false;
LinkedList element = startElement;
uint32_t identifierListSize = 0;
while ((element = LinkedList_getNext(element)) != NULL) {
int elementLength;
elementLength = BerEncoder_determineEncodedStringSize((char*) element->data);
if ((estimatedMmsPduLength + elementLength) > maxPduSize) {
moreFollows = true;
break;
}
else {
estimatedMmsPduLength += elementLength;
identifierListSize += elementLength;
nameCount++;
}
}
uint32_t listOfIdentifierSize = 1 + BerEncoder_determineLengthSize(identifierListSize) + identifierListSize;
uint32_t getNameListSize = listOfIdentifierSize;
if (moreFollows == false)
getNameListSize += 3;
uint32_t confirmedServiceResponseSize = 1 + BerEncoder_determineLengthSize(getNameListSize) + getNameListSize;
uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize((uint32_t) invokeId) + 2;
uint32_t confirmedResponsePDUSize = confirmedServiceResponseSize + invokeIdSize;
/* encode response */
element = startElement;
uint8_t* buffer = response->buffer;
int bufPos = 0;
bufPos = BerEncoder_encodeTL(0xa1, confirmedResponsePDUSize, buffer, bufPos);
bufPos = BerEncoder_encodeTL(0x02, invokeIdSize - 2, buffer, bufPos);
bufPos = BerEncoder_encodeUInt32((uint32_t) invokeId, buffer, bufPos);
bufPos = BerEncoder_encodeTL(0xa1, getNameListSize, buffer, bufPos);
bufPos = BerEncoder_encodeTL(0xa0, identifierListSize, buffer, bufPos);
int i = 0;
while ((element = LinkedList_getNext(element)) != NULL) {
bufPos = BerEncoder_encodeStringWithTag(0x1a, (char*) element->data, buffer, bufPos);
i++;
if (i == nameCount)
break;
}
if (moreFollows == false)
bufPos = BerEncoder_encodeBoolean(0x81, moreFollows, buffer, bufPos);
response->size = bufPos;
if (DEBUG_MMS_SERVER)
printf("MMS_SERVER: getNameList: encoded %i bytes\n", response->size);
}
#endif
void
mmsServer_handleGetNameListRequest(
MmsServerConnection connection,
@ -352,7 +549,7 @@ mmsServer_handleGetNameListRequest(
bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos);
if (bufPos < 0) {
//writeMmsRejectPdu(&invokeId, REJECT_UNRECOGNIZED_SERVICE, response);
mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response);
return;
}
@ -410,7 +607,7 @@ mmsServer_handleGetNameListRequest(
continueAfterId[continueAfterLength] = 0;
if (DEBUG_MMS_SERVER)
printf("continue after: (%s)\n", continueAfterId);
printf("MMS_SERVER: getNameListRequest - continue after: (%s)\n", continueAfterId);
}
if (objectScope == OBJECT_SCOPE_DOMAIN) {
@ -421,13 +618,23 @@ mmsServer_handleGetNameListRequest(
if (objectClass == OBJECT_CLASS_NAMED_VARIABLE) {
if (DEBUG_MMS_SERVER)
printf("get namelist for (%s)\n", domainSpecificName);
printf("MMS_SERVER: get namelist for (%s)\n", domainSpecificName);
LinkedList nameList = getNameListDomainSpecific(connection, domainSpecificName);
if (nameList == NULL)
mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT);
else {
printf("\n-------------\n");
LinkedList_printStringList(nameList);
StringUtils_sortList(nameList);
printf("\n-------------\n");
LinkedList_printStringList(nameList);
printf("\n-------------\n");
createNameListResponse(connection, invokeId, nameList, response, continueAfterId);
LinkedList_destroy(nameList);
}
@ -439,6 +646,8 @@ mmsServer_handleGetNameListRequest(
if (nameList == NULL)
mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT);
else {
StringUtils_sortList(nameList);
createNameListResponse(connection, invokeId, nameList, response, continueAfter);
LinkedList_destroy(nameList);
}
@ -458,6 +667,8 @@ mmsServer_handleGetNameListRequest(
LinkedList nameList = getDomainNames(connection);
StringUtils_sortList(nameList);
createNameListResponse(connection, invokeId, nameList, response, continueAfter);
LinkedList_destroyStatic(nameList);
@ -477,6 +688,8 @@ mmsServer_handleGetNameListRequest(
else if (objectClass == OBJECT_CLASS_NAMED_VARIABLE_LIST) {
LinkedList nameList = getnamedVariableListsVMDSpecific(connection);
StringUtils_sortList(nameList);
createNameListResponse(connection, invokeId, nameList, response, continueAfter);
LinkedList_destroy(nameList);
@ -486,6 +699,8 @@ mmsServer_handleGetNameListRequest(
else if (objectClass == OBJECT_CLASS_JOURNAL) {
LinkedList nameList = LinkedList_create();
// StringUtils_sortList(nameList);
createNameListResponse(connection, invokeId, nameList, response, continueAfter);
LinkedList_destroy(nameList);
@ -505,6 +720,8 @@ mmsServer_handleGetNameListRequest(
if (objectClass == OBJECT_CLASS_NAMED_VARIABLE_LIST) {
LinkedList nameList = getNamedVariableListAssociationSpecific(connection);
StringUtils_sortList(nameList);
createNameListResponse(connection, invokeId, nameList, response, continueAfter);
LinkedList_destroy(nameList);
@ -516,7 +733,7 @@ mmsServer_handleGetNameListRequest(
#endif /* (MMS_DATA_SET_SERVICE == 1) */
else {
if (DEBUG_MMS_SERVER) printf("mms_server: getNameList(%i) not supported!\n", objectScope);
if (DEBUG_MMS_SERVER) printf("MMS_SERVER: getNameList(%i) not supported!\n", objectScope);
mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED);
}

View file

@ -62,6 +62,11 @@ mmsServer_writeMmsRejectPdu(uint32_t* invokeId, int reason, ByteBuffer* response
mmsPdu->choice.rejectPDU.rejectReason.choice.confirmedResponsePDU =
RejectPDU__rejectReason__confirmedRequestPDU_invalidArgument;
}
else if (reason == MMS_ERROR_REJECT_INVALID_PDU) {
mmsPdu->choice.rejectPDU.rejectReason.present = RejectPDU__rejectReason_PR_pduError;
mmsPdu->choice.rejectPDU.rejectReason.choice.confirmedResponsePDU =
RejectPDU__rejectReason__pduError_invalidPdu;
}
else {
mmsPdu->choice.rejectPDU.rejectReason.present = RejectPDU__rejectReason_PR_confirmedRequestPDU;
mmsPdu->choice.rejectPDU.rejectReason.choice.confirmedResponsePDU =