1187 lines
29 KiB
C
1187 lines
29 KiB
C
//
|
|
// --------------------------------------------------------------------------
|
|
// 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 _MSC_VER > 1400
|
|
#include <stdio.h>
|
|
#include <crtdbg.h>
|
|
#endif
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include "gxmem.h"
|
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
#include <windows.h>
|
|
#endif //defined(_WIN32) || defined(_WIN64)
|
|
|
|
#if !defined(DLMS_IGNORE_STRING_CONVERTER) && !defined(DLMS_IGNORE_MALLOC)
|
|
#include <stdio.h> //printf needs this or error is generated.
|
|
#endif //!defined(DLMS_IGNORE_STRING_CONVERTER) && !defined(DLMS_IGNORE_MALLOC)
|
|
|
|
#include "helpers.h"
|
|
#include "errorcodes.h"
|
|
|
|
//Check byte order.
|
|
unsigned char hlp_isBigEndian(void)
|
|
{
|
|
uint16_t a = 0x1234;
|
|
return *((unsigned char*)&a) == 0x12;
|
|
}
|
|
|
|
const char* hlp_getErrorMessage(int error)
|
|
{
|
|
const char* str;
|
|
if ((error & DLMS_ERROR_TYPE_EXCEPTION_RESPONSE) != 0)
|
|
{
|
|
switch (error & 0xFF)
|
|
{
|
|
case DLMS_EXCEPTION_SERVICE_ERROR_OPERATION_NOT_POSSIBLE:
|
|
str = GET_STR_FROM_EEPROM("OperationNotPossible");
|
|
break;
|
|
case DLMS_EXCEPTION_SERVICE_ERROR_SERVICE_NOT_SUPPORTED:
|
|
str = GET_STR_FROM_EEPROM("ServiceNotSupported");
|
|
break;
|
|
case DLMS_EXCEPTION_SERVICE_ERROR_OTHER_REASON:
|
|
str = GET_STR_FROM_EEPROM("OtherReason");
|
|
break;
|
|
case DLMS_EXCEPTION_SERVICE_ERROR_PDU_TOO_LONG:
|
|
str = GET_STR_FROM_EEPROM("PduTooLong");
|
|
break;
|
|
case DLMS_EXCEPTION_SERVICE_ERROR_DECIPHERING_ERROR:
|
|
str = GET_STR_FROM_EEPROM("DecipheringError");
|
|
break;
|
|
case DLMS_EXCEPTION_SERVICE_ERROR_INVOCATION_COUNTER_ERROR:
|
|
str = GET_STR_FROM_EEPROM("InvocationCounterError");
|
|
break;
|
|
default:
|
|
str = GET_STR_FROM_EEPROM("Unknown Exception response.");
|
|
break;
|
|
}
|
|
}
|
|
else if ((error & DLMS_ERROR_TYPE_CONFIRMED_SERVICE_ERROR) != 0)
|
|
{
|
|
str = GET_STR_FROM_EEPROM("Confirmed Service Error.");
|
|
}
|
|
else if ((error & DLMS_ERROR_TYPE_COMMUNICATION_ERROR) != 0)
|
|
{
|
|
#if defined(_WIN32) || defined(_WIN64) || defined(__linux__)
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
wchar_t* s = NULL;
|
|
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
NULL, error & ~DLMS_ERROR_TYPE_COMMUNICATION_ERROR,
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
(LPWSTR)&s, 0, NULL);
|
|
printf("%S\n", s);
|
|
LocalFree(s);
|
|
str = GET_STR_FROM_EEPROM("Connection error.");
|
|
#else
|
|
str = strerror(error & ~DLMS_ERROR_TYPE_COMMUNICATION_ERROR);
|
|
#endif
|
|
str = GET_STR_FROM_EEPROM("Connection error.");
|
|
#else
|
|
str = GET_STR_FROM_EEPROM("Connection error.");
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
switch (error)
|
|
{
|
|
case DLMS_ERROR_CODE_OK:
|
|
str = GET_STR_FROM_EEPROM("OK");
|
|
break;
|
|
case DLMS_ERROR_CODE_INVALID_PARAMETER:
|
|
str = GET_STR_FROM_EEPROM("Invalid parameter.");
|
|
break;
|
|
case DLMS_ERROR_CODE_NOT_INITIALIZED:
|
|
str = GET_STR_FROM_EEPROM("Server is not initialized.");
|
|
break;
|
|
case DLMS_ERROR_CODE_OUTOFMEMORY:
|
|
str = GET_STR_FROM_EEPROM("Not enough memory available.");
|
|
break;
|
|
case DLMS_ERROR_CODE_NOT_REPLY:
|
|
str = GET_STR_FROM_EEPROM("Packet is not a reply for a send packet.");
|
|
break;
|
|
case DLMS_ERROR_CODE_REJECTED:
|
|
str = GET_STR_FROM_EEPROM("Meter rejects send packet.");
|
|
break;
|
|
case DLMS_ERROR_CODE_INVALID_LOGICAL_NAME:
|
|
str = GET_STR_FROM_EEPROM("Invalid Logical Name.");
|
|
break;
|
|
case DLMS_ERROR_CODE_INVALID_CLIENT_ADDRESS:
|
|
str = GET_STR_FROM_EEPROM("Client HDLC Address is not set.");
|
|
break;
|
|
case DLMS_ERROR_CODE_INVALID_SERVER_ADDRESS:
|
|
str = GET_STR_FROM_EEPROM("Server HDLC Address is not set.");
|
|
break;
|
|
case DLMS_ERROR_CODE_INVALID_DATA_FORMAT:
|
|
str = GET_STR_FROM_EEPROM("Not a HDLC frame.");
|
|
break;
|
|
case DLMS_ERROR_CODE_INVALID_VERSION_NUMBER:
|
|
str = GET_STR_FROM_EEPROM("Invalid DLMS version number.");
|
|
break;
|
|
case DLMS_ERROR_CODE_CLIENT_ADDRESS_NO_NOT_MATCH:
|
|
str = GET_STR_FROM_EEPROM("Client addresses do not match.");
|
|
break;
|
|
case DLMS_ERROR_CODE_SERVER_ADDRESS_NO_NOT_MATCH:
|
|
str = GET_STR_FROM_EEPROM("Server addresses do not match.");
|
|
break;
|
|
case DLMS_ERROR_CODE_WRONG_CRC:
|
|
str = GET_STR_FROM_EEPROM("CRC do not match.");
|
|
break;
|
|
case DLMS_ERROR_CODE_INVALID_RESPONSE:
|
|
str = GET_STR_FROM_EEPROM("Invalid response");
|
|
break;
|
|
case DLMS_ERROR_CODE_INVALID_TAG:
|
|
str = GET_STR_FROM_EEPROM("Invalid Tag.");
|
|
break;
|
|
case DLMS_ERROR_CODE_ENCODING_FAILED:
|
|
str = GET_STR_FROM_EEPROM("Encoding failed. Not enough data.");
|
|
break;
|
|
case DLMS_ERROR_CODE_REJECTED_PERMAMENT:
|
|
str = GET_STR_FROM_EEPROM("Rejected permament.");
|
|
break;
|
|
case DLMS_ERROR_CODE_REJECTED_TRANSIENT:
|
|
str = GET_STR_FROM_EEPROM("Rejected transient.");
|
|
break;
|
|
case DLMS_ERROR_CODE_NO_REASON_GIVEN:
|
|
str = GET_STR_FROM_EEPROM("No reason given.");
|
|
break;
|
|
case DLMS_ERROR_CODE_APPLICATION_CONTEXT_NAME_NOT_SUPPORTED:
|
|
str = GET_STR_FROM_EEPROM("Application context name not supported.");
|
|
break;
|
|
case DLMS_ERROR_CODE_AUTHENTICATION_MECHANISM_NAME_NOT_RECOGNISED:
|
|
str = GET_STR_FROM_EEPROM("Authentication mechanism name not recognised.");
|
|
break;
|
|
case DLMS_ERROR_CODE_AUTHENTICATION_MECHANISM_NAME_REQUIRED:
|
|
str = GET_STR_FROM_EEPROM("Authentication mechanism name required.");
|
|
break;
|
|
case DLMS_ERROR_CODE_AUTHENTICATION_FAILURE:
|
|
str = GET_STR_FROM_EEPROM("Authentication failure.");
|
|
break;
|
|
case DLMS_ERROR_CODE_AUTHENTICATION_REQUIRED:
|
|
str = GET_STR_FROM_EEPROM("Authentication required.");
|
|
break;
|
|
case DLMS_ERROR_CODE_HARDWARE_FAULT:
|
|
str = GET_STR_FROM_EEPROM("Access Error : Device reports a hardware fault.");
|
|
break;
|
|
case DLMS_ERROR_CODE_TEMPORARY_FAILURE:
|
|
str = GET_STR_FROM_EEPROM("Access Error : Device reports a temporary failure.");
|
|
break;
|
|
case DLMS_ERROR_CODE_READ_WRITE_DENIED:
|
|
str = GET_STR_FROM_EEPROM("Access Error : Device reports Read-Write denied.");
|
|
break;
|
|
case DLMS_ERROR_CODE_UNDEFINED_OBJECT:
|
|
str = GET_STR_FROM_EEPROM("Access Error : Device reports a undefined object.");
|
|
break;
|
|
case DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT:
|
|
str = GET_STR_FROM_EEPROM("Access Error : Device reports a inconsistent Class or Object.");
|
|
break;
|
|
case DLMS_ERROR_CODE_UNAVAILABLE_OBJECT:
|
|
str = GET_STR_FROM_EEPROM("Access Error : Device reports a unavailable object.");
|
|
break;
|
|
case DLMS_ERROR_CODE_UNMATCH_TYPE:
|
|
str = GET_STR_FROM_EEPROM("Access Error : Device reports a unmatched type.");
|
|
break;
|
|
case DLMS_ERROR_CODE_ACCESS_VIOLATED:
|
|
str = GET_STR_FROM_EEPROM("Access Error : Device reports scope of access violated.");
|
|
break;
|
|
case DLMS_ERROR_CODE_DATA_BLOCK_UNAVAILABLE:
|
|
str = GET_STR_FROM_EEPROM("Access Error : Data Block Unavailable.");
|
|
break;
|
|
case DLMS_ERROR_CODE_LONG_GET_OR_READ_ABORTED:
|
|
str = GET_STR_FROM_EEPROM("Access Error : Long Get Or Read Aborted.");
|
|
break;
|
|
case DLMS_ERROR_CODE_NO_LONG_GET_OR_READ_IN_PROGRESS:
|
|
str = GET_STR_FROM_EEPROM("Access Error : No Long Get Or Read In Progress.");
|
|
break;
|
|
case DLMS_ERROR_CODE_LONG_SET_OR_WRITE_ABORTED:
|
|
str = GET_STR_FROM_EEPROM("Access Error : Long Set Or Write Aborted.");
|
|
break;
|
|
case DLMS_ERROR_CODE_NO_LONG_SET_OR_WRITE_IN_PROGRESS:
|
|
str = GET_STR_FROM_EEPROM("Access Error : No Long Set Or Write In Progress.");
|
|
break;
|
|
case DLMS_ERROR_CODE_DATA_BLOCK_NUMBER_INVALID:
|
|
str = GET_STR_FROM_EEPROM("Access Error : Data Block Number Invalid.");
|
|
break;
|
|
case DLMS_ERROR_CODE_OTHER_REASON:
|
|
str = GET_STR_FROM_EEPROM("Access Error : Other Reason.");
|
|
break;
|
|
case DLMS_ERROR_CODE_UNKNOWN:
|
|
str = GET_STR_FROM_EEPROM("Unknown error.");
|
|
break;
|
|
case DLMS_ERROR_CODE_SEND_FAILED:
|
|
str = GET_STR_FROM_EEPROM("Data send failed.");
|
|
break;
|
|
case DLMS_ERROR_CODE_RECEIVE_FAILED:
|
|
str = GET_STR_FROM_EEPROM("Data receive failed.");
|
|
break;
|
|
case DLMS_ERROR_CODE_NOT_IMPLEMENTED:
|
|
str = GET_STR_FROM_EEPROM("Not implemeted.");
|
|
break;
|
|
case DLMS_ERROR_CODE_INVALID_INVOKE_ID:
|
|
str = GET_STR_FROM_EEPROM("Invalid Invoke ID.");
|
|
break;
|
|
case DLMS_ERROR_CODE_INVOCATION_COUNTER_TOO_SMALL:
|
|
str = GET_STR_FROM_EEPROM("Invocation counter value is too small.");
|
|
break;
|
|
case DLMS_ERROR_CODE_INVALID_DECIPHERING_ERROR:
|
|
str = GET_STR_FROM_EEPROM("Deciphering error.");
|
|
break;
|
|
case DLMS_ERROR_CODE_INVALID_SECURITY_SUITE:
|
|
str = GET_STR_FROM_EEPROM("Client try to connect with wrong security suite.");
|
|
break;
|
|
default:
|
|
str = GET_STR_FROM_EEPROM("Unknown error.");
|
|
break;
|
|
}
|
|
}
|
|
return str;
|
|
}
|
|
|
|
unsigned char hlp_getObjectCountSizeInBytes(uint32_t count)
|
|
{
|
|
if (count < 0x80)
|
|
{
|
|
return 1;
|
|
}
|
|
else if (count < 0x100)
|
|
{
|
|
return 2;
|
|
}
|
|
else if (count < 0x10000)
|
|
{
|
|
return 3;
|
|
}
|
|
else
|
|
{
|
|
return 5;
|
|
}
|
|
}
|
|
|
|
int hlp_getObjectCount(gxByteBuffer* buff)
|
|
{
|
|
int ret;
|
|
unsigned char ch;
|
|
ret = bb_getUInt8(buff, &ch);
|
|
if (ret != 0)
|
|
{
|
|
return -1;
|
|
}
|
|
if (ch > 0x80)
|
|
{
|
|
if (ch == 0x81)
|
|
{
|
|
ret = bb_getUInt8(buff, &ch);
|
|
}
|
|
else if (ch == 0x82)
|
|
{
|
|
uint16_t value;
|
|
ret = bb_getUInt16(buff, &value);
|
|
if (ret != 0)
|
|
{
|
|
return -1;
|
|
}
|
|
return value;
|
|
}
|
|
else if (ch == 0x83)
|
|
{
|
|
uint32_t value;
|
|
ret = bb_getUInt24(buff, &value);
|
|
if (ret != 0)
|
|
{
|
|
return -1;
|
|
}
|
|
return value;
|
|
}
|
|
else if (ch == 0x84)
|
|
{
|
|
uint32_t value;
|
|
ret = bb_getUInt32(buff, &value);
|
|
if (ret != 0)
|
|
{
|
|
return -1;
|
|
}
|
|
return value;
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
return ch;
|
|
}
|
|
|
|
int hlp_getObjectCount2(gxByteBuffer* buff, uint16_t* count)
|
|
{
|
|
int ret;
|
|
unsigned char ch;
|
|
ret = bb_getUInt8(buff, &ch);
|
|
if (ret != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
if (ch > 0x80)
|
|
{
|
|
if (ch == 0x81)
|
|
{
|
|
ret = bb_getUInt8(buff, &ch);
|
|
*count = ch;
|
|
}
|
|
else if (ch == 0x82)
|
|
{
|
|
ret = bb_getUInt16(buff, count);
|
|
}
|
|
else if (ch == 0x83)
|
|
{
|
|
uint32_t value;
|
|
ret = bb_getUInt24(buff, &value);
|
|
*count = (uint16_t)value;
|
|
}
|
|
else if (ch == 0x84)
|
|
{
|
|
uint32_t value;
|
|
ret = bb_getUInt32(buff, &value);
|
|
*count = (uint16_t)value;
|
|
}
|
|
else
|
|
{
|
|
ret = DLMS_ERROR_CODE_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*count = ch;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// Set count of items.
|
|
int hlp_setObjectCount(uint32_t count, gxByteBuffer* buff)
|
|
{
|
|
int ret;
|
|
if (count < 0x80)
|
|
{
|
|
ret = bb_setUInt8(buff, (unsigned char)count);
|
|
}
|
|
else if (count < 0x100)
|
|
{
|
|
if ((ret = bb_setUInt8(buff, 0x81)) == 0)
|
|
{
|
|
ret = bb_setUInt8(buff, (unsigned char)count);
|
|
}
|
|
}
|
|
else if (count < 0x10000)
|
|
{
|
|
if ((ret = bb_setUInt8(buff, 0x82)) == 0)
|
|
{
|
|
ret = bb_setUInt16(buff, (uint16_t)count);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((ret = bb_setUInt8(buff, 0x84)) == 0)
|
|
{
|
|
ret = bb_setUInt32(buff, count);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
#ifndef DLMS_IGNORE_MALLOC
|
|
char* hlp_bytesToHex(const unsigned char* bytes, int count)
|
|
{
|
|
const char hexArray[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
|
|
unsigned char tmp;
|
|
int pos;
|
|
char* hexChars;
|
|
if (count != 0)
|
|
{
|
|
hexChars = (char*)gxmalloc(3 * count);
|
|
if (hexChars != NULL)
|
|
{
|
|
for (pos = 0; pos != count; ++pos)
|
|
{
|
|
tmp = bytes[pos] & 0xFF;
|
|
hexChars[pos * 3] = hexArray[tmp >> 4];
|
|
hexChars[pos * 3 + 1] = hexArray[tmp & 0x0F];
|
|
hexChars[pos * 3 + 2] = ' ';
|
|
}
|
|
hexChars[(3 * count) - 1] = '\0';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hexChars = (char*)gxmalloc(1);
|
|
hexChars[0] = '\0';
|
|
}
|
|
return hexChars;
|
|
}
|
|
#endif //DLMS_IGNORE_MALLOC
|
|
|
|
int hlp_bytesToHex2(const unsigned char* bytes, uint16_t count, char* buff, uint16_t size)
|
|
{
|
|
const char hexArray[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
|
|
unsigned char tmp;
|
|
int pos;
|
|
if (3 * count > size)
|
|
{
|
|
return DLMS_ERROR_CODE_INVALID_PARAMETER;
|
|
}
|
|
if (count != 0)
|
|
{
|
|
for (pos = 0; pos != count; ++pos)
|
|
{
|
|
tmp = bytes[pos] & 0xFF;
|
|
buff[pos * 3] = hexArray[tmp >> 4];
|
|
buff[pos * 3 + 1] = hexArray[tmp & 0x0F];
|
|
buff[pos * 3 + 2] = ' ';
|
|
}
|
|
buff[(3 * count) - 1] = '\0';
|
|
}
|
|
else
|
|
{
|
|
buff[0] = '\0';
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
unsigned char hlp_getValue(char c)
|
|
{
|
|
unsigned char value;
|
|
if (c > '9')
|
|
{
|
|
if (c > 'Z')
|
|
{
|
|
value = (c - 'a' + 10);
|
|
}
|
|
else
|
|
{
|
|
value = (c - 'A' + 10);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
value = (c - '0');
|
|
}
|
|
return value;
|
|
}
|
|
|
|
#ifndef DLMS_IGNORE_MALLOC
|
|
int hlp_hexToBytes(
|
|
const char* str,
|
|
unsigned char** buffer,
|
|
uint16_t* count)
|
|
{
|
|
*count = 0;
|
|
if (buffer != NULL && *buffer != NULL)
|
|
{
|
|
gxfree(*buffer);
|
|
}
|
|
if (str == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
int len = (int)strlen(str);
|
|
if (len == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
unsigned char* tmp = (unsigned char*)gxmalloc(len / 2);
|
|
if (tmp == NULL)
|
|
{
|
|
return DLMS_ERROR_CODE_OUTOFMEMORY;
|
|
}
|
|
*buffer = tmp;
|
|
int lastValue = -1;
|
|
for (int pos = 0; pos != len; ++pos)
|
|
{
|
|
if (*str >= '0' && *str < 'g')
|
|
{
|
|
if (lastValue == -1)
|
|
{
|
|
lastValue = hlp_getValue(*str);
|
|
}
|
|
else if (lastValue != -1)
|
|
{
|
|
tmp[*count] = (unsigned char)(lastValue << 4 | hlp_getValue(*str));
|
|
lastValue = -1;
|
|
++* count;
|
|
}
|
|
}
|
|
else if (lastValue != -1)
|
|
{
|
|
tmp[*count] = hlp_getValue(*str);
|
|
lastValue = -1;
|
|
++* count;
|
|
}
|
|
++str;
|
|
}
|
|
if (len / 2 != *count)
|
|
{
|
|
#ifdef gxrealloc
|
|
//If compiler supports realloc.
|
|
*buffer = gxrealloc(*buffer, *count);
|
|
#else
|
|
//A few extra bytes are returned if compiler doesn't support realloc.
|
|
#endif // gxrealloc
|
|
}
|
|
return 0;
|
|
}
|
|
#endif //DLMS_IGNORE_MALLOC
|
|
|
|
int hlp_hexToBytes2(
|
|
const char* str,
|
|
unsigned char* buffer,
|
|
uint16_t* count)
|
|
{
|
|
uint16_t max = *count;
|
|
*count = 0;
|
|
if (buffer == NULL)
|
|
{
|
|
return DLMS_ERROR_CODE_INVALID_PARAMETER;
|
|
}
|
|
if (str == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
int len = (int)strlen(str);
|
|
if (len == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
int lastValue = -1;
|
|
for (int pos = 0; pos != len; ++pos)
|
|
{
|
|
if (*str >= '0' && *str < 'g')
|
|
{
|
|
if (lastValue == -1)
|
|
{
|
|
lastValue = hlp_getValue(*str);
|
|
}
|
|
else if (lastValue != -1)
|
|
{
|
|
buffer[*count] = (unsigned char)(lastValue << 4 | hlp_getValue(*str));
|
|
lastValue = -1;
|
|
++* count;
|
|
}
|
|
}
|
|
else if (lastValue != -1)
|
|
{
|
|
buffer[*count] = hlp_getValue(*str);
|
|
lastValue = -1;
|
|
++* count;
|
|
}
|
|
if (max < *count)
|
|
{
|
|
return DLMS_ERROR_CODE_OUTOFMEMORY;
|
|
}
|
|
++str;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#if !defined(DLMS_IGNORE_STRING_CONVERTER) && !defined(DLMS_IGNORE_MALLOC)
|
|
void hlp_trace(unsigned char* data, int index, int count, unsigned char send)
|
|
{
|
|
char* buff = hlp_bytesToHex(data + index, count);
|
|
if (send)
|
|
{
|
|
printf("<- %s\r\n", buff);
|
|
}
|
|
else
|
|
{
|
|
printf("-> %s\r\n", buff);
|
|
}
|
|
gxfree(buff);
|
|
}
|
|
|
|
int hlp_parseLogicalName(gxByteBuffer* value, unsigned char ln[6])
|
|
{
|
|
char* ch;
|
|
char* pOriginalBuff;
|
|
char* pBuff;
|
|
int val = 0, count = 0, size = value->size;
|
|
if (size < 11)
|
|
{
|
|
return -1;
|
|
}
|
|
pBuff = (char*)gxmalloc(size + 1);
|
|
pOriginalBuff = pBuff;
|
|
memcpy(pBuff, value->data, size);
|
|
pBuff[value->size] = 0;
|
|
//AVR compiler can't handle this if casting to char* is removed.
|
|
while ((ch = (char*)strchr(pBuff, '.')) != NULL)
|
|
{
|
|
*ch = '\0';
|
|
val = hlp_stringToInt(pBuff);
|
|
if (val == -1)
|
|
{
|
|
return -1;
|
|
}
|
|
ln[count] = (unsigned char)val;
|
|
pBuff = ch + sizeof(char);
|
|
++count;
|
|
}
|
|
if (count == 5)
|
|
{
|
|
val = hlp_stringToInt(pBuff);
|
|
if (val == -1)
|
|
{
|
|
return -1;
|
|
}
|
|
ln[count] = (unsigned char)val;
|
|
pBuff = ch + sizeof(char);
|
|
++count;
|
|
}
|
|
gxfree(pOriginalBuff);
|
|
if (count != 6)
|
|
{
|
|
memset(ln, 0, 6);
|
|
return DLMS_ERROR_CODE_INVALID_PARAMETER;
|
|
}
|
|
return DLMS_ERROR_CODE_OK;
|
|
}
|
|
|
|
//Set logical name from string.
|
|
int hlp_setLogicalName2(dlmsVARIANT* ln, const char* name)
|
|
{
|
|
int ret;
|
|
unsigned char tmp[6];
|
|
var_clear(ln);
|
|
if ((ret = hlp_setLogicalName(tmp, name)) != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
var_addBytes(ln, tmp, 6);
|
|
return DLMS_ERROR_CODE_OK;
|
|
}
|
|
|
|
int hlp_printLogicalName(const char* format, const unsigned char value[6])
|
|
{
|
|
char ln[25];
|
|
int ret = hlp_getLogicalNameToString(value, ln);
|
|
if (ret != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
if (format != NULL)
|
|
{
|
|
printf(format, ln);
|
|
}
|
|
else
|
|
{
|
|
printf("%s", ln);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int hlp_appendLogicalName(gxByteBuffer* bb, const unsigned char value[6])
|
|
{
|
|
char ln[25];
|
|
int ret = hlp_getLogicalNameToString(value, ln);
|
|
if (ret != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
return bb_addString(bb, ln);
|
|
}
|
|
|
|
|
|
#endif //!defined(DLMS_IGNORE_STRING_CONVERTER) && !defined(DLMS_IGNORE_MALLOC)
|
|
|
|
int hlp_getLogicalNameToString(const unsigned char value[6], char* ln)
|
|
{
|
|
int ret;
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
#if _MSC_VER > 1000
|
|
ret = sprintf_s(ln, 25, "%d.%d.%d.%d.%d.%d", value[0], value[1], value[2], value[3], value[4], value[5]);
|
|
#else
|
|
ret = sprintf(ln, "%d.%d.%d.%d.%d.%d", value[0], value[1], value[2], value[3], value[4], value[5]);
|
|
#endif
|
|
if (ret != -1)
|
|
{
|
|
ret = 0;
|
|
}
|
|
#else
|
|
ret = hlp_intToString(ln, 25, value[0], 0, 1);
|
|
if (ret != -1)
|
|
{
|
|
ln += ret;
|
|
*ln = '.';
|
|
++ln;
|
|
ret = hlp_intToString(ln, 25, value[1], 0, 1);
|
|
if (ret != -1)
|
|
{
|
|
ln += ret;
|
|
*ln = '.';
|
|
++ln;
|
|
ret = hlp_intToString(ln, 25, value[2], 0, 1);
|
|
if (ret != -1)
|
|
{
|
|
ln += ret;
|
|
*ln = '.';
|
|
++ln;
|
|
ret = hlp_intToString(ln, 25, value[3], 0, 1);
|
|
if (ret != -1)
|
|
{
|
|
ln += ret;
|
|
*ln = '.';
|
|
++ln;
|
|
ret = hlp_intToString(ln, 25, value[4], 0, 1);
|
|
if (ret != -1)
|
|
{
|
|
ln += ret;
|
|
*ln = '.';
|
|
++ln;
|
|
ret = hlp_intToString(ln, 25, value[5], 0, 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (ret != -1)
|
|
{
|
|
ret = 0;
|
|
}
|
|
#endif //WIN32
|
|
return ret;
|
|
}
|
|
|
|
#if !defined(DLMS_IGNORE_MALLOC)
|
|
//Set logical name from string.
|
|
int hlp_setLogicalName(unsigned char ln[6], const char* name)
|
|
{
|
|
char* ch;
|
|
char* pOriginalBuff;
|
|
char* pBuff;
|
|
int val = 0, count = 0, size = (int)strlen(name);
|
|
if (size < 11)
|
|
{
|
|
return -1;
|
|
}
|
|
pBuff = (char*)gxmalloc(size + 1);
|
|
pOriginalBuff = pBuff;
|
|
memcpy(pBuff, name, size);
|
|
pBuff[size] = 0;
|
|
//AVR compiler can't handle this if casting to char* is removed.
|
|
while ((ch = (char*) strchr(pBuff, '.')) != NULL)
|
|
{
|
|
*ch = '\0';
|
|
val = hlp_stringToInt(pBuff);
|
|
if (val == -1)
|
|
{
|
|
gxfree(pOriginalBuff);
|
|
return -1;
|
|
}
|
|
ln[count] = (unsigned char)val;
|
|
pBuff = ch + sizeof(char);
|
|
++count;
|
|
}
|
|
if (count == 5)
|
|
{
|
|
val = hlp_stringToInt(pBuff);
|
|
if (val == -1)
|
|
{
|
|
gxfree(pOriginalBuff);
|
|
return -1;
|
|
}
|
|
ln[count] = (unsigned char)val;
|
|
pBuff = ch + sizeof(char);
|
|
++count;
|
|
}
|
|
gxfree(pOriginalBuff);
|
|
if (count != 6)
|
|
{
|
|
memset(ln, 0, 6);
|
|
return DLMS_ERROR_CODE_INVALID_PARAMETER;
|
|
}
|
|
return DLMS_ERROR_CODE_OK;
|
|
}
|
|
#endif //!defined(DLMS_IGNORE_MALLOC)
|
|
|
|
void hlp_replace(gxByteBuffer* str, char oldCh, char newCh)
|
|
{
|
|
uint32_t pos;
|
|
for (pos = 0; pos != str->size; ++pos)
|
|
{
|
|
if (str->data[pos] == oldCh)
|
|
{
|
|
str->data[pos] = newCh;
|
|
}
|
|
}
|
|
}
|
|
|
|
double hlp_getScaler(int scaler)
|
|
{
|
|
//If OS
|
|
#if defined(_WIN32) || defined(_WIN64) || defined(__linux__)
|
|
return pow((float)10, scaler);
|
|
#else
|
|
double ret = 1;
|
|
if (scaler > 0)
|
|
{
|
|
while (scaler--)
|
|
{
|
|
ret *= 10;
|
|
}
|
|
}
|
|
else if (scaler < 0)
|
|
{
|
|
while (scaler++)
|
|
{
|
|
ret /= 10;
|
|
}
|
|
}
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
int hlp_getDataTypeSize(DLMS_DATA_TYPE type)
|
|
{
|
|
int size = -1;
|
|
switch (type)
|
|
{
|
|
case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL:
|
|
size = 1;
|
|
break;
|
|
case DLMS_DATA_TYPE_BOOLEAN:
|
|
size = 1;
|
|
break;
|
|
case DLMS_DATA_TYPE_DATE:
|
|
size = 5;
|
|
break;
|
|
case DLMS_DATA_TYPE_DATETIME:
|
|
size = 12;
|
|
break;
|
|
case DLMS_DATA_TYPE_ENUM:
|
|
size = 1;
|
|
break;
|
|
#ifndef GX_DLMS_MICROCONTROLLER
|
|
case DLMS_DATA_TYPE_FLOAT32:
|
|
size = 4;
|
|
break;
|
|
case DLMS_DATA_TYPE_FLOAT64:
|
|
size = 8;
|
|
break;
|
|
#endif //GX_DLMS_MICROCONTROLLER
|
|
case DLMS_DATA_TYPE_INT16:
|
|
size = 2;
|
|
break;
|
|
case DLMS_DATA_TYPE_INT32:
|
|
size = 4;
|
|
break;
|
|
case DLMS_DATA_TYPE_INT64:
|
|
size = 8;
|
|
break;
|
|
case DLMS_DATA_TYPE_INT8:
|
|
size = 1;
|
|
break;
|
|
case DLMS_DATA_TYPE_NONE:
|
|
size = 0;
|
|
break;
|
|
case DLMS_DATA_TYPE_TIME:
|
|
size = 4;
|
|
break;
|
|
case DLMS_DATA_TYPE_UINT16:
|
|
size = 2;
|
|
break;
|
|
case DLMS_DATA_TYPE_UINT32:
|
|
size = 4;
|
|
break;
|
|
case DLMS_DATA_TYPE_UINT64:
|
|
size = 8;
|
|
break;
|
|
case DLMS_DATA_TYPE_UINT8:
|
|
size = 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
int hlp_intToString(char* str, int bufsize, int32_t value, unsigned char isSigned, unsigned char digits)
|
|
{
|
|
int cnt = 0;
|
|
int32_t val = value;
|
|
if (isSigned && value < 0)
|
|
{
|
|
if (bufsize < 1)
|
|
{
|
|
return -1;
|
|
}
|
|
*str = '-';
|
|
++str;
|
|
--bufsize;
|
|
value = -value;
|
|
val = value;
|
|
++cnt;
|
|
}
|
|
if (digits != 0)
|
|
{
|
|
--digits;
|
|
}
|
|
//Find length.
|
|
while ((val = (val / 10)) > 0)
|
|
{
|
|
++str;
|
|
if (digits != 0)
|
|
{
|
|
--digits;
|
|
}
|
|
}
|
|
*(str + digits + 1) = '\0';
|
|
while (digits != 0)
|
|
{
|
|
if (bufsize < 1)
|
|
{
|
|
return -1;
|
|
}
|
|
*str = '0';
|
|
--digits;
|
|
--bufsize;
|
|
++str;
|
|
++cnt;
|
|
}
|
|
do
|
|
{
|
|
if (bufsize < 1)
|
|
{
|
|
return -1;
|
|
}
|
|
*str = (value % 10) + '0';
|
|
value /= 10;
|
|
if (value != 0)
|
|
{
|
|
--str;
|
|
}
|
|
--bufsize;
|
|
++cnt;
|
|
} while (value != 0);
|
|
return cnt;
|
|
}
|
|
|
|
|
|
int hlp_uint64ToString(char* str, int bufsize, uint64_t value, unsigned char digits)
|
|
{
|
|
int cnt = 0;
|
|
uint64_t val = value;
|
|
if (digits != 0)
|
|
{
|
|
--digits;
|
|
}
|
|
//Find length.
|
|
while ((val = (val / 10)) > 0)
|
|
{
|
|
++str;
|
|
if (digits != 0)
|
|
{
|
|
--digits;
|
|
}
|
|
}
|
|
*(str + digits + 1) = '\0';
|
|
while (digits != 0)
|
|
{
|
|
if (bufsize < 1)
|
|
{
|
|
return -1;
|
|
}
|
|
*str = '0';
|
|
--digits;
|
|
--bufsize;
|
|
++str;
|
|
++cnt;
|
|
}
|
|
do
|
|
{
|
|
if (bufsize < 1)
|
|
{
|
|
return -1;
|
|
}
|
|
*str = (value % 10) + '0';
|
|
value /= 10;
|
|
if (value != 0)
|
|
{
|
|
--str;
|
|
}
|
|
--bufsize;
|
|
++cnt;
|
|
} while (value != 0);
|
|
return cnt;
|
|
}
|
|
|
|
int32_t hlp_stringToInt(const char* str)
|
|
{
|
|
if (str == NULL)
|
|
{
|
|
return -1;
|
|
}
|
|
int32_t value = 0;
|
|
unsigned char minus = 0;
|
|
if (*str == '-')
|
|
{
|
|
minus = 1;
|
|
++str;
|
|
}
|
|
while (*str != '\0')
|
|
{
|
|
if (*str < '0' || *str > '9')
|
|
{
|
|
return -1;
|
|
}
|
|
value *= 10;
|
|
value += *str - '0';
|
|
++str;
|
|
}
|
|
if (minus)
|
|
{
|
|
return -value;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
int hlp_int64ToString(char* str, int bufsize, int64_t value, unsigned char isSigned)
|
|
{
|
|
int cnt = 0;
|
|
int64_t val = value;
|
|
if (isSigned && value < 0)
|
|
{
|
|
if (bufsize < 1)
|
|
{
|
|
return -1;
|
|
}
|
|
*str = '-';
|
|
++str;
|
|
--bufsize;
|
|
value = -value;
|
|
++cnt;
|
|
}
|
|
//Find length.
|
|
while ((val = (val / 10)) > 0)
|
|
{
|
|
++str;
|
|
}
|
|
*(str + 1) = '\0';
|
|
do
|
|
{
|
|
if (bufsize < 1)
|
|
{
|
|
return -1;
|
|
}
|
|
*str = (value % 10) + '0';
|
|
--str;
|
|
value /= 10;
|
|
--bufsize;
|
|
++cnt;
|
|
} while (value != 0);
|
|
return cnt;
|
|
}
|
|
|
|
int64_t hlp_stringToInt64(const char* str)
|
|
{
|
|
if (str == NULL)
|
|
{
|
|
return -1;
|
|
}
|
|
int32_t value = 0;
|
|
unsigned char minus = 0;
|
|
if (*str == '-')
|
|
{
|
|
minus = 1;
|
|
++str;
|
|
}
|
|
while (*str != '\0')
|
|
{
|
|
if (*str < '0' || *str > '9')
|
|
{
|
|
return -1;
|
|
}
|
|
value *= 10;
|
|
value += *str - '0';
|
|
++str;
|
|
}
|
|
if (minus)
|
|
{
|
|
return -value;
|
|
}
|
|
return value;
|
|
}
|
|
uint16_t lfsr = 0xACE1u;
|
|
unsigned bit;
|
|
|
|
unsigned char hlp_rand(void)
|
|
{
|
|
bit = ((lfsr >> 0) ^ (lfsr >> 2) ^ (lfsr >> 3) ^ (lfsr >> 5)) & 1;
|
|
return (unsigned char)(lfsr = (uint16_t)((lfsr >> 1) | (bit << 15)));
|
|
}
|
|
|
|
unsigned char hlp_swapBits(unsigned char value)
|
|
{
|
|
unsigned char ret = 0, pos;
|
|
for (pos = 0; pos != 8; ++pos)
|
|
{
|
|
ret = (unsigned char)((ret << 1) | (value & 0x01));
|
|
value = (unsigned char)(value >> 1);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int hlp_add(bitArray* arr, gxByteBuffer* bytes, uint16_t count)
|
|
{
|
|
uint16_t pos, bytePos = 0;
|
|
int ret;
|
|
unsigned char ch = 0;
|
|
if (count == 0xFFFF)
|
|
{
|
|
count = (uint16_t)(bytes->size - bytes->position);
|
|
}
|
|
for (pos = 0; pos != count; ++pos)
|
|
{
|
|
//Get next byte.
|
|
if ((pos % 8) == 0)
|
|
{
|
|
bytePos = 7;
|
|
ret = bb_getUInt8ByIndex(bytes, bytes->position, &ch);
|
|
if (ret != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
++bytes->position;
|
|
}
|
|
if ((ret = ba_setByIndex(arr, pos, (unsigned char)(ch & (1 << bytePos)))) != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
--bytePos;
|
|
++arr->size;
|
|
}
|
|
return 0;
|
|
} |