You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libiec61850/src/common/conversions.c

280 lines
5.8 KiB
C

/*
* conversions.c
*
* Copyright 2013 Michael Zillgith
*
* This file is part of libIEC61850.
*
* libIEC61850 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* libIEC61850 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with libIEC61850. If not, see <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/
#include "conversions.h"
#include <time.h>
#if defined TARGET
#if (TARGET == UCLINUX-WAGO)
time_t timegm (struct tm *tm)
{
time_t ret;
char *tz;
tz = getenv ("TZ");
setenv ("TZ", "", 1);
tzset ();
ret = mktime (tm);
if (tz)
setenv ("TZ", tz, 1);
else
unsetenv ("TZ");
tzset ();
return ret;
}
#endif
#endif
#ifdef _WIN32
time_t
timegm(struct tm* tm_time)
{
return mktime(tm_time) - _timezone;
}
#if defined(__MINGW32__)
static inline // assuming gmtime is thread safe in windows!
struct tm* gmtime_r(const time_t* timep, struct tm* result)
{
struct tm* t;
t = gmtime(timep);
if (t != NULL)
memcpy(result, t, sizeof (struct tm));
return result;
}
#else
#if defined(_MSC_VER)
static inline
struct tm* gmtime_r(const time_t* timep, struct tm* result)
{
gmtime_s(result, timep);
return result;
}
#else
#error "No gmtime_r available for platform!"
#endif
#endif
#endif
void
Conversions_intToStringBuffer(int intValue, int numberOfDigits, uint8_t* buffer)
{
int digitBase = 1;
int i = 1;
while (i < numberOfDigits) {
digitBase = digitBase * 10;
i++;
}
int remainder = intValue;
for (i = 0; i < numberOfDigits; i++) {
int digit = remainder / digitBase;
buffer[i] = (uint8_t) (digit + 48);
remainder = remainder % digitBase;
digitBase = digitBase / 10;
}
buffer[i] = 0;
}
void
Conversions_msTimeToGeneralizedTime(uint64_t msTime, uint8_t* buffer)
{
int msPart = (msTime % 1000);
time_t unixTime = (msTime / 1000);
struct tm tmTime;
gmtime_r(&unixTime, &tmTime);
Conversions_intToStringBuffer(tmTime.tm_year + 1900, 4, buffer);
Conversions_intToStringBuffer(tmTime.tm_mon + 1, 2, buffer + 4);
Conversions_intToStringBuffer(tmTime.tm_mday, 2, buffer + 6);
Conversions_intToStringBuffer(tmTime.tm_hour, 2, buffer + 8);
Conversions_intToStringBuffer(tmTime.tm_min, 2, buffer + 10);
Conversions_intToStringBuffer(tmTime.tm_sec, 2, buffer + 12);
buffer[14] = '.';
Conversions_intToStringBuffer(msPart, 3, buffer + 15);
buffer[18] = 'Z';
buffer[19] = 0;
}
static int
getSecondsOffset(const char* offsetString)
{
int hourOffset = StringUtils_digitsToInt(offsetString, 2);
if (hourOffset < 0)
return -1;
int minOffset = StringUtils_digitsToInt(offsetString + 2, 2);
if (minOffset < 0)
return -1;
int secondsOffset = (hourOffset * (60 * 60)) + (minOffset * 60);
return secondsOffset;
}
uint64_t
Conversions_generalizedTimeToMsTime(const char* gtString)
{
int gtStringLen = strlen(gtString);
if (gtStringLen < 14) return -1;
int year = StringUtils_digitsToInt(gtString, 4);
if (year < 0) return -1;
int month = StringUtils_digitsToInt(gtString + 4, 2);
if (month < 0) return -1;
int day = StringUtils_digitsToInt(gtString + 6, 2);
if (day < 0) return -1;
int hour = StringUtils_digitsToInt(gtString + 8, 2);
if (hour < 0) return -1;
int min = StringUtils_digitsToInt(gtString + 10, 2);
if (min < 0) return -1;
int seconds = StringUtils_digitsToInt(gtString + 12, 2);
if (seconds < 0) return -1;
struct tm tmTime;
tmTime.tm_year = year - 1900;
tmTime.tm_mon = month - 1;
tmTime.tm_mday = day;
tmTime.tm_hour = hour;
tmTime.tm_min = min;
tmTime.tm_sec = seconds;
int msOffset = 0;
const char* parsePos = gtString + 14;
/* parse optional fraction of second field */
if (*(parsePos) == '.') {
parsePos++;
const char* fractionOfSecondStart = parsePos;
int fractionOfSecondLen = 0;
int secondValue = 1;
while (StringUtils_isDigit(fractionOfSecondStart[fractionOfSecondLen])) {
fractionOfSecondLen++;
secondValue = secondValue * 10;
}
if (fractionOfSecondLen > 0) {
int fractionOfSecond = StringUtils_digitsToInt(fractionOfSecondStart, fractionOfSecondLen);
msOffset = (fractionOfSecond * 1000) / secondValue;
}
parsePos += fractionOfSecondLen;
}
time_t t = 0;
switch (*parsePos) {
case 0: /* treat time as localtime */
t = mktime(&tmTime);
break;
case 'Z': /* treat time as GMT(UTC) time */
t = timegm(&tmTime);
break;
case '+': /* subtract offset */
{
t = timegm(&tmTime);
int secondsOffset = getSecondsOffset(parsePos + 1);
t = t - secondsOffset;
}
break;
case '-': /* add offset */
{
t = timegm(&tmTime);
int secondsOffset = getSecondsOffset(parsePos + 1);
t = t + secondsOffset;
}
break;
default:
return -1;
}
uint64_t msTime = t * 1000;
msTime += msOffset;
return msTime;
}
void
memcpyReverseByteOrder(uint8_t* dst, const uint8_t* src, int size)
{
int i = 0;
for (i = 0; i < size; i++) {
dst[i] = src[size - i - 1];
}
}