diff --git a/examples/iec61850_9_2_LE_example/iec61850_9_2_LE_example.c b/examples/iec61850_9_2_LE_example/iec61850_9_2_LE_example.c index d63554d8..259736f6 100644 --- a/examples/iec61850_9_2_LE_example/iec61850_9_2_LE_example.c +++ b/examples/iec61850_9_2_LE_example/iec61850_9_2_LE_example.c @@ -92,6 +92,7 @@ setupSVPublisher(const char* svInterface) vol4q = SVPublisher_ASDU_addQuality(asdu); SVPublisher_ASDU_setSmpCntWrap(asdu, 4000); + SVPublisher_ASDU_setRefrTm(asdu, 0); SVPublisher_setupComplete(svPublisher); } @@ -220,6 +221,8 @@ main(int argc, char** argv) SVPublisher_ASDU_setINT32(asdu, vol4, voltageN); SVPublisher_ASDU_setQuality(asdu, vol4q, q); + SVPublisher_ASDU_setRefrTm(asdu, Hal_getTimeInMs()); + SVPublisher_ASDU_setSmpCnt(asdu, (uint16_t) sampleCount); SVPublisher_publish(svPublisher); diff --git a/src/sampled_values/sv_publisher.c b/src/sampled_values/sv_publisher.c index b703ad46..75e48c72 100644 --- a/src/sampled_values/sv_publisher.c +++ b/src/sampled_values/sv_publisher.c @@ -63,6 +63,8 @@ struct sSVPublisher_ASDU { uint16_t smpRate; uint8_t* smpCntBuf; + uint8_t* refrTmBuf; + uint8_t* smpSynchBuf; SVPublisher_ASDU _next; }; @@ -386,11 +388,13 @@ SVPublisher_ASDU_encodeToBuffer(SVPublisher_ASDU self, uint8_t* buffer, int bufP /* RefrTm */ if (self->hasRefrTm) { bufPos = BerEncoder_encodeTL(0x84, 8, buffer, bufPos); + self->refrTmBuf = buffer + bufPos; bufPos = encodeUtcTime(self->refrTm, buffer, bufPos); } /* SmpSynch */ bufPos = BerEncoder_encodeTL(0x85, 1, buffer, bufPos); + self->smpSynchBuf = buffer + bufPos; buffer[bufPos++] = self->smpSynch; /* SmpRate */ @@ -651,7 +655,8 @@ SVPublisher_ASDU_setSmpCnt(SVPublisher_ASDU self, uint16_t value) { self->smpCnt = value; - encodeUInt16FixedSize(self->smpCnt, self->smpCntBuf, 0); + if (self->smpCntBuf != NULL) + encodeUInt16FixedSize(self->smpCnt, self->smpCntBuf, 0); } void @@ -665,7 +670,14 @@ SVPublisher_ASDU_increaseSmpCnt(SVPublisher_ASDU self) { self->smpCnt = ((self->smpCnt + 1) % self->smpCntLimit); - encodeUInt16FixedSize(self->smpCnt, self->smpCntBuf, 0); + if (self->smpCntBuf != NULL) + encodeUInt16FixedSize(self->smpCnt, self->smpCntBuf, 0); +} + +void +SVPublisher_ASDU_enableRefrTm(SVPublisher_ASDU self) +{ + self->hasRefrTm = true; } void @@ -673,6 +685,9 @@ SVPublisher_ASDU_setRefrTm(SVPublisher_ASDU self, uint64_t refrTm) { self->hasRefrTm = true; self->refrTm = refrTm; + + if (self->refrTmBuf != NULL) + encodeUtcTime(self->refrTm, self->refrTmBuf, 0); } void @@ -689,6 +704,12 @@ SVPublisher_ASDU_setSmpRate(SVPublisher_ASDU self, uint16_t smpRate) self->smpRate = smpRate; } +void +SVPublisher_ASDU_setSmpSynch(SVPublisher_ASDU self, uint16_t smpSynch) +{ + self->smpSynch = smpSynch; + *(self->smpSynchBuf) = self->smpSynch; +} /******************************************************************* * Wrapper functions to support old API (remove in future versions) diff --git a/src/sampled_values/sv_publisher.h b/src/sampled_values/sv_publisher.h index 1ea27c1e..5c7fcebc 100644 --- a/src/sampled_values/sv_publisher.h +++ b/src/sampled_values/sv_publisher.h @@ -304,6 +304,16 @@ SVPublisher_ASDU_increaseSmpCnt(SVPublisher_ASDU self); LIB61850_API void SVPublisher_ASDU_setSmpCntWrap(SVPublisher_ASDU self, uint16_t value); +/** + * \brief Enables the transmission of refresh time attribute of the ASDU + * + * The refresh time is the time when the data in put into the sampled values buffer + * + * \param[in] self the Sampled Values ASDU instance. + */ +void +SVPublisher_ASDU_enableRefrTm(SVPublisher_ASDU self); + /** * \brief Set the refresh time attribute of the ASDU. * @@ -318,8 +328,10 @@ SVPublisher_ASDU_setRefrTm(SVPublisher_ASDU self, uint64_t refrTm); * The attribute SmpMod shall specify if the sample rate is defined in units of samples per nominal period, samples per second or seconds per sample. * If it is missing, the default value is samples per period. * + * NOTE: Function has to be called before calling \ref SVPublisher_setupComplete + * * \param[in] self the Sampled Values ASDU instance. - * \param smpMod one of IEC61850_SV_SMPMOD_PER_NOMINAL_PERIOD, IEC61850_SV_SMPMOD_SAMPLES_PER_SECOND or IEC61850_SV_SMPMOD_SECONDS_PER_SAMPLE + * \param[in] smpMod one of IEC61850_SV_SMPMOD_PER_NOMINAL_PERIOD, IEC61850_SV_SMPMOD_SAMPLES_PER_SECOND or IEC61850_SV_SMPMOD_SECONDS_PER_SAMPLE */ LIB61850_API void SVPublisher_ASDU_setSmpMod(SVPublisher_ASDU self, uint8_t smpMod); @@ -330,12 +342,31 @@ SVPublisher_ASDU_setSmpMod(SVPublisher_ASDU self, uint8_t smpMod); * The attribute SmpRate shall specify the sample rate. * The value shall be interpreted depending on the value of the SmpMod attribute. * + * NOTE: Function has to be called before calling \ref SVPublisher_setupComplete + * * \param[in] self the Sampled Values ASDU instance. - * \param smpRate Amount of samples (default per nominal period, see SmpMod). + * \param[in] smpRate Amount of samples (default per nominal period, see SmpMod). */ LIB61850_API void SVPublisher_ASDU_setSmpRate(SVPublisher_ASDU self, uint16_t smpRate); +/** + * \brief Set the clock synchronization information + * + * Default value is not synchronized (0). + * Possible values are: + * 0 = SV are not synchronized by an external clock signal. + * 1 = SV are synchronized by a clock signal from an unspecified local area clock. + * 2 = SV are synchronized by a global area clock signal (time traceable). + * 5 to 254 = SV are synchronized by a clock signal from a local area clock identified by this value. + * 3;4;255 = Reserved values – Do not use. + * + * \param[in] self the Sampled Values ASDU instance. + * \param[in] smpSynch the clock synchronization state + */ +void +SVPublisher_ASDU_setSmpSynch(SVPublisher_ASDU self, uint16_t smpSynch); + /**@} @}*/ #ifndef DEPRECATED