libiec61850 icon indicating copy to clipboard operation
libiec61850 copied to clipboard

MmsValue_getUtcTimeInMs

Open alikovvl opened this issue 5 years ago • 5 comments

Incorrect parsing

  for (var remainder = 0; remainder < 1000; remainder += 1) {
    var fractionOfSecond = ((remainder) * 16777 + ((remainder * 216) / 1000)) & 0xffc000; // 10 significant bits
    var decoded = fractionOfSecond / 16777;
    Debug.WriteLine("remainder={0} encoded={1} decoded={2}", remainder, fractionOfSecond, decoded);
  }

alikovvl avatar Jun 14 '19 12:06 alikovvl

Correct parsing

  for (var remainder = 0; remainder < 1000; remainder += 1) {
    var fractionOfSecond = ((remainder) * 16777 + ((remainder * 216) / 1000)) & 0xffc000; // 10 significant bits
    var decoded = (int)(fractionOfSecond / 16777F + 0.5F);
    Debug.WriteLine("remainder={0} encoded={1} decoded={2}", remainder, fractionOfSecond, decoded);
  }

alikovvl avatar Jun 14 '19 12:06 alikovvl

uint64_t
MmsValue_getUtcTimeInMs(const MmsValue* self)
{
    uint32_t timeval32;
    const uint8_t* valueArray = self->value.utcTime;

#if (ORDER_LITTLE_ENDIAN == 1)
    memcpyReverseByteOrder((uint8_t*) &timeval32, valueArray, 4);
#else
    memcpy((uint8_t*) &timeval32, valueArray, 4);
#endif

    uint32_t fractionOfSecond = 0;

    fractionOfSecond = (valueArray[4] << 16);
    fractionOfSecond += (valueArray[5] << 8);
    fractionOfSecond += (valueArray[6]);

    uint32_t remainder = fractionOfSecond / 16777.0 + 0.5;

    uint64_t msVal = (timeval32 * 1000LL) + remainder;

    return msVal;
}

alikovvl avatar Jun 14 '19 13:06 alikovvl

MmsValue*
MmsValue_setUtcTimeMs(MmsValue* self, uint64_t timeval)
{
    uint32_t timeval32 = (timeval / 1000LL);

    uint8_t* timeArray = (uint8_t*) &timeval32;
    uint8_t* valueArray = self->value.utcTime;

#if (ORDER_LITTLE_ENDIAN == 1)
    memcpyReverseByteOrder(valueArray, timeArray, 4);
#else
    memcpy(valueArray, timeArray, 4);
#endif

    uint32_t remainder = (timeval % 1000LL);
    uint32_t fractionOfSecond = ((remainder) * 16777 + ((remainder * 216) / 1000)) & 0xffc000; // 10 significant bits;

    /* encode fraction of second */
    valueArray[4] = ((fractionOfSecond >> 16) & 0xff);
    valueArray[5] = ((fractionOfSecond >> 8) & 0xff);
    valueArray[6] = (fractionOfSecond & 0xff);

    /* encode time quality */
    valueArray[7] = 0x0a; /* 10 bit sub-second time accuracy */

    return self;
}

alikovvl avatar Jun 14 '19 13:06 alikovvl

Care to create a pull request or close if already fixed? I fail to see your exact edits as there's no formatted diff. An why do you think it's appropriate to use floats in uint32_t arithmetic?

ALTracer avatar Jun 22 '20 11:06 ALTracer

It's possible to calculate without floats: uint32_t remainder = (fractionOfSecond + 16777 / 2) / 16777;

But encoding also needs rounding before drop insignificant bits: fractionOfSecond = ((remainder) * 16777 + ((remainder * 216) / 1000) + 0x2000) & 0xffc000;

paluke avatar Jan 26 '22 06:01 paluke