// // -------------------------------------------------------------------------- // Gurux Ltd // // // // Filename: $HeadURL$ // // Version: $Revision$, // $Date$ // $Author$ // // Copyright (c) Gurux Ltd // //--------------------------------------------------------------------------- // // DESCRIPTION // // This file is a part of Gurux Device Framework. // // Gurux Device Framework is Open Source 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; version 2 of the License. // Gurux Device Framework 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. // // This code is licensed under the GNU General Public License v2. // Full text may be retrieved at http://www.gnu.org/licenses/gpl-2.0.txt //--------------------------------------------------------------------------- #if defined(_WIN32) || defined(_WIN64) || defined(__linux__) #include #endif #include "gxmem.h" #ifndef DLMS_IGNORE_STRING_CONVERTER #include //printf needs this or error is generated. #if _MSC_VER > 1400 #include #endif #endif //DLMS_IGNORE_STRING_CONVERTER #include /* memset */ #include "variant.h" #include "errorcodes.h" #include "helpers.h" int var_setEnum(dlmsVARIANT* data, unsigned char value) { var_clear(data); data->vt = DLMS_DATA_TYPE_ENUM; data->bVal = value; return DLMS_ERROR_CODE_OK; } int var_setUInt8(dlmsVARIANT* data, unsigned char value) { var_clear(data); data->vt = DLMS_DATA_TYPE_UINT8; data->bVal = value; return DLMS_ERROR_CODE_OK; } int var_setUInt16(dlmsVARIANT* data, uint16_t value) { var_clear(data); data->vt = DLMS_DATA_TYPE_UINT16; data->uiVal = value; return DLMS_ERROR_CODE_OK; } int var_setUInt32(dlmsVARIANT* data, uint32_t value) { var_clear(data); data->vt = DLMS_DATA_TYPE_UINT32; data->ulVal = value; return DLMS_ERROR_CODE_OK; } int var_setUInt64(dlmsVARIANT* data, uint64_t value) { var_clear(data); data->vt = DLMS_DATA_TYPE_UINT64; data->ullVal = value; return DLMS_ERROR_CODE_OK; } int var_setInt8(dlmsVARIANT* data, char value) { var_clear(data); data->vt = DLMS_DATA_TYPE_INT8; data->cVal = value; return DLMS_ERROR_CODE_OK; } int var_setInt16(dlmsVARIANT* data, short value) { var_clear(data); data->vt = DLMS_DATA_TYPE_INT16; data->iVal = value; return DLMS_ERROR_CODE_OK; } int var_setInt32(dlmsVARIANT* data, int32_t value) { var_clear(data); data->vt = DLMS_DATA_TYPE_INT32; data->lVal = value; return DLMS_ERROR_CODE_OK; } int var_setInt64(dlmsVARIANT* data, int64_t value) { var_clear(data); data->vt = DLMS_DATA_TYPE_INT64; data->llVal = value; return DLMS_ERROR_CODE_OK; } #ifndef DLMS_IGNORE_FLOAT64 int var_setDouble(dlmsVARIANT* data, double value) { var_clear(data); data->vt = DLMS_DATA_TYPE_FLOAT64; data->dblVal = value; return DLMS_ERROR_CODE_OK; } #endif //DLMS_IGNORE_FLOAT64 int var_getUInt8(dlmsVARIANT* data, unsigned char* value) { if (data->vt == DLMS_DATA_TYPE_NONE) { *value = 0; } else { *value = data->bVal; } return DLMS_ERROR_CODE_OK; } int var_getUInt16(dlmsVARIANT* data, uint16_t* value) { if (data->vt == DLMS_DATA_TYPE_NONE) { *value = 0; } else { *value = data->uiVal; } return DLMS_ERROR_CODE_OK; } int var_getUInt32(dlmsVARIANT* data, uint32_t* value) { if (data->vt == DLMS_DATA_TYPE_NONE) { *value = 0; } else { *value = data->lVal; } return DLMS_ERROR_CODE_OK; } int var_getUInt64(dlmsVARIANT* data, uint64_t* value) { if (data->vt == DLMS_DATA_TYPE_NONE) { *value = 0; } else { *value = data->ullVal; } return DLMS_ERROR_CODE_OK; } int var_getInt8(dlmsVARIANT* data, char* value) { if (data->vt == DLMS_DATA_TYPE_NONE) { *value = 0; } else { *value = data->cVal; } return DLMS_ERROR_CODE_OK; } int var_getInt16(dlmsVARIANT* data, short* value) { if (data->vt == DLMS_DATA_TYPE_NONE) { *value = 0; } else { *value = data->iVal; } return DLMS_ERROR_CODE_OK; } int var_getInt32(dlmsVARIANT* data, int32_t* value) { var_clear(data); if (data->vt == DLMS_DATA_TYPE_NONE) { *value = 0; } else { *value = data->lVal; } return DLMS_ERROR_CODE_OK; } int var_getInt64(dlmsVARIANT* data, int64_t* value) { if (data->vt == DLMS_DATA_TYPE_NONE) { *value = 0; } else { *value = data->llVal; } return DLMS_ERROR_CODE_OK; } int var_addBytes(dlmsVARIANT* data, const unsigned char* value, uint16_t count) { if (data->vt != DLMS_DATA_TYPE_OCTET_STRING) { #ifdef DLMS_IGNORE_MALLOC return DLMS_ERROR_CODE_INVALID_PARAMETER; #else var_clear(data); data->byteArr = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); BYTE_BUFFER_INIT(data->byteArr); data->vt = DLMS_DATA_TYPE_OCTET_STRING; #endif //DLMS_IGNORE_MALLOC } #ifndef DLMS_IGNORE_MALLOC else { bb_clear(data->byteArr); } #endif //DLMS_IGNORE_MALLOC return bb_set(data->byteArr, value, count); } #ifndef DLMS_IGNORE_MALLOC int var_setString(dlmsVARIANT* data, const char* value, uint16_t count) { var_clear(data); if (data->vt != DLMS_DATA_TYPE_STRING) { var_clear(data); data->strVal = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); BYTE_BUFFER_INIT(data->strVal); data->vt = DLMS_DATA_TYPE_STRING; } bb_set(data->strVal, (const unsigned char*)value, count); return DLMS_ERROR_CODE_OK; } #endif //DLMS_IGNORE_MALLOC int var_addOctetString( dlmsVARIANT* data, gxByteBuffer* ba) { var_clear(data); return var_addBytes(data, ba->data + ba->position, (uint16_t)(ba->size - ba->position)); } int var_addByteArray( dlmsVARIANT* data, gxByteBuffer* ba, uint16_t index, uint16_t count) { return var_addBytes(data, ba->data + index, count); } //Initialize variant. int var_init(dlmsVARIANT* data) { data->vt = DLMS_DATA_TYPE_NONE; data->byteArr = NULL; return DLMS_ERROR_CODE_OK; } #ifndef DLMS_IGNORE_MALLOC void var_attachArray(dlmsVARIANT* data, const variantArray* arr, const uint16_t count) { data->Arr = (variantArray*)gxmalloc(sizeof(variantArray)); data->vt = DLMS_DATA_TYPE_ARRAY; data->Arr->capacity = 0x8000 + count; data->Arr->size = count; data->Arr->data = (void**)arr->data; } #endif //DLMS_IGNORE_MALLOC #ifndef DLMS_IGNORE_MALLOC void var_attachStructure(dlmsVARIANT* data, const dlmsVARIANT** arr, const uint16_t count) { data->Arr = (variantArray*)gxmalloc(sizeof(variantArray)); data->vt = DLMS_DATA_TYPE_STRUCTURE; data->Arr->capacity = 0x8000 + count; data->Arr->size = count; data->Arr->data = (void**)arr; } #endif //DLMS_IGNORE_MALLOC //Clear variant. int var_clear(dlmsVARIANT* data) { #ifdef DLMS_IGNORE_MALLOC //Referenced values are not cleared. User must do it. if ((data->vt & DLMS_DATA_TYPE_BYREF) == 0) { data->llVal = 0; data->vt = DLMS_DATA_TYPE_NONE; } data->size = 0; #else //Referenced values are not cleared. User must do it. if ((data->vt & DLMS_DATA_TYPE_BYREF) != 0) { return 0; } switch (data->vt) { case DLMS_DATA_TYPE_OCTET_STRING: if (data->byteArr != NULL) { bb_clear(data->byteArr); if (!bb_isAttached(data->byteArr)) { gxfree(data->byteArr); data->byteArr = NULL; } } break; case DLMS_DATA_TYPE_STRING_UTF8: if (data->strUtfVal != NULL) { bb_clear(data->strUtfVal); if (!bb_isAttached(data->strUtfVal)) { gxfree(data->strUtfVal); data->strUtfVal = NULL; } } break; case DLMS_DATA_TYPE_STRING: if (data->strVal != NULL) { bb_clear(data->strVal); gxfree(data->strVal); } break; case DLMS_DATA_TYPE_ARRAY: case DLMS_DATA_TYPE_STRUCTURE: case DLMS_DATA_TYPE_COMPACT_ARRAY: if (data->Arr != NULL) { va_clear(data->Arr); gxfree(data->Arr); data->Arr = NULL; } break; case DLMS_DATA_TYPE_BIT_STRING: if (data->bitArr != NULL) { ba_clear(data->bitArr); gxfree(data->bitArr); } break; case DLMS_DATA_TYPE_DATETIME: case DLMS_DATA_TYPE_DATE: case DLMS_DATA_TYPE_TIME: if (data->dateTime != NULL) { gxfree(data->dateTime); data->dateTime = NULL; } break; default: data->llVal = 0; break; } data->vt = DLMS_DATA_TYPE_NONE; #endif //DLMS_IGNORE_MALLOC return DLMS_ERROR_CODE_OK; } int var_getDateTime2( gxtime* dateTime, gxByteBuffer* ba) { uint16_t year = 0xFFFF; unsigned char month = 0xFF, day = 0xFF, hour = 0xFF, minute = 0xFF, second = 0xFF, dayOfWeek = 0xFF; #ifdef DLMS_USE_EPOCH_TIME time_fromUnixTime2(dateTime->value, &year, &month, &day, &hour, &minute, &second, &dayOfWeek); //Add year. if ((dateTime->skip & DATETIME_SKIPS_YEAR) != 0) { year = 0xFFFF; } if ((dateTime->skip & (DATETIME_SKIPS_YEAR | DATETIME_SKIPS_MONTH | DATETIME_SKIPS_DAY)) != 0) { dayOfWeek = 0xFF; } #else if (dateTime->value.tm_isdst && (dateTime->status & DLMS_CLOCK_STATUS_DAYLIGHT_SAVE_ACTIVE) == 0) { time_addMinutes(dateTime, -60); } //Add year. if (dateTime->value.tm_year != -1 && (dateTime->skip & DATETIME_SKIPS_YEAR) == 0) { year = (uint16_t)(1900 + dateTime->value.tm_year); } if (dateTime->value.tm_mon != -1 && (dateTime->skip & DATETIME_SKIPS_MONTH) == 0) { if (dateTime->extraInfo == DLMS_DATE_TIME_EXTRA_INFO_DST_BEGIN) { month = 0xFE; } else if (dateTime->extraInfo == DLMS_DATE_TIME_EXTRA_INFO_DST_END) { month = 0xFD; } else { month = (unsigned char)dateTime->value.tm_mon + 1; } } if (dateTime->value.tm_mday != -1 && (dateTime->skip & DATETIME_SKIPS_DAY) == 0) { if (dateTime->extraInfo == DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY) { day = 0xFE; } else if (dateTime->extraInfo == DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY2) { day = 0xFD; } else { day = (unsigned char)dateTime->value.tm_mday; } } //Add week day if ((dateTime->value.tm_wday != -1 && dateTime->skip & DATETIME_SKIPS_DAYOFWEEK) == 0) { dayOfWeek = (unsigned char)dateTime->value.tm_wday; } //Add Hours if (dateTime->value.tm_hour != -1 && (dateTime->skip & DATETIME_SKIPS_HOUR) == 0) { hour = (unsigned char)dateTime->value.tm_hour; } //Add Minutes if (dateTime->value.tm_min != -1 && (dateTime->skip & DATETIME_SKIPS_MINUTE) == 0) { minute = (unsigned char)dateTime->value.tm_min; } //Add seconds. if (dateTime->value.tm_sec != -1 && (dateTime->skip & DATETIME_SKIPS_SECOND) == 0) { second = (unsigned char)dateTime->value.tm_sec; } #endif // DLMS_USE_EPOCH_TIME //Add year. bb_setUInt16(ba, year); //Add month if ((dateTime->extraInfo & DLMS_DATE_TIME_EXTRA_INFO_DST_BEGIN) != 0) { bb_setUInt8(ba, 0xFE); } else if ((dateTime->extraInfo & DLMS_DATE_TIME_EXTRA_INFO_DST_END) != 0) { bb_setUInt8(ba, 0xFD); } else if ((dateTime->skip & DATETIME_SKIPS_MONTH) == 0) { bb_setUInt8(ba, month); } else { bb_setUInt8(ba, 0xFF); } //Add day if ((dateTime->extraInfo & DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY) != 0) { bb_setUInt8(ba, 0xFE); } else if ((dateTime->extraInfo & DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY2) != 0) { bb_setUInt8(ba, 0xFD); } else if ((dateTime->skip & DATETIME_SKIPS_DAY) == 0) { bb_setUInt8(ba, day); } else { bb_setUInt8(ba, 0xFF); } //Add week day if ((dateTime->skip & DATETIME_SKIPS_DAYOFWEEK) == 0) { //If Sunday. if (dayOfWeek == 0) { dayOfWeek = 7; } bb_setUInt8(ba, dayOfWeek); } else { bb_setUInt8(ba, 0xFF); } //Add Hours if ((dateTime->skip & DATETIME_SKIPS_HOUR) == 0) { bb_setUInt8(ba, hour); } else { bb_setUInt8(ba, 0xFF); } //Add Minutes if ((dateTime->skip & DATETIME_SKIPS_MINUTE) == 0) { bb_setUInt8(ba, minute); } else { bb_setUInt8(ba, 0xFF); } //Add seconds. if ((dateTime->skip & DATETIME_SKIPS_SECOND) == 0) { bb_setUInt8(ba, second); } else { bb_setUInt8(ba, 0xFF); } //Add ms. #ifdef DLMS_ITALIAN_STANDARD //Italian standard uses 0 for ms. bb_setUInt8(ba, 0x00); #else if ((dateTime->skip & DATETIME_SKIPS_MS) == 0) { bb_setUInt8(ba, 0x00); } else { bb_setUInt8(ba, 0xFF); } #endif //DLMS_ITALIAN_STANDARD //Add Deviation if (year == 0xFFFF || (dateTime->skip & DATETIME_SKIPS_DEVITATION) != 0) { bb_setInt16(ba, 0x8000);//(not specified) } else { bb_setInt16(ba, dateTime->deviation); } //Add clock status if ((dateTime->skip & DATETIME_SKIPS_STATUS) != 0) { bb_setUInt8(ba, 0xFF); } else { bb_setUInt8(ba, dateTime->status); } return 0; } int var_getDate( gxtime* dateTime, gxByteBuffer* ba) { uint16_t year = 0xFFFF; unsigned char month = 0xFF, day = 0xFF, dayOfWeek = 0xFF; #ifdef DLMS_USE_EPOCH_TIME time_fromUnixTime2(dateTime->value, &year, &month, &day, NULL, NULL, NULL, &dayOfWeek); //Add year. if ((dateTime->skip & DATETIME_SKIPS_YEAR) != 0) { year = 0xFFFF; } #else //Add year. if (dateTime->value.tm_year != -1 && (dateTime->skip & DATETIME_SKIPS_YEAR) == 0) { year = (uint16_t)(1900 + dateTime->value.tm_year); } if (dateTime->value.tm_mon != -1 && (dateTime->skip & DATETIME_SKIPS_MONTH) == 0) { month = (unsigned char)dateTime->value.tm_mon + 1; } if (dateTime->value.tm_mday != -1 && (dateTime->skip & DATETIME_SKIPS_DAY) == 0) { day = (unsigned char)dateTime->value.tm_mday; } //Add week day if ((dateTime->value.tm_wday != -1 && dateTime->skip & DATETIME_SKIPS_DAYOFWEEK) == 0) { dayOfWeek = (unsigned char)dateTime->value.tm_wday; } #endif // DLMS_USE_EPOCH_TIME //Add year. bb_setUInt16(ba, year); //Add month if ((dateTime->skip & DATETIME_SKIPS_MONTH) == 0) { if ((dateTime->extraInfo & DLMS_DATE_TIME_EXTRA_INFO_DST_BEGIN) != 0) { month = 0xFE; } else if ((dateTime->extraInfo & DLMS_DATE_TIME_EXTRA_INFO_DST_END) != 0) { month = 0xFD; } bb_setUInt8(ba, month); } else { bb_setUInt8(ba, 0xFF); } //Add day if ((dateTime->skip & DATETIME_SKIPS_DAY) == 0) { if ((dateTime->extraInfo & DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY) != 0) { day = 0xFE; } else if ((dateTime->extraInfo & DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY2) != 0) { day = 0xFD; } bb_setUInt8(ba, day); } else { bb_setUInt8(ba, 0xFF); } //Add week day if ((dateTime->skip & DATETIME_SKIPS_DAYOFWEEK) == 0) { //If Sunday. if (dayOfWeek == 0) { dayOfWeek = 7; } bb_setUInt8(ba, dayOfWeek); } else { bb_setUInt8(ba, 0xFF); } return 0; } int var_getTime( gxtime* dateTime, gxByteBuffer* ba) { unsigned char hour = 0xFF, minute = 0xFF, second = 0xFF; #ifdef DLMS_USE_EPOCH_TIME int ret = time_fromUnixTime2(dateTime->value, NULL, NULL, NULL, &hour, &minute, &second, NULL); if (ret != 0) { return ret; } #else //Add Hours if (dateTime->value.tm_hour != -1 && (dateTime->skip & DATETIME_SKIPS_HOUR) == 0) { hour = (unsigned char)dateTime->value.tm_hour; } //Add Minutes if (dateTime->value.tm_min != -1 && (dateTime->skip & DATETIME_SKIPS_MINUTE) == 0) { minute = (unsigned char)dateTime->value.tm_min; } //Add seconds. if (dateTime->value.tm_sec != -1 && (dateTime->skip & DATETIME_SKIPS_SECOND) == 0) { second = (unsigned char)dateTime->value.tm_sec; } #endif // DLMS_USE_EPOCH_TIME //Add Hours if ((dateTime->skip & DATETIME_SKIPS_HOUR) == 0) { bb_setUInt8(ba, hour); } else { bb_setUInt8(ba, 0xFF); } //Add Minutes if ((dateTime->skip & DATETIME_SKIPS_MINUTE) == 0) { bb_setUInt8(ba, minute); } else { bb_setUInt8(ba, 0xFF); } //Add seconds. if ((dateTime->skip & DATETIME_SKIPS_SECOND) == 0) { bb_setUInt8(ba, second); } else { bb_setUInt8(ba, 0xFF); } //Add ms. #ifdef DLMS_ITALIAN_STANDARD //Italian standard uses 0 for ms. bb_setUInt8(ba, 0x00); #else if ((dateTime->skip & DATETIME_SKIPS_MS) == 0) { bb_setUInt8(ba, 0x00); } else { bb_setUInt8(ba, 0xFF); } #endif //DLMS_ITALIAN_STANDARD return 0; } //Get bytes from variant value. int var_getBytes( dlmsVARIANT* data, gxByteBuffer* ba) { return var_getBytes2(data, data->vt, ba); } #ifndef DLMS_IGNORE_MALLOC /** * Convert octetstring to DLMS bytes. * * buff * Byte buffer where data is write. * value * Added value. */ int var_setOctetString(gxByteBuffer* buff, dlmsVARIANT* value) { if (value->vt == DLMS_DATA_TYPE_STRING) { gxByteBuffer bb; BYTE_BUFFER_INIT(&bb); bb_addHexString(&bb, (char*)value->strVal->data); hlp_setObjectCount(bb.size, buff); bb_set2(buff, &bb, 0, bb.size); } else if (value->vt == DLMS_DATA_TYPE_OCTET_STRING) { if (value->byteArr == NULL) { hlp_setObjectCount(0, buff); } else { hlp_setObjectCount(value->byteArr->size, buff); bb_set(buff, value->byteArr->data, value->byteArr->size); } } else if (value->vt == DLMS_DATA_TYPE_NONE) { hlp_setObjectCount(0, buff); } else { // Invalid data type. return DLMS_ERROR_CODE_INVALID_PARAMETER; } return 0; } #endif //DLMS_IGNORE_MALLOC //Get bytes from variant value. int var_getBytes2( dlmsVARIANT* data, DLMS_DATA_TYPE type, gxByteBuffer* ba) { return var_getBytes3(data, type, ba, 1); } //Returns bytes as Big Endian byteorder. int var_getBytes3( dlmsVARIANT* data, DLMS_DATA_TYPE type, gxByteBuffer* ba, unsigned char addType) { int ret = 0, pos; if ((type & DLMS_DATA_TYPE_BYREF) != 0) { return var_getBytes3(data, type & ~DLMS_DATA_TYPE_BYREF, ba, addType); } if (type == DLMS_DATA_TYPE_STRUCTURE || type == DLMS_DATA_TYPE_ARRAY) { dlmsVARIANT* tmp; if ((ret = bb_setUInt8(ba, type)) == 0 && (ret = hlp_setObjectCount(data->Arr != NULL ? data->Arr->size : 0, ba)) == 0) { if (data->Arr != NULL) { for (pos = 0; pos != data->Arr->size; ++pos) { if ((ret = va_getByIndex(data->Arr, pos, &tmp)) != DLMS_ERROR_CODE_OK || (ret = var_getBytes(tmp, ba)) != DLMS_ERROR_CODE_OK) { break; } } } } return ret; } if (addType) { if ((ret = bb_setUInt8(ba, type)) != 0) { return ret; } } switch (type) { case DLMS_DATA_TYPE_NONE: break; case DLMS_DATA_TYPE_UINT8: case DLMS_DATA_TYPE_ENUM: ret = bb_setUInt8(ba, (data->vt & DLMS_DATA_TYPE_BYREF) != 0 ? *data->pbVal : data->bVal); break; case DLMS_DATA_TYPE_BOOLEAN: if ((data->vt & DLMS_DATA_TYPE_BYREF) != 0) { ret = bb_setUInt8(ba, *data->pbVal == 0 ? 0 : 1); } else { ret = bb_setUInt8(ba, data->bVal == 0 ? 0 : 1); } break; case DLMS_DATA_TYPE_UINT16: ret = bb_setUInt16(ba, (data->vt & DLMS_DATA_TYPE_BYREF) != 0 ? *data->puiVal : data->uiVal); break; case DLMS_DATA_TYPE_UINT32: ret = bb_setUInt32(ba, (data->vt & DLMS_DATA_TYPE_BYREF) != 0 ? *data->pulVal : data->ulVal); break; case DLMS_DATA_TYPE_UINT64: ret = bb_setUInt64(ba, (data->vt & DLMS_DATA_TYPE_BYREF) != 0 ? *data->pullVal : data->ullVal); break; case DLMS_DATA_TYPE_INT8: ret = bb_setInt8(ba, (data->vt & DLMS_DATA_TYPE_BYREF) != 0 ? *data->pcVal : data->cVal); break; case DLMS_DATA_TYPE_INT16: ret = bb_setInt16(ba, (data->vt & DLMS_DATA_TYPE_BYREF) != 0 ? *data->puiVal : data->uiVal); break; case DLMS_DATA_TYPE_INT32: ret = bb_setUInt32(ba, (data->vt & DLMS_DATA_TYPE_BYREF) != 0 ? *data->plVal : data->lVal); break; case DLMS_DATA_TYPE_INT64: ret = bb_setInt64(ba, (data->vt & DLMS_DATA_TYPE_BYREF) != 0 ? *data->pllVal : data->llVal); break; case DLMS_DATA_TYPE_FLOAT32: #ifndef DLMS_IGNORE_FLOAT32 ret = bb_setFloat(ba, (data->vt & DLMS_DATA_TYPE_BYREF) != 0 ? *data->pfltVal : data->fltVal); #else ret = DLMS_ERROR_CODE_INVALID_PARAMETER; #endif //DLMS_IGNORE_FLOAT32 break; case DLMS_DATA_TYPE_FLOAT64: #ifndef DLMS_IGNORE_FLOAT64 ret = bb_setDouble(ba, (data->vt & DLMS_DATA_TYPE_BYREF) != 0 ? *data->pdblVal : data->dblVal); #else ret = DLMS_ERROR_CODE_INVALID_PARAMETER; #endif //DLMS_IGNORE_FLOAT64 break; case DLMS_DATA_TYPE_STRING: #ifndef DLMS_IGNORE_MALLOC if (data->strVal == NULL) { ret = hlp_setObjectCount(0, ba); } else { if ((ret = hlp_setObjectCount(data->strVal->size, ba)) == 0) { ret = bb_set(ba, data->strVal->data, data->strVal->size); } } #else if (data->vt == (DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_STRING)) { if ((ret = hlp_setObjectCount(data->size, ba)) != 0 || (ret = bb_set(ba, data->pbVal, data->size)) != 0) { //Error code is returned at the end of the function. } } else { ret = DLMS_ERROR_CODE_INVALID_PARAMETER; } #endif //DLMS_IGNORE_MALLOC break; case DLMS_DATA_TYPE_OCTET_STRING: #ifndef DLMS_IGNORE_MALLOC if (data->vt == DLMS_DATA_TYPE_DATETIME) { if ((ret = bb_setUInt8(ba, 12)) == 0) { ret = var_getDateTime2(data->dateTime, ba); } } else if (data->vt == DLMS_DATA_TYPE_DATE) { if ((ret = bb_setUInt8(ba, 5)) == 0) { ret = var_getDate(data->dateTime, ba); } } else if (data->vt == DLMS_DATA_TYPE_TIME) { if ((ret = bb_setUInt8(ba, 4)) == 0) { ret = var_getTime(data->dateTime, ba); } } else { ret = var_setOctetString(ba, data); } #else if (data->vt == (DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_DATETIME)) { if ((ret = bb_setUInt8(ba, 12)) == 0) { ret = var_getDateTime2(data->pVal, ba); } } else if (data->vt == (DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_DATE)) { if ((ret = bb_setUInt8(ba, 5)) == 0) { ret = var_getDate(data->pVal, ba); } } else if (data->vt == (DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_TIME)) { if ((ret = bb_setUInt8(ba, 4)) == 0) { ret = var_getTime(data->pVal, ba); } } else if (data->vt == (DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_OCTET_STRING)) { if ((ret = hlp_setObjectCount(data->size, ba)) != 0 || (ret = bb_set(ba, data->pbVal, data->size)) != 0) { //Error code is returned at the end of the function. } } else { if ((ret = hlp_setObjectCount(data->byteArr->size, ba)) != 0 || (ret = bb_set(ba, data->byteArr->data, data->byteArr->size)) != 0) { //Error code is returned at the end of the function. } } #endif //DLMS_IGNORE_MALLOC break; case DLMS_DATA_TYPE_DATETIME: { #ifdef DLMS_IGNORE_MALLOC ret = var_getDateTime2(data->pVal, ba); #else ret = var_getDateTime2(data->dateTime, ba); #endif //DLMS_IGNORE_MALLOC break; } case DLMS_DATA_TYPE_DATE: { #ifdef DLMS_IGNORE_MALLOC ret = var_getDate(data->pVal, ba); #else ret = var_getDate(data->dateTime, ba); #endif //DLMS_IGNORE_MALLOC break; } case DLMS_DATA_TYPE_TIME: { #ifdef DLMS_IGNORE_MALLOC ret = var_getTime(data->pVal, ba); #else ret = var_getTime(data->dateTime, ba); #endif //DLMS_IGNORE_MALLOC break; } case DLMS_DATA_TYPE_BIT_STRING: { #ifdef DLMS_IGNORE_MALLOC if ((ret = hlp_setObjectCount(data->size, ba)) == 0) { ret = bb_set(ba, data->pVal, ba_getByteCount(data->size)); } #else if ((ret = hlp_setObjectCount(data->bitArr->size, ba)) == 0) { ret = bb_set(ba, data->bitArr->data, ba_getByteCount(data->bitArr->size)); } #endif //DLMS_IGNORE_MALLOC break; } default: #if defined(_WIN32) || defined(_WIN64) || defined(__linux__) assert(0); #endif ret = DLMS_ERROR_CODE_INVALID_PARAMETER; } return ret; } //Get size in bytes. int var_getSize(DLMS_DATA_TYPE vt) { int nSize = -1; switch (vt) { case DLMS_DATA_TYPE_NONE: nSize = 0; break; case DLMS_DATA_TYPE_BOOLEAN: case DLMS_DATA_TYPE_INT8: case DLMS_DATA_TYPE_UINT8: case DLMS_DATA_TYPE_ENUM: nSize = 1; break; case DLMS_DATA_TYPE_INT16: case DLMS_DATA_TYPE_UINT16: nSize = 2; break; case DLMS_DATA_TYPE_INT32: case DLMS_DATA_TYPE_UINT32: case DLMS_DATA_TYPE_FLOAT32: nSize = 4; break; case DLMS_DATA_TYPE_INT64: case DLMS_DATA_TYPE_UINT64: case DLMS_DATA_TYPE_FLOAT64: nSize = 8; break; case DLMS_DATA_TYPE_BIT_STRING: case DLMS_DATA_TYPE_OCTET_STRING: case DLMS_DATA_TYPE_STRING: case DLMS_DATA_TYPE_STRING_UTF8: nSize = -1; break; case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL: break; case DLMS_DATA_TYPE_DATETIME: nSize = 12; break; //case DLMS_DATA_TYPE_DATE: //case DLMS_DATA_TYPE_TIME: //case DLMS_DATA_TYPE_ARRAY: //case DLMS_DATA_TYPE_STRUCTURE: //case DLMS_DATA_TYPE_COMPACT_ARRAY: default: break; } return nSize; } //Convert variant value to integer. int var_toInteger(dlmsVARIANT* data) { int ret; if ((data->vt & DLMS_DATA_TYPE_BYREF) != 0) { dlmsVARIANT tmp; if ((ret = var_copy(&tmp, data)) == 0) { ret = var_toInteger(&tmp); } else { #if defined(_WIN32) || defined(_WIN64) || defined(__linux__) assert(0); #endif ret = -1; } return ret; } switch (data->vt) { case DLMS_DATA_TYPE_NONE: ret = 0; break; case DLMS_DATA_TYPE_BOOLEAN: ret = data->boolVal ? 1 : 0; break; case DLMS_DATA_TYPE_INT32: ret = data->lVal; break; case DLMS_DATA_TYPE_UINT32: ret = data->ulVal; break; case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL: #if defined(_WIN32) || defined(_WIN64) || defined(__linux__) assert(0); #endif ret = 0; break; case DLMS_DATA_TYPE_STRING_UTF8: #if defined(_WIN32) || defined(_WIN64) || defined(__linux__) assert(0); #endif ret = 0; break; case DLMS_DATA_TYPE_INT8: ret = data->cVal; break; case DLMS_DATA_TYPE_INT16: ret = data->iVal; break; case DLMS_DATA_TYPE_UINT8: ret = data->bVal; break; case DLMS_DATA_TYPE_UINT16: ret = data->uiVal; break; case DLMS_DATA_TYPE_INT64: ret = (int)data->llVal; break; case DLMS_DATA_TYPE_UINT64: ret = (int)data->ullVal; break; case DLMS_DATA_TYPE_ENUM: ret = data->bVal; break; #ifndef DLMS_IGNORE_FLOAT32 case DLMS_DATA_TYPE_FLOAT32: ret = (int)data->fltVal; break; #endif //DLMS_IGNORE_FLOAT32 #ifndef DLMS_IGNORE_FLOAT64 case DLMS_DATA_TYPE_FLOAT64: ret = (int)data->dblVal; break; #endif //DLMS_IGNORE_FLOAT64 #ifndef DLMS_IGNORE_MALLOC case DLMS_DATA_TYPE_STRING: ret = hlp_stringToInt((const char*)data->strVal); break; case DLMS_DATA_TYPE_BIT_STRING: { uint32_t value; ba_toInteger(data->bitArr, &value); ret = (int)value; } break; #endif //DLMS_IGNORE_MALLOC default: #if defined(_WIN32) || defined(_WIN64) || defined(__linux__) assert(0); #endif ret = 0; break; } return ret; } char va_isAttached(variantArray* arr) { return (arr->capacity & 0x8000) == 0x8000; } uint16_t va_size(variantArray* arr) { return arr == NULL ? 0 : arr->size; } uint16_t va_getCapacity(variantArray* arr) { return arr->capacity & 0x7FFF; } //Initialize variantArray. void va_init(variantArray* arr) { arr->capacity = 0; arr->data = NULL; arr->size = 0; } //Allocate new size for the array in bytes. int va_capacity(variantArray* arr, uint16_t capacity) { #ifndef DLMS_IGNORE_MALLOC if (!va_isAttached(arr)) { if (capacity == 0) { if (arr->capacity != 0) { gxfree(arr->data); arr->size = 0; } } else { if (arr->capacity == 0) { arr->data = (void**)gxmalloc(capacity * sizeof(dlmsVARIANT*)); if (arr->data == NULL) { return DLMS_ERROR_CODE_OUTOFMEMORY; } } else { #ifdef gxrealloc //If compiler supports realloc. void** tmp = (void**)gxrealloc(arr->data, capacity * sizeof(dlmsVARIANT*)); if (tmp == NULL) { return DLMS_ERROR_CODE_OUTOFMEMORY; } arr->data = tmp; #else //If compiler doesn't support realloc. void** old = arr->data; arr->data = (void**)gxmalloc(capacity * sizeof(dlmsVARIANT*)); //If not enought memory available. if (arr->data == NULL) { arr->data = old; return DLMS_ERROR_CODE_OUTOFMEMORY; } memcpy(arr->data, old, sizeof(dlmsVARIANT*) * arr->size); gxfree(old); #endif // gxrealloc } } arr->capacity = capacity; } #endif //DLMS_IGNORE_MALLOC if (va_getCapacity(arr) < capacity) { return DLMS_ERROR_CODE_OUTOFMEMORY; } return 0; } //Push new data to the variantArray. int va_push(variantArray* arr, dlmsVARIANT* item) { dlmsVARIANT** p; #ifndef DLMS_IGNORE_MALLOC if (!va_isAttached(arr)) { if (arr->size >= arr->capacity) { arr->capacity += VARIANT_ARRAY_CAPACITY; if (arr->size == 0) { arr->data = (void**)gxmalloc(arr->capacity * sizeof(dlmsVARIANT*)); } else { #ifdef gxrealloc //If compiler supports realloc. void** tmp = (void**)gxrealloc(arr->data, arr->capacity * sizeof(dlmsVARIANT*)); if (tmp == NULL) { return DLMS_ERROR_CODE_OUTOFMEMORY; } arr->data = tmp; #else //If compiler doesn't support realloc. void** old = arr->data; arr->data = (void**)gxmalloc(arr->capacity * sizeof(dlmsVARIANT*)); //If not enought memory available. if (arr->data == NULL) { arr->data = old; return DLMS_ERROR_CODE_OUTOFMEMORY; } memcpy(arr->data, old, sizeof(dlmsVARIANT*) * arr->size); gxfree(old); #endif // gxrealloc } } } #endif //DLMS_IGNORE_MALLOC if (va_getCapacity(arr) <= arr->size) { return DLMS_ERROR_CODE_OUTOFMEMORY; } p = (dlmsVARIANT**)arr->data; p[arr->size] = item; ++arr->size; return 0; } void va_clear( variantArray* arr) { #ifndef DLMS_IGNORE_MALLOC int pos; unsigned char attached = va_isAttached(arr); if (arr->data != NULL && !attached) { for (pos = 0; pos != arr->size; ++pos) { var_clear((dlmsVARIANT*)arr->data[pos]); gxfree(arr->data[pos]); } gxfree(arr->data); arr->data = NULL; } if (!attached) { arr->capacity = 0; } #endif //DLMS_IGNORE_MALLOC arr->size = 0; } #ifdef DLMS_IGNORE_MALLOC void va_attach( variantArray* trg, dlmsVARIANT* src, uint16_t size, uint16_t capacity) { trg->data = src; trg->capacity = (uint16_t)(0x8000 | capacity); trg->size = size; } #endif //DLMS_IGNORE_MALLOC void va_attach2( variantArray* trg, variantArray* src) { trg->capacity = src->capacity; trg->data = src->data; trg->size = src->size; src->data = NULL; src->size = src->capacity = 0; } //Get item from variant array by index. int va_getByIndex(variantArray* arr, int index, dlmsVARIANT_PTR* item) { if (index >= arr->size) { return DLMS_ERROR_CODE_OUTOFMEMORY; } #ifdef DLMS_IGNORE_MALLOC dlmsVARIANT_PTR p = (dlmsVARIANT_PTR)arr->data; *item = &p[index]; return DLMS_ERROR_CODE_OK; #else dlmsVARIANT** p = (dlmsVARIANT**)arr->data; *item = p[index]; return DLMS_ERROR_CODE_OK; #endif //DLMS_IGNORE_MALLOC } #ifndef DLMS_IGNORE_MALLOC int va_copyArray( variantArray* target, variantArray* source) { int ret = DLMS_ERROR_CODE_OK; dlmsVARIANT* tmp, * tmp2; int pos; va_clear(target); for (pos = 0; pos != source->size; ++pos) { ret = va_getByIndex(source, pos, &tmp); if (ret != DLMS_ERROR_CODE_OK) { return ret; } tmp2 = (dlmsVARIANT*)gxmalloc(sizeof(dlmsVARIANT)); var_init(tmp2); ret = var_copy(tmp2, tmp); if (ret != DLMS_ERROR_CODE_OK) { return ret; } va_push(target, tmp2); } return ret; } int va_addValue( variantArray* target, dlmsVARIANT* value, uint16_t count) { int pos, ret = DLMS_ERROR_CODE_OK; dlmsVARIANT* tmp; for (pos = 0; pos != count; ++pos) { tmp = (dlmsVARIANT*)gxmalloc(sizeof(dlmsVARIANT)); if (tmp == NULL) { ret = DLMS_ERROR_CODE_OUTOFMEMORY; break; } if ((ret = var_init(tmp)) != 0 || (ret = var_copy(tmp, value)) != 0 || (ret = va_push(target, tmp)) != 0) { break; } } return ret; } #endif //DLMS_IGNORE_MALLOC #ifndef DLMS_IGNORE_MALLOC //Note! var_toString do not clear existing bytearray. int var_toString(dlmsVARIANT* item, gxByteBuffer* value) { int ret = DLMS_ERROR_CODE_OK; uint16_t pos; if (item->vt == DLMS_DATA_TYPE_ARRAY || item->vt == DLMS_DATA_TYPE_STRUCTURE) { dlmsVARIANT* it; bb_setInt8(value, item->vt == DLMS_DATA_TYPE_ARRAY ? '{' : '['); for (pos = 0; pos != item->Arr->size; ++pos) { if (pos != 0) { bb_setInt8(value, ','); bb_setInt8(value, ' '); } if ((ret = va_getByIndex(item->Arr, pos, &it)) != 0 || (ret = var_toString(it, value)) != 0) { break; } } bb_setInt8(value, item->vt == DLMS_DATA_TYPE_ARRAY ? '}' : ']'); } else { dlmsVARIANT tmp; var_init(&tmp); ret = var_copy(&tmp, item); if (ret == 0) { ret = var_changeType(&tmp, DLMS_DATA_TYPE_STRING); if (ret == 0 && tmp.strVal != NULL) { bb_set(value, tmp.strVal->data, tmp.strVal->size); } } var_clear(&tmp); } return ret; } //Note! va_toString do not clear existing bytearray. int va_toString( variantArray* items, gxByteBuffer* ba) { dlmsVARIANT* it; int pos, ret = DLMS_ERROR_CODE_OK; for (pos = 0; pos != items->size; ++pos) { if ((ret = va_getByIndex(items, pos, &it)) != 0) { return ret; } if (pos != 0) { bb_addString(ba, ", "); } if ((ret = var_toString(it, ba)) != 0) { return ret; } } return ret; } static int convert(dlmsVARIANT* item, DLMS_DATA_TYPE type) { int ret, fromSize, toSize; uint16_t pos; char buff[250]; dlmsVARIANT tmp, tmp3; dlmsVARIANT* it; if (item->vt == type) { return DLMS_ERROR_CODE_OK; } var_init(&tmp); var_init(&tmp3); ret = var_copy(&tmp, item); if (ret != DLMS_ERROR_CODE_OK) { return ret; } var_clear(item); if (type == DLMS_DATA_TYPE_STRING) { item->strVal = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); BYTE_BUFFER_INIT(item->strVal); switch (tmp.vt) { case DLMS_DATA_TYPE_ARRAY: case DLMS_DATA_TYPE_STRUCTURE: { bb_setUInt8(item->strVal, '{'); for (pos = 0; pos != tmp.Arr->size; ++pos) { ret = va_getByIndex(tmp.Arr, pos, &it); if (ret != DLMS_ERROR_CODE_OK) { return ret; } if (pos != 0) { bb_setUInt8(item->strVal, ','); bb_setUInt8(item->strVal, ' '); } ret = var_copy(&tmp3, it); if (ret != DLMS_ERROR_CODE_OK) { return ret; } ret = var_toString(&tmp3, item->strVal); var_clear(&tmp3); if (ret != DLMS_ERROR_CODE_OK) { var_clear(&tmp); return ret; } } bb_setUInt8(item->strVal, '}'); bb_setUInt8(item->strVal, '\0'); --item->strVal->size; item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } case DLMS_DATA_TYPE_BOOLEAN: { if (tmp.boolVal == 0) { bb_addString(item->strVal, "False"); } else { bb_addString(item->strVal, "True"); } item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } case DLMS_DATA_TYPE_INT32: { hlp_intToString(buff, 250, tmp.lVal, 1, 0); bb_addString(item->strVal, buff); item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } case DLMS_DATA_TYPE_UINT32: { hlp_uint64ToString(buff, 250, tmp.ulVal, 0); if ((ret = bb_addString(item->strVal, buff)) == 0) { item->vt = type; } var_clear(&tmp); return ret; } case DLMS_DATA_TYPE_INT8: { hlp_intToString(buff, 250, tmp.cVal, 1, 0); bb_addString(item->strVal, buff); item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } case DLMS_DATA_TYPE_INT16: { hlp_intToString(buff, 250, tmp.iVal, 1, 0); bb_addString(item->strVal, buff); item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } case DLMS_DATA_TYPE_UINT8: { hlp_intToString(buff, 250, tmp.bVal, 0, 0); bb_addString(item->strVal, buff); item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } case DLMS_DATA_TYPE_UINT16: { hlp_intToString(buff, 250, tmp.uiVal, 0, 0); bb_addString(item->strVal, buff); item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } case DLMS_DATA_TYPE_INT64: { hlp_int64ToString(buff, 250, tmp.llVal, 1); bb_addString(item->strVal, buff); item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } case DLMS_DATA_TYPE_UINT64: { hlp_uint64ToString(buff, 250, tmp.ullVal, 0); bb_addString(item->strVal, buff); item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } case DLMS_DATA_TYPE_ENUM: { hlp_intToString(buff, 250, tmp.bVal, 0, 0); bb_addString(item->strVal, buff); item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } #if !defined(DLMS_IGNORE_STRING_CONVERTER) && !defined(DLMS_IGNORE_FLOAT32) case DLMS_DATA_TYPE_FLOAT32: { #if _MSC_VER > 1000 sprintf_s(buff, 250, "%f", tmp.fltVal); #else sprintf(buff, "%f", tmp.fltVal); #endif bb_addString(item->strVal, buff); item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } #endif //!defined(DLMS_IGNORE_STRING_CONVERTER) && !defined(DLMS_IGNORE_FLOAT32) #if !defined(DLMS_IGNORE_STRING_CONVERTER) && !defined(DLMS_IGNORE_FLOAT64) case DLMS_DATA_TYPE_FLOAT64: { #if _MSC_VER > 1000 sprintf_s(buff, 250, "%lf", tmp.dblVal); #else sprintf(buff, "%lf", tmp.dblVal); #endif bb_addString(item->strVal, buff); item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } #endif //!defined(DLMS_IGNORE_STRING_CONVERTER) && !defined(DLMS_IGNORE_FLOAT64) case DLMS_DATA_TYPE_BIT_STRING: { char* str = ba_toString(tmp.bitArr); bb_attachString(item->strVal, str); item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } #ifndef DLMS_IGNORE_STRING_CONVERTER case DLMS_DATA_TYPE_DATETIME: case DLMS_DATA_TYPE_DATE: case DLMS_DATA_TYPE_TIME: { time_toString(tmp.dateTime, item->strVal); item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } #endif //DLMS_IGNORE_STRING_CONVERTER case DLMS_DATA_TYPE_OCTET_STRING: { #ifndef DLMS_IGNORE_STRING_CONVERTER if (tmp.byteArr != NULL) { char* str = bb_toHexString(tmp.byteArr); bb_addString(item->strVal, str); gxfree(str); } item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; #else return DLMS_ERROR_CODE_INVALID_PARAMETER; #endif //DLMS_IGNORE_STRING_CONVERTER } case DLMS_DATA_TYPE_NONE: { item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } default: return DLMS_ERROR_CODE_NOT_IMPLEMENTED; } } else if (item->vt == DLMS_DATA_TYPE_STRING) { if (type == DLMS_DATA_TYPE_BOOLEAN) { item->boolVal = strcmp((char*)tmp.strVal->data, "False") == 0 ? 0 : 1; item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } else if (type == DLMS_DATA_TYPE_INT32) { item->lVal = hlp_stringToInt((char*)tmp.strVal->data); item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } else if (type == DLMS_DATA_TYPE_UINT32) { item->ulVal = hlp_stringToInt((char*)tmp.strVal->data) & 0xFFFFFFFF; item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } else if (type == DLMS_DATA_TYPE_INT8) { item->cVal = (char)hlp_stringToInt((char*)tmp.strVal->data); item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } else if (type == DLMS_DATA_TYPE_INT16) { item->iVal = (short)hlp_stringToInt((char*)tmp.strVal->data); item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } else if (type == DLMS_DATA_TYPE_UINT8) { item->bVal = (unsigned char)hlp_stringToInt((char*)tmp.strVal->data); item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } else if (type == DLMS_DATA_TYPE_UINT16) { item->uiVal = (uint16_t)hlp_stringToInt((char*)tmp.strVal->data); item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } else if (type == DLMS_DATA_TYPE_INT64) { item->llVal = hlp_stringToInt64((char*)tmp.strVal->data); item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } else if (type == DLMS_DATA_TYPE_UINT64) { item->ullVal = (uint64_t)hlp_stringToInt64((char*)tmp.strVal->data); item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } else if (type == DLMS_DATA_TYPE_ENUM) { item->bVal = (unsigned char)hlp_stringToInt((char*)tmp.strVal->data); item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } #if !defined(DLMS_IGNORE_FLOAT32) && !defined(DLMS_IGNORE_STRING_CONVERTER) else if (type == DLMS_DATA_TYPE_FLOAT32) { #if _MSC_VER > 1000 sscanf_s((char*)tmp.strVal->data, "%f", &item->fltVal); #else sscanf((char*)tmp.strVal->data, "%f", &item->fltVal); #endif item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } #endif //DLMS_IGNORE_FLOAT32 #if !defined(DLMS_IGNORE_FLOAT64) && !defined(DLMS_IGNORE_STRING_CONVERTER) else if (type == DLMS_DATA_TYPE_FLOAT64) { #if _MSC_VER > 1000 sscanf_s((char*)tmp.strVal->data, "%lf", &item->dblVal); #else sscanf((char*)tmp.strVal->data, "%lf", &item->dblVal); #endif item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } #endif //DLMS_IGNORE_FLOAT64 else if (type == DLMS_DATA_TYPE_OCTET_STRING) { char* pBuff = (char*)tmp.strVal->data; item->byteArr = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); BYTE_BUFFER_INIT(item->byteArr); bb_addHexString(item->byteArr, pBuff); item->vt = type; var_clear(&tmp); bb_trim(item->byteArr); return DLMS_ERROR_CODE_OK; } return DLMS_ERROR_CODE_NOT_IMPLEMENTED; } fromSize = var_getSize(tmp.vt); toSize = var_getSize(item->vt); //If we try to change bigger valut to smaller check that value is not too big. //Example Int16 to Int8. if (fromSize > toSize) { unsigned char* pValue = &tmp.bVal; for (pos = (unsigned char)toSize; pos != (unsigned char)fromSize; ++pos) { if (pValue[pos] != 0) { return DLMS_ERROR_CODE_INVALID_PARAMETER; } } } if (fromSize > toSize) { memcpy(&item->bVal, &tmp.bVal, toSize); } else { memset(&item->bVal, 0, toSize); memcpy(&item->bVal, &tmp.bVal, fromSize); } item->vt = type; var_clear(&tmp); return DLMS_ERROR_CODE_OK; } int var_changeType(dlmsVARIANT* value, DLMS_DATA_TYPE newType) { if (newType == value->vt) { return DLMS_ERROR_CODE_OK; } if (newType == DLMS_DATA_TYPE_NONE) { return var_clear(value); } if (value->vt == DLMS_DATA_TYPE_ARRAY && newType == DLMS_DATA_TYPE_OCTET_STRING) { return DLMS_ERROR_CODE_OK; } if (value->vt == DLMS_DATA_TYPE_STRING) { return convert(value, newType); } switch (newType) { case DLMS_DATA_TYPE_STRING: case DLMS_DATA_TYPE_BOOLEAN: case DLMS_DATA_TYPE_INT32: case DLMS_DATA_TYPE_UINT32: case DLMS_DATA_TYPE_INT8: case DLMS_DATA_TYPE_INT16: case DLMS_DATA_TYPE_UINT8: case DLMS_DATA_TYPE_UINT16: case DLMS_DATA_TYPE_INT64: case DLMS_DATA_TYPE_UINT64: case DLMS_DATA_TYPE_ENUM: #ifndef DLMS_IGNORE_FLOAT32 case DLMS_DATA_TYPE_FLOAT32: #endif //DLMS_IGNORE_FLOAT32 #ifndef DLMS_IGNORE_FLOAT64 case DLMS_DATA_TYPE_FLOAT64: #endif //DLMS_IGNORE_FLOAT64 return convert(value, newType); default: //Handled later. break; } switch (value->vt) { case DLMS_DATA_TYPE_BOOLEAN: return DLMS_ERROR_CODE_INVALID_PARAMETER; case DLMS_DATA_TYPE_BIT_STRING: { return DLMS_ERROR_CODE_INVALID_PARAMETER; } case DLMS_DATA_TYPE_INT32: switch (newType) { case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL: return DLMS_ERROR_CODE_NOT_IMPLEMENTED; default: return DLMS_ERROR_CODE_INVALID_PARAMETER; } case DLMS_DATA_TYPE_UINT32: switch (newType) { case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL: return DLMS_ERROR_CODE_NOT_IMPLEMENTED; default: return DLMS_ERROR_CODE_INVALID_PARAMETER; } case DLMS_DATA_TYPE_OCTET_STRING: switch (newType) { case DLMS_DATA_TYPE_DATETIME: return DLMS_ERROR_CODE_NOT_IMPLEMENTED; case DLMS_DATA_TYPE_DATE: return DLMS_ERROR_CODE_NOT_IMPLEMENTED; case DLMS_DATA_TYPE_TIME: return DLMS_ERROR_CODE_NOT_IMPLEMENTED; default: return DLMS_ERROR_CODE_INVALID_PARAMETER; } case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL: switch (newType) { case DLMS_DATA_TYPE_INT32: break; case DLMS_DATA_TYPE_UINT32: break; case DLMS_DATA_TYPE_STRING: break; case DLMS_DATA_TYPE_INT8: break; case DLMS_DATA_TYPE_INT16: break; case DLMS_DATA_TYPE_UINT8: break; case DLMS_DATA_TYPE_UINT16: break; case DLMS_DATA_TYPE_INT64: break; case DLMS_DATA_TYPE_UINT64: break; case DLMS_DATA_TYPE_ENUM: break; case DLMS_DATA_TYPE_FLOAT32: break; case DLMS_DATA_TYPE_FLOAT64: break; default: return DLMS_ERROR_CODE_INVALID_PARAMETER; } break; case DLMS_DATA_TYPE_INT8: switch (newType) { case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL: return DLMS_ERROR_CODE_NOT_IMPLEMENTED; default: return DLMS_ERROR_CODE_INVALID_PARAMETER; } case DLMS_DATA_TYPE_INT16: switch (newType) { case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL: return DLMS_ERROR_CODE_NOT_IMPLEMENTED; default: return DLMS_ERROR_CODE_INVALID_PARAMETER; } case DLMS_DATA_TYPE_UINT8: switch (newType) { case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL: return DLMS_ERROR_CODE_NOT_IMPLEMENTED; default: return DLMS_ERROR_CODE_INVALID_PARAMETER; } case DLMS_DATA_TYPE_UINT16: switch (newType) { case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL: return DLMS_ERROR_CODE_NOT_IMPLEMENTED; default: return DLMS_ERROR_CODE_INVALID_PARAMETER; } case DLMS_DATA_TYPE_INT64: switch (newType) { case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL: return DLMS_ERROR_CODE_NOT_IMPLEMENTED; default: return DLMS_ERROR_CODE_INVALID_PARAMETER; } case DLMS_DATA_TYPE_UINT64: switch (newType) { case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL: return DLMS_ERROR_CODE_NOT_IMPLEMENTED; default: return DLMS_ERROR_CODE_INVALID_PARAMETER; } case DLMS_DATA_TYPE_ENUM: switch (newType) { case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL: return DLMS_ERROR_CODE_NOT_IMPLEMENTED; default: return DLMS_ERROR_CODE_INVALID_PARAMETER; } case DLMS_DATA_TYPE_FLOAT32: switch (newType) { case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL: return DLMS_ERROR_CODE_NOT_IMPLEMENTED; default: return DLMS_ERROR_CODE_INVALID_PARAMETER; } case DLMS_DATA_TYPE_FLOAT64: switch (newType) { case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL: return DLMS_ERROR_CODE_NOT_IMPLEMENTED; default: return DLMS_ERROR_CODE_INVALID_PARAMETER; } case DLMS_DATA_TYPE_DATETIME: switch (newType) { case DLMS_DATA_TYPE_OCTET_STRING: break; case DLMS_DATA_TYPE_STRING: break; case DLMS_DATA_TYPE_DATE: break; case DLMS_DATA_TYPE_TIME: break; default: return DLMS_ERROR_CODE_INVALID_PARAMETER; } break; case DLMS_DATA_TYPE_DATE: switch (newType) { case DLMS_DATA_TYPE_OCTET_STRING: break; case DLMS_DATA_TYPE_STRING: break; case DLMS_DATA_TYPE_DATETIME: break; case DLMS_DATA_TYPE_DATE: break; case DLMS_DATA_TYPE_TIME: break; default: return DLMS_ERROR_CODE_INVALID_PARAMETER; } break; case DLMS_DATA_TYPE_TIME: switch (newType) { case DLMS_DATA_TYPE_OCTET_STRING: break; case DLMS_DATA_TYPE_STRING: break; case DLMS_DATA_TYPE_DATETIME: break; case DLMS_DATA_TYPE_DATE: break; case DLMS_DATA_TYPE_TIME: break; default: return DLMS_ERROR_CODE_INVALID_PARAMETER; } break; case DLMS_DATA_TYPE_ARRAY: case DLMS_DATA_TYPE_STRUCTURE: case DLMS_DATA_TYPE_COMPACT_ARRAY: default: return DLMS_ERROR_CODE_INVALID_PARAMETER; } return DLMS_ERROR_CODE_OK; } #endif //DLMS_IGNORE_MALLOC //copy variant. int var_copy(dlmsVARIANT* target, dlmsVARIANT* source) { #ifndef DLMS_IGNORE_MALLOC dlmsVARIANT* it; dlmsVARIANT* item; #endif //DLMS_IGNORE_MALLOC int ret = DLMS_ERROR_CODE_OK; if ((source->vt & DLMS_DATA_TYPE_BYREF) != 0) { if (source->vt == (DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_ARRAY) || source->vt == (DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_STRUCTURE)) { target->vt = source->vt & ~DLMS_DATA_TYPE_BYREF; target->pVal = source->pVal; return 0; } if (source->vt == (DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_OCTET_STRING) || source->vt == (DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_STRING) || source->vt == (DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_BIT_STRING) || source->vt == (DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_DATETIME) || source->vt == (DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_DATE) || source->vt == (DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_TIME)) { return var_getBytes2(source, source->vt, target->byteArr); } target->vt = source->vt & ~DLMS_DATA_TYPE_BYREF; target->ullVal = *source->pullVal; return 0; } if ((target->vt & DLMS_DATA_TYPE_BYREF) != 0) { uint16_t count; if (source->vt == DLMS_DATA_TYPE_OCTET_STRING || source->vt == DLMS_DATA_TYPE_STRING) { if ((ret = hlp_getObjectCount2(source->byteArr, &count)) != 0) { return ret; } #ifdef DLMS_IGNORE_MALLOC if (count > target->capacity) { return DLMS_ERROR_CODE_INVALID_PARAMETER; } target->size = count; #endif //DLMS_IGNORE_MALLOC memcpy(target->pVal, source->byteArr + source->byteArr->position, count); } else { count = (uint16_t)hlp_getDataTypeSize(source->vt); if (count != hlp_getDataTypeSize(target->vt ^ DLMS_DATA_TYPE_BYREF)) { return DLMS_ERROR_CODE_INVALID_PARAMETER; } memcpy(target->pVal, &source->bVal, count); } return 0; } #ifndef DLMS_IGNORE_MALLOC unsigned char attaced = 0; if ((target->vt == DLMS_DATA_TYPE_ARRAY || target->vt == DLMS_DATA_TYPE_STRUCTURE) && va_isAttached(target->Arr)) { attaced = 1; } else #endif //DLMS_IGNORE_MALLOC { ret = var_clear(target); if (ret != DLMS_ERROR_CODE_OK) { return ret; } target->vt = source->vt; } if (source->vt == DLMS_DATA_TYPE_STRING) { #ifndef DLMS_IGNORE_MALLOC if (source->strVal != NULL) { target->strVal = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); BYTE_BUFFER_INIT(target->strVal); bb_set(target->strVal, source->strVal->data, source->strVal->size); } #else return DLMS_ERROR_CODE_INVALID_PARAMETER; #endif //DLMS_IGNORE_MALLOC } else if (source->vt == DLMS_DATA_TYPE_OCTET_STRING) { #ifndef DLMS_IGNORE_MALLOC if (source->byteArr != 0) { target->byteArr = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); BYTE_BUFFER_INIT(target->byteArr); bb_set(target->byteArr, source->byteArr->data, source->byteArr->size); } #else return DLMS_ERROR_CODE_INVALID_PARAMETER; #endif //DLMS_IGNORE_MALLOC } else if (source->vt == DLMS_DATA_TYPE_ARRAY || source->vt == DLMS_DATA_TYPE_STRUCTURE) { #ifndef DLMS_IGNORE_MALLOC int pos; if (source->Arr != NULL && source->Arr->size != 0) { if (target->Arr == NULL) { target->Arr = (variantArray*)gxmalloc(sizeof(variantArray)); va_init(target->Arr); } va_capacity(target->Arr, source->Arr->size); for (pos = 0; pos != source->Arr->size; ++pos) { if ((ret = va_getByIndex(source->Arr, pos, &it)) != DLMS_ERROR_CODE_OK) { return ret; } if (attaced) { if ((ret = va_getByIndex(target->Arr, pos, &item)) != DLMS_ERROR_CODE_OK || (ret = var_copy(item, it)) != DLMS_ERROR_CODE_OK) { return ret; } } else { item = (dlmsVARIANT*)gxmalloc(sizeof(dlmsVARIANT)); ret = var_init(item); if (ret != DLMS_ERROR_CODE_OK) { return ret; } ret = var_copy(item, it); if (ret != DLMS_ERROR_CODE_OK) { return ret; } va_push(target->Arr, item); } } } #else return DLMS_ERROR_CODE_INVALID_PARAMETER; #endif //DLMS_IGNORE_MALLOC } #ifndef DLMS_IGNORE_MALLOC else if (source->vt == DLMS_DATA_TYPE_DATETIME) { ret = var_setDateTime(target, source->dateTime); } else if (source->vt == DLMS_DATA_TYPE_DATE) { ret = var_setDate(target, source->dateTime); } else if (source->vt == DLMS_DATA_TYPE_TIME) { ret = var_setTime(target, source->dateTime); } #endif //DLMS_IGNORE_MALLOC else if (source->vt == DLMS_DATA_TYPE_BIT_STRING) { #ifndef DLMS_IGNORE_MALLOC target->bitArr = (bitArray*)gxmalloc(sizeof(bitArray)); ba_init(target->bitArr); ret = ba_copy(target->bitArr, source->bitArr->data, (uint16_t)source->bitArr->size); #else return DLMS_ERROR_CODE_INVALID_PARAMETER; #endif //DLMS_IGNORE_MALLOC } else { ret = var_getSize(source->vt); if (ret > 0) { memcpy(&target->pVal, &source->pVal, ret); } ret = 0; } return ret; } #ifndef DLMS_IGNORE_MALLOC int var_setDateTime(dlmsVARIANT* target, gxtime* value) { int ret; if ((ret = var_clear(target)) == DLMS_ERROR_CODE_OK) { target->dateTime = (gxtime*)gxmalloc(sizeof(gxtime)); time_copy(target->dateTime, value); target->vt = DLMS_DATA_TYPE_DATETIME; } return ret; } int var_setDate(dlmsVARIANT* target, gxtime* value) { int ret; if ((ret = var_clear(target)) == DLMS_ERROR_CODE_OK) { target->dateTime = (gxtime*)gxmalloc(sizeof(gxtime)); time_copy(target->dateTime, value); target->vt = DLMS_DATA_TYPE_DATE; } return ret; } int var_setTime(dlmsVARIANT* target, gxtime* value) { int ret; if ((ret = var_clear(target)) == DLMS_ERROR_CODE_OK) { target->dateTime = (gxtime*)gxmalloc(sizeof(gxtime)); time_copy(target->dateTime, value); target->vt = DLMS_DATA_TYPE_TIME; } return ret; } int var_setDateTimeAsOctetString( dlmsVARIANT* target, gxtime* value) { int ret; if ((ret = var_clear(target)) == DLMS_ERROR_CODE_OK) { target->byteArr = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); BYTE_BUFFER_INIT(target->byteArr); bb_capacity(target->byteArr, 12); if ((ret = var_getDateTime2(value, target->byteArr)) == 0) { target->vt = DLMS_DATA_TYPE_OCTET_STRING; } } return ret; } int var_setDateAsOctetString( dlmsVARIANT* target, gxtime* value) { int ret; if ((ret = var_clear(target)) == DLMS_ERROR_CODE_OK) { target->byteArr = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); BYTE_BUFFER_INIT(target->byteArr); bb_capacity(target->byteArr, 5); if ((ret = var_getDate(value, target->byteArr)) == 0) { target->vt = DLMS_DATA_TYPE_OCTET_STRING; } } return ret; } int var_setTimeAsOctetString( dlmsVARIANT* target, gxtime* value) { int ret; if ((ret = var_clear(target)) == DLMS_ERROR_CODE_OK) { target->byteArr = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); BYTE_BUFFER_INIT(target->byteArr); bb_capacity(target->byteArr, 4); if ((ret = var_getTime(value, target->byteArr)) == 0) { target->vt = DLMS_DATA_TYPE_OCTET_STRING; } } return ret; } #endif //DLMS_IGNORE_MALLOC int var_setBoolean(dlmsVARIANT* target, char value) { int ret; if ((ret = var_clear(target)) == DLMS_ERROR_CODE_OK) { target->boolVal = value; target->vt = DLMS_DATA_TYPE_BOOLEAN; } return ret; } #ifdef DLMS_IGNORE_MALLOC //Attach value by ref. int var_byRef(dlmsVARIANT* target, DLMS_DATA_TYPE type, void* value) { int ret; ret = var_clear(target); if (ret != DLMS_ERROR_CODE_OK) { return ret; } target->pVal = value; target->vt = type | DLMS_DATA_TYPE_BYREF; return ret; } #endif //DLMS_IGNORE_MALLOC #ifndef DLMS_IGNORE_MALLOC void var_attach( dlmsVARIANT* target, gxByteBuffer* source) { target->byteArr = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); target->byteArr->data = source->data; target->byteArr->capacity = source->capacity; target->byteArr->size = source->size; target->byteArr->position = source->position; source->data = 0; source->size = source->position = source->capacity = 0; target->vt = DLMS_DATA_TYPE_OCTET_STRING; } #endif //DLMS_IGNORE_MALLOC int var_getDateTime(dlmsVARIANT* target, gxtime* value) { if (target->vt == DLMS_DATA_TYPE_NONE) { time_clear(value); } #ifndef DLMS_IGNORE_MALLOC else if (target->vt == DLMS_DATA_TYPE_DATETIME || target->vt == DLMS_DATA_TYPE_DATE || target->vt == DLMS_DATA_TYPE_TIME) { value->extraInfo = target->dateTime->extraInfo; value->skip = target->dateTime->skip; value->status = target->dateTime->status; value->value = target->dateTime->value; } #endif //DLMS_IGNORE_MALLOC else { return DLMS_ERROR_CODE_INVALID_PARAMETER; } return DLMS_ERROR_CODE_OK; } double var_toDouble(dlmsVARIANT* target) { switch (target->vt) { case DLMS_DATA_TYPE_NONE: { return 0; } case DLMS_DATA_TYPE_BOOLEAN: { return target->boolVal ? 1 : 0; } case DLMS_DATA_TYPE_INT32: { return target->lVal; } case DLMS_DATA_TYPE_UINT32: { return target->ulVal; } case DLMS_DATA_TYPE_STRING_UTF8: { #if defined(_WIN32) || defined(_WIN64) || defined(__linux__) assert(0); #endif return 0; } case DLMS_DATA_TYPE_STRING: { #if defined(_WIN32) || defined(_WIN64) || defined(__linux__) assert(0); #endif return 0; } case DLMS_DATA_TYPE_INT8: { return target->cVal; } case DLMS_DATA_TYPE_INT16: { return target->iVal; } case DLMS_DATA_TYPE_UINT8: { return target->bVal; } case DLMS_DATA_TYPE_UINT16: { return target->uiVal; } case DLMS_DATA_TYPE_INT64: { return (double)target->llVal; } case DLMS_DATA_TYPE_UINT64: { return (double)target->ullVal; } case DLMS_DATA_TYPE_ENUM: { return target->bVal; } #ifndef DLMS_IGNORE_FLOAT32 case DLMS_DATA_TYPE_FLOAT32: { return target->fltVal; } #endif //DLMS_IGNORE_FLOAT32 #ifndef DLMS_IGNORE_FLOAT64 case DLMS_DATA_TYPE_FLOAT64: { return target->dblVal; } #endif //DLMS_IGNORE_FLOAT64 default: break; } #if defined(_WIN32) || defined(_WIN64) || defined(__linux__) assert(0); #endif return 0; } #if !defined(DLMS_IGNORE_STRING_CONVERTER) && !defined(DLMS_IGNORE_MALLOC) //Print content of the variant to cout. int var_print(const char* format, dlmsVARIANT* target) { int ret = DLMS_ERROR_CODE_OK; dlmsVARIANT tmp; var_init(&tmp); ret = var_copy(&tmp, target); if (ret == 0) { ret = var_changeType(&tmp, DLMS_DATA_TYPE_STRING); if (ret == 0 && tmp.strVal != NULL) { if (format == NULL) { format = "%s\r\n"; } printf(format, tmp.strVal->data); } } var_clear(&tmp); return ret; } int va_print( variantArray* items) { dlmsVARIANT* it; int pos, ret = DLMS_ERROR_CODE_OK; const char* format = "%s,\r\n"; for (pos = 0; pos != items->size; ++pos) { if ((ret = va_getByIndex(items, pos, &it)) != 0) { return ret; } if (pos + 1 == items->size) { format = NULL; } if ((ret = var_print(format, it)) != 0) { return ret; } } return ret; } #endif //!defined(DLMS_IGNORE_STRING_CONVERTER) && defined(DLMS_IGNORE_MALLOC)