- fixed problem in MmsValue_printToBuffer

- extended ClientControlBlock
pull/6/head
Michael Zillgith 10 years ago
parent a4730069ff
commit c3dace4150

@ -57,6 +57,35 @@ int main(int argc, char** argv) {
free(msvID); free(msvID);
} }
char* datSetName = ClientSVControlBlock_getDatSet(svcb);
if (datSetName != NULL) {
printf("DatSet: %s\n", datSetName);
free(datSetName);
}
printf("ConfRev: %i\n", ClientSVControlBlock_getConfRev(svcb));
printf("SmpRate: %i\n", ClientSVControlBlock_getSmpRate(svcb));
printf("SmpMod: %i\n", ClientSVControlBlock_getSmpMod(svcb));
int optFlds = ClientSVControlBlock_getOptFlds(svcb);
printf("OptFlds: ");
if (optFlds & IEC61850_SV_OPT_REFRESH_TIME)
printf("refresh-time ");
if (optFlds & IEC61850_SV_OPT_SAMPLE_SYNC)
printf("sample-synch ");
if (optFlds & IEC61850_SV_OPT_SAMPLE_RATE)
printf("sample-rate ");
if (optFlds & IEC61850_SV_OPT_DATA_SET)
printf("date-set ");
if (optFlds & IEC61850_SV_OPT_SECURITY)
printf("security ");
printf("\n");
printf("noASDU: %i\n", ClientSVControlBlock_getNoASDU(svcb));
} }
else { else {
printf("SVCB %s does not exist on server!\n", svcbRef); printf("SVCB %s does not exist on server!\n", svcbRef);

@ -312,9 +312,31 @@ IedConnection_getMmsConnection(IedConnection self);
* @{ * @{
*/ */
/** SV ASDU contains attribute RefrTm */
#define IEC61850_SV_OPT_REFRESH_TIME 1
/** SV ASDU contains attribute SmpSynch */
#define IEC61850_SV_OPT_SAMPLE_SYNC 2
/** SV ASDU contains attribute SmpRate */
#define IEC61850_SV_OPT_SAMPLE_RATE 4
/** SV ASDU contains attribute DatSet */
#define IEC61850_SV_OPT_DATA_SET 8
/** SV ASDU contains attribute Security */
#define IEC61850_SV_OPT_SECURITY 16
/** an opaque handle to the instance data of a ClientSVControlBlock object */ /** an opaque handle to the instance data of a ClientSVControlBlock object */
typedef struct sClientSVControlBlock* ClientSVControlBlock; typedef struct sClientSVControlBlock* ClientSVControlBlock;
typedef struct {
uint8_t addr[6];
uint8_t priority;
uint16_t vid;
uint16_t appId;
} DstAddress;
/** /**
* \brief Create a new ClientSVControlBlock instance * \brief Create a new ClientSVControlBlock instance
* *
@ -340,15 +362,83 @@ ClientSVControlBlock_destroy(ClientSVControlBlock self);
bool bool
ClientSVControlBlock_isMulticast(ClientSVControlBlock self); ClientSVControlBlock_isMulticast(ClientSVControlBlock self);
/**
* \brief Return the error code of the last write or write acccess to the SVCB
*
* \param self the ClientSVControlBlock instance to operate on
*
* \return the error code of the last read or write access
*/
IedClientError
ClientSVControlBlock_getLastError(ClientSVControlBlock self);
bool bool
ClientSVControlBlock_setSvEna(ClientSVControlBlock self, bool svEna); ClientSVControlBlock_setSvEna(ClientSVControlBlock self, bool svEna);
bool bool
ClientSVControlBlock_getSvEna(ClientSVControlBlock self); ClientSVControlBlock_getSvEna(ClientSVControlBlock self);
bool
ClientSVControlBlock_setResv(ClientSVControlBlock self, bool svEna);
char* char*
ClientSVControlBlock_getMsvID(ClientSVControlBlock self); ClientSVControlBlock_getMsvID(ClientSVControlBlock self);
/**
* \brief Get the (MMS) reference to the data set
*
* NOTE: the returned string is dynamically allocated with the
* GLOBAL_MALLOC macro. The application is responsible to release
* the memory when the string is no longer needed.
*
* \param self the ClientSVControlBlock instance to operate on
*
* \return the data set reference as a NULL terminated string
*/
char*
ClientSVControlBlock_getDatSet(ClientSVControlBlock self);
uint32_t
ClientSVControlBlock_getConfRev(ClientSVControlBlock self);
uint16_t
ClientSVControlBlock_getSmpRate(ClientSVControlBlock self);
/**
* \brief returns the destination address of the SV publisher
*
* \param self the ClientSVControlBlock instance to operate on
*/
DstAddress
ClientSVControlBlock_getDstAddress(ClientSVControlBlock self);
/**
* \brief returns the OptFlds bit string as integer
*
* \param self the ClientSVControlBlock instance to operate on
*/
int
ClientSVControlBlock_getOptFlds(ClientSVControlBlock self);
/**
* \brief returns number of sample mode of the SV publisher
*
* \param self the ClientSVControlBlock instance to operate on
*/
uint8_t
ClientSVControlBlock_getSmpMod(ClientSVControlBlock self);
/**
* \brief returns number of ASDUs included in the SV message
*
* \param self the ClientSVControlBlock instance to operate on
*/
int
ClientSVControlBlock_getNoASDU(ClientSVControlBlock self);
/** @} */ /** @} */
/** /**

@ -358,7 +358,11 @@ createSVControlBlockMmsStructure(char* gcbName, bool isUnicast)
return gcb; return gcb;
} }
static void
createDataSetReference(char* buffer, char* domainName, char* lnName, char* dataSetName)
{
StringUtils_createStringInBuffer(buffer, 5, domainName, "/", lnName, "$", dataSetName);
}
MmsVariableSpecification* MmsVariableSpecification*
LIBIEC61850_SV_createSVControlBlocks(MmsMapping* self, MmsDomain* domain, LIBIEC61850_SV_createSVControlBlocks(MmsMapping* self, MmsDomain* domain,
@ -380,6 +384,8 @@ LIBIEC61850_SV_createSVControlBlocks(MmsMapping* self, MmsDomain* domain,
int currentSVCB = 0; int currentSVCB = 0;
char dataRefBuffer[130];
while (currentSVCB < svCount) { while (currentSVCB < svCount) {
SVControlBlock* svControlBlock = getSVCBForLogicalNodeWithIndex( SVControlBlock* svControlBlock = getSVCBForLogicalNodeWithIndex(
self, logicalNode, currentSVCB, unicast); self, logicalNode, currentSVCB, unicast);
@ -409,7 +415,11 @@ LIBIEC61850_SV_createSVControlBlocks(MmsMapping* self, MmsDomain* domain,
/* DatSet */ /* DatSet */
MmsValue* dataSetRef = MmsValue_getElement(svValues, currentIndex++); MmsValue* dataSetRef = MmsValue_getElement(svValues, currentIndex++);
MmsValue_setVisibleString(dataSetRef, svControlBlock->dataSetName);
createDataSetReference(dataRefBuffer, MmsDomain_getName(domain),
logicalNode->name, svControlBlock->dataSetName);
MmsValue_setVisibleString(dataSetRef, dataRefBuffer);
/* ConfRev */ /* ConfRev */
MmsValue* confRev = MmsValue_getElement(svValues, currentIndex++); MmsValue* confRev = MmsValue_getElement(svValues, currentIndex++);

@ -935,6 +935,18 @@ MmsValue_getSubElement(MmsValue* self, MmsVariableSpecification* varSpec, char*
char* char*
MmsValue_getTypeString(MmsValue* self); MmsValue_getTypeString(MmsValue* self);
/**
* \brief create a string representation of the MmsValue object in the provided buffer
*
* NOTE: This function is for debugging purposes only. It may not be aimed to be used
* in embedded systems. It requires a full featured snprintf function.
*
* \param self the MmsValue instance
* \param buffer the buffer where to copy the string representation
* \param bufferSize the size of the provided buffer
*
* \return a pointer to the start of the buffer
*/
char* char*
MmsValue_printToBuffer(MmsValue* self, char* buffer, int bufferSize); MmsValue_printToBuffer(MmsValue* self, char* buffer, int bufferSize);

@ -1,7 +1,7 @@
/* /*
* MmsValue.c * MmsValue.c
* *
* Copyright 2013 Michael Zillgith * Copyright 2013-2015 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -1968,6 +1968,22 @@ MmsValue_getTypeString(MmsValue* self)
} }
} }
static void
msTimeToGeneralizedTime(uint64_t msTime, uint8_t* buffer, size_t bufferSize)
{
time_t unixTime = (msTime / 1000);
struct tm tmTime;
int msPart = (msTime % 1000);
gmtime_r(&unixTime, &tmTime);
snprintf((char*) buffer, bufferSize, "%04d%02d%02d%02d%02d%02d.%03dZ", tmTime.tm_year + 1900, tmTime.tm_mon + 1,
tmTime.tm_mday, tmTime.tm_hour, tmTime.tm_min, tmTime.tm_sec, msPart);
}
char* char*
MmsValue_printToBuffer(MmsValue* self, char* buffer, int bufferSize) MmsValue_printToBuffer(MmsValue* self, char* buffer, int bufferSize)
{ {
@ -1995,19 +2011,32 @@ MmsValue_printToBuffer(MmsValue* self, char* buffer, int bufferSize)
} }
} }
buffer[bufPos++] = '}'; if (bufPos < (bufferSize - 1)) {
buffer[bufPos] = 0; buffer[bufPos++] = '}';
buffer[bufPos] = 0;
}
else
buffer[bufferSize - 1] = 0;
} }
break; break;
case MMS_BINARY_TIME: case MMS_BINARY_TIME:
Conversions_msTimeToGeneralizedTime(MmsValue_getBinaryTimeAsUtcMs(self), (uint8_t*) buffer); msTimeToGeneralizedTime(MmsValue_getBinaryTimeAsUtcMs(self), (uint8_t*) buffer, bufferSize);
break; break;
case MMS_BIT_STRING: case MMS_BIT_STRING:
{ {
int bufPos = 0; int bufPos = 0;
int size = MmsValue_getBitStringSize(self); int size = MmsValue_getBitStringSize(self);
/* Behave like strncpy and fill buffer with zeros */
if (size > bufferSize) {
memset(buffer, 0, bufferSize);
break;
}
int i; int i;
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
if (MmsValue_getBitStringBit(self, i)) if (MmsValue_getBitStringBit(self, i))
@ -2018,24 +2047,40 @@ MmsValue_printToBuffer(MmsValue* self, char* buffer, int bufferSize)
buffer[bufPos] = 0; buffer[bufPos] = 0;
} }
break; break;
case MMS_BOOLEAN: case MMS_BOOLEAN:
if (MmsValue_getBoolean(self)) if (MmsValue_getBoolean(self))
strncpy(buffer, "true", bufferSize); strncpy(buffer, "true", bufferSize);
else else
strncpy(buffer, "false", bufferSize); strncpy(buffer, "false", bufferSize);
/* Ensure buffer is always 0 terminated */
if (bufferSize > 0)
buffer[bufferSize - 1] = 0;
break; break;
case MMS_DATA_ACCESS_ERROR: case MMS_DATA_ACCESS_ERROR:
snprintf(buffer, bufferSize, "error %i", self->value.dataAccessError); snprintf(buffer, bufferSize, "error %i", self->value.dataAccessError);
break; break;
case MMS_FLOAT: case MMS_FLOAT:
snprintf(buffer, bufferSize, "%f", MmsValue_toFloat(self)); snprintf(buffer, bufferSize, "%f", MmsValue_toFloat(self));
break; break;
case MMS_GENERALIZED_TIME:
case MMS_GENERALIZED_TIME: /* type not supported */
strncpy(buffer, "generalized time", bufferSize); strncpy(buffer, "generalized time", bufferSize);
/* Ensure buffer is always 0 terminated */
if (bufferSize > 0)
buffer[bufferSize - 1] = 0;
break; break;
case MMS_INTEGER: case MMS_INTEGER:
snprintf(buffer, bufferSize, "%i", MmsValue_toInt32(self)); snprintf(buffer, bufferSize, "%i", MmsValue_toInt32(self));
break; break;
case MMS_OCTET_STRING: case MMS_OCTET_STRING:
{ {
int size = MmsValue_getOctetStringSize(self); int size = MmsValue_getOctetStringSize(self);
@ -2049,20 +2094,33 @@ MmsValue_printToBuffer(MmsValue* self, char* buffer, int bufferSize)
break; break;
} }
} }
break; break;
case MMS_UNSIGNED: case MMS_UNSIGNED:
snprintf(buffer, bufferSize, "%u", MmsValue_toUint32(self)); snprintf(buffer, bufferSize, "%u", MmsValue_toUint32(self));
break; break;
case MMS_UTC_TIME: case MMS_UTC_TIME:
Conversions_msTimeToGeneralizedTime(MmsValue_getUtcTimeInMs(self), (uint8_t*) buffer); msTimeToGeneralizedTime(MmsValue_getUtcTimeInMs(self), (uint8_t*) buffer, bufferSize);
break; break;
case MMS_STRING: case MMS_STRING:
case MMS_VISIBLE_STRING: case MMS_VISIBLE_STRING:
strncpy(buffer, MmsValue_toString(self), bufferSize); strncpy(buffer, MmsValue_toString(self), bufferSize);
/* Ensure buffer is always 0 terminated */
if (bufferSize > 0)
buffer[bufferSize - 1] = 0;
break; break;
default: default:
strncpy(buffer, "unknown type", bufferSize); strncpy(buffer, "unknown type", bufferSize);
/* Ensure buffer is always 0 terminated */
if (bufferSize > 0)
buffer[bufferSize - 1] = 0;
break; break;
} }

Loading…
Cancel
Save