515 lines
14 KiB
C
515 lines
14 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 "gxignore.h"
|
|
#if defined(_WIN32) || defined(_WIN64) || defined(__linux__)
|
|
#include <assert.h>
|
|
#endif
|
|
#include "gxmem.h"
|
|
#if _MSC_VER > 1400
|
|
#include <crtdbg.h>
|
|
#endif
|
|
|
|
#include "notify.h"
|
|
#include "cosem.h"
|
|
#include "gxset.h"
|
|
#include "serverevents.h"
|
|
|
|
int notify_getData(
|
|
dlmsSettings* settings,
|
|
gxByteBuffer* reply,
|
|
gxReplyData* data)
|
|
{
|
|
return dlms_getData2(settings, reply, data, 0);
|
|
}
|
|
|
|
int notify_addData(
|
|
dlmsSettings* settings,
|
|
gxObject* obj,
|
|
unsigned char index,
|
|
gxByteBuffer* buff)
|
|
{
|
|
int ret;
|
|
gxValueEventArg e;
|
|
ve_init(&e);
|
|
e.target = obj;
|
|
e.index = index;
|
|
#ifdef DLMS_IGNORE_MALLOC
|
|
e.value.byteArr = buff;
|
|
e.value.vt = DLMS_DATA_TYPE_OCTET_STRING;
|
|
#endif //DLMS_IGNORE_MALLOC
|
|
if ((ret = cosem_getValue(settings, &e)) != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
if (e.byteArray)
|
|
{
|
|
if (!bb_isAttached(buff))
|
|
{
|
|
bb_set(buff, e.value.byteArr->data, e.value.byteArr->size);
|
|
var_clear(&e.value);
|
|
}
|
|
return 0;
|
|
}
|
|
ret = dlms_setData(buff, e.value.vt, &e.value);
|
|
var_clear(&e.value);
|
|
return ret;
|
|
}
|
|
|
|
int notify_generateDataNotificationMessages2(
|
|
dlmsSettings* settings,
|
|
#ifdef DLMS_USE_EPOCH_TIME
|
|
uint32_t time,
|
|
#else
|
|
struct tm* time,
|
|
#endif //DLMS_USE_EPOCH_TIME
|
|
gxByteBuffer* data,
|
|
message* messages)
|
|
{
|
|
int ret;
|
|
if (settings->useLogicalNameReferencing)
|
|
{
|
|
gxLNParameters p;
|
|
params_initLN(&p, settings, 0, DLMS_COMMAND_DATA_NOTIFICATION, 0, data, NULL, 0xff, DLMS_COMMAND_NONE, 0, 0);
|
|
p.time = time;
|
|
ret = dlms_getLnMessages(&p, messages);
|
|
}
|
|
else
|
|
{
|
|
#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC)
|
|
gxSNParameters p;
|
|
params_initSN(&p, settings, DLMS_COMMAND_DATA_NOTIFICATION, 1, 0, data, NULL, DLMS_COMMAND_NONE);
|
|
ret = dlms_getSnMessages(&p, messages);
|
|
#else
|
|
ret = DLMS_ERROR_CODE_INVALID_PARAMETER;
|
|
#endif //!defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC)
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int notify_generateDataNotificationMessages(
|
|
dlmsSettings* settings,
|
|
#ifdef DLMS_USE_EPOCH_TIME
|
|
uint32_t date,
|
|
#else
|
|
struct tm* date,
|
|
#endif //DLMS_USE_EPOCH_TIME
|
|
gxArray* objects,
|
|
message* messages)
|
|
{
|
|
int ret = 0;
|
|
uint16_t pos;
|
|
gxListItem* it;
|
|
gxByteBuffer buff;
|
|
BYTE_BUFFER_INIT(&buff);
|
|
bb_setUInt8(&buff, DLMS_DATA_TYPE_STRUCTURE);
|
|
hlp_setObjectCount(objects->size, &buff);
|
|
for (pos = 0; pos != objects->size; ++pos)
|
|
{
|
|
#ifdef DLMS_IGNORE_MALLOC
|
|
if ((ret = arr_getByIndex(objects, pos, (void**)&it, sizeof(gxListItem))) != 0)
|
|
{
|
|
break;
|
|
}
|
|
#else
|
|
if ((ret = arr_getByIndex(objects, pos, (void**)&it)) != 0)
|
|
{
|
|
break;
|
|
}
|
|
#endif //DLMS_IGNORE_MALLOC
|
|
|
|
if ((ret = notify_addData(settings, it->key, it->value, &buff)) != 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (ret == 0)
|
|
{
|
|
return notify_generateDataNotificationMessages2(settings, date, &buff, messages);
|
|
}
|
|
bb_clear(&buff);
|
|
return ret;
|
|
}
|
|
|
|
//Sends Event Notification Request.
|
|
int notify_generateEventNotificationMessages(
|
|
dlmsSettings* settings,
|
|
#ifdef DLMS_USE_EPOCH_TIME
|
|
uint32_t time,
|
|
#else
|
|
struct tm* time,
|
|
#endif //DLMS_USE_EPOCH_TIME
|
|
gxListItem* item,
|
|
variantArray* data,
|
|
gxByteBuffer* pdu,
|
|
message* messages)
|
|
{
|
|
int ret;
|
|
uint16_t pos;
|
|
dlmsVARIANT* it;
|
|
if ((ret = bb_setUInt16(pdu, item->key->objectType)) != 0 ||
|
|
(ret = bb_set(pdu, item->key->logicalName, 6)) != 0 ||
|
|
(ret = bb_setUInt8(pdu, item->value)) != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
if (data == NULL)
|
|
{
|
|
if ((ret = notify_addData(settings, item->key, item->value, pdu)) != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((ret = bb_setUInt8(pdu, DLMS_DATA_TYPE_ARRAY)) == 0 &&
|
|
(ret = hlp_setObjectCount(data->size, pdu)) == 0)
|
|
{
|
|
for (pos = 0; pos != data->size; ++pos)
|
|
{
|
|
if ((ret = va_getByIndex(data, pos, &it)) != 0 ||
|
|
(ret = dlms_setData(pdu, it->vt, it)) != 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (ret == 0)
|
|
{
|
|
gxLNParameters p;
|
|
params_initLN(&p, settings, 0, DLMS_COMMAND_EVENT_NOTIFICATION, 0, pdu, NULL, 0xff, DLMS_COMMAND_NONE, 0, 0);
|
|
p.time = time;
|
|
ret = dlms_getLnMessages(&p, messages);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
//Sends Event Notification Request.
|
|
int notify_generateEventNotificationMessages2(
|
|
dlmsSettings* settings,
|
|
#ifdef DLMS_USE_EPOCH_TIME
|
|
uint32_t time,
|
|
#else
|
|
struct tm* time,
|
|
#endif //DLMS_USE_EPOCH_TIME
|
|
gxListItem* item,
|
|
gxByteBuffer* data,
|
|
gxByteBuffer* pdu,
|
|
message* messages)
|
|
{
|
|
int ret;
|
|
if ((ret = bb_setUInt16(pdu, item->key->objectType)) != 0 ||
|
|
(ret = bb_set(pdu, item->key->logicalName, 6)) != 0 ||
|
|
(ret = bb_setUInt8(pdu, item->value)) != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
ret = bb_set2(pdu, data, data->position, bb_available(data));
|
|
if (ret == 0)
|
|
{
|
|
gxLNParameters p;
|
|
params_initLN(&p, settings, 0, DLMS_COMMAND_EVENT_NOTIFICATION, 0, pdu, NULL, 0xff, DLMS_COMMAND_NONE, 0, 0);
|
|
p.time = time;
|
|
ret = dlms_getLnMessages(&p, messages);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
#ifndef DLMS_IGNORE_PUSH_SETUP
|
|
|
|
int notify_generatePushSetupMessages(
|
|
dlmsSettings* settings,
|
|
#ifdef DLMS_USE_EPOCH_TIME
|
|
uint32_t date,
|
|
#else
|
|
struct tm* date,
|
|
#endif //DLMS_USE_EPOCH_TIME
|
|
gxPushSetup* push,
|
|
message* messages)
|
|
{
|
|
int ret = 0;
|
|
uint16_t pos;
|
|
gxByteBuffer pdu;
|
|
gxValueEventCollection args;
|
|
#ifdef DLMS_IGNORE_MALLOC
|
|
gxTarget* it;
|
|
pdu = *settings->serializedPdu;
|
|
gxValueEventArg p[1];
|
|
ve_init(&p[0]);
|
|
p[0].action = 1;
|
|
vec_attach(&args, p, 1, 1);
|
|
#else
|
|
gxValueEventArg e;
|
|
gxKey* it;
|
|
BYTE_BUFFER_INIT(&pdu);
|
|
ve_init(&e);
|
|
vec_init(&args);
|
|
vec_push(&args, &e);
|
|
#endif //DLMS_IGNORE_MALLOC
|
|
if (push == NULL || messages == NULL)
|
|
{
|
|
return DLMS_ERROR_CODE_INVALID_PARAMETER;
|
|
}
|
|
mes_clear(messages);
|
|
if ((ret = bb_setUInt8(&pdu, DLMS_DATA_TYPE_STRUCTURE)) == 0 &&
|
|
(ret = hlp_setObjectCount(push->pushObjectList.size, &pdu)) == 0)
|
|
{
|
|
for (pos = 0; pos != push->pushObjectList.size; ++pos)
|
|
{
|
|
#ifdef DLMS_IGNORE_MALLOC
|
|
if ((ret = arr_getByIndex(&push->pushObjectList, pos, (void**)&it, sizeof(gxTarget))) != 0)
|
|
{
|
|
break;
|
|
}
|
|
#else
|
|
if ((ret = arr_getByIndex(&push->pushObjectList, pos, (void**)&it)) != 0)
|
|
{
|
|
break;
|
|
}
|
|
#endif //DLMS_IGNORE_MALLOC
|
|
#ifdef DLMS_IGNORE_MALLOC
|
|
p[0].target = it->target;
|
|
p[0].index = it->attributeIndex;
|
|
svr_preRead(settings, &args);
|
|
if (p[0].error != 0)
|
|
{
|
|
break;
|
|
}
|
|
if ((ret = notify_addData(settings, it->target, it->attributeIndex, &pdu)) != 0)
|
|
{
|
|
break;
|
|
}
|
|
#else
|
|
e.target = (gxObject*)it->key;
|
|
e.index = ((gxTarget*)it->value)->attributeIndex;
|
|
#ifndef DLMS_IGNORE_SERVER
|
|
svr_preRead(settings, &args);
|
|
#endif
|
|
if (e.error != 0)
|
|
{
|
|
break;
|
|
}
|
|
if (e.value.vt != DLMS_DATA_TYPE_NONE)
|
|
{
|
|
ret = dlms_setData(&pdu, e.value.vt, &e.value);
|
|
var_clear(&e.value);
|
|
}
|
|
else
|
|
{
|
|
if ((ret = notify_addData(settings, (gxObject*)it->key, ((gxTarget*)it->value)->attributeIndex, &pdu)) != 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
#endif //DLMS_IGNORE_MALLOC
|
|
#ifndef DLMS_IGNORE_SERVER
|
|
svr_postRead(settings, &args);
|
|
#endif //DLMS_IGNORE_SERVER
|
|
#ifdef DLMS_IGNORE_MALLOC
|
|
ve_clear(&p[0]);
|
|
if (p[0].error != 0)
|
|
{
|
|
break;
|
|
}
|
|
#else
|
|
ve_clear(&e);
|
|
if (e.error != 0)
|
|
{
|
|
break;
|
|
}
|
|
#endif //DLMS_IGNORE_MALLOC
|
|
}
|
|
}
|
|
vec_empty(&args);
|
|
if (ret == 0)
|
|
{
|
|
#ifdef DLMS_IGNORE_MALLOC
|
|
//Update size and position
|
|
settings->serializedPdu->position = pdu.position;
|
|
settings->serializedPdu->size = pdu.size;
|
|
#endif //DLMS_IGNORE_MALLOC
|
|
ret = notify_generateDataNotificationMessages2(settings, date, &pdu, messages);
|
|
}
|
|
#ifndef DLMS_IGNORE_MALLOC
|
|
bb_clear(&pdu);
|
|
#endif //DLMS_IGNORE_MALLOC
|
|
return ret;
|
|
}
|
|
|
|
int notify_parsePush(
|
|
dlmsSettings* settings,
|
|
variantArray* data,
|
|
gxArray* items)
|
|
{
|
|
gxListItem* k;
|
|
gxObject* obj;
|
|
unsigned char index;
|
|
int classID, ret;
|
|
uint16_t pos;
|
|
gxValueEventArg e;
|
|
dlmsVARIANT* it, * list, * tmp;
|
|
if ((ret = va_getByIndex(data, 0, &list)) != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
for (pos = 0; pos != list->Arr->size; ++pos)
|
|
{
|
|
if ((ret = va_getByIndex(list->Arr, pos, &it)) != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
if ((ret = va_getByIndex(it->Arr, 0, &tmp)) != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
classID = var_toInteger(tmp) & 0xFFFF;
|
|
if (classID > 0)
|
|
{
|
|
if ((ret = va_getByIndex(it->Arr, 1, &tmp)) != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
if ((ret = oa_findByLN(&settings->objects, (DLMS_OBJECT_TYPE)classID, tmp->byteArr->data, &obj)) != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
if (obj == NULL)
|
|
{
|
|
#ifdef DLMS_IGNORE_MALLOC
|
|
return DLMS_ERROR_CODE_OUTOFMEMORY;
|
|
#else
|
|
if ((ret = cosem_createObject((DLMS_OBJECT_TYPE)classID, &obj)) != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
memcpy(obj->logicalName, tmp->byteArr, 6);
|
|
oa_push(&settings->objects, obj);
|
|
//Add object to released objects list.
|
|
ret = oa_push(&settings->releasedObjects, obj);
|
|
#endif //DLMS_IGNORE_MALLOC
|
|
}
|
|
#ifdef DLMS_IGNORE_MALLOC
|
|
return DLMS_ERROR_CODE_OUTOFMEMORY;
|
|
#else
|
|
if ((ret = va_getByIndex(it->Arr, 2, &tmp)) != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
index = (unsigned char)var_toInteger(tmp);
|
|
#if defined(_WIN64) || defined(__LP64__) || defined(_LP64)
|
|
arr_push(items, key_init(obj, (void*)(uint64_t)index));
|
|
#else
|
|
arr_push(items, key_init(obj, (void*)(uint32_t)index));
|
|
#endif //DLMS_IGNORE_MALLOC
|
|
|
|
#endif //DLMS_IGNORE_MALLOC
|
|
}
|
|
}
|
|
ve_init(&e);
|
|
for (pos = 0; pos != items->size; ++pos)
|
|
{
|
|
#ifdef DLMS_IGNORE_MALLOC
|
|
if ((ret = arr_getByIndex(items, pos, (void**)&k, sizeof(gxListItem))) != 0)
|
|
{
|
|
break;
|
|
}
|
|
#else
|
|
if ((ret = arr_getByIndex(items, pos, (void**)&k)) != 0)
|
|
{
|
|
break;
|
|
}
|
|
#endif //DLMS_IGNORE_MALLOC
|
|
|
|
obj = (gxObject*)k->key;
|
|
if ((ret = va_getByIndex(data, pos, &it)) != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
index = k->value;
|
|
e.target = obj;
|
|
e.index = index;
|
|
e.value = *it;
|
|
if ((ret = cosem_setValue(settings, &e)) != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
#if !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES)
|
|
int notify_getPushValues(
|
|
dlmsSettings* settings,
|
|
gxPushSetup* pushSetup,
|
|
variantArray* data,
|
|
gxArray* items)
|
|
{
|
|
gxObject* tmp;
|
|
gxKey* k;
|
|
int ret = 0;
|
|
uint16_t pos;
|
|
gxValueEventArg e;
|
|
dlmsVARIANT* it;
|
|
for (pos = 0; pos != pushSetup->pushObjectList.size; ++pos)
|
|
{
|
|
if ((ret = arr_getByIndex(&pushSetup->pushObjectList, pos, (void**)&k)) != 0)
|
|
{
|
|
break;
|
|
}
|
|
if ((ret = cosem_createObject(((gxObject*)k->key)->objectType, &tmp)) != 0)
|
|
{
|
|
break;
|
|
}
|
|
memcpy(tmp->logicalName, ((gxObject*)k->key)->logicalName, 6);
|
|
|
|
if ((ret = va_getByIndex(data, pos, &it)) != 0)
|
|
{
|
|
return ret;
|
|
}
|
|
e.target = (gxObject*)tmp;
|
|
e.index = ((gxTarget*)k->value)->attributeIndex;
|
|
e.value = *it;
|
|
if ((ret = cosem_setValue(settings, &e)) != 0)
|
|
{
|
|
break;
|
|
}
|
|
arr_push(items, key_init(e.target, co_init(e.index, 0)));
|
|
}
|
|
return ret;
|
|
}
|
|
#endif //!defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES)
|
|
|
|
#endif //DLMS_IGNORE_PUSH_SETUP
|