- IED Server: added function to set time quality for internally updated times (LIB61850-372)

pull/417/head
Michael Zillgith 3 years ago
parent 23d71f322d
commit b6cd6b61e0

@ -2243,6 +2243,9 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServer_setRCBEventHandler(IntPtr self, InternalRCBEventHandler handler, IntPtr parameter);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedServer_setTimeQuality(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool leapSecondKnown, [MarshalAs(UnmanagedType.I1)] bool clockFailure, [MarshalAs(UnmanagedType.I1)] bool clockNotSynchronized, int subsecondPrecision);
private IntPtr self = IntPtr.Zero;
private InternalControlHandler internalControlHandlerRef = null;
@ -2966,6 +2969,18 @@ namespace IEC61850
}
}
/// <summary>
/// Set the time quality for all timestamps internally generated by this IedServer instance
/// </summary>
/// <param name="leapSecondKnown">set/unset leap seconds known flag</param>
/// <param name="clockFailure">set/unset clock failure flag</param>
/// <param name="clockNotSynchronized">set/unset clock not synchronized flag</param>
/// <param name="subsecondPrecision">set the subsecond precision (number of significant bits of the fractionOfSecond part of the time stamp)</param>
public void SetTimeQuality(bool leapSecondKnown, bool clockFailure, bool clockNotSynchronized, int subsecondPrecision)
{
IedServer_setTimeQuality(self, leapSecondKnown, clockFailure, clockNotSynchronized, subsecondPrecision);
}
}
}

