345 lines
8.0 KiB
C
345 lines
8.0 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
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include "gxmem.h"
|
|
#if defined(_WIN32) || defined(_WIN64) || defined(__linux__)
|
|
#include <assert.h>
|
|
#endif
|
|
|
|
#if _MSC_VER > 1400
|
|
#include <crtdbg.h>
|
|
#endif
|
|
#include <string.h>
|
|
#include "errorcodes.h"
|
|
#include "bitarray.h"
|
|
#include "helpers.h"
|
|
|
|
//Returs needed amount of bytes to store bits.
|
|
uint16_t ba_getByteCount(uint16_t bitCount)
|
|
{
|
|
double d = bitCount;
|
|
if (bitCount != 0)
|
|
{
|
|
d /= 8;
|
|
if (bitCount == 0 || (bitCount % 8) != 0)
|
|
{
|
|
++d;
|
|
}
|
|
}
|
|
return (uint16_t)d;
|
|
}
|
|
|
|
//Return byte index where bit is saved.
|
|
int getByteIndex(int bitCount)
|
|
{
|
|
double d = bitCount;
|
|
d /= 8;
|
|
return (int)d;
|
|
}
|
|
|
|
//Initialize bit array.
|
|
void ba_init(bitArray* arr)
|
|
{
|
|
arr->capacity = 0;
|
|
arr->data = NULL;
|
|
#ifndef GX_DLMS_MICROCONTROLLER
|
|
arr->position = 0;
|
|
#endif //GX_DLMS_MICROCONTROLLER
|
|
arr->size = 0;
|
|
}
|
|
|
|
|
|
char ba_isAttached(bitArray* arr)
|
|
{
|
|
return (arr->capacity & 0x8000) == 0x8000;
|
|
}
|
|
|
|
uint16_t ba_getCapacity(bitArray* arr)
|
|
{
|
|
return arr->capacity & 0x7FFF;
|
|
}
|
|
|
|
uint16_t ba_size(bitArray* bb)
|
|
{
|
|
return bb != 0 ? bb->size : 0;
|
|
}
|
|
|
|
void ba_attach(
|
|
bitArray* arr,
|
|
unsigned char* value,
|
|
uint16_t count,
|
|
uint16_t capacity)
|
|
{
|
|
arr->data = value;
|
|
arr->capacity = (uint16_t)(0x8000 | capacity);
|
|
arr->size = count;
|
|
#ifndef GX_DLMS_MICROCONTROLLER
|
|
arr->position = 0;
|
|
#endif //GX_DLMS_MICROCONTROLLER
|
|
}
|
|
|
|
//Allocate new size for the array in bytes.
|
|
int ba_capacity(bitArray* arr, uint16_t capacity)
|
|
{
|
|
#ifndef DLMS_IGNORE_MALLOC
|
|
if (!ba_isAttached(arr))
|
|
{
|
|
arr->capacity = capacity;
|
|
if (capacity == 0)
|
|
{
|
|
if (arr->data != NULL)
|
|
{
|
|
gxfree(arr->data);
|
|
arr->data = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (arr->data == NULL)
|
|
{
|
|
arr->data = (unsigned char*)gxmalloc(ba_getByteCount(arr->capacity));
|
|
if (arr->data == NULL)
|
|
{
|
|
return DLMS_ERROR_CODE_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef gxrealloc
|
|
//If compiler supports realloc.
|
|
unsigned char* tmp = (unsigned char*)gxrealloc(arr->data, ba_getByteCount(arr->capacity));
|
|
//If not enought memory available.
|
|
if (tmp == NULL)
|
|
{
|
|
return DLMS_ERROR_CODE_OUTOFMEMORY;
|
|
}
|
|
arr->data = tmp;
|
|
#else
|
|
//If compiler doesn't support realloc.
|
|
unsigned char* old = arr->data;
|
|
arr->data = (unsigned char*)gxmalloc(ba_getByteCount(arr->capacity));
|
|
//If not enought memory available.
|
|
if (arr->data == NULL)
|
|
{
|
|
arr->data = old;
|
|
return DLMS_ERROR_CODE_OUTOFMEMORY;
|
|
}
|
|
memcpy(arr->data, old, ba_getByteCount(arr->size));
|
|
gxfree(old);
|
|
#endif // gxrealloc
|
|
}
|
|
}
|
|
}
|
|
#endif //DLMS_IGNORE_MALLOC
|
|
if (ba_getCapacity(arr) < capacity)
|
|
{
|
|
return DLMS_ERROR_CODE_OUTOFMEMORY;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//Push new data to the bit array.
|
|
int ba_set(bitArray* arr, unsigned char item)
|
|
{
|
|
int ret = ba_setByIndex(arr, arr->size, item);
|
|
if (ret == 0)
|
|
{
|
|
++arr->size;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
//Set bit by index.
|
|
int ba_setByIndex(bitArray* arr, uint16_t index, unsigned char item)
|
|
{
|
|
int ret;
|
|
unsigned char newItem = 0;
|
|
int byteIndex;
|
|
item = item == 0 ? 0 : 1;
|
|
if (!ba_isAttached(arr))
|
|
{
|
|
if (index >= arr->capacity)
|
|
{
|
|
if ((ret = ba_capacity(arr, arr->capacity + BIT_ARRAY_CAPACITY)) != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
//If we are adding a bit to the higher than next byte.
|
|
if (index >= arr->capacity)
|
|
{
|
|
return ba_setByIndex(arr, index, item);
|
|
}
|
|
newItem = 1;
|
|
}
|
|
}
|
|
if (index >= arr->capacity)
|
|
{
|
|
return DLMS_ERROR_CODE_OUTOFMEMORY;
|
|
}
|
|
byteIndex = getByteIndex(index);
|
|
if (index % 8 == 0 || newItem)
|
|
{
|
|
arr->data[byteIndex] = (unsigned char)(item << 7);
|
|
}
|
|
else
|
|
{
|
|
arr->data[byteIndex] |= (item << (7 - (index % 8)));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int ba_copy(
|
|
bitArray* target,
|
|
unsigned char* source,
|
|
uint16_t count)
|
|
{
|
|
int ret = 0;
|
|
ba_clear(target);
|
|
if (count != 0)
|
|
{
|
|
if ((ret = ba_capacity(target, count)) == 0)
|
|
{
|
|
memcpy(target->data, source, ba_getByteCount(count));
|
|
target->size = count;
|
|
#ifndef GX_DLMS_MICROCONTROLLER
|
|
target->position = 0;
|
|
#endif //GX_DLMS_MICROCONTROLLER
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void ba_clear(bitArray* arr)
|
|
{
|
|
#ifndef DLMS_IGNORE_MALLOC
|
|
if (!ba_isAttached(arr))
|
|
{
|
|
if (arr->data != NULL)
|
|
{
|
|
gxfree(arr->data);
|
|
arr->data = NULL;
|
|
}
|
|
arr->capacity = 0;
|
|
}
|
|
#endif //DLMS_IGNORE_MALLOC
|
|
arr->size = 0;
|
|
#ifndef GX_DLMS_MICROCONTROLLER
|
|
arr->position = 0;
|
|
#endif //GX_DLMS_MICROCONTROLLER
|
|
}
|
|
|
|
#ifndef GX_DLMS_MICROCONTROLLER
|
|
int ba_get(bitArray* arr, unsigned char* value)
|
|
{
|
|
int ret = ba_getByIndex(arr, arr->position, value);
|
|
if (ret == 0)
|
|
{
|
|
++arr->position;
|
|
}
|
|
return ret;
|
|
}
|
|
#endif //GX_DLMS_MICROCONTROLLER
|
|
|
|
int ba_getByIndex(bitArray* arr, int index, unsigned char* value)
|
|
{
|
|
char ch;
|
|
if (index >= arr->size)
|
|
{
|
|
return DLMS_ERROR_CODE_OUTOFMEMORY;
|
|
}
|
|
ch = arr->data[getByteIndex(index)];
|
|
*value = (ch & (1 << (7 - (index % 8)))) != 0;
|
|
return 0;
|
|
}
|
|
|
|
int ba_toInteger(bitArray* arr, uint32_t* value)
|
|
{
|
|
*value = 0;
|
|
unsigned char ch;
|
|
int pos, ret;
|
|
for (pos = 0; pos != arr->size; ++pos)
|
|
{
|
|
if ((ret = ba_getByIndex(arr, pos, &ch)) != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
*value |= ch << pos;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#ifndef DLMS_IGNORE_MALLOC
|
|
char* ba_toString(bitArray* arr)
|
|
{
|
|
unsigned char ch;
|
|
#if defined(_WIN32) || defined(_WIN64) || defined(__linux__)
|
|
int pos, ret;
|
|
#else
|
|
int pos;
|
|
#endif
|
|
char* buff = (char*)gxmalloc(arr->size + 1);
|
|
for (pos = 0; pos != arr->size; ++pos)
|
|
{
|
|
#if defined(_WIN32) || defined(_WIN64) || defined(__linux__)
|
|
ret = ba_getByIndex(arr, pos, &ch);
|
|
assert(ret == 0);
|
|
#else
|
|
ba_getByIndex(arr, pos, &ch);
|
|
#endif
|
|
buff[pos] = ch == 0 ? '0' : '1';
|
|
}
|
|
*(buff + arr->size) = 0;
|
|
return buff;
|
|
}
|
|
#endif //DLMS_IGNORE_MALLOC
|
|
|
|
int ba_toString2(
|
|
gxByteBuffer* bb,
|
|
bitArray* ba)
|
|
{
|
|
unsigned char ch;
|
|
int pos, ret = 0;
|
|
if ((ret = bb_capacity(bb, bb->size + ba->size)) == 0)
|
|
{
|
|
for (pos = 0; pos != ba->size; ++pos)
|
|
{
|
|
if ((ret = ba_getByIndex(ba, pos, &ch)) != 0 ||
|
|
(ret = bb_setInt8(bb, ch == 0 ? '0' : '1')) != 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|