@ -97,7 +97,10 @@ readAccessHandler(LogicalDevice* ld, LogicalNode* ln, DataObject* dataObject, Fu
{
void* securityToken = ClientConnection_getSecurityToken(connection);
printf("Read access to %s/%s.%s\n", ld->name, ln->name, dataObject->name);
if (dataObject)
printf("Read access to %s/%s.%s[%s]\n", ld->name, ln->name, dataObject->name, FunctionalConstraint_toString(fc));
else
printf("Read access to %s/%s[%s]\n", ld->name, ln->name, FunctionalConstraint_toString(fc));
return DATA_ACCESS_ERROR_SUCCESS;
}
@ -112,6 +115,8 @@ main(int argc, char** argv)
iedServer = IedServer_createWithConfig(&iedModel, NULL, config);
IedServer_setTimeQuality(iedServer, true, false, false, 10);
IedServerConfig_destroy(config);
LogicalDevice* ld = IEDMODEL_PROT;

@ -687,6 +687,21 @@ IedServer_setGooseInterfaceIdEx(IedServer self, LogicalNode* ln, const char* gcb
LIB61850_API void
IedServer_useGooseVlanTag(IedServer self, LogicalNode* ln, const char* gcbName, bool useVlanTag);
/**
* \brief Set the time quality for all timestamps internally generated by this IedServer instance
*
* You can call this function during the initialization of the server or whenever a time quality
* flag has to be updated (on clock failure or change of time synchronization state).
*
* \param self the instance of IedServer to operate on.
* \param leapSecondKnown set/unset leap seconds known flag
* \param clockFailure set/unset clock failure flag
* \param clockNotSynchronized set/unset clock not synchronized flag
* \param subsecondPrecision set the subsecond precision (number of significant bits of the fractionOfSecond part of the time stamp)
*/
LIB61850_API void
IedServer_setTimeQuality(IedServer self, bool leapSecondKnown, bool clockFailure, bool clockNotSynchronized, int subsecondPrecision);
/**@}*/
/**
@ -710,8 +725,6 @@ IedServer_useGooseVlanTag(IedServer self, LogicalNode* ln, const char* gcbName,
LIB61850_API void
IedServer_setAuthenticator(IedServer self, AcseAuthenticator authenticator, void* authenticatorParameter);
/**
* \brief get the peer address of this connection as string
*

@ -78,6 +78,8 @@ struct sIedServer
uint8_t edition;
uint8_t timeQuality; /* user settable time quality for internally updated times */
bool running;
};

@ -562,6 +562,7 @@ IedServer_createWithConfig(IedModel* dataModel, TLSConfiguration tlsConfiguratio
}
#endif
IedServer_setTimeQuality(self, true, false, false, 10);
}
else {
IedServer_destroy(self);
@ -1382,7 +1383,7 @@ IedServer_updateUTCTimeAttributeValue(IedServer self, DataAttribute* dataAttribu
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_wait(self->dataModelLock);
#endif
MmsValue_setUtcTimeMs(dataAttribute->mmsValue, value);
MmsValue_setUtcTimeMsEx(dataAttribute->mmsValue, value, self->timeQuality);
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_post(self->dataModelLock);
#endif
@ -1785,7 +1786,6 @@ private_IedServer_removeClientConnection(IedServer self, ClientConnection client
#endif
}
void
IedServer_setGooseInterfaceId(IedServer self, const char* interfaceId)
{
@ -1793,3 +1793,22 @@ IedServer_setGooseInterfaceId(IedServer self, const char* interfaceId)
self->mmsMapping->gooseInterfaceId = StringUtils_copyString(interfaceId);
#endif
}
void
IedServer_setTimeQuality(IedServer self, bool leapSecondKnown, bool clockFailure, bool clockNotSynchronized, int subsecondPrecision)
{
uint8_t timeQuality = 0;
if (clockNotSynchronized)
timeQuality += 0x20;
if (clockFailure)
timeQuality += 0x40;
if (leapSecondKnown)
timeQuality += 0x80;
timeQuality += (subsecondPrecision & 0x1f);
self->timeQuality = timeQuality;
}

@ -258,7 +258,7 @@ copyControlValuesToTrackingObject(MmsMapping* self, ControlObject* controlObject
MmsValue_update(trkInst->ctlNum->mmsValue, controlObject->ctlNum);
if (trkInst->operTm)
MmsValue_setUtcTimeMs(trkInst->operTm->mmsValue, controlObject->operateTime);
MmsValue_setUtcTimeMsEx(trkInst->operTm->mmsValue, controlObject->operateTime, self->iedServer->timeQuality);
if (trkInst->respAddCause)
MmsValue_update(trkInst->respAddCause->mmsValue, controlObject->addCause);
@ -394,7 +394,7 @@ updateGenericTrackingObjectValues(MmsMapping* self, ControlObject* controlObject
MmsValue_setInt32(trkInst->serviceType->mmsValue, (int) serviceType);
if (trkInst->t)
MmsValue_setUtcTimeMs(trkInst->t->mmsValue, Hal_getTimeInMs());
MmsValue_setUtcTimeMsEx(trkInst->t->mmsValue, Hal_getTimeInMs(), self->iedServer->timeQuality);
if (trkInst->errorCode)
MmsValue_setInt32(trkInst->errorCode->mmsValue, errVal);
@ -590,9 +590,7 @@ setOpOk(ControlObject* self, bool value, uint64_t currentTimeInMs)
if (self->tOpOk) {
MmsValue* timestamp = self->tOpOk->mmsValue;
MmsValue_setUtcTimeMs(timestamp, currentTimeInMs);
/* TODO update time quality */
MmsValue_setUtcTimeMsEx(timestamp, currentTimeInMs, self->iedServer->timeQuality);
}
self->pendingEvents |= PENDING_EVENT_OP_OK_TRUE;
@ -862,6 +860,7 @@ executeStateMachine:
MmsValue* operTm = getOperParameterOperTime(controlObject->oper);
MmsValue_setUtcTime(operTm, 0);
MmsValue_setUtcTimeQuality(operTm, self->iedServer->timeQuality);
}
else {
MmsServerConnection_sendWriteResponse(controlObject->mmsConnection, controlObject->operateInvokeId,

@ -418,7 +418,7 @@ updateGenericTrackingObjectValues(MmsMapping* self, LogControl* logControl, IEC6
MmsValue_setInt32(trkInst->serviceType->mmsValue, (int) serviceType);
if (trkInst->t)
MmsValue_setUtcTimeMs(trkInst->t->mmsValue, Hal_getTimeInMs());
MmsValue_setUtcTimeMsEx(trkInst->t->mmsValue, Hal_getTimeInMs(), self->iedServer->timeQuality);
if (trkInst->errorCode)
MmsValue_setInt32(trkInst->errorCode->mmsValue,

@ -1,7 +1,7 @@
/*
* mms_goose.c
*
* Copyright 2013-2021 Michael Zillgith
* Copyright 2013-2022 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -231,7 +231,7 @@ updateGenericTrackingObjectValues(MmsGooseControlBlock gc, IEC61850_ServiceType
MmsValue_setInt32(trkInst->serviceType->mmsValue, (int) serviceType);
if (trkInst->t)
MmsValue_setUtcTimeMs(trkInst->t->mmsValue, Hal_getTimeInMs());
MmsValue_setUtcTimeMsEx(trkInst->t->mmsValue, Hal_getTimeInMs(), gc->mmsMapping->iedServer->timeQuality);
if (trkInst->errorCode)
MmsValue_setInt32(trkInst->errorCode->mmsValue,

@ -671,7 +671,7 @@ updateGenericTrackingObjectValues(MmsMapping* self, SettingGroupControlBlock* sg
MmsValue_setInt32(trkInst->serviceType->mmsValue, (int) serviceType);
if (trkInst->t)
MmsValue_setUtcTimeMs(trkInst->t->mmsValue, Hal_getTimeInMs());
MmsValue_setUtcTimeMsEx(trkInst->t->mmsValue, Hal_getTimeInMs(), self->iedServer->timeQuality);
if (trkInst->errorCode)
MmsValue_setInt32(trkInst->errorCode->mmsValue,
@ -818,7 +818,7 @@ MmsMapping_changeActiveSettingGroup(MmsMapping* self, SettingGroupControlBlock*
MmsValue* lActTm = MmsValue_getElement(sg->sgcbMmsValues, 4);
MmsValue_setUint8(actSg, sgcb->actSG);
MmsValue_setUtcTimeMs(lActTm, Hal_getTimeInMs());
MmsValue_setUtcTimeMsEx(lActTm, Hal_getTimeInMs(), self->iedServer->timeQuality);
#if (CONFIG_IEC61850_SERVICE_TRACKING == 1)
copySGCBValuesToTrackingObject(self, sgcb);
@ -2669,7 +2669,7 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
MmsValue* lActTm = MmsValue_getElement(sg->sgcbMmsValues, 4);
MmsValue_setUint8(actSg, sg->sgcb->actSG);
MmsValue_setUtcTimeMs(lActTm, Hal_getTimeInMs());
MmsValue_setUtcTimeMsEx(lActTm, Hal_getTimeInMs(), self->iedServer->timeQuality);
}
else
retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;

@ -579,7 +579,7 @@ updateGenericTrackingObjectValues(MmsMapping* self, ReportControl* rc, IEC61850_
MmsValue_setInt32(trkInst->serviceType->mmsValue, (int) serviceType);
if (trkInst->t)
MmsValue_setUtcTimeMs(trkInst->t->mmsValue, Hal_getTimeInMs());
MmsValue_setUtcTimeMsEx(trkInst->t->mmsValue, Hal_getTimeInMs(), self->iedServer->timeQuality);
if (trkInst->errorCode)
MmsValue_setInt32(trkInst->errorCode->mmsValue,

@ -498,12 +498,30 @@ MmsValue_getUtcTimeInMsWithUs(const MmsValue* self, uint32_t* usec);
* bit 0-4 = subsecond time accuracy (number of significant bits of subsecond time)
*
* \param self MmsValue instance to operate on. Has to be of a type MMS_UTCTIME.
*
* \param timeQuality the byte representing the time quality
*/
LIB61850_API void
MmsValue_setUtcTimeQuality(MmsValue* self, uint8_t timeQuality);
/**
* \brief Update an MmsValue object of type MMS_UTCTIME with a millisecond time.
*
* Meaning of the bits in the timeQuality byte:
*
* bit 7 = leapSecondsKnown
* bit 6 = clockFailure
* bit 5 = clockNotSynchronized
* bit 0-4 = subsecond time accuracy (number of significant bits of subsecond time)
*
* \param self MmsValue instance to operate on. Has to be of a type MMS_UTCTIME.
* \param timeval the new value in milliseconds since epoch (1970/01/01 00:00 UTC)
* \param timeQuality the byte representing the time quality
*
* \return the updated MmsValue instance
*/
LIB61850_API MmsValue*
MmsValue_setUtcTimeMsEx(MmsValue* self, uint64_t timeval, uint8_t timeQuality);
/**
* \brief get the TimeQuality byte of the UtcTime
*

@ -763,8 +763,8 @@ MmsValue_setUtcTime(MmsValue* self, uint32_t timeval)
return self;
}
MmsValue*
MmsValue_setUtcTimeMs(MmsValue* self, uint64_t timeval)
static void
setUtcTimeMs(MmsValue* self, uint64_t timeval, uint8_t timeQuality)
{
uint32_t timeval32 = (timeval / 1000LL);
@ -786,7 +786,21 @@ MmsValue_setUtcTimeMs(MmsValue* self, uint64_t timeval)
valueArray[6] = (fractionOfSecond & 0xff);
/* encode time quality */
valueArray[7] = 0x0a; /* 10 bit sub-second time accuracy */
valueArray[7] = timeQuality;
}
MmsValue*
MmsValue_setUtcTimeMs(MmsValue* self, uint64_t timeval)
{
setUtcTimeMs(self, timeval, 0x0a); /* set quality as 10 bit sub-second time accuracy */
return self;
}
MmsValue*
MmsValue_setUtcTimeMsEx(MmsValue* self, uint64_t timeval, uint8_t timeQuality)
{
setUtcTimeMs(self, timeval, timeQuality);
return self;
}

Loading…
Cancel
Save