commit 9c23deac0e817922c0f9dff1df62666e6fb7bf25 Author: Tomer27cz Date: Tue Nov 4 18:39:59 2025 +0100 Initial commit diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d8b4157 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +# Gitignore settings for ESPHome +# This is an example and may include too much for your use-case. +# You can modify this file to suit your needs. +/.esphome/ +/secrets.yaml diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0974205 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Tomer27cz + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..72bfd66 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# xt211 +ESPHome component for ČEZ Sagecom XT211 AMM diff --git a/components/xt211/ArduinoIgnore.h b/components/xt211/ArduinoIgnore.h new file mode 100644 index 0000000..849854b --- /dev/null +++ b/components/xt211/ArduinoIgnore.h @@ -0,0 +1,134 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- +#ifndef ARDUINO_IGNORE_H +#define ARDUINO_IGNORE_H + +#ifdef __cplusplus +extern "C" { +#endif + +//Use UTC time zone. Read more: https://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSClock +//#define DLMS_USE_UTC_TIME_ZONE + +/* Uncomment defines to ignore non-needed parts to make image size smaller. */ + +// #define DLMS_IGNORE_HDLC +// #define DLMS_IGNORE_WRAPPER +#define DLMS_IGNORE_PLC +#define DLMS_IGNORE_SERVER +#define GX_DLMS_MICROCONTROLLER +#define DLMS_IGNORE_HIGH_SHA256 +#define DLMS_IGNORE_HIGH_SHA1 +#define DLMS_IGNORE_HIGH_MD5 +// #define DLMS_IGNORE_AES +// #define DLMS_IGNORE_HIGH_GMAC +// #define DLMS_IGNORE_DATA +// #define DLMS_IGNORE_REGISTER +// #define DLMS_IGNORE_EXTENDED_REGISTER +// #define DLMS_IGNORE_DEMAND_REGISTER +// #define DLMS_IGNORE_REGISTER_ACTIVATION +// #define DLMS_IGNORE_PROFILE_GENERIC +// #define DLMS_IGNORE_CLOCK +// #define DLMS_IGNORE_SCRIPT_TABLE +// #define DLMS_IGNORE_SCHEDULE +// #define DLMS_IGNORE_SPECIAL_DAYS_TABLE +// #define DLMS_IGNORE_ASSOCIATION_SHORT_NAME +// #define DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME +// #define DLMS_IGNORE_SAP_ASSIGNMENT +// #define DLMS_IGNORE_IMAGE_TRANSFER +// #define DLMS_IGNORE_IEC_LOCAL_PORT_SETUP +// #define DLMS_IGNORE_ACTIVITY_CALENDAR +// #define DLMS_IGNORE_REGISTER_MONITOR +// #define DLMS_IGNORE_ACTION_SCHEDULE +// #define DLMS_IGNORE_IEC_HDLC_SETUP +// #define DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP +// #define DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP +// #define DLMS_IGNORE_UTILITY_TABLES +// #define DLMS_IGNORE_MODEM_CONFIGURATION +// #define DLMS_IGNORE_AUTO_ANSWER +// #define DLMS_IGNORE_AUTO_CONNECT +// #define DLMS_IGNORE_TCP_UDP_SETUP +// #define DLMS_IGNORE_IP4_SETUP +// #define DLMS_IGNORE_IP6_SETUP +// #define DLMS_IGNORE_MAC_ADDRESS_SETUP +// #define DLMS_IGNORE_PPP_SETUP +// #define DLMS_IGNORE_GPRS_SETUP +// #define DLMS_IGNORE_SMTP_SETUP +// #define DLMS_IGNORE_GSM_DIAGNOSTIC +// #define DLMS_IGNORE_REGISTER_TABLE +// #define DLMS_IGNORE_STATUS_MAPPING +// #define DLMS_IGNORE_SECURITY_SETUP +// #define DLMS_IGNORE_DISCONNECT_CONTROL +// #define DLMS_IGNORE_LIMITER +#define DLMS_IGNORE_MBUS_CLIENT +// #define DLMS_IGNORE_PUSH_SETUP +#define DLMS_IGNORE_PARAMETER_MONITOR +#define DLMS_IGNORE_WIRELESS_MODE_Q_CHANNEL +#define DLMS_IGNORE_MBUS_MASTER_PORT_SETUP +#define DLMS_IGNORE_ZIG_BEE_SAS_STARTUP +#define DLMS_IGNORE_ZIG_BEE_SAS_JOIN +#define DLMS_IGNORE_ZIG_BEE_SAS_APS_FRAGMENTATION +#define DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL +#define DLMS_IGNORE_DATA_PROTECTION +// #define DLMS_IGNORE_ACCOUNT +// #define DLMS_IGNORE_CREDIT +// #define DLMS_IGNORE_CHARGE +#define DLMS_IGNORE_TOKEN_GATEWAY +#define DLMS_IGNORE_COMPACT_DATA +#define DLMS_IGNORE_LLC_SSCS_SETUP +#define DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +#define DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +#define DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +#define DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +#define DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA +#define DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION +#define DLMS_IGNORE_ARBITRATOR +#define DLMS_IGNORE_SERIALIZER + +// #define DLMS_IGNORE_FLOAT32 +// #define DLMS_IGNORE_FLOAT64 + +// #define DLMS_ITALIAN_STANDARD + +////////////////////////////////////////////////////////////////////// +//Arduino client spesific settings. + +//Use EPOCH time. This can be used to improve memory usage. +#define DLMS_USE_EPOCH_TIME +#define DLMS_IGNORE_NOTIFY +#define DLMS_IGNORE_SERVER +#define DLMS_IGNORE_NOTIFY +#ifdef __cplusplus +} +#endif + +#endif //ARDUINO_IGNORE_H diff --git a/components/xt211/__init__.py b/components/xt211/__init__.py new file mode 100644 index 0000000..a11de1f --- /dev/null +++ b/components/xt211/__init__.py @@ -0,0 +1,73 @@ +import re +from esphome import pins +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import uart, binary_sensor +from esphome.const import ( + CONF_ID, + CONF_BAUD_RATE, + CONF_RECEIVE_TIMEOUT, +) + +DEPENDENCIES = ["uart"] + +DEFAULTS_BAUD_RATE_SESSION = 9600 +DEFAULTS_RECEIVE_TIMEOUT = "2000ms" + +CONF_XT211_ID = "xt211_id" +CONF_OBIS_CODE = "obis_code" +CONF_DONT_PUBLISH = "dont_publish" +CONF_CLASS = "class" + +CONF_PUSH_SHOW_LOG = "push_show_log" +CONF_PUSH_CUSTOM_PATTERN = "push_custom_pattern" + + +xt211_ns = cg.esphome_ns.namespace("xt211") +XT211 = xt211_ns.class_( + "XT211Component", cg.Component, uart.UARTDevice +) + +BAUD_RATES = [300, 600, 1200, 2400, 4800, 9600, 19200] + +def obis_code(value): + value = cv.string(value) + # match = re.match(r"^\d{1,3}-\d{1,3}:\d{1,3}\.\d{1,3}\.\d{1,3}$", value) + match = re.match(r"^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}\.\d{1,3}\.\d{1,3}$", value) + if match is None: + raise cv.Invalid(f"{value} is not a valid OBIS code") + return value + + +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(XT211), + cv.Optional(CONF_BAUD_RATE, default=DEFAULTS_BAUD_RATE_SESSION): cv.one_of( + *BAUD_RATES + ), + cv.Optional( + CONF_RECEIVE_TIMEOUT, default=DEFAULTS_RECEIVE_TIMEOUT + ): cv.positive_time_period_milliseconds, + cv.Optional(CONF_PUSH_SHOW_LOG, default=False): cv.boolean, + cv.Optional(CONF_PUSH_CUSTOM_PATTERN, default=""): cv.string, + } + ) + .extend(cv.COMPONENT_SCHEMA) + .extend(uart.UART_DEVICE_SCHEMA) +) + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) + + cg.add(var.set_baud_rate(config[CONF_BAUD_RATE])) + cg.add(var.set_receive_timeout_ms(config[CONF_RECEIVE_TIMEOUT])) + + cg.add(var.set_push_show_log(config[CONF_PUSH_SHOW_LOG])) + cg.add(var.set_push_custom_pattern_dsl(config[CONF_PUSH_CUSTOM_PATTERN])) + + cg.add_build_flag("-Wno-error=implicit-function-declaration") + # cg.add_library("GuruxDLMS", None, "https://github.com/latonita/GuruxDLMS.c#platformio") + # cg.add_library("GuruxDLMS", None, "https://github.com/Gurux/GuruxDLMS.c#platformio") \ No newline at end of file diff --git a/components/xt211/apdu.c b/components/xt211/apdu.c new file mode 100644 index 0000000..2e5efd6 --- /dev/null +++ b/components/xt211/apdu.c @@ -0,0 +1,2072 @@ +// +// -------------------------------------------------------------------------- +// 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" +#include "gxmem.h" +#include "enums.h" +#include "helpers.h" +#include "apdu.h" +#include "errorcodes.h" +#include "ciphering.h" +#include "serverevents.h" + +#ifndef DLMS_IGNORE_CLIENT +/** + * Retrieves the string that indicates the level of authentication, if any. + */ +int apdu_getAuthenticationString( + dlmsSettings* settings, + gxByteBuffer* data) +{ + int ret = 0; + gxByteBuffer* callingAuthenticationValue = NULL; + if (settings->authentication != DLMS_AUTHENTICATION_NONE +#ifndef DLMS_IGNORE_HIGH_GMAC + || settings->cipher.security != DLMS_SECURITY_NONE +#endif //DLMS_IGNORE_HIGH_GMAC + ) + { + unsigned char p[] = { 0x60, 0x85, 0x74, 0x05, 0x08, 0x02 }; + // Add sender ACSE-requirements field component. + if ((ret = bb_setUInt8(data, (uint16_t)BER_TYPE_CONTEXT | (char)PDU_TYPE_SENDER_ACSE_REQUIREMENTS)) != 0 || + (ret = bb_setUInt8(data, 2)) != 0 || + (ret = bb_setUInt8(data, BER_TYPE_BIT_STRING | BER_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(data, 0x80)) != 0 || + (ret = bb_setUInt8(data, (uint16_t)BER_TYPE_CONTEXT | (char)PDU_TYPE_MECHANISM_NAME)) != 0 || + // Len + (ret = bb_setUInt8(data, 7)) != 0 || + // OBJECT IDENTIFIER + (ret = bb_set(data, p, 6)) != 0 || + (ret = bb_setUInt8(data, settings->authentication)) != 0) + { + //Error code is returned at the end of the function. + } + } + // If authentication is used. + if (settings->authentication != DLMS_AUTHENTICATION_NONE) + { + // Add Calling authentication information. + if (settings->authentication == DLMS_AUTHENTICATION_LOW) + { + if (settings->password.size != 0) + { + callingAuthenticationValue = &settings->password; + } + } + else + { + callingAuthenticationValue = &settings->ctoSChallenge; + } + // 0xAC + if ((ret = bb_setUInt8(data, BER_TYPE_CONTEXT | BER_TYPE_CONSTRUCTED | PDU_TYPE_CALLING_AUTHENTICATION_VALUE)) == 0 && + // Len + (ret = bb_setUInt8(data, (unsigned char)(2 + bb_size(callingAuthenticationValue)))) == 0 && + // Add authentication information. + (ret = bb_setUInt8(data, BER_TYPE_CONTEXT)) == 0 && + // Len. + (ret = bb_setUInt8(data, (unsigned char)bb_size(callingAuthenticationValue))) == 0) + { + if (callingAuthenticationValue != NULL) + { + ret = bb_set(data, callingAuthenticationValue->data, bb_size(callingAuthenticationValue)); + } + } + } + return ret; +} +#endif //DLMS_IGNORE_CLIENT + +/** +* Code application context name. +* +* @param settings +* DLMS settings-> +* @param data +* Byte buffer where data is saved. +* @param cipher +* Is ciphering settings-> +*/ +int apdu_generateApplicationContextName( + dlmsSettings* settings, + gxByteBuffer* data) +{ + int ret; + //ProtocolVersion + if (settings->protocolVersion != 0) + { + if ((ret = bb_setUInt8(data, BER_TYPE_CONTEXT | PDU_TYPE_PROTOCOL_VERSION)) != 0 || + (ret = bb_setUInt8(data, 2)) != 0 || + //Un-used bits. + (ret = bb_setUInt8(data, 2)) != 0 || + (ret = bb_setUInt8(data, settings->protocolVersion)) != 0) + { + return ret; + } + } + unsigned char ciphered; +#ifndef DLMS_IGNORE_HIGH_GMAC + ciphered = isCiphered(&settings->cipher); +#else + ciphered = 0; +#endif //DLMS_IGNORE_HIGH_GMAC + + // Application context name tag + if ((ret = bb_setUInt8(data, (BER_TYPE_CONTEXT | BER_TYPE_CONSTRUCTED | PDU_TYPE_APPLICATION_CONTEXT_NAME))) != 0 || + // Len + (ret = bb_setUInt8(data, 0x09)) != 0 || + (ret = bb_setUInt8(data, BER_TYPE_OBJECT_IDENTIFIER)) != 0 || + // Len + (ret = bb_setUInt8(data, 0x07)) != 0 || + (ret = bb_setUInt8(data, 0x60)) != 0 || + (ret = bb_setUInt8(data, 0x85)) != 0 || + (ret = bb_setUInt8(data, 0x74)) != 0 || + (ret = bb_setUInt8(data, 0x05)) != 0 || + (ret = bb_setUInt8(data, 0x08)) != 0 || + (ret = bb_setUInt8(data, 0x01)) != 0) + { + return ret; + } + + if (settings->useLogicalNameReferencing) + { + if ((ret = bb_setUInt8(data, ciphered ? 0x03 : 0x01)) != 0) + { + return ret; + } + } + else + { + if ((ret = bb_setUInt8(data, ciphered ? 0x04 : 0x02)) != 0) + { + return ret; + } + } + // Add system title. +#ifndef DLMS_IGNORE_HIGH_GMAC + if (!settings->server && (ciphered || settings->authentication == DLMS_AUTHENTICATION_HIGH_GMAC)) + { +#ifndef DLMS_IGNORE_MALLOC + if (settings->cipher.systemTitle.size == 0) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } +#endif //DLMS_IGNORE_MALLOC + // Add calling-AP-title + if ((ret = bb_setUInt8(data, (BER_TYPE_CONTEXT | BER_TYPE_CONSTRUCTED | 6))) != 0 || + // LEN + (ret = bb_setUInt8(data, (unsigned char)(2 + 8))) != 0 || + (ret = bb_setUInt8(data, BER_TYPE_OCTET_STRING)) != 0 || + // LEN + (ret = bb_setUInt8(data, (unsigned char)8)) != 0 || +#ifndef DLMS_IGNORE_MALLOC + (ret = bb_set(data, settings->cipher.systemTitle.data, 8)) != 0) +#else + (ret = bb_set(data, settings->cipher.systemTitle, 8)) != 0) +#endif //DLMS_IGNORE_MALLOC + { + return ret; + } + } + //Add CallingAEInvocationId. + if (!settings->server && settings->userId != -1 && settings->cipher.security != DLMS_SECURITY_NONE) + { + if ((ret = bb_setUInt8(data, (BER_TYPE_CONTEXT | BER_TYPE_CONSTRUCTED | PDU_TYPE_CALLING_AE_INVOCATION_ID))) != 0 || + //LEN + (ret = bb_setUInt8(data, 3)) != 0 || + (ret = bb_setUInt8(data, BER_TYPE_INTEGER)) != 0 || + //LEN + (ret = bb_setUInt8(data, 1)) != 0 || + (ret = bb_setUInt8(data, (unsigned char)settings->userId)) != 0) + { + return ret; + } + } +#endif //DLMS_IGNORE_HIGH_GMAC + return 0; +} + +#ifndef DLMS_IGNORE_HIGH_GMAC +unsigned char useDedicatedKey(dlmsSettings* settings) +{ +#ifndef DLMS_IGNORE_MALLOC + if (settings->cipher.dedicatedKey == NULL) + { + return 0; + } + return settings->cipher.dedicatedKey->size == 16; +#else + return memcmp(settings->cipher.dedicatedKey, EMPTY_KEY, sizeof(EMPTY_KEY)) != 0; +#endif //DLMS_IGNORE_MALLOC +} +#endif //DLMS_IGNORE_HIGH_GMAC + +// Reserved for internal use. +int apdu_getConformanceFromArray(gxByteBuffer* data, uint32_t* value) +{ + int ret; + unsigned char v; + uint32_t tmp; + if ((ret = bb_getUInt8(data, &v)) == 0) + { + *value = hlp_swapBits(v); + if ((ret = bb_getUInt8(data, &v)) == 0) + { + tmp = hlp_swapBits(v); + tmp <<= 8; + *value |= tmp; + if ((ret = bb_getUInt8(data, &v)) == 0) + { + tmp = hlp_swapBits(v); + tmp <<= 16; + *value |= tmp; + } + } + } + return ret; +} + +// Reserved for internal use. +int apdu_setConformanceToArray(uint32_t value, gxByteBuffer* data) +{ + int ret; + if ((ret = bb_setUInt8(data, hlp_swapBits((unsigned char)(value & 0xFF)))) == 0) + { + value >>= 8; + if ((ret = bb_setUInt8(data, hlp_swapBits((unsigned char)(value & 0xFF)))) == 0) + { + value >>= 8; + ret = bb_setUInt8(data, hlp_swapBits((unsigned char)(value & 0xFF))); + } + } + return ret; +} + +/** + * Generate User information initiate request. + * + * @param settings + * DLMS settings-> + * @param cipher + * @param data + */ +int apdu_getInitiateRequest( + dlmsSettings* settings, + gxByteBuffer* data) +{ + int ret; + // Tag for xDLMS-Initiate request + bb_setUInt8(data, DLMS_COMMAND_INITIATE_REQUEST); + // Usage field for the response allowed component. + +#ifdef DLMS_IGNORE_HIGH_GMAC + bb_setUInt8(data, 0); +#else + // Usage field for dedicated-key component. + if (settings->cipher.security == DLMS_SECURITY_NONE || !useDedicatedKey(settings)) + { + bb_setUInt8(data, 0); + } + else + { + bb_setUInt8(data, 1); +#ifndef DLMS_IGNORE_MALLOC + hlp_setObjectCount(settings->cipher.dedicatedKey->size, data); + bb_set(data, settings->cipher.dedicatedKey->data, settings->cipher.dedicatedKey->size); +#else + hlp_setObjectCount(8, data); + bb_set(data, settings->cipher.dedicatedKey, 8); +#endif //DLMS_IGNORE_MALLOC + + } +#endif //DLMS_IGNORE_HIGH_GMAC + + // encoding of the response-allowed component (bool DEFAULT TRUE) + // usage flag (FALSE, default value TRUE conveyed) + bb_setUInt8(data, 0); + + // Usage field of the proposed-quality-of-service component. + if (settings->qualityOfService == 0) + { + // Not used + bb_setUInt8(data, 0x00); + } + else + { + bb_setUInt8(data, 0x01); + bb_setUInt8(data, settings->qualityOfService); + } + if ((ret = bb_setUInt8(data, settings->dlmsVersionNumber)) != 0 || + // Tag for conformance block + (ret = bb_setUInt8(data, 0x5F)) != 0 || + (ret = bb_setUInt8(data, 0x1F)) != 0 || + // length of the conformance block + (ret = bb_setUInt8(data, 0x04)) != 0 || + // encoding the number of unused bits in the bit string + (ret = bb_setUInt8(data, 0x00)) != 0 || + (ret = apdu_setConformanceToArray(settings->proposedConformance, data)) != 0 || + (ret = bb_setUInt16(data, settings->maxPduSize)) != 0) + { + return ret; + } + return 0; +} + +#ifndef DLMS_IGNORE_CLIENT +/** + * Generate user information. + * + * @param settings + * DLMS settings-> + * @param cipher + * @param data + * Generated user information. + */ +int apdu_generateUserInformation( + dlmsSettings* settings, + gxByteBuffer* data) +{ + int ret = 0; + bb_setUInt8(data, BER_TYPE_CONTEXT | BER_TYPE_CONSTRUCTED | PDU_TYPE_USER_INFORMATION); +#ifndef DLMS_IGNORE_HIGH_GMAC + if (!isCiphered(&settings->cipher)) +#endif //DLMS_IGNORE_HIGH_GMAC + { + // Length for AARQ user field + bb_setUInt8(data, 0x10); + // Coding the choice for user-information (Octet STRING, universal) + bb_setUInt8(data, BER_TYPE_OCTET_STRING); + // Length + bb_setUInt8(data, 0x0E); + if ((ret = apdu_getInitiateRequest(settings, data)) != 0) + { + return ret; + } + } +#ifndef DLMS_IGNORE_HIGH_GMAC + else + { + gxByteBuffer crypted; +#ifndef DLMS_IGNORE_MALLOC + BYTE_BUFFER_INIT(&crypted); +#else + unsigned char tmp[25 + 12]; + bb_attach(&crypted, tmp, 0, sizeof(tmp)); +#endif //DLMS_IGNORE_MALLOC + + if ((ret = apdu_getInitiateRequest(settings, &crypted)) != 0) + { + return ret; + } +#ifndef DLMS_IGNORE_MALLOC + ret = cip_encrypt( + &settings->cipher, + settings->cipher.security, + DLMS_COUNT_TYPE_PACKET, + settings->cipher.invocationCounter, + DLMS_COMMAND_GLO_INITIATE_REQUEST, + settings->cipher.systemTitle.data, + &settings->cipher.blockCipherKey, + &crypted); +#else + ret = cip_encrypt( + &settings->cipher, + settings->cipher.security, + DLMS_COUNT_TYPE_PACKET, + settings->cipher.invocationCounter, + DLMS_COMMAND_GLO_INITIATE_REQUEST, + settings->cipher.systemTitle, + settings->cipher.blockCipherKey, + &crypted); +#endif //DLMS_IGNORE_MALLOC + if (ret == 0) + { + // Length for AARQ user field + if ((ret = bb_setUInt8(data, (unsigned char)(2 + crypted.size))) != 0 || + // Coding the choice for user-information (Octet string, universal) + (ret = bb_setUInt8(data, BER_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(data, (unsigned char)crypted.size)) != 0 || + (ret = bb_set2(data, &crypted, 0, crypted.size)) != 0) + { + //Error code is returned at the end of the function. + } + } +#ifndef DLMS_IGNORE_MALLOC + bb_clear(&crypted); +#endif //DLMS_IGNORE_MALLOC + } +#endif //DLMS_IGNORE_HIGH_GMAC + return ret; +} +#endif //DLMS_IGNORE_CLIENT + +/** + * Parse User Information from PDU. + */ +int apdu_parseUserInformation( + dlmsSettings* settings, + gxByteBuffer* data, + unsigned char ciphered, + unsigned char* command) +{ + int ret; + unsigned char response; + uint16_t pduSize; + unsigned char ch, len, tag; + uint32_t v; + if ((ret = bb_getUInt8(data, &len)) != 0) + { + return ret; + } + if (data->size - data->position < len) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + // Encoding the choice for user information + if ((ret = bb_getUInt8(data, &tag)) != 0) + { + return ret; + } + if (tag != 0x4) + { + return DLMS_ERROR_CODE_INVALID_TAG; + } + if ((ret = bb_getUInt8(data, &len)) != 0) + { + return ret; + } + // Tag for xDLMS-Initate.response + if ((ret = bb_getUInt8(data, &tag)) != 0) + { + return ret; + } +#ifndef DLMS_IGNORE_HIGH_GMAC + DLMS_SECURITY security; + DLMS_SECURITY_SUITE suite; + uint64_t invocationCounter; + if (tag == DLMS_COMMAND_GLO_INITIATE_RESPONSE || + tag == DLMS_COMMAND_GLO_INITIATE_REQUEST || + tag == DLMS_COMMAND_DED_INITIATE_RESPONSE || + tag == DLMS_COMMAND_DED_INITIATE_REQUEST || + tag == DLMS_COMMAND_GENERAL_GLO_CIPHERING || + tag == DLMS_COMMAND_GENERAL_DED_CIPHERING) + { + *command = (unsigned char)tag; + data->position = (data->position - 1); +#ifndef DLMS_IGNORE_MALLOC + if ((ret = cip_decrypt(&settings->cipher, + settings->sourceSystemTitle, + &settings->cipher.blockCipherKey, + data, + &security, + &suite, + &invocationCounter)) != 0) + { + return ret; + } +#else + if ((ret = cip_decrypt(&settings->cipher, + settings->sourceSystemTitle, + settings->cipher.blockCipherKey, + data, + &security, + &suite, + &invocationCounter)) != 0) + { + return DLMS_ERROR_CODE_INVALID_DECIPHERING_ERROR; + } +#endif //DLMS_IGNORE_MALLOC + + if (settings->expectedSecurityPolicy != 0xFF && security != settings->expectedSecurityPolicy << 4) + { + return DLMS_ERROR_CODE_INVALID_DECIPHERING_ERROR; + } + if (settings->expectedSecuritySuite != 0xFF && suite != settings->expectedSecuritySuite) + { + return DLMS_ERROR_CODE_INVALID_SECURITY_SUITE; + } + if (settings->expectedInvocationCounter != NULL) + { + if (invocationCounter < 1 + *settings->expectedInvocationCounter) + { + return DLMS_ERROR_CODE_INVOCATION_COUNTER_TOO_SMALL; + } +#ifdef DLMS_COSEM_INVOCATION_COUNTER_SIZE64 + *settings->expectedInvocationCounter = 1 + invocationCounter; +#else + *settings->expectedInvocationCounter = (uint32_t)(1 + invocationCounter); +#endif //DLMS_COSEM_INVOCATION_COUNTER_SIZE64 + + } + //If client system title doesn't match. + if (settings->expectedClientSystemTitle != NULL && + memcmp(settings->expectedClientSystemTitle, EMPTY_SYSTEM_TITLE, 8) != 0 && + memcmp(settings->sourceSystemTitle, settings->expectedClientSystemTitle, 8) != 0) + { + return DLMS_ERROR_CODE_INVALID_DECIPHERING_ERROR; + } + + settings->cipher.security = security; + settings->cipher.suite = suite; + if ((ret = bb_getUInt8(data, &tag)) != 0) + { + return ret; + } + } +#endif //DLMS_IGNORE_HIGH_GMAC + response = tag == DLMS_COMMAND_INITIATE_RESPONSE; + if (response) + { + // Optional usage field of the negotiated quality of service + // component + if ((ret = bb_getUInt8(data, &tag)) != 0) + { + return ret; + } + if (tag != 0) + { + if ((ret = bb_getUInt8(data, &settings->qualityOfService)) != 0) + { + return ret; + } + } + } + else if (tag == DLMS_COMMAND_INITIATE_REQUEST) + { + // Optional usage field of the negotiated quality of service + // component + if ((ret = bb_getUInt8(data, &tag)) != 0) + { + return ret; + } + // Dedicated key. +#ifdef DLMS_IGNORE_HIGH_GMAC + +#else + if (tag != 0) + { + //Return error if ciphering is not used. + if (!ciphered || settings->cipher.security != DLMS_SECURITY_AUTHENTICATION_ENCRYPTION) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if ((ret = bb_getUInt8(data, &len)) != 0) + { + return ret; + } + if (len != 16) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } +#ifndef DLMS_IGNORE_MALLOC + if (settings->cipher.dedicatedKey == NULL) + { + settings->cipher.dedicatedKey = gxmalloc(sizeof(gxByteBuffer)); + BYTE_BUFFER_INIT(settings->cipher.dedicatedKey); + } + else + { + bb_clear(settings->cipher.dedicatedKey); + } + bb_set2(settings->cipher.dedicatedKey, data, data->position, len); +#else + hlp_setObjectCount(8, data); + bb_get(data, settings->cipher.dedicatedKey, len); +#endif //DLMS_IGNORE_MALLOC + } + else + { +#ifndef DLMS_IGNORE_MALLOC + if (settings->cipher.dedicatedKey != NULL) + { + bb_clear(settings->cipher.dedicatedKey); + gxfree(settings->cipher.dedicatedKey); + settings->cipher.dedicatedKey = NULL; + } +#else + memset(settings->cipher.dedicatedKey, 0, 8); +#endif //DLMS_IGNORE_MALLOC + } +#endif //DLMS_IGNORE_HIGH_GMAC + // Optional usage field of the negotiated quality of service + // component + if ((ret = bb_getUInt8(data, &tag)) != 0) + { + return ret; + } + // Skip if used. + if (tag != 0) + { + if ((ret = bb_getUInt8(data, &tag)) != 0) + { + return ret; + } + } + // Optional usage field of the proposed quality of service component + if ((ret = bb_getUInt8(data, &tag)) != 0) + { + return ret; + } + if (tag != 0) + { + if ((ret = bb_getUInt8(data, &settings->qualityOfService)) != 0) + { + return ret; + } + } + } + else + { + return DLMS_ERROR_CODE_INVALID_TAG; + } + // Get DLMS version number. + if (settings->server) + { + if ((ret = bb_getUInt8(data, &ch)) != 0) + { + return ret; + } + settings->dlmsVersionNumber = ch; + } + else + { + if ((ret = bb_getUInt8(data, &ch)) != 0) + { + return ret; + } + if (ch < 6) + { + //Invalid DLMS version number. + return DLMS_ERROR_CODE_INVALID_VERSION_NUMBER; + } + } + + // Tag for conformance block + if ((ret = bb_getUInt8(data, &tag)) != 0) + { + return ret; + } + if (tag != 0x5F) + { + return DLMS_ERROR_CODE_INVALID_TAG; + } + // Old Way... + tag = data->data[data->position]; + if (tag == 0x1F) + { + data->position = (data->position + 1); + } + if ((ret = bb_getUInt8(data, &len)) != 0) + { + return ret; + } + // The number of unused bits in the bit string. + if ((ret = bb_getUInt8(data, &tag)) != 0) + { + return ret; + } + if ((ret = apdu_getConformanceFromArray(data, &v)) != 0) + { + return ret; + } + if (settings->server) + { + settings->negotiatedConformance = (DLMS_CONFORMANCE)(v & settings->proposedConformance); + //Remove general protection if ciphered connection is not used. + if (!ciphered && (settings->negotiatedConformance & DLMS_CONFORMANCE_GENERAL_PROTECTION) != 0) + { + settings->negotiatedConformance &= ~DLMS_CONFORMANCE_GENERAL_PROTECTION; + } + } + else + { + settings->negotiatedConformance = (DLMS_CONFORMANCE)v; + } + if (settings->server) + { + if ((ret = bb_getUInt16(data, &pduSize)) != 0) + { + return ret; + } + //If client asks too high PDU. + if (pduSize > settings->maxServerPDUSize) + { + pduSize = settings->maxServerPDUSize; + } + settings->maxPduSize = pduSize; + } + else + { + if ((ret = bb_getUInt16(data, &pduSize)) != 0) + { + return ret; + } + settings->maxPduSize = pduSize; + } + if (response) + { + // VAA Name + uint16_t vaa; + if ((ret = bb_getUInt16(data, &vaa)) != 0) + { + return ret; + } + if (vaa == 0x0007) + { + // If LN + if (!settings->useLogicalNameReferencing) + { + //Invalid VAA. + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + } + else if (vaa == 0xFA00) + { + // If SN + if (settings->useLogicalNameReferencing) + { + //Invalid VAA. + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + } + else + { + // Unknown VAA. + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + } + return 0; +} + +/** + * Parse application context name. + * + * @param settings + * DLMS settings-> + * @param buff + * Received data-> + */ +int apdu_parseApplicationContextName( + dlmsSettings* settings, + gxByteBuffer* buff, + unsigned char* ciphered) +{ + int ret; + unsigned char len, ch; + // Get length. + if ((ret = bb_getUInt8(buff, &len)) != 0) + { + return ret; + } + if (buff->size - buff->position < len) + { + //Encoding failed. Not enough data-> + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + if (ch != 0x6) + { + //Encoding failed. Not an Object ID. + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } +#ifndef DLMS_IGNORE_HIGH_GMAC + if (settings->server) + { + settings->cipher.security = DLMS_SECURITY_NONE; + } +#endif //DLMS_IGNORE_HIGH_GMAC + // Object ID length. + if ((ret = bb_getUInt8(buff, &len)) != 0) + { + return ret; + } + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + if (ch != 0x60) + { + //Encoding failed. Not an Object ID. + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + if (ch != 0x85) + { + //Encoding failed. Not an Object ID. + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + if (ch != 0x74) + { + //Encoding failed. Not an Object ID. + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + if (ch != 0x05) + { + //Encoding failed. Not an Object ID. + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + if (ch != 0x08) + { + //Encoding failed. Not an Object ID. + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + if (ch != 0x01) + { + //Encoding failed. Not an Object ID. + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + if (settings->useLogicalNameReferencing) + { + *ciphered = ch == 3; + if (ch == 1 || *ciphered) + { + return 0; + } + return DLMS_ERROR_CODE_FALSE; + } + *ciphered = ch == 4; + if (ch == 2 || *ciphered) + { + return 0; + } + return DLMS_ERROR_CODE_FALSE; +} + +int apdu_validateAare( + dlmsSettings* settings, + gxByteBuffer* buff) +{ + int ret; + unsigned char tag; + if ((ret = bb_getUInt8(buff, &tag)) != 0) + { + return ret; + } + if (settings->server) + { + if (tag != (BER_TYPE_APPLICATION + | BER_TYPE_CONSTRUCTED + | PDU_TYPE_PROTOCOL_VERSION)) + { + ret = DLMS_ERROR_CODE_INVALID_TAG; + } + } + else + { + if (tag != (BER_TYPE_APPLICATION + | BER_TYPE_CONSTRUCTED + | PDU_TYPE_APPLICATION_CONTEXT_NAME)) + { + ret = DLMS_ERROR_CODE_INVALID_TAG; + } + } + return ret; +} + +int apdu_updatePassword( + dlmsSettings* settings, + gxByteBuffer* buff) +{ + int ret; + unsigned char ch, len; + if ((ret = bb_getUInt8(buff, &len)) == 0 && + // Get authentication information. + (ret = bb_getUInt8(buff, &ch)) == 0) + { + if (ch != 0x80) + { + ret = DLMS_ERROR_CODE_INVALID_TAG; + } + else if ((ret = bb_getUInt8(buff, &len)) == 0) + { + if (settings->authentication == DLMS_AUTHENTICATION_LOW) + { + if ((ret = bb_clear(&settings->password)) != 0 || + (ret = bb_set2(&settings->password, buff, buff->position, len)) != 0) + { + //Error code is returned at the end of the function. +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("updating password failed. "), ret); +#endif //DLMS_DEBUG + } + } + else + { + if (len < 8 || len > 64) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + else + { + if ((ret = bb_clear(&settings->ctoSChallenge)) != 0 || + (ret = bb_set2(&settings->ctoSChallenge, buff, buff->position, len)) != 0) + { + //Error code is returned at the end of the function. + } + } + } + } + } + return ret; +} + +int apdu_updateAuthentication( + dlmsSettings* settings, + gxByteBuffer* buff) +{ + int ret; + unsigned char ch; + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + if (ch != 0x60) + { + return DLMS_ERROR_CODE_INVALID_TAG; + } + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + if (ch != 0x85) + { + return DLMS_ERROR_CODE_INVALID_TAG; + } + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + if (ch != 0x74) + { + return DLMS_ERROR_CODE_INVALID_TAG; + } + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + if (ch != 0x05) + { + return DLMS_ERROR_CODE_INVALID_TAG; + } + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + if (ch != 0x08) + { + return DLMS_ERROR_CODE_INVALID_TAG; + } + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + if (ch != 0x02) + { + return DLMS_ERROR_CODE_INVALID_TAG; + } + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + switch (ch) + { + case DLMS_AUTHENTICATION_NONE: + case DLMS_AUTHENTICATION_LOW: + case DLMS_AUTHENTICATION_HIGH: +#ifndef DLMS_IGNORE_HIGH_MD5 + case DLMS_AUTHENTICATION_HIGH_MD5: +#endif //DLMS_IGNORE_HIGH_MD5 +#ifndef DLMS_IGNORE_HIGH_SHA1 + case DLMS_AUTHENTICATION_HIGH_SHA1: +#endif //DLMS_IGNORE_HIGH_SHA1 +#ifndef DLMS_IGNORE_HIGH_SHA256 + case DLMS_AUTHENTICATION_HIGH_SHA256: +#endif //DLMS_IGNORE_HIGH_SHA256 +#ifndef DLMS_IGNORE_HIGH_GMAC + case DLMS_AUTHENTICATION_HIGH_GMAC: +#endif //DLMS_IGNORE_HIGH_GMAC + break; + default: + return DLMS_ERROR_CODE_INVALID_TAG; + } + settings->authentication = (DLMS_AUTHENTICATION)ch; + return 0; +} + +int apdu_getUserInformation( + dlmsSettings* settings, + gxByteBuffer* data, + unsigned char command) +{ + int ret = 0; + // Tag for xDLMS-Initiate + if ((ret = bb_setUInt8(data, DLMS_COMMAND_INITIATE_RESPONSE)) != 0) + { + return ret; + } + //NegotiatedQualityOfService + if (settings->qualityOfService == 0) + { + // Not used. + if ((ret = bb_setUInt8(data, 0x00)) != 0) + { + return ret; + } + } + else + { + if ((ret = bb_setUInt8(data, 0x01)) != 0 || + (ret = bb_setUInt8(data, settings->qualityOfService)) != 0) + { + return ret; + } + } + // DLMS Version Number + if ((ret = bb_setUInt8(data, 06)) != 0 || + (ret = bb_setUInt8(data, 0x5F)) != 0 || + (ret = bb_setUInt8(data, 0x1F)) != 0 || + // length of the conformance block + (ret = bb_setUInt8(data, 0x04)) != 0 || + // encoding the number of unused bits in the bit string + (ret = bb_setUInt8(data, 0x00)) != 0 || + (ret = apdu_setConformanceToArray(settings->negotiatedConformance, data)) != 0 || + (ret = bb_setUInt16(data, settings->maxPduSize)) != 0) + { + return ret; + } + // VAA Name VAA name (0x0007 for LN referencing and 0xFA00 for SN) + if ((ret = bb_setUInt16(data, settings->useLogicalNameReferencing ? 0x0007 : 0xFA00)) != 0) + { + return ret; + } +#ifndef DLMS_IGNORE_HIGH_GMAC + if (isCiphered(&settings->cipher)) + { + unsigned char cmd; + if (command == DLMS_COMMAND_GENERAL_DED_CIPHERING) + { + cmd = DLMS_COMMAND_GENERAL_DED_CIPHERING; + } + else if (command == DLMS_COMMAND_GENERAL_GLO_CIPHERING) + { + cmd = DLMS_COMMAND_GENERAL_GLO_CIPHERING; + } + else + { + cmd = DLMS_COMMAND_GLO_INITIATE_RESPONSE; + } +#ifndef DLMS_IGNORE_MALLOC + ret = cip_encrypt(&settings->cipher, + settings->cipher.security, + DLMS_COUNT_TYPE_PACKET, + settings->cipher.invocationCounter, + cmd, + settings->cipher.systemTitle.data, + &settings->cipher.blockCipherKey, + data); +#else + ret = cip_encrypt(&settings->cipher, + settings->cipher.security, + DLMS_COUNT_TYPE_PACKET, + settings->cipher.invocationCounter, + cmd, + settings->cipher.systemTitle, + settings->cipher.blockCipherKey, + data); +#endif //DLMS_IGNORE_MALLOC + } +#endif //DLMS_IGNORE_HIGH_GMAC + return ret; +} +#ifndef DLMS_IGNORE_CLIENT +int apdu_generateAarq( + dlmsSettings* settings, + gxByteBuffer* data) +{ +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + uint32_t offset; +#else + uint16_t offset; +#endif + int ret; + // Length is updated later. + offset = data->size + 1; + // AARQ APDU Tag + if ((ret = bb_setUInt8(data, BER_TYPE_APPLICATION | BER_TYPE_CONSTRUCTED)) == 0 && + (ret = bb_setUInt8(data, 0)) == 0 && + /////////////////////////////////////////// + // Add Application context name. + (ret = apdu_generateApplicationContextName(settings, data)) == 0 && + (ret = apdu_getAuthenticationString(settings, data)) == 0 && + (ret = apdu_generateUserInformation(settings, data)) == 0) + { + return bb_setUInt8ByIndex(data, offset, (unsigned char)(data->size - offset - 1)); + } + return ret; +} +#endif //DLMS_IGNORE_CLIENT + +int apdu_handleResultComponent(unsigned char value) +{ + int ret; + switch (value) + { + case DLMS_SOURCE_DIAGNOSTIC_NO_REASON_GIVEN: + ret = DLMS_ERROR_CODE_NO_REASON_GIVEN; + break; + case DLMS_SOURCE_DIAGNOSTIC_APPLICATION_CONTEXT_NAME_NOT_SUPPORTED: + ret = DLMS_ERROR_CODE_APPLICATION_CONTEXT_NAME_NOT_SUPPORTED; + break; + case DLMS_SOURCE_DIAGNOSTIC_AUTHENTICATION_MECHANISM_NAME_NOT_RECOGNISED: + ret = DLMS_ERROR_CODE_AUTHENTICATION_MECHANISM_NAME_NOT_RECOGNISED; + break; + case DLMS_SOURCE_DIAGNOSTIC_AUTHENTICATION_MECHANISM_NAME_REQUIRED: + ret = DLMS_ERROR_CODE_AUTHENTICATION_MECHANISM_NAME_REQUIRED; + break; + case DLMS_SOURCE_DIAGNOSTIC_AUTHENTICATION_FAILURE: + ret = DLMS_ERROR_CODE_AUTHENTICATION_FAILURE; + break; + default: + //OK. + ret = 0; + break; + } + return ret; +} + +int apdu_parseProtocolVersion(dlmsSettings* settings, + gxByteBuffer* buff) +{ + unsigned char cnt, unusedBits, value; + int ret; + if ((ret = bb_getUInt8(buff, &cnt)) != 0) + { + return ret; + } + if ((ret = bb_getUInt8(buff, &unusedBits)) != 0) + { + return ret; + } + if (unusedBits > 8) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if ((ret = bb_getUInt8(buff, &value)) != 0) + { + return ret; + } + //Protocol version must be 100001. + //This is not checked in client side because some meters are returning wrong value here. + if (settings->server && value != 0x84) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + settings->protocolVersion = value; + return 0; +} + +int apdu_parsePDU( + dlmsSettings* settings, + gxByteBuffer* buff, + DLMS_ASSOCIATION_RESULT* result, + unsigned char* diagnostic, + unsigned char* command) +{ + unsigned char ciphered = 0; + uint16_t size; + unsigned char len; + unsigned char tag; + int ret; + *result = DLMS_ASSOCIATION_RESULT_ACCEPTED; + *diagnostic = DLMS_SOURCE_DIAGNOSTIC_NONE; +#ifndef DLMS_IGNORE_SERVER + typedef enum + { + DLMS_AFU_MISSING_NONE = 0x0, + DLMS_AFU_MISSING_SENDER_ACSE_REQUIREMENTS = 0x1, + DLMS_AFU_MISSING_MECHANISM_NAME = 0x2, + DLMS_AFU_MISSING_CALLING_AUTHENTICATION_VALUE = 0x4 + } + DLMS_AFU_MISSING; + DLMS_AFU_MISSING afu = DLMS_AFU_MISSING_NONE; +#endif //DLMS_IGNORE_SERVER + // Get AARE tag and length + if ((ret = apdu_validateAare(settings, buff)) != 0) + { + return ret; + } + if ((ret = hlp_getObjectCount2(buff, &size)) != 0) + { + return ret; + } + if (size > buff->size - buff->position) + { + //Encoding failed. Not enough data-> + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + while (ret == 0 && buff->position < buff->size) + { + if ((ret = bb_getUInt8(buff, &tag)) != 0) + { + break; + } + switch (tag) + { + //0xA1 + case BER_TYPE_CONTEXT | BER_TYPE_CONSTRUCTED | PDU_TYPE_APPLICATION_CONTEXT_NAME: + { + if ((ret = apdu_parseApplicationContextName(settings, buff, &ciphered)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("apdu_parseApplicationContextName "), ret); +#endif //DLMS_DEBUG + * diagnostic = DLMS_SOURCE_DIAGNOSTIC_APPLICATION_CONTEXT_NAME_NOT_SUPPORTED; + *result = DLMS_ASSOCIATION_RESULT_PERMANENT_REJECTED; + return 0; + } +#ifndef DLMS_IGNORE_SERVER + if (ciphered) + { + afu = (DLMS_AFU_MISSING)(DLMS_AFU_MISSING_SENDER_ACSE_REQUIREMENTS | DLMS_AFU_MISSING_MECHANISM_NAME | DLMS_AFU_MISSING_CALLING_AUTHENTICATION_VALUE); + } +#endif //DLMS_IGNORE_SERVER + } + break; + // 0xA2 + case BER_TYPE_CONTEXT | BER_TYPE_CONSTRUCTED | PDU_TYPE_CALLED_AP_TITLE: + // Get len. + if ((ret = bb_getUInt8(buff, &len)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid AP title "), -1); +#endif //DLMS_DEBUG + break; + } + if (len != 3) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid AP title "), -1); +#endif //DLMS_DEBUG + ret = DLMS_ERROR_CODE_INVALID_TAG; + break; + } + // Choice for result. + if ((ret = bb_getUInt8(buff, &tag)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid AP title "), -1); +#endif //DLMS_DEBUG + break; + } + if (settings->server) + { + //Ignore if client sends CalledAPTitle. + if (tag != BER_TYPE_OCTET_STRING) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid AP title "), -1); +#endif //DLMS_DEBUG + ret = DLMS_ERROR_CODE_INVALID_TAG; + break; + } + // Get len. + if ((ret = bb_getUInt8(buff, &len)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid AP title "), -1); +#endif //DLMS_DEBUG + break; + } + buff->position += len; + } + else + { + if (tag != BER_TYPE_INTEGER) + { + ret = DLMS_ERROR_CODE_INVALID_TAG; + break; + } + // Get len. + if ((ret = bb_getUInt8(buff, &len)) != 0) + { + break; + } + if (len != 1) + { + ret = DLMS_ERROR_CODE_INVALID_TAG; + break; + } + if ((ret = bb_getUInt8(buff, &tag)) != 0) + { + break; + } + *result = (DLMS_ASSOCIATION_RESULT)tag; + } + break; + // 0xA3 SourceDiagnostic + case BER_TYPE_CONTEXT | BER_TYPE_CONSTRUCTED | PDU_TYPE_CALLED_AE_QUALIFIER: + if ((ret = bb_getUInt8(buff, &len)) != 0 || + // ACSE service user tag. + (ret = bb_getUInt8(buff, &tag)) != 0 || + (ret = bb_getUInt8(buff, &len)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid AE qualifier. "), -1); +#endif //DLMS_DEBUG + break; + } + if (settings->server) + { + //Ignore if client sends CalledAEQualifier. + if (tag != BER_TYPE_OCTET_STRING) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid AE qualifier. "), -1); +#endif //DLMS_DEBUG + ret = DLMS_ERROR_CODE_INVALID_TAG; + break; + } + buff->position += len; + } + else + { + // Result source diagnostic component. + if ((ret = bb_getUInt8(buff, &tag)) != 0) + { + break; + } + if (tag != BER_TYPE_INTEGER) + { + ret = DLMS_ERROR_CODE_INVALID_TAG; + break; + } + if ((ret = bb_getUInt8(buff, &len)) != 0) + { + break; + } + if (len != 1) + { + ret = DLMS_ERROR_CODE_INVALID_TAG; + break; + } + if ((ret = bb_getUInt8(buff, &tag)) != 0) + { + break; + } + *diagnostic = (DLMS_SOURCE_DIAGNOSTIC)tag; + } + break; + // 0xA4 Result + case BER_TYPE_CONTEXT | BER_TYPE_CONSTRUCTED | PDU_TYPE_CALLED_AP_INVOCATION_ID: + // Get len. + if ((ret = bb_getUInt8(buff, &len)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid AP invocationID. "), -1); +#endif //DLMS_DEBUG + break; + } + if (settings->server) + { + if (len != 3) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid AP invocationID. "), -1); +#endif //DLMS_DEBUG + ret = DLMS_ERROR_CODE_INVALID_TAG; + break; + } + // ACSE service user tag. + if ((ret = bb_getUInt8(buff, &tag)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid AP invocationID. "), -1); +#endif //DLMS_DEBUG + break; + } + if (tag != BER_TYPE_INTEGER) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid AP invocationID. "), -1); +#endif //DLMS_DEBUG + ret = DLMS_ERROR_CODE_INVALID_TAG; + break; + } + if ((ret = bb_getUInt8(buff, &len)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid AP invocationID. "), -1); +#endif //DLMS_DEBUG + break; + } + //Ignore if client sends CalledAEQualifier. + buff->position += len; + } + else + { + if (len != 0xA) + { + ret = DLMS_ERROR_CODE_INVALID_TAG; + break; + } + // Choice for result (Universal, Octet string type) + if ((ret = bb_getUInt8(buff, &tag)) != 0) + { + break; + } + if (tag != BER_TYPE_OCTET_STRING) + { + ret = DLMS_ERROR_CODE_INVALID_TAG; + break; + } + // responding-AP-title-field + // Get len. + if ((ret = bb_getUInt8(buff, &len)) != 0) + { + break; + } + if ((ret = bb_get(buff, settings->sourceSystemTitle, len)) != 0) + { + break; + } + //If system title is invalid. + if (len != 8) + { + memset(settings->sourceSystemTitle, 0, 8); + } + } + break; + // 0xA6 Client system title. + case BER_TYPE_CONTEXT | BER_TYPE_CONSTRUCTED | PDU_TYPE_CALLING_AP_TITLE: + if ((ret = bb_getUInt8(buff, &len)) != 0 || + (ret = bb_getUInt8(buff, &tag)) != 0 || + (ret = bb_getUInt8(buff, &len)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid client system title. "), -1); +#endif //DLMS_DEBUG + break; + } + if (ciphered && len != 8) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid client system title. "), -1); +#endif //DLMS_DEBUG + * diagnostic = DLMS_SOURCE_DIAGNOSTIC_CALLING_AP_TITLE_NOT_RECOGNIZED; + *result = DLMS_ASSOCIATION_RESULT_PERMANENT_REJECTED; + return 0; + } + if ((ret = bb_get(buff, settings->sourceSystemTitle, len)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid client system title. "), -1); +#endif //DLMS_DEBUG + break; + } + break; + // 0xAA Server system title. + case BER_TYPE_CONTEXT | BER_TYPE_CONSTRUCTED | PDU_TYPE_SENDER_ACSE_REQUIREMENTS: + if ((ret = bb_getUInt8(buff, &len)) != 0 || + (ret = bb_getUInt8(buff, &tag)) != 0 || + (ret = bb_getUInt8(buff, &len)) != 0 || + (ret = bb_clear(&settings->stoCChallenge)) != 0 || + (ret = bb_set2(&settings->stoCChallenge, buff, buff->position, len)) != 0) + { + break; + } + break; + //Client AE Invocation id. + case BER_TYPE_CONTEXT | BER_TYPE_CONSTRUCTED | PDU_TYPE_CALLING_AE_INVOCATION_ID: + if ((ret = bb_getUInt8(buff, &len)) != 0 || + (ret = bb_getUInt8(buff, &tag)) != 0 || + (ret = bb_getUInt8(buff, &len)) != 0 || + (ret = bb_getUInt8(buff, &len)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid AE Invocation ID. "), -1); +#endif //DLMS_DEBUG + break; + } + break; + //Client CalledAeInvocationId. + case BER_TYPE_CONTEXT | BER_TYPE_CONSTRUCTED | PDU_TYPE_CALLED_AE_INVOCATION_ID://0xA5 + if (settings->server) + { + if ((ret = bb_getUInt8(buff, &len)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid AE Invocation ID. "), -1); +#endif //DLMS_DEBUG + break; + } + //Invalid length. + if (len != 3) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid AE Invocation ID. "), -1); +#endif //DLMS_DEBUG + ret = DLMS_ERROR_CODE_INVALID_TAG; + break; + } + if ((ret = bb_getUInt8(buff, &len)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid AE Invocation ID. "), -1); +#endif //DLMS_DEBUG + break; + } + //Invalid length. + if (len != 2) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid AE Invocation ID. "), -1); +#endif //DLMS_DEBUG + ret = DLMS_ERROR_CODE_INVALID_TAG; + break; + } + if ((ret = bb_getUInt8(buff, &len)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid AE Invocation ID. "), -1); +#endif //DLMS_DEBUG + break; + } + //Invalid tag length. + if (len != 1) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid AE Invocation ID. "), -1); +#endif //DLMS_DEBUG + ret = DLMS_ERROR_CODE_INVALID_TAG; + break; + } + //Get value. + if ((ret = bb_getUInt8(buff, &len)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid AE Invocation ID. "), -1); +#endif //DLMS_DEBUG + break; + } + } + else + { + if ((ret = bb_getUInt8(buff, &len)) != 0 || + (ret = bb_getUInt8(buff, &tag)) != 0 || + (ret = bb_getUInt8(buff, &len)) != 0 || + (ret = bb_getUInt8(buff, &len)) != 0) + { + break; + } + if (ciphered) + { + settings->userId = len; + } + } + break; + //Server RespondingAEInvocationId. + case BER_TYPE_CONTEXT | BER_TYPE_CONSTRUCTED | PDU_TYPE_CALLING_AE_QUALIFIER://0xA7 + if ((ret = bb_getUInt8(buff, &len)) != 0 || + (ret = bb_getUInt8(buff, &tag)) != 0 || + (ret = bb_getUInt8(buff, &len)) != 0 || + (ret = bb_getUInt8(buff, &len)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid Responding AE Invocation ID. "), -1); +#endif //DLMS_DEBUG + break; + } + if (ciphered && len == 0) + { + settings->userId = len; + } + break; + case BER_TYPE_CONTEXT | BER_TYPE_CONSTRUCTED | PDU_TYPE_CALLING_AP_INVOCATION_ID://0xA8 + if ((ret = bb_getUInt8(buff, &tag)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid Calling AP Invocation ID. "), -1); +#endif //DLMS_DEBUG + break; + } + if (tag != 3) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid Calling AP Invocation ID. "), -1); +#endif //DLMS_DEBUG + ret = DLMS_ERROR_CODE_INVALID_TAG; + break; + } + if ((ret = bb_getUInt8(buff, &len)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid Calling AP Invocation ID. "), -1); +#endif //DLMS_DEBUG + break; + } + if (len != 2) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid Calling AP Invocation ID. "), -1); +#endif //DLMS_DEBUG + ret = DLMS_ERROR_CODE_INVALID_TAG; + break; + } + //Invalid tag length. + if ((ret = bb_getUInt8(buff, &len)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid Calling AP Invocation ID. "), -1); +#endif //DLMS_DEBUG + return ret; + } + if (len != 1) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid Calling AP Invocation ID. "), -1); +#endif //DLMS_DEBUG + ret = DLMS_ERROR_CODE_INVALID_TAG; + break; + } + //Get value. + if ((ret = bb_getUInt8(buff, &len)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid Calling AP Invocation ID. "), -1); +#endif //DLMS_DEBUG + break; + } + break; + // 0x8A or 0x88 + case (uint16_t)BER_TYPE_CONTEXT | (unsigned char)PDU_TYPE_SENDER_ACSE_REQUIREMENTS: + case (uint16_t)BER_TYPE_CONTEXT | (unsigned char)PDU_TYPE_CALLING_AP_INVOCATION_ID: + // Get sender ACSE-requirements field component. + if ((ret = bb_getUInt8(buff, &len)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid sender ACSE-requirements field. "), -1); +#endif //DLMS_DEBUG + break; + } + if (len != 2) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid sender ACSE-requirements field. "), -1); +#endif //DLMS_DEBUG + ret = DLMS_ERROR_CODE_INVALID_TAG; + break; + } + if ((ret = bb_getUInt8(buff, &tag)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid sender ACSE-requirements field. "), -1); +#endif //DLMS_DEBUG + break; + } + if (tag != BER_TYPE_OBJECT_DESCRIPTOR) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid sender ACSE-requirements field. "), -1); +#endif //DLMS_DEBUG + ret = DLMS_ERROR_CODE_INVALID_TAG; + break; + } + //Get only value because client app is sending system title with LOW authentication. + if ((ret = bb_getUInt8(buff, &tag)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid sender ACSE-requirements field. "), -1); +#endif //DLMS_DEBUG + break; + } +#ifndef DLMS_IGNORE_SERVER + if (ciphered && tag == 0x80) + { + afu &= ~DLMS_AFU_MISSING_SENDER_ACSE_REQUIREMENTS; + } +#endif //DLMS_IGNORE_SERVER + break; + // 0x8B or 0x89 + case (uint16_t)BER_TYPE_CONTEXT | (unsigned char)PDU_TYPE_MECHANISM_NAME: + case (uint16_t)BER_TYPE_CONTEXT | (unsigned char)PDU_TYPE_CALLING_AE_INVOCATION_ID: + if ((ret = apdu_updateAuthentication(settings, buff)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid mechanism name. "), ret); +#endif //DLMS_DEBUG + break; + } +#ifndef DLMS_IGNORE_HIGH_GMAC + unsigned char invalidSystemTitle; + invalidSystemTitle = memcmp(settings->sourceSystemTitle, EMPTY_SYSTEM_TITLE, 8) == 0; + if (settings->server && settings->authentication == DLMS_AUTHENTICATION_HIGH_GMAC && invalidSystemTitle) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid mechanism name. "), -1); +#endif //DLMS_DEBUG + * diagnostic = DLMS_SOURCE_DIAGNOSTIC_CALLING_AP_TITLE_NOT_RECOGNIZED; + *result = DLMS_ASSOCIATION_RESULT_PERMANENT_REJECTED; + return 0; + } +#endif //DLMS_IGNORE_HIGH_GMAC +#ifndef DLMS_IGNORE_SERVER + if (ciphered) + { + afu &= ~DLMS_AFU_MISSING_MECHANISM_NAME; + } +#endif //DLMS_IGNORE_SERVER + break; + // 0xAC + case BER_TYPE_CONTEXT | BER_TYPE_CONSTRUCTED | PDU_TYPE_CALLING_AUTHENTICATION_VALUE: + if ((ret = apdu_updatePassword(settings, buff)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid password. "), ret); +#endif //DLMS_DEBUG + break; + } +#ifndef DLMS_IGNORE_SERVER + if (ciphered) + { + afu &= ~DLMS_AFU_MISSING_CALLING_AUTHENTICATION_VALUE; + } +#endif //DLMS_IGNORE_SERVER + break; + // 0xBE + case BER_TYPE_CONTEXT | BER_TYPE_CONSTRUCTED | PDU_TYPE_USER_INFORMATION: + //Check result component. Some meters are returning invalid user-information if connection failed. + if (*result != DLMS_ASSOCIATION_RESULT_ACCEPTED + && *diagnostic != DLMS_SOURCE_DIAGNOSTIC_NONE) + { + if ((ret = apdu_handleResultComponent(*diagnostic)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Invalid result component. "), ret); +#endif //DLMS_DEBUG + } + return ret; + } + if ((ret = apdu_parseUserInformation(settings, buff, ciphered, command)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("parseUserInformation. "), ret); +#endif //DLMS_DEBUG + if (ret == DLMS_ERROR_CODE_INVOCATION_COUNTER_TOO_SMALL || + ret == DLMS_ERROR_CODE_INVALID_DECIPHERING_ERROR || + ret == DLMS_ERROR_CODE_INVALID_SECURITY_SUITE) + { + return ret; + } + if (ciphered) + { + ret = DLMS_ERROR_CODE_INVALID_DECIPHERING_ERROR; + } + else + { + //Return confirmed service error. + ret = DLMS_ERROR_CODE_INVALID_TAG; + } + break; + } + break; + case BER_TYPE_CONTEXT: //0x80 + if ((ret = apdu_parseProtocolVersion(settings, buff)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("parseProtocolVersion. "), ret); +#endif //DLMS_DEBUG + * diagnostic = 0x80 | DLMS_ACSE_SERVICE_PROVIDER_NO_COMMON_ACSE_VERSION; + *result = DLMS_ASSOCIATION_RESULT_PERMANENT_REJECTED; + return 0; + } + break; + default: + // Unknown tags. +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("Unknown tag. "), -1); +#endif //DLMS_DEBUG + if (buff->position < buff->size) + { + if ((ret = bb_getUInt8(buff, &len)) != 0) + { + break; + } + buff->position = (buff->position + len); + } + break; + } + } + if (ret == 0) + { +#ifndef DLMS_IGNORE_SERVER + if (settings->server && afu != 0 && + *result == DLMS_ASSOCIATION_RESULT_ACCEPTED && + !( + afu == DLMS_AFU_MISSING_CALLING_AUTHENTICATION_VALUE && + settings->authentication == DLMS_AUTHENTICATION_NONE)) + { +#ifdef DLMS_DEBUG + switch (afu) + { + case DLMS_AFU_MISSING_SENDER_ACSE_REQUIREMENTS: + svr_notifyTrace(GET_STR_FROM_EEPROM("Sender ACSE requirements is missing."), -1); + break; + case DLMS_AFU_MISSING_MECHANISM_NAME: + svr_notifyTrace(GET_STR_FROM_EEPROM("Mechanism name is missing."), -1); + break; + case DLMS_AFU_MISSING_CALLING_AUTHENTICATION_VALUE: + svr_notifyTrace(GET_STR_FROM_EEPROM("Calling authentication value is missing."), -1); + break; + case DLMS_AFU_MISSING_NONE: + break; + } +#endif //DLMS_DEBUG + * result = DLMS_ASSOCIATION_RESULT_PERMANENT_REJECTED; + *diagnostic = DLMS_SOURCE_DIAGNOSTIC_AUTHENTICATION_FAILURE; + return 0; + } +#endif //DLMS_IGNORE_SERVER + //All meters don't send user-information if connection is failed. + //For this reason result component is check again. + if ((ret = apdu_handleResultComponent(*diagnostic)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("handleResultComponent."), ret); +#endif //DLMS_DEBUG + } +#ifndef DLMS_IGNORE_HIGH_GMAC + //Check that user is not trying to connect without ciphered connection. + if (ret == 0 && settings->expectedSecurityPolicy != 0xFF) + { + if (settings->cipher.security != settings->expectedSecurityPolicy << 4) + { + return DLMS_ERROR_CODE_INVALID_DECIPHERING_ERROR; + } + } +#endif //DLMS_IGNORE_HIGH_GMAC + } + return ret; +} + +#ifndef DLMS_IGNORE_SERVER +int apdu_generateAARE( + dlmsSettings* settings, + gxByteBuffer* data, + DLMS_ASSOCIATION_RESULT result, + unsigned char diagnostic, + gxByteBuffer* errorData, + gxByteBuffer* encryptedData, + unsigned char command) +{ + int ret; +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + uint32_t offset = data->size; +#else + uint16_t offset = data->size; +#endif + // Set AARE tag and length 0x61 + bb_setUInt8(data, BER_TYPE_APPLICATION | BER_TYPE_CONSTRUCTED | PDU_TYPE_APPLICATION_CONTEXT_NAME); + // Length is updated later. + bb_setUInt8(data, 0); + if ((ret = apdu_generateApplicationContextName(settings, data)) != 0) + { + return ret; + } + // Result 0xA2 + bb_setUInt8(data, BER_TYPE_CONTEXT | BER_TYPE_CONSTRUCTED | BER_TYPE_INTEGER); + bb_setUInt8(data, 3); // len + // Tag + bb_setUInt8(data, BER_TYPE_INTEGER); + // Choice for result (INTEGER, universal) + bb_setUInt8(data, 1); // Len + // ResultValue + bb_setUInt8(data, result); + // SourceDiagnostic + bb_setUInt8(data, 0xA3); + // len + bb_setUInt8(data, 5); + // Tag + if ((diagnostic & 0x80) == 0) + { + bb_setUInt8(data, 0xA1); + } + else + { + bb_setUInt8(data, 0xA2); + diagnostic &= ~0x80; + } + bb_setUInt8(data, 3); // len + bb_setUInt8(data, 2); // Tag + // Choice for result (INTEGER, universal) + bb_setUInt8(data, 1); // Len + // diagnostic + bb_setUInt8(data, diagnostic); + // SystemTitle +#ifndef DLMS_IGNORE_HIGH_GMAC + if (settings->authentication == DLMS_AUTHENTICATION_HIGH_GMAC + || isCiphered(&settings->cipher)) + { + bb_setUInt8(data, BER_TYPE_CONTEXT | BER_TYPE_CONSTRUCTED | PDU_TYPE_CALLED_AP_INVOCATION_ID); + bb_setUInt8(data, 2 + 8); + bb_setUInt8(data, BER_TYPE_OCTET_STRING); + bb_setUInt8(data, 8); +#ifndef DLMS_IGNORE_MALLOC + bb_set(data, settings->cipher.systemTitle.data, 8); +#else + bb_set(data, settings->cipher.systemTitle, 8); +#endif //DLMS_IGNORE_MALLOC + } +#endif //LMS_IGNORE_HIGH_GMAC + + //Add CalledAEInvocationId. +#ifndef DLMS_IGNORE_HIGH_GMAC + if (settings->userId != -1 && settings->cipher.security != DLMS_SECURITY_NONE) +#else + if (settings->userId != -1) +#endif + { + bb_setUInt8(data, BER_TYPE_CONTEXT | BER_TYPE_CONSTRUCTED | PDU_TYPE_CALLING_AE_QUALIFIER); + //LEN + bb_setUInt8(data, 3); + bb_setUInt8(data, BER_TYPE_INTEGER); + //LEN + bb_setUInt8(data, 1); + bb_setUInt8(data, (unsigned char)settings->userId); + } + if (settings->authentication > DLMS_AUTHENTICATION_LOW) + { + if (settings->stoCChallenge.size == 0) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + // Add server ACSE-requirenents field component. + if ((ret = bb_setUInt8(data, 0x88)) != 0 || + (ret = bb_setUInt8(data, 0x02)) != 0 || // Len. + (ret = bb_setUInt16(data, 0x0780)) != 0 || + // Add tag. + (ret = bb_setUInt8(data, 0x89)) != 0 || + (ret = bb_setUInt8(data, 0x07)) != 0 || // Len + (ret = bb_setUInt8(data, 0x60)) != 0 || + (ret = bb_setUInt8(data, 0x85)) != 0 || + (ret = bb_setUInt8(data, 0x74)) != 0 || + (ret = bb_setUInt8(data, 0x05)) != 0 || + (ret = bb_setUInt8(data, 0x08)) != 0 || + (ret = bb_setUInt8(data, 0x02)) != 0 || + (ret = bb_setUInt8(data, settings->authentication)) != 0 || + // Add tag. + (ret = bb_setUInt8(data, 0xAA)) != 0 || + (ret = bb_setUInt8(data, (unsigned char)(2 + settings->stoCChallenge.size))) != 0 || // Len + (ret = bb_setUInt8(data, BER_TYPE_CONTEXT)) != 0 || + (ret = bb_setUInt8(data, (unsigned char)settings->stoCChallenge.size)) != 0 || + (ret = bb_set(data, settings->stoCChallenge.data, settings->stoCChallenge.size)) != 0) + { + return ret; + } + } +#ifndef DLMS_IGNORE_HIGH_GMAC + if (result == DLMS_ASSOCIATION_RESULT_ACCEPTED || !isCiphered(&settings->cipher)) +#endif //DLMS_IGNORE_HIGH_GMAC + { + gxByteBuffer tmp; + unsigned char buff[200]; + // Add User Information. Tag 0xBE + bb_setUInt8(data, BER_TYPE_CONTEXT | BER_TYPE_CONSTRUCTED | PDU_TYPE_USER_INFORMATION); + bb_attach(&tmp, buff, 0, sizeof(buff)); +#ifndef DLMS_IGNORE_HIGH_GMAC + if (encryptedData != NULL && encryptedData->size != 0) + { + bb_capacity(&tmp, 2 + encryptedData->size); + bb_setUInt8(&tmp, DLMS_COMMAND_GLO_INITIATE_RESPONSE); + hlp_setObjectCount(encryptedData->size, &tmp); + bb_set2(&tmp, encryptedData, 0, encryptedData->size); + } + else +#endif //DLMS_IGNORE_HIGH_GMAC + { + if (errorData != NULL && errorData->size != 0) + { + bb_set2(&tmp, errorData, 0, errorData->size); + } + else + { + if ((ret = apdu_getUserInformation(settings, &tmp, command)) != 0) + { + bb_clear(&tmp); + return ret; + } + } + } + + if ((ret = bb_setUInt8(data, (unsigned char)(2 + tmp.size))) != 0 || + // Coding the choice for user-information (Octet STRING, universal) + (ret = bb_setUInt8(data, BER_TYPE_OCTET_STRING)) != 0 || + // Length + (ret = bb_setUInt8(data, (unsigned char)tmp.size)) != 0 || + (ret = bb_set2(data, &tmp, 0, tmp.size)) != 0) + { + return ret; + } + } + return bb_setUInt8ByIndex(data, (offset + 1), (unsigned char)(data->size - offset - 2)); +} +#endif //DLMS_IGNORE_SERVER diff --git a/components/xt211/apdu.h b/components/xt211/apdu.h new file mode 100644 index 0000000..9240b8f --- /dev/null +++ b/components/xt211/apdu.h @@ -0,0 +1,97 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef APDU_H +#define APDU_H + +#include "dlmssettings.h" +#include "bytebuffer.h" + +#ifdef __cplusplus +extern "C" { +#endif +#ifndef DLMS_IGNORE_CLIENT + /** + * Generates Aarq. + */ + int apdu_generateAarq( + dlmsSettings* settings, + gxByteBuffer* data); +#endif //DLMS_IGNORE_CLIENT + + /** + * Parse APDU. + */ + int apdu_parsePDU( + dlmsSettings* settings, + gxByteBuffer* buff, + DLMS_ASSOCIATION_RESULT* result, + unsigned char* diagnostic, + unsigned char* command); + +#ifndef DLMS_IGNORE_SERVER + /** + * Server generates AARE message. + */ + int apdu_generateAARE( + dlmsSettings* settings, + gxByteBuffer* data, + DLMS_ASSOCIATION_RESULT result, + unsigned char diagnostic, + gxByteBuffer* errorData, + gxByteBuffer* encryptedData, + unsigned char command); +#endif //DLMS_IGNORE_SERVER + + /** + * Generate user information. + * + * @param settings + * DLMS settings + * @param cipher + * @param data + * Generated user information. + */ + int apdu_generateUserInformation( + dlmsSettings* settings, + gxByteBuffer* data); + + int apdu_getUserInformation( + dlmsSettings* settings, + gxByteBuffer* data, + unsigned char command); + +#ifdef __cplusplus +} +#endif + +#endif //APDU_H diff --git a/components/xt211/binary_sensor.py b/components/xt211/binary_sensor.py new file mode 100644 index 0000000..97a8037 --- /dev/null +++ b/components/xt211/binary_sensor.py @@ -0,0 +1,102 @@ +# import esphome.codegen as cg +# import esphome.config_validation as cv +# from esphome.components import binary_sensor +# from esphome.const import ( +# DEVICE_CLASS_CONNECTIVITY, +# ENTITY_CATEGORY_DIAGNOSTIC, +# ) +# from . import ( +# XT211, +# xt211_ns, +# CONF_XT211_ID, +# ) +# +# AUTO_LOAD = ["xt211"] +# +# CONF_TRANSMISSION = "transmission" +# CONF_SESSION = "session" +# CONF_CONNECTION = "connection" +# +# ICON_TRANSMISSION = "mdi:swap-horizontal" +# ICON_CONNECTION = "mdi:lan-connect" +# ICON_SESSION = "mdi:sync" +# +# CONFIG_SCHEMA = cv.Schema( +# { +# cv.GenerateID(CONF_XT211_ID): cv.use_id(XT211), +# cv.Optional(CONF_TRANSMISSION): binary_sensor.binary_sensor_schema( +# device_class=DEVICE_CLASS_CONNECTIVITY, +# entity_category=ENTITY_CATEGORY_DIAGNOSTIC, +# icon=ICON_TRANSMISSION, +# ), +# cv.Optional(CONF_SESSION): binary_sensor.binary_sensor_schema( +# device_class=DEVICE_CLASS_CONNECTIVITY, +# entity_category=ENTITY_CATEGORY_DIAGNOSTIC, +# icon=ICON_SESSION, +# ), +# cv.Optional(CONF_CONNECTION): binary_sensor.binary_sensor_schema( +# device_class=DEVICE_CLASS_CONNECTIVITY, +# entity_category=ENTITY_CATEGORY_DIAGNOSTIC, +# icon=ICON_CONNECTION, +# ), +# } +# ) +# +# async def to_code(config): +# hub = await cg.get_variable(config[CONF_XT211_ID]) +# +# if conf := config.get(CONF_TRANSMISSION): +# sensor = await binary_sensor.new_binary_sensor(config[CONF_TRANSMISSION]) +# cg.add(hub.set_transmission_binary_sensor(sensor)) +# +# if conf := config.get(CONF_SESSION): +# sensor = await binary_sensor.new_binary_sensor(config[CONF_SESSION]) +# cg.add(hub.set_session_binary_sensor(sensor)) +# +# if conf := config.get(CONF_CONNECTION): +# sensor = await binary_sensor.new_binary_sensor(config[CONF_CONNECTION]) +# cg.add(hub.set_connection_binary_sensor(sensor)) + +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import binary_sensor +from . import ( + XT211, + xt211_ns, + obis_code, + CONF_XT211_ID, + CONF_OBIS_CODE, + CONF_DONT_PUBLISH, + CONF_CLASS, +) + +AUTO_LOAD = ["xt211"] + +XT211BinarySensor = xt211_ns.class_( + "XT211BinarySensor", binary_sensor.BinarySensor +) + + +CONFIG_SCHEMA = cv.All( + binary_sensor.binary_sensor_schema( + XT211BinarySensor, + ).extend( + { + cv.GenerateID(CONF_XT211_ID): cv.use_id(XT211), + cv.Required(CONF_OBIS_CODE): obis_code, + cv.Optional(CONF_DONT_PUBLISH, default=False): cv.boolean, + cv.Optional(CONF_CLASS, default=1): cv.int_, + } + ), + cv.has_exactly_one_key(CONF_OBIS_CODE), +) + + +async def to_code(config): + component = await cg.get_variable(config[CONF_XT211_ID]) + var = await binary_sensor.new_binary_sensor(config) + cg.add(var.set_obis_code(config[CONF_OBIS_CODE])) + cg.add(var.set_dont_publish(config.get(CONF_DONT_PUBLISH))) + cg.add(var.set_obis_class(config[CONF_CLASS])) + + cg.add(component.register_sensor(var)) \ No newline at end of file diff --git a/components/xt211/bitarray.c b/components/xt211/bitarray.c new file mode 100644 index 0000000..f563af7 --- /dev/null +++ b/components/xt211/bitarray.c @@ -0,0 +1,344 @@ +// +// -------------------------------------------------------------------------- +// 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 +#endif + +#if _MSC_VER > 1400 +#include +#endif +#include +#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; +} + diff --git a/components/xt211/bitarray.h b/components/xt211/bitarray.h new file mode 100644 index 0000000..484b340 --- /dev/null +++ b/components/xt211/bitarray.h @@ -0,0 +1,144 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef BIT_ARRAY_H +#define BIT_ARRAY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "gxignore.h" +#include "bytebuffer.h" + +#define BIT_ARRAY_CAPACITY 8 + + typedef struct + { + unsigned char* data; + uint16_t capacity; + uint16_t size; +#ifndef GX_DLMS_MICROCONTROLLER + uint16_t position; +#endif //GX_DLMS_MICROCONTROLLER + } bitArray; + + //Initialize gxByteBuffer. + void ba_init( + bitArray* arr); + + //Attach bit array. + void ba_attach( + bitArray* arr, + unsigned char* value, + uint16_t count, + uint16_t capacity); + + /* + * Is static buffer used. + */ + char ba_isAttached( + bitArray* arr); + + //Bit array capacity. + uint16_t ba_getCapacity( + bitArray* arr); + + /* + * Get size. + */ + uint16_t ba_size(bitArray* bb); + + //How many bytes bit array will take. + uint16_t ba_getByteCount( + uint16_t bitCount); + + //Allocate new size for the array in bits. + int ba_capacity( + bitArray* arr, + uint16_t capacity); + + //Push new data to the bit array. + int ba_set( + bitArray* arr, + unsigned char item); + + //Push new data to the bit array. + int ba_setByIndex( + bitArray* arr, + uint16_t index, + unsigned char item); + + //Copy bit array. + int ba_copy( + bitArray* target, + unsigned char* source, + uint16_t count); + + //Clear bit array. + void ba_clear( + bitArray* arr); + + //Get bit value. + int ba_get( + bitArray* arr, + unsigned char* value); + + //Get bit value by index. + int ba_getByIndex( + bitArray* arr, + int index, + unsigned char* value); + + //Convert bit array to integer. + int ba_toInteger( + bitArray* arr, + uint32_t* value); + +#ifndef DLMS_IGNORE_MALLOC + //Get bit array as a string. + char* ba_toString( + bitArray* arr); +#endif //DLMS_IGNORE_MALLOC + + //Add bit array as a string. + int ba_toString2( + gxByteBuffer* bb, + bitArray* ba); + +#define BIT_ATTACH(X, V, S) ba_attach(&X, V, S, 8 * sizeof(V)/sizeof(V[0])) + +#ifdef __cplusplus +} +#endif + +#endif //BYTE_ARRAY_H diff --git a/components/xt211/bytebuffer.c b/components/xt211/bytebuffer.c new file mode 100644 index 0000000..23bee6b --- /dev/null +++ b/components/xt211/bytebuffer.c @@ -0,0 +1,1309 @@ +// +// -------------------------------------------------------------------------- +// 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" +#ifndef DLMS_IGNORE_STRING_CONVERTER +#include //printf needs this or error is generated. +#endif //DLMS_IGNORE_STRING_CONVERTER + +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) +#include +#if _MSC_VER > 1400 +#include +#endif +#endif +#include +#include "errorcodes.h" +#include "bytebuffer.h" +#include "helpers.h" + +char bb_isAttached(gxByteBuffer* arr) +{ + if (arr == NULL) + { + return 0; + } +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + //If byte buffer is attached. + return (arr->capacity & 0x80000000) == 0x80000000; +#else + return (arr->capacity & 0x8000) == 0x8000; +#endif +} + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +uint32_t bb_available(gxByteBuffer* arr) +#else +uint16_t bb_available(gxByteBuffer* arr) +#endif +{ + if (arr == NULL) + { + return 0; + } + return arr->size - arr->position; +} + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +uint32_t bb_getCapacity(gxByteBuffer* arr) +#else +uint16_t bb_getCapacity(gxByteBuffer* arr) +#endif +{ +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER)&& (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + //If byte buffer is attached. + return arr->capacity & 0x7FFFFFFF; +#else + return arr->capacity & 0x7FFF; +#endif +} + + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +uint32_t bb_size(gxByteBuffer* arr) +#else +uint16_t bb_size(gxByteBuffer* arr) +#endif +{ + return arr != NULL ? arr->size : 0; +} + +int BYTE_BUFFER_INIT( + gxByteBuffer* arr) +{ + arr->capacity = 0; + arr->data = NULL; + arr->position = 0; + arr->size = 0; + return 0; +} + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +int bb_capacity( + gxByteBuffer* arr, + uint32_t capacity) +#else +int bb_capacity( + gxByteBuffer* arr, + uint16_t capacity) +#endif +{ +#ifndef DLMS_IGNORE_MALLOC + //Capacity can't change if it's attached. + if (!bb_isAttached(arr)) + { + if (capacity == 0) + { + if (arr->data != NULL) + { + gxfree(arr->data); + arr->data = NULL; + arr->size = 0; + } + } + else + { + if (arr->capacity == 0) + { + arr->data = (unsigned char*)gxmalloc(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, 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(capacity); + //If not enought memory available. + if (arr->data == NULL) + { + arr->data = old; + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + memcpy(arr->data, old, arr->size); + gxfree(old); + #endif // gxrealloc + } + if (arr->size > capacity) + { + arr->size = capacity; + } + } + arr->capacity = capacity; + } +#endif //DLMS_IGNORE_MALLOC + if (bb_getCapacity(arr) < capacity) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + return DLMS_ERROR_CODE_OK; +} + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +int bb_zero( + gxByteBuffer* arr, + uint32_t index, + uint32_t count) +#else +int bb_zero( + gxByteBuffer* arr, + uint16_t index, + uint16_t count) +#endif +{ + int ret; + if (index + count > arr->capacity) + { + if ((ret = bb_capacity(arr, (index + count))) != 0) + { + return ret; + } + } + if (arr->size < index + count) + { + arr->size = index + count; + } + memset(arr->data + index, 0, count); + return 0; +} + +int bb_setUInt8( + gxByteBuffer* arr, + unsigned char item) +{ + int ret = bb_setUInt8ByIndex(arr, bb_size(arr), item); + if (ret == 0) + { + ++arr->size; + } + return ret; +} + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +int bb_insertUInt8( + gxByteBuffer* arr, + uint32_t index, + unsigned char item) +#else +int bb_insertUInt8( + gxByteBuffer* arr, + uint16_t index, + unsigned char item) +#endif +{ + int ret; + if ((ret = bb_move(arr, index, index + 1, arr->size)) == 0) + { + if (index == 0 && arr->size == 0) + { + //If buffer is empty and there is no data to move. + ++arr->size; + } + ret = bb_setUInt8ByIndex(arr, index, item); + } + return ret; +} + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +int bb_allocate( + gxByteBuffer* arr, + uint32_t index, + uint32_t dataSize) +#else +int bb_allocate( + gxByteBuffer* arr, + uint16_t index, + uint16_t dataSize) +#endif +{ +#ifndef DLMS_IGNORE_MALLOC + if (!bb_isAttached(arr) && (arr->capacity == 0 || index + dataSize > arr->capacity)) + { + unsigned char empty = arr->capacity == 0; + //If data is append fist time. + if (dataSize > VECTOR_CAPACITY || arr->capacity == 0) + { + arr->capacity += dataSize; + } + else + { + arr->capacity += VECTOR_CAPACITY; + } + if (empty) + { + arr->data = (unsigned char*)gxmalloc(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, arr->capacity); + if (tmp == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + arr->data = tmp; +#else + //If compiler doesn't supports realloc. + unsigned char* old = arr->data; + arr->data = (unsigned char*)gxmalloc(arr->capacity); + //If not enought memory available. + if (arr->data == NULL) + { + arr->data = old; + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + memcpy(arr->data, old, arr->size); + gxfree(old); +#endif //gxrealloc + } + } +#endif //DLMS_IGNORE_MALLOC + if (bb_getCapacity(arr) < index + dataSize) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + return 0; +} + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +int bb_setUInt8ByIndex( + gxByteBuffer* arr, + uint32_t index, + unsigned char item) +#else +int bb_setUInt8ByIndex( + gxByteBuffer* arr, + uint16_t index, + unsigned char item) +#endif +{ + if (arr == NULL) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + int ret = bb_allocate(arr, index, 1); + if (ret == 0) + { + arr->data[index] = item; + } + return ret; +} + +int bb_setUInt16( + gxByteBuffer* arr, + uint16_t item) +{ + int ret = bb_setUInt16ByIndex(arr, arr->size, item); + if (ret == 0) + { + arr->size += 2; + } + return ret; +} + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +int bb_setUInt16ByIndex( + gxByteBuffer* arr, + uint32_t index, + uint16_t item) +#else +int bb_setUInt16ByIndex( + gxByteBuffer* arr, + uint16_t index, + uint16_t item) +#endif +{ + int ret = 0; + if (index + 2 > arr->size) + { + bb_allocate(arr, arr->size, 2); + } + if (ret == 0) + { + arr->data[index] = (item >> 8) & 0xFF; + arr->data[index + 1] = item & 0xFF; + } + return ret; +} + +int bb_setUInt32( + gxByteBuffer* arr, + uint32_t item) +{ + int ret = bb_setUInt32ByIndex(arr, arr->size, item); + if (ret == 0) + { + arr->size += 4; + } + return ret; +} + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +int bb_setUInt32ByIndex( + gxByteBuffer* arr, + uint32_t index, + uint32_t item) +#else +int bb_setUInt32ByIndex( + gxByteBuffer* arr, + uint16_t index, + uint32_t item) +#endif //defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +{ + int ret = bb_allocate(arr, index, 4); + if (ret == 0) + { + PUT32(arr->data + index, item); + } + return ret; +} + +int bb_setUInt64( + gxByteBuffer* arr, + uint64_t item) +{ + int ret = bb_allocate(arr, arr->size, 8); + if (ret == 0) + { + ((unsigned char*)arr->data)[arr->size + 7] = item & 0xFF; + item >>= 8; + ((unsigned char*)arr->data)[arr->size + 6] = item & 0xFF; + item >>= 8; + ((unsigned char*)arr->data)[arr->size + 5] = item & 0xFF; + item >>= 8; + ((unsigned char*)arr->data)[arr->size + 4] = item & 0xFF; + item >>= 8; + ((unsigned char*)arr->data)[arr->size + 3] = item & 0xFF; + item >>= 8; + ((unsigned char*)arr->data)[arr->size + 2] = item & 0xFF; + item >>= 8; + ((unsigned char*)arr->data)[arr->size + 1] = item & 0xFF; + item >>= 8; + ((unsigned char*)arr->data)[arr->size] = item & 0xFF; + arr->size += 8; + } + return ret; +} + +#ifndef DLMS_IGNORE_FLOAT32 +int bb_setFloat( + gxByteBuffer* arr, + float value) +{ + typedef union + { + float value; + char b[sizeof(float)]; + } HELPER; + + HELPER tmp; + tmp.value = value; + int ret = bb_allocate(arr, arr->size, 4); + if (ret == 0) + { + arr->data[arr->size] = tmp.b[3]; + arr->data[arr->size + 1] = tmp.b[2]; + arr->data[arr->size + 2] = tmp.b[1]; + arr->data[arr->size + 3] = tmp.b[0]; + arr->size += 4; + } + return ret; +} +#endif //DLMS_IGNORE_FLOAT32 + +#ifndef DLMS_IGNORE_FLOAT64 +int bb_setDouble( + gxByteBuffer* arr, + double value) +{ + typedef union + { + double value; + char b[sizeof(double)]; + } HELPER; + + HELPER tmp; + tmp.value = value; + int ret = bb_allocate(arr, arr->size, 8); + if (ret == 0) + { + arr->data[arr->size] = tmp.b[7]; + arr->data[arr->size + 1] = tmp.b[6]; + arr->data[arr->size + 2] = tmp.b[5]; + arr->data[arr->size + 3] = tmp.b[4]; + arr->data[arr->size + 4] = tmp.b[3]; + arr->data[arr->size + 5] = tmp.b[2]; + arr->data[arr->size + 6] = tmp.b[1]; + arr->data[arr->size + 7] = tmp.b[0]; + arr->size += 8; + } + return ret; +} +#endif //DLMS_IGNORE_FLOAT64 + +int bb_setInt8( + gxByteBuffer* arr, + char item) +{ + return bb_setUInt8(arr, (unsigned char)item); +} + +int bb_setInt16( + gxByteBuffer* arr, + short item) +{ + return bb_setUInt16(arr, (uint16_t)item); +} + +int bb_setInt32( + gxByteBuffer* arr, + int32_t item) +{ + return bb_setUInt32(arr, (uint32_t)item); +} + +int bb_setInt64( + gxByteBuffer* arr, + int64_t item) +{ + return bb_setUInt64(arr, (uint64_t)item); +} + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +int bb_set( + gxByteBuffer* arr, + const unsigned char* pSource, + uint32_t count) +#else +int bb_set( + gxByteBuffer* arr, + const unsigned char* pSource, + uint16_t count) +#endif +{ + if (count != 0) + { + int ret = bb_allocate(arr, arr->size, count); + if (ret == 0) + { + if (arr->size + count > arr->capacity) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + memcpy(arr->data + arr->size, pSource, count); + arr->size += count; + } + return ret; + } + else + { + return 0; + } +} + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +int bb_set2( + gxByteBuffer* arr, + gxByteBuffer* data, + uint32_t index, + uint32_t count) +#else +int bb_set2( + gxByteBuffer* arr, + gxByteBuffer* data, + uint16_t index, + uint16_t count) +#endif +{ + if (data != NULL && count != 0) + { +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + if (count == (uint32_t)-1) +#else + if (count == (uint16_t)-1) +#endif + { + count = data->size - index; + } + int ret = bb_set(arr, data->data + index, count); + if (ret == 0) + { + data->position += count; + } + return ret; +} + return 0; +} + +int bb_addString( + gxByteBuffer* arr, + const char* value) +{ + if (value != NULL) + { + int len = (int)strlen(value); + if (len > 0) + { + int ret = bb_set(arr, (const unsigned char*)value, (uint16_t)(len + 1)); + if (ret == 0) + { + //Add end of string, but that is not added to the length. + arr->data[arr->size - 1] = '\0'; + --arr->size; + } + return ret; + } + } + return 0; +} + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +int bb_attach( + gxByteBuffer* arr, + unsigned char* value, + uint32_t count, + uint32_t capacity) +#else +int bb_attach( + gxByteBuffer* arr, + unsigned char* value, + uint16_t count, + uint16_t capacity) +#endif +{ + //If capacity is 1 value is cast t + if (value == NULL || capacity < count) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + arr->data = value; +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + if (capacity >= 0x80000000) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + arr->capacity = (0x80000000 | capacity); +#else + if (capacity >= 0x8000) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + arr->capacity = (uint16_t)(0x8000 | capacity); +#endif + arr->size = count; + arr->position = 0; + return 0; +} + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +int bb_attachString2( + gxByteBuffer* arr, + char* value, + uint32_t count, + uint32_t capacity) +#else +int bb_attachString2( + gxByteBuffer* arr, + char* value, + uint16_t count, + uint16_t capacity) +#endif +{ + return bb_attach(arr, (unsigned char*)value, count, capacity); +} + +#ifndef DLMS_IGNORE_MALLOC +int bb_attachString( + gxByteBuffer* arr, + char* value) +{ + int len = (int)strlen(value); + int ret = bb_set(arr, (const unsigned char*)value, (uint16_t)len); + gxfree(value); + return ret; +} +#endif //DLMS_IGNORE_MALLOC + +int bb_clear( + gxByteBuffer* arr) +{ +#ifndef DLMS_IGNORE_MALLOC + //If byte buffer is attached. + if (!bb_isAttached(arr)) + { + if (arr->data != NULL) + { + gxfree(arr->data); + arr->data = NULL; + } + arr->capacity = 0; + } +#endif //DLMS_IGNORE_MALLOC + arr->size = 0; + arr->position = 0; + return 0; +} + +int bb_empty( + gxByteBuffer* arr) +{ + arr->size = 0; + arr->position = 0; + return 0; +} + +int bb_getUInt8( + gxByteBuffer* arr, + unsigned char* value) +{ + if (arr->position >= arr->size) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + *value = ((unsigned char*)arr->data)[arr->position]; + ++arr->position; + return 0; +} + +int bb_getInt8( + gxByteBuffer* arr, + signed char* value) +{ + if (arr->position >= arr->size) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + *value = (signed char)((unsigned char*)arr->data)[arr->position]; + ++arr->position; + return 0; +} + +int bb_getUInt8ByIndex( + gxByteBuffer* arr, + uint32_t index, + unsigned char* value) +{ + if (index >= arr->size) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + *value = ((unsigned char*)arr->data)[index]; + return 0; +} + + +int bb_getUInt16( + gxByteBuffer* arr, + uint16_t* value) +{ + if (arr->position + 2 > arr->size) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + *value = (uint16_t)(((unsigned char*)arr->data)[arr->position] << 8 | + ((unsigned char*)arr->data)[arr->position + 1]); + arr->position += 2; + return 0; +} + +int bb_getUInt32( + gxByteBuffer* arr, + uint32_t* value) +{ + + if (arr->position + 4 > arr->size) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + *value = GETU32(arr->data + arr->position); + arr->position += 4; + return 0; +} + +int bb_getInt16( + gxByteBuffer* arr, + short* value) +{ + + if (arr->position + 2 > arr->size) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + *value = (short)(((unsigned char*)arr->data)[arr->position] << 8 | + ((unsigned char*)arr->data)[arr->position + 1]); + arr->position += 2; + return 0; +} + +int bb_getUInt24( + gxByteBuffer* arr, + uint32_t* value) +{ + int ret = bb_getUInt24ByIndex(arr, arr->position, value); + arr->position += 3; + return ret; +} + +int bb_getInt32( + gxByteBuffer* arr, + int32_t* value) +{ + + int ret = bb_getUInt32ByIndex(arr, arr->position, (uint32_t*)value); + arr->position += 4; + return ret; +} + +int bb_getUInt24ByIndex( + gxByteBuffer* arr, + uint32_t index, + uint32_t* value) +{ + if (index + 3 > bb_size(arr)) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + *value = ((uint32_t)(arr->data)[index] << 16) | + ((uint32_t)(arr->data)[index + 1] << 8) | + ((uint32_t)(arr->data)[index + 2]); + return 0; +} + +int bb_getUInt32ByIndex( + gxByteBuffer* arr, + uint32_t index, + uint32_t* value) +{ + + if (index + 4 > arr->size) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + *value = GETU32(arr->data + index); + return 0; +} + +int bb_getInt64( + gxByteBuffer* arr, + int64_t* value) +{ + int ret = bb_getUInt64ByIndex(arr, arr->position, (uint64_t*)value); + if (ret == 0) + { + arr->position += 8; + } + return ret; +} + +int bb_getUInt64( + gxByteBuffer* arr, + uint64_t* value) +{ + int ret = bb_getUInt64ByIndex(arr, arr->position, value); + if (ret == 0) + { + arr->position += 8; + } + return ret; +} + +int bb_getUInt64ByIndex( + gxByteBuffer* arr, + uint32_t index, + uint64_t* value) +{ + if (index + 8 > arr->size) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + *value = GETU32(arr->data + index); + //Some 32 bit microcontrollers can't handle *value <<= 32; + //For this reason value is sifted on two parts. + *value <<= 16; + *value <<= 16; + *value |= GETU32(arr->data + index + 4); + return 0; +} + +int bb_getUInt128ByIndex( + gxByteBuffer* arr, + uint32_t index, + unsigned char* value) +{ + int ret = bb_getUInt32ByIndex(arr, index, (uint32_t*)value); + if (ret == 0) + { + ret = bb_getUInt32ByIndex(arr, index + 4, (uint32_t*)value + 1); + if (ret == 0) + { + ret = bb_getUInt32ByIndex(arr, index + 8, (uint32_t*)value + 2); + if (ret == 0) + { + ret = bb_getUInt32ByIndex(arr, index + 12, (uint32_t*)value + 3); + } + } + } + return ret; +} + +#ifndef DLMS_IGNORE_FLOAT32 +int bb_getFloat( + gxByteBuffer* arr, + float* value) +{ + typedef union + { + float value; + char b[sizeof(float)]; + } HELPER; + HELPER tmp; + if (arr->position + 4 > arr->size) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + tmp.b[3] = arr->data[arr->position]; + tmp.b[2] = arr->data[arr->position + 1]; + tmp.b[1] = arr->data[arr->position + 2]; + tmp.b[0] = arr->data[arr->position + 3]; + *value = tmp.value; + arr->position += 4; + return 0; +} +#endif //DLMS_IGNORE_FLOAT32 + +#ifndef DLMS_IGNORE_FLOAT64 +int bb_getDouble( + gxByteBuffer* arr, + double* value) +{ + typedef union + { + double value; + char b[sizeof(double)]; + } HELPER; + HELPER tmp; + if (arr->position + 8 > arr->size) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + tmp.b[7] = arr->data[arr->position]; + tmp.b[6] = arr->data[arr->position + 1]; + tmp.b[5] = arr->data[arr->position + 2]; + tmp.b[4] = arr->data[arr->position + 3]; + tmp.b[3] = arr->data[arr->position + 4]; + tmp.b[2] = arr->data[arr->position + 5]; + tmp.b[1] = arr->data[arr->position + 6]; + tmp.b[0] = arr->data[arr->position + 7]; + *value = tmp.value; + arr->position += 8; + return 0; +} +#endif //DLMS_IGNORE_FLOAT64 + +int bb_getUInt16ByIndex( + gxByteBuffer* arr, + uint32_t index, + uint16_t* value) +{ + if (index + 2 > arr->size) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + *value = (uint16_t)(((unsigned char*)arr->data)[index] << 8 | + ((unsigned char*)arr->data)[index + 1]); + return 0; +} + +#ifndef DLMS_IGNORE_MALLOC +int bb_addHexString( + gxByteBuffer* arr, + const char* str) +{ + uint16_t count; + int ret; + unsigned char* buffer = NULL; + ret = hlp_hexToBytes(str, &buffer, &count); + if (ret != 0) + { + return ret; + } + if (buffer != NULL) + { + bb_set(arr, buffer, count); + gxfree(buffer); + } + return 0; +} +#endif //DLMS_IGNORE_MALLOC + +int bb_addHexString2( + gxByteBuffer* arr, + const char* str) +{ + if (str == NULL) + { + return 0; + } + int len = (int)strlen(str); + if (len == 0) + { + return 0; + } + int ret = 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) + { + if ((ret = bb_setUInt8(arr, (unsigned char)(lastValue << 4 | hlp_getValue(*str)))) != 0) + { + break; + } + lastValue = -1; + } + } + else if (lastValue != -1) + { + ret = bb_setUInt8(arr, hlp_getValue(*str)); + lastValue = -1; + } + ++str; + } + return ret; +} + +int bb_addLogicalName( + gxByteBuffer* arr, + const unsigned char* str) +{ + int ret; + char buffer[25]; + if ((ret = hlp_bytesToHex2(str, 6, buffer, sizeof(buffer))) == 0) + { + ret = bb_addString(arr, buffer); + } + return ret; +} + +int bb_toHexString2( + gxByteBuffer* arr, + char* buffer, + uint16_t size) +{ + return hlp_bytesToHex2(arr->data, (uint16_t)arr->size, buffer, size); +} + +#if !(defined(DLMS_IGNORE_STRING_CONVERTER) || defined(DLMS_IGNORE_MALLOC)) +char* bb_toString( + gxByteBuffer* arr) +{ + char* buff = (char*)gxmalloc(arr->size + 1); + if (buff != NULL) + { + memcpy(buff, arr->data, arr->size); + *(buff + arr->size) = 0; + } + return buff; +} + +char* bb_toHexString( + gxByteBuffer* arr) +{ + char* buff = hlp_bytesToHex(arr->data, arr->size); + return buff; +} + +int bb_addDoubleAsString( + gxByteBuffer* bb, + double value) +{ + char buff[20]; + //Show as integer value if there is no fractal part. + if (value - (int32_t)value == 0) + { + return bb_addIntAsString(bb, (int)value); + } + else + { +#if _MSC_VER > 1000 + sprintf_s(buff, 20, "%lf", value); +#else + sprintf(buff, "%lf", value); +#endif + return bb_addString(bb, buff); +} +} +#endif //!(defined(DLMS_IGNORE_STRING_CONVERTER) || defined(DLMS_IGNORE_MALLOC)) + +int bb_addIntAsString(gxByteBuffer* bb, int value) +{ + return bb_addIntAsString2(bb, value, 0); +} + +int bb_addIntAsString2(gxByteBuffer* bb, int value, unsigned char digits) +{ + int ret; + char str[20]; + hlp_intToString(str, 20, value, 1, digits); + if ((ret = bb_addString(bb, str)) != 0) + { + + } + return ret; +} + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +int bb_subArray( + gxByteBuffer* bb, + uint32_t index, + uint32_t count, + gxByteBuffer* target) +#else +int bb_subArray( + gxByteBuffer* bb, + uint16_t index, + uint16_t count, + gxByteBuffer* target) +#endif +{ + bb_clear(target); + bb_set2(target, bb, index, count); + return 0; +} + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +int bb_insert(const unsigned char* src, + uint32_t count, + gxByteBuffer* target, + uint32_t index) +#else +int bb_insert(const unsigned char* src, + uint16_t count, + gxByteBuffer* target, + uint16_t index) +#endif +{ + int ret; + if (target->size == 0) + { + ret = bb_set(target, src, count); + } + else + { + if ((ret = bb_capacity(target, target->size + count)) == 0 && + (ret = bb_move(target, index, index + count, target->size - index)) == 0) + { + //Do not use memcpy here! + memmove(target->data + index, src + index, count); + } + } + return ret; +} + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +int bb_move( + gxByteBuffer* bb, + uint32_t srcPos, + uint32_t destPos, + uint32_t count) +#else +int bb_move( + gxByteBuffer* bb, + uint16_t srcPos, + uint16_t destPos, + uint16_t count) +#endif +{ + //If items are removed. + if (srcPos > destPos) + { + if (bb->size < destPos + count) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + } + else + { + //Append data. + if (bb_getCapacity(bb) < count + destPos) + { + int ret; + if (bb_isAttached(bb)) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if ((ret = bb_capacity(bb, count + destPos)) != 0) + { + return ret; + } + } + } + if (count != 0) + { + //Do not use memcpy here! + memmove(bb->data + destPos, bb->data + srcPos, count); + bb->size = (destPos + count); + if (bb->position > bb->size) + { + bb->position = bb->size; + } + } + return DLMS_ERROR_CODE_OK; +} + +int bb_trim( + gxByteBuffer* bb) +{ + int ret; + if (bb->size == bb->position) + { + bb->size = 0; + } + else + { + if ((ret = bb_move(bb, bb->position, 0, bb->size - bb->position)) != 0) + { + return ret; + } + } + bb->position = 0; + return DLMS_ERROR_CODE_OK; +} + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +unsigned char bb_compare( + gxByteBuffer* bb, + unsigned char* buff, + uint32_t length) +#else +unsigned char bb_compare( + gxByteBuffer* bb, + unsigned char* buff, + uint16_t length) +#endif + +{ + unsigned char equal; + if (bb_available(bb) != length) + { + return 0; + } + equal = memcmp(bb->data + bb->position, buff, length) == 0; + if (equal) + { + bb->position += length; + } + return equal; +} + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +int bb_get( + gxByteBuffer* bb, + unsigned char* value, + uint32_t count) +#else +int bb_get( + gxByteBuffer* bb, + unsigned char* value, + uint16_t count) +#endif +{ + if (bb == NULL || value == NULL || bb->size - bb->position < count) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + memcpy(value, bb->data + bb->position, count); + bb->position += count; + return 0; +} + +uint32_t bb_indexOf( + gxByteBuffer* bb, + char ch) +{ + uint32_t pos; + if (bb == NULL) + { + return (uint32_t)-1; + } + for (pos = bb->position; pos < bb->size; ++pos) + { + if (bb->data[pos] == ch) + { + return pos; + } + } + return (uint32_t)-1; +} + +#ifndef GX_DLMS_MICROCONTROLLER +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) +int bb_print(gxByteBuffer* bb) +{ + const char hexArray[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; + uint32_t pos; + char hexChars[4]; + hexChars[2] = ' '; + hexChars[3] = '\0'; + for (pos = 0; pos != bb->size; ++pos) + { + hexChars[0] = hexArray[bb->data[pos] >> 4]; + hexChars[1] = hexArray[bb->data[pos] & 0x0F]; + printf("%s", hexChars); + } + return 0; +} +#endif //defined(_WIN32) || defined(_WIN64) || defined(__linux__) +#endif //GX_DLMS_MICROCONTROLLER diff --git a/components/xt211/bytebuffer.h b/components/xt211/bytebuffer.h new file mode 100644 index 0000000..5720f04 --- /dev/null +++ b/components/xt211/bytebuffer.h @@ -0,0 +1,541 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef BYTE_BUFFER_H +#define BYTE_BUFFER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "gxint.h" +#include "gxignore.h" + +//Arduino DOIT ESP32 uses bb_init. bb_Init is used instead. +#ifndef ESP_PLATFORM +#define BYTE_BUFFER_INIT bb_init +#else +#define BYTE_BUFFER_INIT bb_Init +#endif //DESP_PLATFORM + +#define VECTOR_CAPACITY 50 + + typedef struct + { +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + unsigned char* data; + uint32_t capacity; + uint32_t size; + uint32_t position; +#else + unsigned char* data; + uint16_t capacity; + uint16_t size; + uint16_t position; +#endif + } gxByteBuffer; + + /* + * Is static buffer used. + */ + char bb_isAttached( + gxByteBuffer* arr); + + /*Get maximum buffer size.*/ +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + uint32_t bb_getCapacity( + gxByteBuffer* arr); +#else + uint16_t bb_getCapacity( + gxByteBuffer* arr); +#endif + + /*Returns amount of the available bytes.*/ +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + uint32_t bb_available(gxByteBuffer* arr); +#else + uint16_t bb_available(gxByteBuffer* arr); +#endif + /* + * Initialize gxByteBuffer. + */ + int BYTE_BUFFER_INIT( + gxByteBuffer* bb); + + /* + * Allocate new size for the array in bytes. + */ +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + int bb_capacity( + gxByteBuffer* bb, + uint32_t capacity); +#else + int bb_capacity( + gxByteBuffer* bb, + uint16_t capacity); +#endif + + /* + * Get size. + */ +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + uint32_t bb_size( + gxByteBuffer* bb); +#else + uint16_t bb_size( + gxByteBuffer* bb); +#endif + + + /* + * Fill buffer it with zeros. + */ +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + int bb_zero( + gxByteBuffer* bb, + uint32_t index, + uint32_t count); +#else + int bb_zero( + gxByteBuffer* bb, + uint16_t index, + uint16_t count); +#endif + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + int bb_insertUInt8( + gxByteBuffer* arr, + uint32_t index, + unsigned char item); +#else + int bb_insertUInt8( + gxByteBuffer* arr, + uint16_t index, + unsigned char item); +#endif + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + int bb_allocate( + gxByteBuffer* arr, + uint32_t index, + uint32_t dataSize); +#else + int bb_allocate( + gxByteBuffer* arr, + uint16_t index, + uint16_t dataSize); +#endif + //Set new data to the gxByteBuffer. + int bb_setUInt8( + gxByteBuffer* bb, + unsigned char item); + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + int bb_setUInt8ByIndex( + gxByteBuffer* arr, + uint32_t index, + unsigned char item); +#else + int bb_setUInt8ByIndex( + gxByteBuffer* arr, + uint16_t index, + unsigned char item); +#endif + + int bb_setUInt16( + gxByteBuffer* bb, + uint16_t item); + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + int bb_setUInt16ByIndex( + gxByteBuffer* arr, + uint32_t index, + uint16_t item); +#else + int bb_setUInt16ByIndex( + gxByteBuffer* arr, + uint16_t index, + uint16_t item); +#endif + + int bb_setUInt32( + gxByteBuffer* bb, + uint32_t item); + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + int bb_setUInt32ByIndex( + gxByteBuffer* arr, + uint32_t index, + uint32_t item); +#else + int bb_setUInt32ByIndex( + gxByteBuffer* arr, + uint16_t index, + uint32_t item); +#endif //!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + + int bb_setUInt64( + gxByteBuffer* bb, + uint64_t item); + +#ifndef DLMS_IGNORE_FLOAT32 + int bb_setFloat( + gxByteBuffer* arr, + float value); +#endif //DLMS_IGNORE_FLOAT32 + +#ifndef DLMS_IGNORE_FLOAT64 + int bb_setDouble( + gxByteBuffer* arr, + double value); +#endif //DLMS_IGNORE_FLOAT64 + + int bb_setInt8( + gxByteBuffer* bb, + char item); + + int bb_setInt16( + gxByteBuffer* bb, + int16_t item); + + int bb_setInt32( + gxByteBuffer* bb, + int32_t item); + + int bb_setInt64( + gxByteBuffer* bb, + int64_t item); + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + int bb_insert( + const unsigned char* src, + uint32_t count, + gxByteBuffer* target, + uint32_t index); + +#else + int bb_insert( + const unsigned char* src, + uint16_t count, + gxByteBuffer* target, + uint16_t index); +#endif + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + int bb_set( + gxByteBuffer* bb, + const unsigned char* pSource, + uint32_t count); +#else + int bb_set( + gxByteBuffer* bb, + const unsigned char* pSource, + uint16_t count); +#endif + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + int bb_set2( + gxByteBuffer* bb, + gxByteBuffer* data, + uint32_t index, + uint32_t count); +#else + int bb_set2( + gxByteBuffer* bb, + gxByteBuffer* data, + uint16_t index, + uint16_t count); +#endif + + int bb_addString( + gxByteBuffer* bb, + const char* value); + + int bb_attachString( + gxByteBuffer* bb, + char* value); + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + int bb_attach( + gxByteBuffer* arr, + unsigned char* value, + uint32_t count, + uint32_t capacity); + int bb_attachString2( + gxByteBuffer* arr, + char* value, + uint32_t count, + uint32_t capacity); +#else + int bb_attach( + gxByteBuffer* arr, + unsigned char* value, + uint16_t count, + uint16_t capacity); + int bb_attachString2( + gxByteBuffer* arr, + char* value, + uint16_t count, + uint16_t capacity); +#endif + //Clean byte buffer and release allocated memory. + int bb_clear( + gxByteBuffer* bb); + + //Set size and position to zero. Allocated memory is not released. + int bb_empty( + gxByteBuffer* bb); + + int bb_getUInt8( + gxByteBuffer* bb, + unsigned char* value); + + int bb_getUInt8ByIndex( + gxByteBuffer* bb, + uint32_t index, + unsigned char* value); + + int bb_getUInt16( + gxByteBuffer* bb, + uint16_t* value); + + int bb_getUInt24( + gxByteBuffer* bb, + uint32_t* value); + + int bb_getUInt32( + gxByteBuffer* bb, + uint32_t* value); + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + int bb_get( + gxByteBuffer* bb, + unsigned char* value, + uint32_t count); +#else + int bb_get( + gxByteBuffer* bb, + unsigned char* value, + uint16_t count); +#endif + + int bb_getInt8( + gxByteBuffer* arr, + signed char* value); + + int bb_getInt16( + gxByteBuffer* bb, + int16_t* value); + + int bb_getInt32( + gxByteBuffer* bb, + int32_t* value); + + int bb_getInt64( + gxByteBuffer* bb, + int64_t* value); + + int bb_getUInt64( + gxByteBuffer* bb, + uint64_t* value); + +#ifndef DLMS_IGNORE_FLOAT32 + int bb_getFloat( + gxByteBuffer* bb, + float* value); +#endif //DLMS_IGNORE_FLOAT32 + +#ifndef DLMS_IGNORE_FLOAT64 + int bb_getDouble( + gxByteBuffer* bb, + double* value); +#endif //DLMS_IGNORE_FLOAT64 + + int bb_getUInt16ByIndex( + gxByteBuffer* bb, + uint32_t index, + uint16_t* value); + + int bb_getUInt24ByIndex( + gxByteBuffer* bb, + uint32_t index, + uint32_t* value); + + int bb_getUInt32ByIndex( + gxByteBuffer* bb, + uint32_t index, + uint32_t* value); + + int bb_getUInt64ByIndex( + gxByteBuffer* bb, + uint32_t index, + uint64_t* value); + + int bb_getUInt128ByIndex( + gxByteBuffer* bb, + uint32_t index, + unsigned char* value); + +#ifndef DLMS_IGNORE_MALLOC + //Add hex string to byte buffer. + int bb_addHexString( + gxByteBuffer* arr, + const char* str); +#endif //DLMS_IGNORE_MALLOC + + //Add hex string to byte buffer. + int bb_addHexString2( + gxByteBuffer* arr, + const char* str); + + //Add hex string to byte buffer. + int bb_addLogicalName( + gxByteBuffer* arr, + const unsigned char* str); + + //Get byte array as hex string. + int bb_toHexString2( + gxByteBuffer* arr, + char* buffer, + uint16_t size); + +#if !(defined(DLMS_IGNORE_STRING_CONVERTER) || defined(DLMS_IGNORE_MALLOC)) + //Get byte array as a string. + char* bb_toString( + gxByteBuffer* bb); + + //Get byte array as hex string. + char* bb_toHexString( + gxByteBuffer* bb); + + //Add double value to byte array as a string. + int bb_addDoubleAsString( + gxByteBuffer* ba, + double value); +#endif //!(defined(DLMS_IGNORE_STRING_CONVERTER) || defined(DLMS_IGNORE_MALLOC)) + + //Add integer value to byte array as a string. + int bb_addIntAsString( + gxByteBuffer* ba, + int value); + + //Add integer value to byte array as a string. + int bb_addIntAsString2( + gxByteBuffer* ba, + int value, + unsigned char digits); + + /** + * Returns data as byte array. + * + * @param bb Byte buffer as a byte array. + */ +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + int bb_subArray( + gxByteBuffer* bb, + uint32_t index, + uint32_t count, + gxByteBuffer* target); +#else + int bb_subArray( + gxByteBuffer* bb, + uint16_t index, + uint16_t count, + gxByteBuffer* target); +#endif + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + //Move data insize byte array. + int bb_move( + gxByteBuffer* ba, + uint32_t srcPos, + uint32_t destPos, + uint32_t count); +#else + //Move data insize byte array. + int bb_move( + gxByteBuffer* ba, + uint16_t srcPos, + uint16_t destPos, + uint16_t count); +#endif + + /** + * Remove handled bytes. This can be used in debugging to remove handled + * bytes. + */ + int bb_trim( + gxByteBuffer* bb); + + /** + * Compares, whether two given arrays are similar starting from current + * position. + * + * @param bb + * Bytebuffer to compare. + * @param arr + * Array to compare. + * @param length + * Array length. + * @return True, if arrays are similar. False, if the arrays differ. + */ +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + unsigned char bb_compare( + gxByteBuffer* bb, + unsigned char* buff, + uint32_t length); +#else + unsigned char bb_compare( + gxByteBuffer* bb, + unsigned char* buff, + uint16_t length); +#endif + + //Find index of given char. + uint32_t bb_indexOf( + gxByteBuffer* bb, + char ch); + +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + //Print content of byte buffer to cout. + int bb_print(gxByteBuffer* bb); +#endif //defined(_WIN32) || defined(_WIN64) || defined(__linux__) + +#define BB_ATTACH(X, V, S) bb_attach(&X, V, S, sizeof(V)) + +#define BB_ATTACH_STR(X, V, S) bb_attachString2(&X, V, S, sizeof(V)) + +#ifdef __cplusplus +} +#endif + +#endif //BYTE_BUFFER_H diff --git a/components/xt211/ciphering.c b/components/xt211/ciphering.c new file mode 100644 index 0000000..37eb0fa --- /dev/null +++ b/components/xt211/ciphering.c @@ -0,0 +1,1072 @@ +// +// -------------------------------------------------------------------------- +// 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" +#include "gxmem.h" +#ifndef DLMS_IGNORE_HIGH_GMAC + +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) +#include +#endif + +#if defined(USE_AVR) || defined(ARDUINO_ARCH_AVR) +//If AVR is used. +#include +#endif //#if defined(USE_AVR) || defined(ARDUINO_ARCH_AVR) + +#if _MSC_VER > 1400 +#include +#endif +#include +#include "enums.h" +#include "errorcodes.h" +#include "ciphering.h" +#include "helpers.h" +#include "gxaes.h" + +static const unsigned char DEFAUlT_BROADCAST_BLOCK_CIPHER_KEY[] = { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA }; +static const unsigned char DEFAUlT_BLOCK_CIPHER_KEY[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; +static const unsigned char DEFAULT_SYSTEM_TITLE[] = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48 }; +static const unsigned char DEFAUlT_AUTHENTICATION_KEY[] = { 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF +}; + +void cip_init(ciphering* target) +{ + target->invocationCounter = 0; + target->suite = DLMS_SECURITY_SUITE_V0; + target->security = DLMS_SECURITY_NONE; + target->encrypt = 0; +#ifndef DLMS_IGNORE_MALLOC + BYTE_BUFFER_INIT(&target->blockCipherKey); + bb_set(&target->blockCipherKey, DEFAUlT_BLOCK_CIPHER_KEY, sizeof(DEFAUlT_BLOCK_CIPHER_KEY)); + BYTE_BUFFER_INIT(&target->broadcastBlockCipherKey); + bb_set(&target->broadcastBlockCipherKey, DEFAUlT_BROADCAST_BLOCK_CIPHER_KEY, sizeof(DEFAUlT_BROADCAST_BLOCK_CIPHER_KEY)); + BYTE_BUFFER_INIT(&target->systemTitle); + bb_set(&target->systemTitle, DEFAULT_SYSTEM_TITLE, sizeof(DEFAULT_SYSTEM_TITLE)); + BYTE_BUFFER_INIT(&target->authenticationKey); + bb_set(&target->authenticationKey, DEFAUlT_AUTHENTICATION_KEY, sizeof(DEFAUlT_AUTHENTICATION_KEY)); + target->dedicatedKey = NULL; +#else + memcpy(target->blockCipherKey, DEFAUlT_BLOCK_CIPHER_KEY, sizeof(DEFAUlT_BLOCK_CIPHER_KEY)); + memcpy(target->broadcastBlockCipherKey, DEFAUlT_BROADCAST_BLOCK_CIPHER_KEY, sizeof(DEFAUlT_BROADCAST_BLOCK_CIPHER_KEY)); + memcpy(target->systemTitle, DEFAULT_SYSTEM_TITLE, sizeof(DEFAULT_SYSTEM_TITLE)); + memcpy(target->authenticationKey, DEFAUlT_AUTHENTICATION_KEY, sizeof(DEFAUlT_AUTHENTICATION_KEY)); + memset(target->dedicatedKey, 0, 16); +#endif //DLMS_IGNORE_MALLOC + target->broacast = 0; +} + +void cip_clear(ciphering* target) +{ + target->invocationCounter = 1; + target->security = DLMS_SECURITY_NONE; + target->encrypt = 0; +#ifndef DLMS_IGNORE_MALLOC + bb_clear(&target->blockCipherKey); + bb_clear(&target->broadcastBlockCipherKey); + bb_clear(&target->systemTitle); + bb_clear(&target->authenticationKey); + if (target->dedicatedKey != NULL) + { + bb_clear(target->dedicatedKey); + gxfree(target->dedicatedKey); + target->dedicatedKey = NULL; + } +#else + memset(target->blockCipherKey, 0, sizeof(DEFAUlT_BLOCK_CIPHER_KEY)); + memset(target->broadcastBlockCipherKey, 0, sizeof(DEFAUlT_BROADCAST_BLOCK_CIPHER_KEY)); + memset(target->systemTitle, 0, 8); + memset(target->authenticationKey, 0, sizeof(DEFAUlT_AUTHENTICATION_KEY)); + memset(target->dedicatedKey, 0, sizeof(DEFAUlT_BLOCK_CIPHER_KEY)); +#endif //DLMS_IGNORE_MALLOC +} + +/** +* Get nonse from frame counter and system title. +* +* @param frameCounter +* Frame counter. +* @param systemTitle +* System title. +* @return +*/ +static int cip_getNonse(uint32_t frameCounter, unsigned char* systemTitle, gxByteBuffer* nonce) +{ + int ret; + nonce->size = 0; + if ((ret = bb_capacity(nonce, 12)) != 0 || + (ret = bb_set(nonce, systemTitle, 8)) != 0 || + (ret = bb_setUInt32(nonce, frameCounter)) != 0) + { + return ret; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////////////// +//Note! Rcon value is different than in aes! +#ifndef USE_PROGMEM +static const unsigned char __R_CON[11] = { +#else +static const unsigned char __R_CON[11] PROGMEM = { +#endif //#if defined(_WIN32) || defined(_WIN64) + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 }; +/////////////////////////////////////////////////////////////////////////////////////// + +//There is only one TE table. Counting is taking little bit longer, but memory is needed less. +#ifndef USE_PROGMEM + static const uint32_t __TE[256] = { +#else + static const uint32_t __TE[256] PROGMEM = { +#endif //#if defined(_WIN32) || defined(_WIN64) + 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, + 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, + 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, + 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, + 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, + 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, + 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, + 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, + 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, + 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, + 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, + 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, + 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, + 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, + 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, + 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, + 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, + 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, + 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, + 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, + 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, + 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, + 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, + 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, + 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, + 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, + 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, + 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, + 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, + 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, + 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, + 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, + 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, + 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, + 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, + 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, + 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, + 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, + 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, + 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, + 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, + 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, + 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, + 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, + 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, + 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, + 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, + 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, + 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, + 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, + 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, + 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, + 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, + 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, + 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, + 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, + 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, + 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, + 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, + 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, + 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, + 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, + 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, + 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, +}; + +//Note! return value must be uint32_t. +static inline uint32_t GetRcon(unsigned char offset) +{ +#ifdef ARDUINO_ARCH_AVR + return pgm_read_dword_far(__R_CON + offset); +#else + return __R_CON[offset]; +#endif //ARDUINO_ARCH_AVR +} + +static inline uint32_t GetTe(unsigned char offset) +{ +#ifdef ARDUINO_ARCH_AVR + return pgm_read_dword_far(__TE + offset); +#else + return __TE[offset]; +#endif //ARDUINO_ARCH_AVR +} + +#define RCON(i) (GetRcon(i) << 24) + +#define ROTATE(val, bits) ((val >> bits) | (val << (32 - bits))) + +#define TE0(i) GetTe(((i) >> 24) & 0xff) + +#define TE1(i) ROTATE(GetTe(((i) >> 16) & 0xff), 8) + +#define TE2(i) ROTATE(GetTe(((i) >> 8) & 0xff), 16) + +#define TE3(i) ROTATE(GetTe((i) & 0xff), 24) + +#define TE41(i) ((GetTe(((i) >> 24) & 0xff) << 8) & 0xff000000) + +#define TE42(i) (GetTe(((i) >> 16) & 0xff) & 0x00ff0000) + +#define TE43(i) (GetTe(((i) >> 8) & 0xff) & 0x0000ff00) + +#define TE44(i) ((GetTe((i) & 0xff) >> 8) & 0x000000ff) + +#define TE421(i) ((GetTe(((i) >> 16) & 0xff) << 8) & 0xff000000) + +#define TE432(i) (GetTe(((i) >> 8) & 0xff) & 0x00ff0000) + +#define TE443(i) (GetTe((i) & 0xff) & 0x0000ff00) + +#define TE414(i) ((GetTe(((i) >> 24) & 0xff) >> 8) & 0x000000ff) + +#define TE411(i) ((GetTe(((i) >> 24) & 0xff) << 8) & 0xff000000) + +#define TE422(i) (GetTe(((i) >> 16) & 0xff) & 0x00ff0000) + +#define TE433(i) (GetTe(((i) >> 8) & 0xff) & 0x0000ff00) + +#define TE444(i) ((GetTe((i) & 0xff) >> 8) & 0x000000ff) + +int cip_int(uint32_t* rk, + const unsigned char* cipherKey, + uint16_t keyBits) +{ + uint8_t i; + uint32_t temp; + + rk[0] = GETU32(cipherKey); + rk[1] = GETU32(cipherKey + 4); + rk[2] = GETU32(cipherKey + 8); + rk[3] = GETU32(cipherKey + 12); + + if (keyBits == 128) + { + for (i = 0; i < 10; i++) + { + temp = rk[3]; + rk[4] = rk[0] ^ TE421(temp) ^ TE432(temp) ^ + TE443(temp) ^ TE414(temp); + rk[4] = rk[0] ^ TE421(temp) ^ TE432(temp) ^ + TE443(temp) ^ TE414(temp) ^ RCON(i); + rk[5] = rk[1] ^ rk[4]; + rk[6] = rk[2] ^ rk[5]; + rk[7] = rk[3] ^ rk[6]; + rk += 4; + } + return 0; + } + if (keyBits != 256) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + rk[4] = GETU32(cipherKey + 16); + rk[5] = GETU32(cipherKey + 20); + rk[6] = GETU32(cipherKey + 24); + rk[7] = GETU32(cipherKey + 28); + for (i = 0; i < 7; i++) + { + temp = rk[7]; + rk[8] = rk[0] ^ TE421(temp) ^ TE432(temp) ^ + TE443(temp) ^ TE414(temp) ^ RCON(i); + rk[9] = rk[1] ^ rk[8]; + rk[10] = rk[2] ^ rk[9]; + rk[11] = rk[3] ^ rk[10]; + if (i == 6) + { + return 0; + } + temp = rk[11]; + rk[12] = rk[4] ^ TE411(temp) ^ TE422(temp) ^ + TE433(temp) ^ TE444(temp); + rk[13] = rk[5] ^ rk[12]; + rk[14] = rk[6] ^ rk[13]; + rk[15] = rk[7] ^ rk[14]; + rk += 8; + } + return DLMS_ERROR_CODE_OK; +} + +//Arduino DOIT ESP32 uses aes_encrypt. For that reason aes_Encrypt is used. +void aes_Encrypt(const uint32_t* rk, int Nr, const unsigned char* pt, unsigned char* ct) +{ + uint32_t s0, s1, s2, s3, t0, t1, t2, t3; + int r; + s0 = GETU32(pt) ^ rk[0]; + s1 = GETU32(pt + 4) ^ rk[1]; + s2 = GETU32(pt + 8) ^ rk[2]; + s3 = GETU32(pt + 12) ^ rk[3]; + +#define ROUND(i,d,s) \ +d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \ +d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \ +d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \ +d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3] + + /* Nr - 1 full rounds: */ + r = Nr >> 1; + for (;;) + { + ROUND(1, t, s); + rk += 8; + if (--r == 0) + break; + ROUND(0, s, t); + } + +#undef ROUND + + s0 = TE41(t0) ^ TE42(t1) ^ TE43(t2) ^ TE44(t3) ^ rk[0]; + PUT32(ct, s0); + s1 = TE41(t1) ^ TE42(t2) ^ TE43(t3) ^ TE44(t0) ^ rk[1]; + PUT32(ct + 4, s1); + s2 = TE41(t2) ^ TE42(t3) ^ TE43(t0) ^ TE44(t1) ^ rk[2]; + PUT32(ct + 8, s2); + s3 = TE41(t3) ^ TE42(t0) ^ TE43(t1) ^ TE44(t2) ^ rk[3]; + PUT32(ct + 12, s3); +} + +/** +* Make cip_xor for 128 bits. +* +* @param block +* block. +* @param val +*/ +static void cip_xor( + unsigned char* dst, + const unsigned char* src) +{ + int pos; + for (pos = 0; pos != 16; ++pos) + { + dst[pos] ^= src[pos]; + } + /* + uint32_t *d = (uint32_t *)dst; + uint32_t *s = (uint32_t *)src; + *d++ ^= *s++; + *d++ ^= *s++; + *d++ ^= *s++; + *d++ ^= *s++; + */ +} + +static void shift_right_block(unsigned char* v) +{ + uint32_t val = GETU32(v + 12); + val >>= 1; + if (v[11] & 0x01) + { + val |= 0x80000000; + } + PUT32(v + 12, val); + + val = GETU32(v + 8); + val >>= 1; + if (v[7] & 0x01) + val |= 0x80000000; + PUT32(v + 8, val); + + val = GETU32(v + 4); + val >>= 1; + if (v[3] & 0x01) + val |= 0x80000000; + PUT32(v + 4, val); + + val = GETU32(v); + val >>= 1; + PUT32(v, val); +} + +static void cip_multiplyH(const unsigned char* x, const unsigned char* y, unsigned char* z) +{ + unsigned char tmp[16]; + int i, j; + + memset(z, 0, 16); + memcpy(tmp, y, 16); + + for (i = 0; i < 16; i++) + { + for (j = 0; j < 8; j++) + { + if (x[i] & 1 << (7 - j)) + { + cip_xor(z, tmp); + } + //If last bit. + if (tmp[15] & 0x01) + { + shift_right_block(tmp); + tmp[0] ^= 0xe1; + } + else + { + shift_right_block(tmp); + } + } + } +} + +/** +* Count GHash. +*/ +static void cip_getGHash( + const unsigned char* h, + const unsigned char* x, + int xlen, + unsigned char* y) +{ + int m, i; + const unsigned char* xpos = x; + unsigned char tmp[16]; + m = xlen / 16; + for (i = 0; i < m; i++) + { + cip_xor(y, xpos); + xpos += 16; + cip_multiplyH(y, h, tmp); + memcpy(y, tmp, 16); + } + if (x + xlen > xpos) + { + size_t last = x + xlen - xpos; + memcpy(tmp, xpos, last); + memset(tmp + last, 0, sizeof(tmp) - last); + + cip_xor(y, tmp); + + cip_multiplyH(y, h, tmp); + memcpy(y, tmp, 16); + } +} + +static void cip_init_j0( + const unsigned char* iv, + unsigned char len, + const unsigned char* H, + unsigned char* J0) +{ + //IV length. + if (len == 12) + { + memcpy(J0, iv, len); + memset(J0 + len, 0, 16 - len); + J0[15] = 0x01; + } + else + { + unsigned char tmp[16]; + memset(J0, 0, 16); + cip_getGHash(H, iv, len, J0); + PUT32(tmp, (uint32_t)0); + PUT32(tmp + 4, (uint32_t)0); + //Here is expected that data is newer longger than 32 bit. + //This is done because microcontrollers show warning here. + PUT32(tmp + 8, (uint32_t)0); + PUT32(tmp + 12, (uint32_t)(len * 8)); + cip_getGHash(H, tmp, sizeof(tmp), J0); + } +} + +static void cip_inc32(unsigned char* block) +{ + uint32_t val; + val = GETU32(block + 16 - 4); + val++; + PUT32(block + 16 - 4, val); +} + +static void cip_gctr(uint32_t* aes, const unsigned char* icb, unsigned char* in, int len, unsigned char* out) +{ + size_t i, n, last; + unsigned char cb[16], tmp[16]; + unsigned char* pin = in; + unsigned char* pout = out; + if (len == 0) + { + return; + } + n = len / 16; + memcpy(cb, icb, 16); + //Full blocks. + for (i = 0; i < n; i++) + { + if (out == NULL) + { + aes_Encrypt(aes, aes[60], cb, tmp); + cip_xor(pin, tmp); + } + else + { + aes_Encrypt(aes, aes[60], cb, pout); + cip_xor(pout, pin); + } + pin += 16; + pout += 16; + cip_inc32(cb); + } + + last = in + len - pin; + //Last, partial block. + if (last) + { + aes_Encrypt(aes, aes[60], cb, tmp); + for (i = 0; i < last; i++) + { + if (out == NULL) + { + *pin ^= tmp[i]; + ++pin; + } + else + { + *pout = *pin++ ^ tmp[i]; + ++pout; + } + } + } +} + +static void aes_gcm_gctr(uint32_t* aes, const unsigned char* J0, unsigned char* in, int len, unsigned char* out) +{ + unsigned char J0inc[16]; + if (len == 0) + { + return; + } + + memcpy(J0inc, J0, 16); + cip_inc32(J0inc); + cip_gctr(aes, J0inc, in, len, out); +} + +static void aes_gcm_ghash(const unsigned char* H, const unsigned char* aad, int aad_len, + const unsigned char* crypt, int crypt_len, unsigned char* S) +{ + unsigned char len_buf[16]; + cip_getGHash(H, aad, aad_len, S); + cip_getGHash(H, crypt, crypt_len, S); + //Here is expected that data is never longer than 32 bit. + //This is done because microcontrollers show warning here. + PUT32(len_buf, (uint32_t)0); + PUT32(len_buf + 4, (uint32_t)(aad_len * 8)); + PUT32(len_buf + 8, (uint32_t)0); + PUT32(len_buf + 12, (uint32_t)(crypt_len * 8)); + cip_getGHash(H, len_buf, sizeof(len_buf), S); +} + +#ifndef DLMS_IGNORE_MALLOC +int cip_crypt( + ciphering* settings, + DLMS_SECURITY security, + DLMS_COUNT_TYPE type, + uint32_t frameCounter, + unsigned char tag, + unsigned char* systemTitle, + gxByteBuffer* key, + gxByteBuffer* input, + unsigned char encrypt) +#else +int cip_crypt( + ciphering* settings, + DLMS_SECURITY security, + DLMS_COUNT_TYPE type, + uint32_t frameCounter, + unsigned char tag, + unsigned char* systemTitle, + unsigned char* key, + gxByteBuffer* input, + unsigned char encrypt) +#endif //DLMS_IGNORE_MALLOC +{ + int ret; +#ifdef GX_DLMS_MICROCONTROLLER + static uint32_t aes[61] = { 0 }; + static unsigned char H[16] = { 0 }; + static unsigned char J0[16] = { 0 }; + static unsigned char S[16] = { 0 }; + //Nonse must be 20 bytes because it's used later. + static unsigned char NONSE[20] = { 0 }; + memset(H, 0, sizeof(H)); + memset(S, 0, sizeof(S)); +#else + uint32_t aes[61] = { 0 }; + unsigned char H[16] = { 0 }; + unsigned char J0[16] = { 0 }; + unsigned char S[16] = { 0 }; + //Nonse must be 20 bytes because it's used later. + unsigned char NONSE[20] = { 0 }; +#endif //GX_DLMS_MICROCONTROLLER + gxByteBuffer nonse; + if (memcmp(systemTitle, EMPTY_SYSTEM_TITLE, 8) == 0) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + bb_attach(&nonse, NONSE, 0, sizeof(NONSE)); + if ((ret = cip_getNonse(frameCounter, systemTitle, &nonse)) != 0) + { + return ret; + } + if ((ret = cip_int( + aes, +#ifndef DLMS_IGNORE_MALLOC + key->data, +#else + key, +#endif //DLMS_IGNORE_MALLOC + settings->suite == DLMS_SECURITY_SUITE_V2 ? 32 * 8 : 16 * 8)) != 0) + { + return ret; + } + if (settings->suite == DLMS_SECURITY_SUITE_V2) + { + aes[60] = 14; + } + else + { + aes[60] = 10; + } + //Hash subkey. + aes_Encrypt(aes, aes[60], H, H); + cip_init_j0(nonse.data, (unsigned char)nonse.size, H, J0); + //Allocate space for authentication tag. + if (security != DLMS_SECURITY_ENCRYPTION && !encrypt) + { + //Save authentication key to nonse. + bb_clear(&nonse); + ret = bb_set(&nonse, input->data + input->size - 12, 12); + input->size -= 12; + } + unsigned char offset; + if (settings->suite == DLMS_SECURITY_SUITE_V2) + { + offset = 33; + } + else + { + offset = 17; + } + if (security == DLMS_SECURITY_AUTHENTICATION) + { + if ((ret = bb_move(input, input->position, offset, bb_available(input))) == 0) + { + input->position = 0; + bb_setUInt8ByIndex(input, 0, security | settings->suite); +#ifndef DLMS_IGNORE_MALLOC + memcpy(input->data + 1, settings->authenticationKey.data, settings->authenticationKey.size); +#else + memcpy(input->data + 1, settings->authenticationKey, offset - 1); +#endif //DLMS_IGNORE_MALLOC + aes_gcm_ghash(H, input->data, input->size, input->data, 0, S); + if ((ret = bb_move(input, offset, 0, input->size - offset)) == 0) + { + cip_gctr(aes, J0, S, sizeof(S), input->data + input->size); + if (encrypt) + { + input->size += 12; + } + else + { + if (memcmp(NONSE, input->data + input->size, 12) != 0) + { + ret = DLMS_ERROR_CODE_INVALID_TAG; + } + } + } + } + } + else if (security == DLMS_SECURITY_ENCRYPTION) + { + //Encrypt the data. + aes_gcm_ghash(H, input->data, input->size, input->data, 0, S); + if (!encrypt) + { + ret = bb_move(input, input->position, 0, bb_available(input)); + input->position = 0; + } + aes_gcm_gctr(aes, J0, input->data + input->position, bb_available(input), NULL); + } + else if (security == DLMS_SECURITY_AUTHENTICATION_ENCRYPTION) + { + if (encrypt) + { + //Encrypt the data. + aes_gcm_gctr(aes, J0, input->data + input->position, bb_available(input), NULL); + } + if ((ret = bb_move(input, input->position, offset, bb_available(input))) == 0) + { + input->position = 0; + ret = bb_setUInt8ByIndex(input, 0, security | settings->suite); +#ifndef DLMS_IGNORE_MALLOC + memcpy(input->data + 1, settings->authenticationKey.data, settings->authenticationKey.size); +#else + memcpy(input->data + 1, settings->authenticationKey, offset - 1); +#endif //DLMS_IGNORE_MALLOC + aes_gcm_ghash(H, input->data, offset, input->data + offset, input->size - offset, S); + if ((ret = bb_move(input, offset, 0, input->size - offset)) == 0) + { + if (!encrypt) + { + cip_gctr(aes, J0, S, sizeof(S), input->data + input->size); + //Decrypt the data. + aes_gcm_gctr(aes, J0, input->data + input->position, bb_available(input), NULL); + } + cip_gctr(aes, J0, S, sizeof(S), input->data + input->size); + if (encrypt) + { + input->size += 12; + } + else + { + //Check authentication tag. + if (memcmp(NONSE, input->data + input->size, 12) != 0) + { + ret = DLMS_ERROR_CODE_INVALID_TAG; + } + else + { + ret = bb_move(input, input->position, 0, bb_available(input)); + } + input->position = 0; + } + } + } + } + if (ret == 0 && encrypt) + { + ++settings->invocationCounter; + } + if (ret == 0 && encrypt && type == DLMS_COUNT_TYPE_PACKET) + { + if ((ret = bb_clear(&nonse)) == 0 && + (ret = bb_setUInt8(&nonse, tag)) == 0) + { + if (tag == DLMS_COMMAND_GENERAL_GLO_CIPHERING || + tag == DLMS_COMMAND_GENERAL_DED_CIPHERING) + { + hlp_setObjectCount(8, &nonse); + bb_set(&nonse, systemTitle, 8); + } + tag = security | settings->suite; + if (settings->broacast) + { + tag |= 0x40; + } + if ((ret = hlp_setObjectCount(5 + input->size, &nonse)) == 0 && + (ret = bb_setUInt8(&nonse, tag)) == 0 && + (ret = bb_setUInt32(&nonse, frameCounter)) == 0 && + (ret = bb_insert(nonse.data, nonse.size, input, 0)) == 0) + { + memcpy(input->data, nonse.data, nonse.size); + } + } + } + return ret; +} + +#ifndef DLMS_IGNORE_MALLOC +int cip_encrypt( + ciphering* settings, + DLMS_SECURITY security, + DLMS_COUNT_TYPE type, + uint32_t frameCounter, + unsigned char tag, + unsigned char* systemTitle, + gxByteBuffer* key, + gxByteBuffer* input) +#else +int cip_encrypt( + ciphering* settings, + DLMS_SECURITY security, + DLMS_COUNT_TYPE type, + uint32_t frameCounter, + unsigned char tag, + unsigned char* systemTitle, + unsigned char* key, + gxByteBuffer* input) +#endif //DLMS_IGNORE_MALLOC +{ + return cip_crypt( + settings, + security, + type, + frameCounter, + tag, + systemTitle, + key, + input, + 1); +} + +#ifndef DLMS_IGNORE_MALLOC +int cip_decrypt( + ciphering* settings, + unsigned char* title, + gxByteBuffer* key, + gxByteBuffer* data, + DLMS_SECURITY* security, + DLMS_SECURITY_SUITE* suite, + uint64_t* invocationCounter) +#else +int cip_decrypt( + ciphering* settings, + unsigned char* title, + unsigned char* key, + gxByteBuffer* data, + DLMS_SECURITY* security, + DLMS_SECURITY_SUITE* suite, + uint64_t* invocationCounter) +#endif //DLMS_IGNORE_MALLOC +{ +#ifdef GX_DLMS_MICROCONTROLLER + static unsigned char systemTitle[8]; +#else + unsigned char systemTitle[8]; +#endif //GX_DLMS_MICROCONTROLLER + uint16_t length; + int ret; + unsigned char ch; + uint32_t frameCounter; + DLMS_COMMAND cmd; + if (data == NULL || data->size - data->position < 2) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if ((ret = bb_getUInt8(data, &ch)) != 0) + { + return ret; + } + cmd = (DLMS_COMMAND)ch; + switch (cmd) + { + case DLMS_COMMAND_GENERAL_GLO_CIPHERING: + case DLMS_COMMAND_GENERAL_DED_CIPHERING: + if ((ret = hlp_getObjectCount2(data, &length)) != 0) + { + return ret; + } + if (length != 0) + { + if (length != 8) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + bb_get(data, systemTitle, length); + title = systemTitle; + } + break; + case DLMS_COMMAND_GLO_INITIATE_REQUEST: + case DLMS_COMMAND_GLO_INITIATE_RESPONSE: + case DLMS_COMMAND_GLO_READ_REQUEST: + case DLMS_COMMAND_GLO_READ_RESPONSE: + case DLMS_COMMAND_GLO_WRITE_REQUEST: + case DLMS_COMMAND_GLO_WRITE_RESPONSE: + case DLMS_COMMAND_GLO_GET_REQUEST: + case DLMS_COMMAND_GLO_GET_RESPONSE: + case DLMS_COMMAND_GLO_SET_REQUEST: + case DLMS_COMMAND_GLO_SET_RESPONSE: + case DLMS_COMMAND_GLO_METHOD_REQUEST: + case DLMS_COMMAND_GLO_METHOD_RESPONSE: + case DLMS_COMMAND_GLO_EVENT_NOTIFICATION_REQUEST: + case DLMS_COMMAND_DED_INITIATE_REQUEST: + case DLMS_COMMAND_DED_INITIATE_RESPONSE: + case DLMS_COMMAND_DED_GET_REQUEST: + case DLMS_COMMAND_DED_GET_RESPONSE: + case DLMS_COMMAND_DED_SET_REQUEST: + case DLMS_COMMAND_DED_SET_RESPONSE: + case DLMS_COMMAND_DED_METHOD_REQUEST: + case DLMS_COMMAND_DED_METHOD_RESPONSE: + case DLMS_COMMAND_DED_EVENT_NOTIFICATION: + break; + default: + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if ((ret = hlp_getObjectCount2(data, &length)) != 0) + { + return ret; + } + if ((ret = bb_getUInt8(data, &ch)) != 0) + { + return ret; + } + *security = (DLMS_SECURITY)(ch & 0x30); + if (suite != NULL) + { + *suite = (DLMS_SECURITY_SUITE) (ch & 0x3); + } + //If Key_Set or authentication or encryption is not used. + if (ch & 0x40 || *security == DLMS_SECURITY_NONE) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if ((ret = bb_getUInt32(data, &frameCounter)) != 0) + { + return ret; + } + if (invocationCounter != NULL) + { + *invocationCounter = frameCounter; + } + ret = cip_crypt( + settings, + *security, + DLMS_COUNT_TYPE_DATA, + frameCounter, + 0, + title, + key, + data, + 0); + return ret; +} + +static const unsigned char WRAP_IV[] = { 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6 }; + +int cip_encryptKey( + unsigned char* kek, + unsigned char size, + gxByteBuffer* data, + gxByteBuffer* output) +{ + unsigned char buf[16] = { 0 }; + unsigned char buf2[16] = { 0 }; + unsigned char n, j, i; + + if (kek == NULL || size != 16 || + data == NULL || data->size != 16 || + output == NULL) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + bb_capacity(output, 24); + output->size = 24; + output->position = 0; + // Amount of 64-bit blocks. + n = (unsigned char)(data->size >> 3); + memcpy(output->data, WRAP_IV, 8); + memcpy(output->data + 8, data->data, data->size); + for (j = 0; j != 6; j++) + { + for (i = 1; i <= n; i++) + { + memcpy(buf, output->data, 8); + memcpy(buf + 8, output->data + (8 * i), 8); + gxaes_ecb_encrypt(buf, kek, buf2, 16); + unsigned int t = n * j + i; + for (int k = 1; t != 0; k++) + { + unsigned char v = (unsigned char)t; + buf2[sizeof(WRAP_IV) - k] ^= v; + t = (int)((unsigned int)t >> 8); + } + memcpy(output->data, buf2, 8); + memcpy(output->data + (8 * i), buf2 + 8, 8); + } + } + return 0; +} + +int cip_decryptKey( + unsigned char* kek, + //KEK size. + unsigned char size, + gxByteBuffer* data, + gxByteBuffer* output) +{ + int ret; + unsigned char a[8]; + unsigned char buf[16]; + unsigned char buf2[16]; + signed char j, i; + unsigned char k, v, n; + uint16_t t; + // Amount of 64-bit blocks. + n = (unsigned char)(bb_size(data) >> 3); + if (kek == NULL || size != 16 || data == NULL || data->size != n * 8 || + output == NULL) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if ((ret = bb_capacity(output, 16)) != 0) + { + return ret; + } + output->size = 16; + output->position = 0; + memcpy(a, data->data, sizeof(WRAP_IV)); + memcpy(output->data, data->data + sizeof(WRAP_IV), data->size - sizeof(WRAP_IV)); + if (--n == 0) + { + n = 1; + } + for (j = 5; j >= 0; j--) + { + for (i = n; i >= 1; i--) + { + memcpy(buf, a, sizeof(WRAP_IV)); + memcpy(buf + sizeof(WRAP_IV), output->data + 8 * (i - 1), 8); + t = n * j + i; + for (k = 1; t != 0; k++) + { + v = (unsigned char)t; + buf[sizeof(WRAP_IV) - k] ^= v; + t = (uint16_t)(t >> 8); + } + gxaes_ecb_decrypt(buf, kek, buf2, 16); + memcpy(a, buf2, 8); + memcpy(output->data + 8 * (i - 1), buf2 + 8, 8); + } + } + if (memcmp(a, WRAP_IV, sizeof(WRAP_IV)) != 0) + { + output->size = 0; + return DLMS_ERROR_CODE_FALSE; + } + return 0; +} + +#endif //DLMS_IGNORE_HIGH_GMAC diff --git a/components/xt211/ciphering.h b/components/xt211/ciphering.h new file mode 100644 index 0000000..e67facf --- /dev/null +++ b/components/xt211/ciphering.h @@ -0,0 +1,177 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef CHIPPERING_H +#define CHIPPERING_H +#include "gxignore.h" +#ifndef DLMS_IGNORE_HIGH_GMAC +#ifdef __cplusplus +extern "C" { +#endif + +#include "bytebuffer.h" +#include "enums.h" + + +typedef struct +{ + /** + * Used security. + */ + DLMS_SECURITY security; + DLMS_SECURITY_SUITE suite; + + /** + * Is data encrypted. + */ + unsigned char encrypt; + + /** + * Block cipher key. + */ +#ifndef DLMS_IGNORE_MALLOC + gxByteBuffer blockCipherKey; +#else + unsigned char blockCipherKey[32]; +#endif //DLMS_IGNORE_MALLOC + +/** +* Broadcast block cipher key. +*/ +#ifndef DLMS_IGNORE_MALLOC + gxByteBuffer broadcastBlockCipherKey; +#else + unsigned char broadcastBlockCipherKey[32]; +#endif //DLMS_IGNORE_MALLOC + + /** + * System title. + */ +#ifndef DLMS_IGNORE_MALLOC + gxByteBuffer systemTitle; +#else + unsigned char systemTitle[8]; +#endif //DLMS_IGNORE_MALLOC + + /** + * Invocation (Frame) counter. + */ + uint32_t invocationCounter; +#ifndef DLMS_IGNORE_MALLOC + gxByteBuffer authenticationKey; +#else + unsigned char authenticationKey[32]; +#endif //DLMS_IGNORE_MALLOC + + //Dedicated key. +#ifndef DLMS_IGNORE_MALLOC + gxByteBuffer* dedicatedKey; +#else + unsigned char dedicatedKey[32]; +#endif //DLMS_IGNORE_MALLOC + //Is data send as a broadcast or unicast. + unsigned char broacast; +} ciphering; + + +void cip_init(ciphering* target); +void cip_clear(ciphering* target); +/** +* Encrypt data. +*/ +#ifndef DLMS_IGNORE_MALLOC +int cip_encrypt( + ciphering* settings, + DLMS_SECURITY security, + DLMS_COUNT_TYPE type, + uint32_t frameCounter, + unsigned char tag, + unsigned char* systemTitle, + gxByteBuffer* key, + gxByteBuffer* input); +#else +int cip_encrypt( + ciphering* settings, + DLMS_SECURITY security, + DLMS_COUNT_TYPE type, + uint32_t frameCounter, + unsigned char tag, + unsigned char* systemTitle, + unsigned char* key, + gxByteBuffer* input); +#endif //DLMS_IGNORE_MALLOC + +/** +* Decrypt data. +*/ +#ifndef DLMS_IGNORE_MALLOC +int cip_decrypt( + ciphering* settings, + unsigned char* title, + gxByteBuffer* key, + gxByteBuffer* data, + DLMS_SECURITY* security, + DLMS_SECURITY_SUITE* suite, + uint64_t* invocationCounter); +#else +int cip_decrypt( + ciphering* settings, + unsigned char* title, + unsigned char* key, + gxByteBuffer* data, + DLMS_SECURITY* security, + DLMS_SECURITY_SUITE* suite, + uint64_t* invocationCounter); +#endif //DLMS_IGNORE_MALLOC + +// Encrypt data using AES RFC3394. +int cip_encryptKey( + unsigned char* kek, + //KEK size. + unsigned char size, + gxByteBuffer* data, + gxByteBuffer* output); + +// Decrypt data using AES RFC3394. +//Returns DLMS_ERROR_CODE_FALSE if data is not encrypted with the key. +int cip_decryptKey( + unsigned char* kek, + //KEK size. + unsigned char size, + gxByteBuffer* data, + gxByteBuffer* output); + +#ifdef __cplusplus +} +#endif +#endif //DLMS_IGNORE_HIGH_GMAC +#endif //CHIPPERING_H diff --git a/components/xt211/client.c b/components/xt211/client.c new file mode 100644 index 0000000..f8e5738 --- /dev/null +++ b/components/xt211/client.c @@ -0,0 +1,2251 @@ +// +// -------------------------------------------------------------------------- +// 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(DLMS_IGNORE_CLIENT) +#include "gxmem.h" + +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) +#include +#endif + +#if _MSC_VER > 1400 +#include +#endif +#include "apdu.h" +#include "client.h" +#include "gxkey.h" +#include "gxset.h" +#include "gxget.h" +#include "dlms.h" +#include "cosem.h" +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) +#include "gxsetignoremalloc.h" +#else +#include "gxsetmalloc.h" +#endif //DLMS_IGNORE_MALLOC + +#ifndef DLMS_IGNORE_HDLC +int cl_snrmRequest(dlmsSettings* settings, message* messages) +{ + int ret; + gxByteBuffer* reply; + gxByteBuffer* pData; + mes_clear(messages); + //Save default values. + settings->initializeMaxInfoTX = settings->maxInfoTX; + settings->initializeMaxInfoRX = settings->maxInfoRX; + settings->initializeWindowSizeTX = settings->windowSizeTX; + settings->initializeWindowSizeRX = settings->windowSizeRX; + settings->connected = DLMS_CONNECTION_STATE_NONE; + settings->isAuthenticationRequired = 0; +#ifndef DLMS_IGNORE_PLC + // SNRM request is not used for all communication channels. + if (settings->interfaceType == DLMS_INTERFACE_TYPE_PLC_HDLC) + { + reply = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + BYTE_BUFFER_INIT(reply); + ret = dlms_getMacHdlcFrame(settings, DLMS_COMMAND_SNRM, 0, NULL, reply); + if (ret == 0) + { + mes_push(messages, reply); + } + return ret; + } +#endif //DLMS_IGNORE_PLC + if (settings->interfaceType != DLMS_INTERFACE_TYPE_HDLC && settings->interfaceType != DLMS_INTERFACE_TYPE_HDLC_WITH_MODE_E) + { + return 0; + } + if (settings->interfaceType == DLMS_INTERFACE_TYPE_WRAPPER) + { + return DLMS_ERROR_CODE_OK; + } + resetFrameSequence(settings); +#ifdef DLMS_IGNORE_MALLOC + if (!(messages->capacity > messages->size)) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + reply = messages->data[messages->size]; + ++messages->size; + bb_clear(reply); + pData = settings->serializedPdu; + if (pData == NULL) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + bb_clear(pData); +#else + reply = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + BYTE_BUFFER_INIT(reply); + gxByteBuffer bb; + BYTE_BUFFER_INIT(&bb); + bb_capacity(&bb, 30); + pData = &bb; +#endif //DLMS_IGNORE_MALLOC + + // FromatID + if ((ret = bb_setUInt8(pData, 0x81)) == 0 && + // GroupID + (ret = bb_setUInt8(pData, 0x80)) == 0 && + // Length is updated later. + (ret = bb_setUInt8(pData, 0)) == 0) + { + // If custom HDLC parameters are used. + if (ret == 0 && + (DEFAULT_MAX_INFO_TX != settings->maxInfoTX || + DEFAULT_MAX_INFO_RX != settings->maxInfoRX || + DEFAULT_MAX_WINDOW_SIZE_TX != settings->windowSizeTX || + DEFAULT_MAX_WINDOW_SIZE_RX != settings->windowSizeRX)) + { + if ((ret = bb_setUInt8(pData, HDLC_INFO_MAX_INFO_TX)) != 0 || + (ret = dlms_appendHdlcParameter(pData, settings->maxInfoTX)) != 0 || + (ret = bb_setUInt8(pData, HDLC_INFO_MAX_INFO_RX)) != 0 || + (ret = dlms_appendHdlcParameter(pData, settings->maxInfoRX)) != 0 || + (ret = bb_setUInt8(pData, HDLC_INFO_WINDOW_SIZE_TX)) != 0 || + (ret = bb_setUInt8(pData, 4)) != 0 || + (ret = bb_setUInt32(pData, settings->windowSizeTX)) != 0 || + (ret = bb_setUInt8(pData, HDLC_INFO_WINDOW_SIZE_RX)) != 0 || + (ret = bb_setUInt8(pData, 4)) != 0 || + (ret = bb_setUInt32(pData, settings->windowSizeRX)) != 0) + { + //Error is returned in the end of this method. + } + } + // If default HDLC parameters are not used. + if (ret == 0) + { + if (pData->size != 3) + { + // Length. + ret = bb_setUInt8ByIndex(pData, 2, (unsigned char)(pData->size - 3)); + } + else + { + bb_clear(pData); + } + } + if (ret == 0 && (ret = dlms_getHdlcFrame(settings, DLMS_COMMAND_SNRM, pData, reply)) != 0) + { + bb_clear(pData); + bb_clear(reply); +#ifndef DLMS_IGNORE_MALLOC + gxfree(reply); +#endif //DLMS_IGNORE_MALLOC + return ret; + } + } + bb_clear(pData); +#ifndef DLMS_IGNORE_MALLOC + mes_push(messages, reply); +#endif //DLMS_IGNORE_MALLOC + return ret; +} + +int cl_parseUAResponse(dlmsSettings* settings, gxByteBuffer* data) +{ + int ret = dlms_parseSnrmUaResponse(settings, data); + if (ret == 0 && bb_size(data) != 0) + { + settings->connected = DLMS_CONNECTION_STATE_HDLC; + } + return ret; +} + +int cl_getFrameSize(dlmsSettings* settings, gxByteBuffer* data, uint32_t* size) +{ + static const unsigned char HDLC_FRAME_START_END = 0x7E; + int ret = 0; + uint16_t value; + unsigned char ch; + *size = 1; + switch (settings->interfaceType) + { + case DLMS_INTERFACE_TYPE_HDLC: + case DLMS_INTERFACE_TYPE_HDLC_WITH_MODE_E: + { + uint32_t pos, index = data->position; + // If whole frame is not received yet. + if (bb_available(data) > 8) + { + // Find start of HDLC frame. + for (pos = data->position; pos < data->size; ++pos) + { + ret = bb_getUInt8(data, &ch); + if (ret != 0 || ch == HDLC_FRAME_START_END) + { + break; + } + } + if ((ret = bb_getUInt8(data, &ch)) == 0) + { + // Check frame length. + if ((ch & 0x7) != 0) + { + *size = ((ch & 0x7) << 8); + } + if ((ret = bb_getUInt8(data, &ch)) == 0) + { + *size += 1 + ch; + } + } + } + data->position = index; + } + break; + case DLMS_INTERFACE_TYPE_WRAPPER: + if (bb_available(data) < 8 || + (ret = bb_getUInt16ByIndex(data, data->position, &value)) != 0 || + value != 1) + { + *size = 8; + } + else + { + if ((ret = bb_getUInt16ByIndex(data, data->position + 6, &value)) == 0) + { + *size = 8 + value; + } + } + break; + case DLMS_INTERFACE_TYPE_PLC: + if (bb_available(data) < 2 || + (ret = bb_getUInt8ByIndex(data, data->position, &ch)) != 0 || + ch != 2) + { + *size = 2; + } + else + { + if ((ret = bb_getUInt8ByIndex(data, data->position + 1, &ch)) == 0) + { + *size = 2 + ch; + } + } + break; + default: + *size = 1; + break; + } + if (*size < 1) + { + *size = 1; + } + return ret; +} + +int cl_getRemainingFrameSize(dlmsSettings* settings, gxByteBuffer* data, uint32_t* size) +{ + int ret = cl_getFrameSize(settings, data, size); + if (ret == 0) + { + *size -= bb_available(data); + } + return ret; +} + +#endif //DLMS_IGNORE_HDLC + +int cl_aarqRequest( + dlmsSettings* settings, + message* messages) +{ + if (settings->proposedConformance == 0) + { + //Invalid conformance. + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if (dlms_usePreEstablishedConnection(settings)) + { + //Invalid conformance. + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + + //Save default values. + settings->initializePduSize = settings->maxPduSize; + int ret; + gxByteBuffer* pdu; +#ifdef DLMS_IGNORE_MALLOC + if (!(messages->size < messages->capacity)) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + pdu = settings->serializedPdu; + if (pdu == NULL) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + bb_clear(pdu); +#else + gxByteBuffer buff; +#ifdef GX_DLMS_MICROCONTROLLER + static unsigned char GX_AARQ_PDU[130]; + if ((ret = bb_attach(&buff, GX_AARQ_PDU, 0, sizeof(GX_AARQ_PDU))) != 0) + { + return ret; + } + pdu = &buff; +#else + BYTE_BUFFER_INIT(&buff); + if ((ret = bb_capacity(&buff, 100)) != 0) + { + return ret; + } + pdu = &buff; +#endif +#endif //DLMS_IGNORE_MALLOC + + settings->connected &= ~DLMS_CONNECTION_STATE_DLMS; + resetBlockIndex(settings); + mes_clear(messages); + ret = dlms_checkInit(settings); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + bb_clear(&settings->stoCChallenge); + if (settings->autoIncreaseInvokeID) + { + settings->invokeID = 0; + } + else + { + settings->invokeID = 1; + } + // If authentication or ciphering is used. + if (settings->authentication > DLMS_AUTHENTICATION_LOW && settings->customChallenges == 0) + { + if ((ret = dlms_generateChallenge(&settings->ctoSChallenge)) != 0) + { + return ret; + } + } + if ((ret = apdu_generateAarq(settings, pdu)) == 0) + { + if (settings->useLogicalNameReferencing) + { + gxLNParameters p; + params_initLN(&p, settings, 0, DLMS_COMMAND_AARQ, 0, pdu, NULL, 0xFF, DLMS_COMMAND_NONE, 0, 0); + ret = dlms_getLnMessages(&p, messages); + } + else + { +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + gxSNParameters p; + params_initSN(&p, settings, DLMS_COMMAND_AARQ, 0, 0, NULL, pdu, DLMS_COMMAND_NONE); + ret = dlms_getSnMessages(&p, messages); +#else + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + } + } + settings->connected &= ~DLMS_CONNECTION_STATE_DLMS; + bb_clear(pdu); + return ret; +} + +int cl_parseAAREResponse(dlmsSettings* settings, gxByteBuffer* reply) +{ + int ret; + unsigned char sd; + DLMS_ASSOCIATION_RESULT result; + unsigned char command = 0; + if ((ret = apdu_parsePDU(settings, reply, &result, &sd, &command)) != 0) + { + return ret; + } + if (result != DLMS_ASSOCIATION_RESULT_ACCEPTED) + { + if (result == DLMS_ASSOCIATION_RESULT_TRANSIENT_REJECTED) + { + return DLMS_ERROR_CODE_REJECTED_TRANSIENT; + } + return DLMS_ERROR_CODE_REJECTED_PERMAMENT; + } + settings->isAuthenticationRequired = sd == DLMS_SOURCE_DIAGNOSTIC_AUTHENTICATION_REQUIRED; + if (!settings->isAuthenticationRequired) + { + settings->connected |= DLMS_CONNECTION_STATE_DLMS; + } + if (settings->dlmsVersionNumber != 6) + { + //Invalid DLMS version number. + return DLMS_ERROR_CODE_INVALID_VERSION_NUMBER; + } + return 0; +} + +int cl_getApplicationAssociationRequest( + dlmsSettings* settings, + message* messages) +{ + int ret; + gxByteBuffer challenge; + gxByteBuffer* pw; + dlmsVARIANT data; +#ifndef DLMS_IGNORE_HIGH_GMAC +#ifdef DLMS_IGNORE_MALLOC + gxByteBuffer pw2; +#endif //DLMS_IGNORE_MALLOC +#endif //DLMS_IGNORE_HIGH_GMAC +#ifndef GX_DLMS_MICROCONTROLLER + unsigned char APPLICATION_ASSOCIATION_REQUEST[32]; +#else + static unsigned char APPLICATION_ASSOCIATION_REQUEST[32]; +#endif //DLMS_IGNORE_HIGH_GMAC + bb_attach(&challenge, APPLICATION_ASSOCIATION_REQUEST, 0, sizeof(APPLICATION_ASSOCIATION_REQUEST)); + if (settings->authentication != DLMS_AUTHENTICATION_HIGH_ECDSA && +#ifndef DLMS_IGNORE_HIGH_GMAC + settings->authentication != DLMS_AUTHENTICATION_HIGH_GMAC && +#endif // DLMS_IGNORE_HIGH_GMAC + settings->password.size == 0) + { + //Password is invalid. + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + resetBlockIndex(settings); +#ifndef DLMS_IGNORE_HIGH_GMAC + if (settings->authentication == DLMS_AUTHENTICATION_HIGH_GMAC) + { +#ifndef DLMS_IGNORE_MALLOC + pw = &settings->cipher.systemTitle; +#else + bb_attach(&pw2, settings->cipher.systemTitle, 8, 8); + pw = &pw2; +#endif //DLMS_IGNORE_MALLOC + } + else +#endif //DLMS_IGNORE_HIGH_GMAC + { + pw = &settings->password; + } + ret = dlms_secure(settings, +#ifndef DLMS_IGNORE_HIGH_GMAC + settings->cipher.invocationCounter, +#else + 0, +#endif //DLMS_IGNORE_HIGH_GMAC + & settings->stoCChallenge, + pw, + &challenge); + if (ret == 0) + { + ++settings->cipher.invocationCounter; + var_init(&data); + data.vt = DLMS_DATA_TYPE_OCTET_STRING; + data.byteArr = &challenge; + { + if (settings->useLogicalNameReferencing) + { + static const unsigned char LN[6] = { 0, 0, 40, 0, 0, 255 }; + ret = cl_methodLN(settings, LN, DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME, + 1, &data, messages); + } + else + { +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + ret = cl_methodSN(settings, 0xFA00, DLMS_OBJECT_TYPE_ASSOCIATION_SHORT_NAME, 8, &data, + messages); +#else + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + } + } +#ifndef DLMS_IGNORE_MALLOC + var_clear(&data); + bb_clear(&challenge); +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +int cl_parseApplicationAssociationResponse( + dlmsSettings* settings, + gxByteBuffer* reply) +{ + unsigned char empty, equals = 0; + gxByteBuffer* secret; + gxByteBuffer challenge; +#ifndef DLMS_IGNORE_HIGH_GMAC + gxByteBuffer bb2; +#endif //DLMS_IGNORE_HIGH_GMAC + int ret; + uint32_t ic = 0; + gxByteBuffer value; + static unsigned char tmp[MAX_CHALLENGE_SIZE]; + static unsigned char CHALLENGE_BUFF[MAX_CHALLENGE_SIZE]; + bb_attach(&value, tmp, 0, sizeof(tmp)); + bb_attach(&challenge, CHALLENGE_BUFF, 0, sizeof(CHALLENGE_BUFF)); + if ((ret = cosem_getOctetString(reply, &value)) != 0) + { + settings->connected &= ~DLMS_CONNECTION_STATE_DLMS; + //ParseApplicationAssociationResponse failed. Server to Client do not match. + return DLMS_ERROR_CODE_AUTHENTICATION_FAILURE; + } + empty = value.size == 0; + if (!empty) + { +#ifndef DLMS_IGNORE_HIGH_GMAC + if (settings->authentication == DLMS_AUTHENTICATION_HIGH_GMAC) + { + unsigned char ch; + bb_attach(&bb2, settings->sourceSystemTitle, sizeof(settings->sourceSystemTitle), sizeof(settings->sourceSystemTitle)); + secret = &bb2; + if ((ret = bb_set(&challenge, value.data, value.size)) != 0 || + (ret = bb_getUInt8(&challenge, &ch)) != 0 || + (ret = bb_getUInt32(&challenge, &ic)) != 0) + { + return ret; + } + bb_clear(&challenge); + } + else +#endif //DLMS_IGNORE_HIGH_GMAC + { + secret = &settings->password; + } + if ((ret = dlms_secure( + settings, + ic, + &settings->ctoSChallenge, + secret, + &challenge)) != 0) + { + return ret; + } + equals = bb_compare( + &challenge, + value.data, + value.size); + } + else + { + // Server did not accept CtoS. + } + if (!equals) + { + settings->connected &= ~DLMS_CONNECTION_STATE_DLMS; + //ParseApplicationAssociationResponse failed. Server to Client do not match. + return DLMS_ERROR_CODE_AUTHENTICATION_FAILURE; + } + settings->connected |= DLMS_CONNECTION_STATE_DLMS; + return 0; +} + +int cl_getObjectsRequest(dlmsSettings* settings, message* messages) +{ + int ret; + if (settings->useLogicalNameReferencing) + { + static const unsigned char ln[] = { 0, 0, 40, 0, 0, 0xFF }; + ret = cl_readLN(settings, ln, DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME, 2, NULL, messages); + } + else + { +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + ret = cl_readSN(settings, 0xFA00, 2, NULL, messages); +#else + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + } + return ret; +} + +#ifndef DLMS_IGNORE_MALLOC +int cl_parseObjects(dlmsSettings* settings, gxByteBuffer* data) +{ + int ret; + oa_clear(&settings->objects, 0); + oa_clear(&settings->releasedObjects, 1); + if (settings->useLogicalNameReferencing) + { +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + ret = cosem_parseLNObjects(settings, data, &settings->objects); +#else + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif // DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + } + else + { +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + ret = cosem_parseSNObjects(settings, data, &settings->objects); +#else + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif // DLMS_IGNORE_ASSOCIATION_SHORT_NAME + } + return ret; +} +#endif //DLMS_IGNORE_MALLOC + +int cl_parseObjectCount( + gxByteBuffer* data, + uint16_t* count) +{ + unsigned char ch; + int ret; + //Get array tag. + ret = bb_getUInt8(data, &ch); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + //Check that data is in the array + if (ch != DLMS_DATA_TYPE_ARRAY) + { + return DLMS_ERROR_CODE_INVALID_RESPONSE; + } + //get object count + if (hlp_getObjectCount2(data, count) != 0) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + return ret; +} + +int cl_parseNextObject( + dlmsSettings* settings, + gxByteBuffer* data, + gxObject* object) +{ + int ret = 0; + uint16_t size, capacity = sizeof(object->logicalName); + if (settings->useLogicalNameReferencing) + { + uint16_t pos; + signed char id; + unsigned char mode; + dlmsVARIANT selector; + if ((ret = cosem_checkStructure(data, 4)) == 0 && + (ret = cosem_getUInt16(data, &object->objectType)) == 0 && + (ret = cosem_getUInt8(data, &object->version)) == 0 && + (ret = cosem_getOctetString2(data, object->logicalName, capacity, &size)) == 0 && + (ret = cosem_checkStructure(data, 2)) == 0) + { + size = 0xFFFF; + if ((ret = cosem_checkArray(data, &size)) == 0) + { + var_init(&selector); + //Get access modes. + for (pos = 0; pos != size; ++pos) + { + if ((ret = cosem_checkStructure(data, 3)) != 0 || + (ret = cosem_getInt8(data, &id)) != 0 || + (ret = cosem_getEnum(data, &mode)) != 0 || + (ret = cosem_getVariant(data, &selector)) != 0) + { + break; + } + //Save access mode if user wants to know it. + if (object->access != NULL) + { + if ((ret = bb_setUInt8ByIndex(&object->access->attributeAccessModes, pos, mode)) != 0) + { + break; + } + } + } + //Get action access modes. + if (ret == 0) + { + size = 0xFFFF; + if ((ret = cosem_checkArray(data, &size)) == 0) + { + for (pos = 0; pos != size; ++pos) + { + if ((ret = cosem_checkStructure(data, 2)) != 0 || + (ret = cosem_getInt8(data, &id)) != 0) + { + break; + } + if ((ret = bb_getUInt8(data, &mode)) != 0) + { + return ret; + } + //Version 0 uses boolean and other versions uses enum. + if (mode != DLMS_DATA_TYPE_ENUM && mode != DLMS_DATA_TYPE_BOOLEAN) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if ((ret = bb_getUInt8(data, &mode)) != 0) + { + return ret; + } + //Save action access mode if user wants to know it. + if (object->access != NULL) + { + if ((ret = bb_setUInt8ByIndex(&object->access->methodAccessModes, pos, mode)) != 0) + { + break; + } + } + } + } + } + } + } + } + else + { +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + if ((ret = cosem_checkStructure(data, 4)) == 0 && + (ret = cosem_getInt16(data, (int16_t*)&object->shortName)) == 0 && + (ret = cosem_getUInt16(data, &object->objectType)) == 0 && + (ret = cosem_getUInt8(data, &object->version)) == 0 && + (ret = cosem_getOctetString2(data, object->logicalName, capacity, &size)) == 0) + { + + } +#else + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif // DLMS_IGNORE_ASSOCIATION_SHORT_NAME + } + return ret; +} + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME +int cl_readSN( + dlmsSettings* settings, + uint16_t address, + unsigned char attributeOrdinal, + gxByteBuffer* data, + message* messages) +{ + int ret; + DLMS_VARIABLE_ACCESS_SPECIFICATION requestType; + gxSNParameters p; + gxByteBuffer attributeDescriptor; + if ((attributeOrdinal < 1)) + { + //Invalid parameter + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + BYTE_BUFFER_INIT(&attributeDescriptor); + resetBlockIndex(settings); + address += (attributeOrdinal - 1) * 8; + bb_setUInt16(&attributeDescriptor, address); + // Add Selector. + if (data != NULL && data->size != 0) + { + requestType = DLMS_VARIABLE_ACCESS_SPECIFICATION_PARAMETERISED_ACCESS; + } + else + { + requestType = DLMS_VARIABLE_ACCESS_SPECIFICATION_VARIABLE_NAME; + } + params_initSN(&p, settings, DLMS_COMMAND_READ_REQUEST, 1, + requestType, &attributeDescriptor, data, DLMS_COMMAND_NONE); + ret = dlms_getSnMessages(&p, messages); + bb_clear(&attributeDescriptor); + return ret; +} +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + +int cl_readLN( + dlmsSettings* settings, + const unsigned char* name, + DLMS_OBJECT_TYPE objectType, + unsigned char attributeOrdinal, + gxByteBuffer* data, + message* messages) +{ + int ret; + gxLNParameters p; + gxByteBuffer* pdu; + if ((attributeOrdinal < 1)) + { + //Invalid parameter + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } +#ifdef DLMS_IGNORE_MALLOC + if (settings->serializedPdu == NULL) + { + //Invalid parameter + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + pdu = settings->serializedPdu; + bb_clear(pdu); +#else + gxByteBuffer attributeDescriptor; + BYTE_BUFFER_INIT(&attributeDescriptor); + pdu = &attributeDescriptor; +#endif //DLMS_IGNORE_MALLOC + resetBlockIndex(settings); + // CI + if ((ret = bb_setUInt16(pdu, objectType)) == 0 && + // Add LN + (ret = bb_set(pdu, name, 6)) == 0 && + // Attribute ID. + (ret = bb_setUInt8(pdu, attributeOrdinal)) == 0) + { + if (data == NULL || data->size == 0) + { + // Access selection is not used. + ret = bb_setUInt8(pdu, 0); + } + else + { + // Access selection is used. + if ((ret = bb_setUInt8(pdu, 1)) == 0) + { + // Add data. + ret = bb_set2(pdu, data, 0, data->size); + } + } + } + if (ret == 0) + { + params_initLN(&p, settings, 0, + DLMS_COMMAND_GET_REQUEST, DLMS_GET_COMMAND_TYPE_NORMAL, + pdu, data, 0xFF, DLMS_COMMAND_NONE, 0, 0); + ret = dlms_getLnMessages(&p, messages); + } + bb_clear(pdu); + return ret; +} + +int cl_readList( + dlmsSettings* settings, + gxArray* list, + message* reply) +{ + gxListItem* it; + gxObject* obj; + uint16_t pos = 0, count; + int ret; +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + uint16_t sn; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + gxByteBuffer bb; + if (list->size == 0) + { + //Invalid parameter + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + BYTE_BUFFER_INIT(&bb); + resetBlockIndex(settings); + if (settings->useLogicalNameReferencing) + { + gxLNParameters p; + params_initLN(&p, settings, 0, DLMS_COMMAND_GET_REQUEST, DLMS_GET_COMMAND_TYPE_WITH_LIST, + &bb, NULL, 0xff, DLMS_COMMAND_NONE, 0, 0); + //Request service primitive shall always fit in a single APDU. + count = (settings->maxPduSize - 12) / 10; + if (list->size < count) + { + count = list->size; + } + //All meters can handle 10 items. + if (count > 10) + { + count = 10; + } + // Add length. + hlp_setObjectCount(count, &bb); + for (pos = 0; pos != list->size; ) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(list, pos, (void**)&it, sizeof(gxObject*))) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(list, pos, (void**)&it)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + obj = (gxObject*)it->key; + // CI. + bb_setUInt16(&bb, obj->objectType); + bb_set(&bb, obj->logicalName, 6); + // Attribute ID. + bb_setUInt8(&bb, it->value); + // Attribute selector is not used. + bb_setUInt8(&bb, 0); + ++pos; + if (pos % count == 0 && list->size != pos) + { + if ((ret = dlms_getLnMessages(&p, reply)) != 0) + { + return ret; + } + bb_clear(&bb); + if (list->size - pos < count) + { + hlp_setObjectCount(list->size - pos, &bb); + } + else + { + hlp_setObjectCount(count, &bb); + } + } + } + ret = dlms_getLnMessages(&p, reply); + } + else + { +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + gxSNParameters p; + for (pos = 0; pos != list->size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(list, pos, (void**)&it, sizeof(gxListItem))) != 0) + { + return ret; + } +#else + if ((ret = arr_getByIndex(list, pos, (void**)&it)) != 0) + { + return ret; + } +#endif //DLMS_IGNORE_MALLOC + + // Add variable type. + bb_setUInt8(&bb, 2); + sn = ((gxObject*)it->key)->shortName; + sn += ((uint16_t)it->value - 1) * 8; + bb_setUInt16(&bb, sn); + } + params_initSN(&p, settings, DLMS_COMMAND_READ_REQUEST, list->size, 0xFF, &bb, NULL, DLMS_COMMAND_NONE); + ret = dlms_getSnMessages(&p, reply); +#else + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + } + bb_clear(&bb); + return ret; +} + +int cl_read( + dlmsSettings* settings, + gxObject* object, + unsigned char attributeOrdinal, + message* messages) +{ + int ret; + if (object == NULL) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + else if (settings->useLogicalNameReferencing) + { + ret = cl_readLN(settings, object->logicalName, object->objectType, attributeOrdinal, NULL, messages); + } + else + { +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + ret = cl_readSN(settings, object->shortName, attributeOrdinal, NULL, messages); +#else + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + } + return ret; +} + +int cl_getKeepAlive( + dlmsSettings* settings, + message* messages) +{ + int ret; + if (settings->useLogicalNameReferencing) + { + static const unsigned char ln[6] = { 0, 0, 40, 0, 0, 255 }; + ret = cl_readLN(settings, ln, DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME, 1, NULL, messages); + } + else + { +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + ret = cl_readSN(settings, 0xFA00, 1, NULL, messages); +#else + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + } + return ret; +} + +#ifndef DLMS_IGNORE_PROFILE_GENERIC +int cl_readRowsByEntry(dlmsSettings* settings, gxProfileGeneric* object, uint32_t index, uint32_t count, message* messages) +{ + return cl_readRowsByEntry2(settings, object, index, count, 1, 0, messages); +} + +int cl_readRowsByEntry2(dlmsSettings* settings, gxProfileGeneric* object, uint32_t index, uint32_t count, uint16_t colStart, uint16_t colEnd, message* messages) +{ + int ret; + gxByteBuffer data; + if (object == NULL) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } +#ifdef DLMS_IGNORE_MALLOC + unsigned char buff[20]; + bb_attach(&data, buff, 0, sizeof(buff)); +#else + BYTE_BUFFER_INIT(&data); +#endif //DLMS_IGNORE_MALLOC + //Add AccessSelector + if ((ret = bb_setUInt8(&data, 2)) == 0 && + //Add structure tag. + (ret = cosem_setStructure(&data, 4)) == 0 && + //Add start index + (ret = cosem_setUInt32(&data, index)) == 0 && + //Add Count + (ret = cosem_setUInt32(&data, count == 0 ? 0 : index + count - 1)) == 0 && + //Add columns. + (ret = cosem_setUInt16(&data, colStart)) == 0 && + (ret = cosem_setUInt16(&data, colEnd)) == 0) + { + if (settings->useLogicalNameReferencing) + { + ret = cl_readLN(settings, object->base.logicalName, object->base.objectType, 2, &data, messages); + } + else + { +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + ret = cl_readSN(settings, object->base.shortName, 2, &data, messages); +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + } + } + bb_clear(&data); + return ret; +} + +int cl_readRowsByRange2( + dlmsSettings* settings, + gxProfileGeneric* object, + gxtime* start, + gxtime* end, + message* messages) +{ + unsigned char unixTime = 0; + static unsigned char LN[] = { 0, 0, 1, 0, 0, 255 }; + DLMS_OBJECT_TYPE type = DLMS_OBJECT_TYPE_CLOCK; + unsigned char* ln = LN; + int ret; + gxByteBuffer data; + if (object == NULL || start == NULL || end == NULL || messages == NULL) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if (object->captureObjects.size != 0) + { +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + gxTarget* kv; + ret = arr_getByIndex2(&object->captureObjects, 0, (void**)&kv, sizeof(gxTarget)); + if (ret != 0) + { + return ret; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + type = kv->target->objectType; + ln = kv->target->logicalName; +#else + type = kv->objectType; + ln = kv->logicalName; +#endif //DLMS_IGNORE_OBJECT_POINTERS +#else + gxKey* kv; + ret = arr_getByIndex(&object->captureObjects, 0, (void**)&kv); + if (ret != 0) + { + return ret; + } + type = ((gxObject*)kv->key)->objectType; + ln = ((gxObject*)kv->key)->logicalName; +#endif //DLMS_IGNORE_MALLOC + unixTime = type == DLMS_OBJECT_TYPE_DATA; + } +#ifndef DLMS_IGNORE_MALLOC + if ((ret = obj_clearProfileGenericBuffer(&object->buffer)) != 0) + { + return ret; + } +#endif //DLMS_IGNORE_MALLOC +#ifdef DLMS_IGNORE_MALLOC + unsigned char buff[100]; + bb_attach(&data, buff, 0, sizeof(buff)); +#else + BYTE_BUFFER_INIT(&data); +#endif //DLMS_IGNORE_MALLOC + //Add AccessSelector + if ((ret = bb_setUInt8(&data, 1)) == 0 && + //Add structure tag. + (ret = cosem_setStructure(&data, 4)) == 0 && + //Add structure tag. + (ret = cosem_setStructure(&data, 4)) == 0 && + // Add class_id + (ret = cosem_setUInt16(&data, type)) == 0 && + // Add parameter Logical name + (ret = cosem_setOctetString2(&data, ln, 6)) == 0 && + //Add attribute index. + (ret = cosem_setInt8(&data, 2)) == 0 && + //Add data index. + (ret = cosem_setUInt16(&data, 0)) == 0) + { + //Add start time + if (unixTime) + { + ret = cosem_setUInt32(&data, time_toUnixTime2(start)); + } + else + { + if ((ret = cosem_setDateTimeAsOctetString(&data, start)) != 0) + { + bb_clear(&data); + return ret; + } + } + //Add end time + if (unixTime) + { + ret = cosem_setUInt32(&data, time_toUnixTime2(end)); + } + else + { + if ((ret = cosem_setDateTimeAsOctetString(&data, end)) != 0) + { + bb_clear(&data); + return ret; + } + } + //Add array of read columns. Read All... + bb_setUInt8(&data, 0x01); + //Add item count + bb_setUInt8(&data, 0x00); + if (settings->useLogicalNameReferencing) + { + ret = cl_readLN(settings, object->base.logicalName, object->base.objectType, 2, &data, messages); + } + else + { +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + ret = cl_readSN(settings, object->base.shortName, 2, &data, messages); +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + } + } + bb_clear(&data); + return ret; +} + +#ifdef DLMS_INDONESIA_STANDARD +int cl_readRowsByRange3( + dlmsSettings* settings, + gxProfileGeneric* object, + gxtime* start, + gxtime* end, + unsigned char startRegister, + unsigned char numberOfRegisters, + message* messages) +{ + int ret; + gxByteBuffer data; + if (start == NULL || end == NULL || messages == NULL) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } +#ifdef DLMS_IGNORE_MALLOC + unsigned char buff[100]; + bb_attach(&data, buff, 0, sizeof(buff)); +#else + BYTE_BUFFER_INIT(&data); +#endif //DLMS_IGNORE_MALLOC + //Add AccessSelector + if ((ret = bb_setUInt8(&data, 1)) == 0 && + //Add structure tag. + (ret = cosem_setStructure(&data, 4)) == 0) + { + //Add start time + if ((ret = cosem_setDateTimeAsOctetString(&data, start)) != 0) + { + bb_clear(&data); + return ret; + } + //Add end time + if ((ret = cosem_setDateTimeAsOctetString(&data, end)) != 0) + { + bb_clear(&data); + return ret; + } + //Add start register + bb_setUInt8(&data, startRegister); + //Add number of registers. + bb_setUInt8(&data, numberOfRegisters); + if (settings->useLogicalNameReferencing) + { + ret = cl_readLN(settings, object->base.logicalName, object->base.objectType, 2, &data, messages); + } + else + { +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + ret = cl_readSN(settings, object->base.shortName, 2, &data, messages); +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + } + } + bb_clear(&data); + return ret; +} +#endif //DLMS_INDONESIA_STANDARD + +#ifdef DLMS_USE_EPOCH_TIME +int cl_readRowsByRange( + dlmsSettings* settings, + gxProfileGeneric* object, + uint32_t start, + uint32_t end, + message* messages) +#else +int cl_readRowsByRange( + dlmsSettings* settings, + gxProfileGeneric* object, + struct tm* start, + struct tm* end, + message* messages) +#endif //DLMS_USE_EPOCH_TIME +{ + gxtime s, e; +#ifdef DLMS_USE_EPOCH_TIME + time_initUnix(&s, start); + time_initUnix(&e, end); +#else + time_initUnix(&s, time_toUnixTime(start)); + time_initUnix(&e, time_toUnixTime(end)); +#endif //DLMS_USE_EPOCH_TIME + return cl_readRowsByRange2(settings, object, &s, &e, messages); +} +#endif // DLMS_IGNORE_PROFILE_GENERIC + +int cl_getData(dlmsSettings* settings, gxByteBuffer* reply, gxReplyData* data) +{ + return dlms_getData2(settings, reply, data, 0); +} + +int cl_getData2( + dlmsSettings* settings, + gxByteBuffer* reply, + gxReplyData* data, + gxReplyData* notify, + unsigned char* isNotify) +{ + return dlms_getData3(settings, reply, data, notify, 0, isNotify); +} + +int cl_changeType( + gxByteBuffer* value, + DLMS_DATA_TYPE type, + dlmsVARIANT* newValue) +{ + return dlms_changeType(value, type, newValue); +} + +int cl_updateValue( + dlmsSettings* settings, + gxObject* target, + unsigned char attributeIndex, + dlmsVARIANT* value) +{ + gxValueEventArg e; + if (target == NULL) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + e.target = target; + e.index = attributeIndex; + e.value = *value; + return cosem_setValue(settings, &e); +} + +int cl_updateValues( + dlmsSettings* settings, + gxArray* list, + gxByteBuffer* data) +{ + uint16_t count; + int ret = 0; + uint16_t pos; + gxListItem* it; + gxDataInfo info; + unsigned char ch; + gxValueEventArg e; + ve_init(&e); + if ((ret = hlp_getObjectCount2(data, &count)) != 0) + { + return ret; + } + if (count != list->size) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + + for (pos = 0; pos != list->size; ++pos) + { + di_init(&info); +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(list, pos, (void**)&it, sizeof(gxListItem))) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(list, pos, (void**)&it)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + ret = bb_getUInt8(data, &ch); + if (ret != 0) + { + break; + } + if (ch == 0) + { +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + e.value.vt = DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_OCTET_STRING; + e.value.byteArr = data; +#else + if ((ret = dlms_getData(data, &info, &e.value)) != 0) + { + break; + } +#endif //defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + e.target = (gxObject*)it->key; + e.index = it->value; + ret = cosem_setValue(settings, &e); + ve_clear(&e); + if (ret != 0) + { + break; + } + } + else + { + ret = ch; + break; + } + } + ve_clear(&e); + return ret; +} + +int cl_receiverReady(dlmsSettings* settings, DLMS_DATA_REQUEST_TYPES type, gxByteBuffer* reply) +{ + return dlms_receiverReady(settings, type, reply); +} + +/** +* Generates a release request. +* +* @return Release request, as byte array. +*/ +int cl_releaseRequest(dlmsSettings* settings, message* packets) +{ + return cl_releaseRequest2(settings, packets, 0); +} + +/** +* Generates a release request. +* +* @return Release request, as byte array. +*/ +int cl_releaseRequest2(dlmsSettings* settings, message* packets, unsigned char useProtectedRelease) +{ + int ret; + gxByteBuffer bb; + mes_clear(packets); + // If connection is not established, there is no need to send + // DisconnectRequest. + if ((settings->connected & DLMS_CONNECTION_STATE_DLMS) == 0) + { + return 0; + } + settings->connected &= ~DLMS_CONNECTION_STATE_DLMS; + BYTE_BUFFER_INIT(&bb); + if (!useProtectedRelease) + { + if ((ret = bb_setUInt8(&bb, 0x3)) != 0 || + (ret = bb_setUInt8(&bb, 0x80)) != 0 || + (ret = bb_setUInt8(&bb, 0x01)) != 0 || + (ret = bb_setUInt8(&bb, 0x0)) != 0) + { + return ret; + } + } + else + { + // Length. + if ((ret = bb_setUInt8(&bb, 0x0)) != 0 || + (ret = bb_setUInt8(&bb, 0x80)) != 0 || + (ret = bb_setUInt8(&bb, 0x01)) != 0 || + (ret = bb_setUInt8(&bb, 0x0)) != 0) + { + return ret; + } + apdu_generateUserInformation(settings, &bb); + bb.data[0] = (unsigned char)(bb.size - 1); + } + if (settings->useLogicalNameReferencing) + { + gxLNParameters p; + params_initLN(&p, settings, 0, + DLMS_COMMAND_RELEASE_REQUEST, DLMS_SET_COMMAND_TYPE_NORMAL, + &bb, NULL, 0xff, DLMS_COMMAND_NONE, 0, 0); + ret = dlms_getLnMessages(&p, packets); + } + else + { +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + gxSNParameters p; + params_initSN(&p, settings, + DLMS_COMMAND_RELEASE_REQUEST, 1, + DLMS_VARIABLE_ACCESS_SPECIFICATION_VARIABLE_NAME, + NULL, &bb, DLMS_COMMAND_NONE); + ret = dlms_getSnMessages(&p, packets); +#else + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + } + bb_clear(&bb); + //Restore default values. + settings->maxPduSize = settings->initializePduSize; + return ret; +} + +int cl_disconnectRequest(dlmsSettings* settings, message* packets) +{ + int ret = 0; +#ifndef DLMS_IGNORE_WRAPPER + gxByteBuffer bb; +#endif //DLMS_IGNORE_WRAPPER + gxByteBuffer* reply = NULL; + mes_clear(packets); + settings->maxPduSize = 0xFFFF; + // If connection is not established, there is no need to send DisconnectRequest. + if ((settings->connected & DLMS_CONNECTION_STATE_HDLC) == 0) + { + return ret; + } + settings->connected &= ~DLMS_CONNECTION_STATE_HDLC; +#ifdef DLMS_IGNORE_MALLOC + reply = packets->data[0]; + ++packets->size; + bb_clear(reply); +#else + reply = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + BYTE_BUFFER_INIT(reply); +#endif //DLMS_IGNORE_MALLOC + switch (settings->interfaceType) + { +#ifndef DLMS_IGNORE_HDLC + case DLMS_INTERFACE_TYPE_HDLC: + case DLMS_INTERFACE_TYPE_HDLC_WITH_MODE_E: + { + ret = dlms_getHdlcFrame(settings, DLMS_COMMAND_DISC, NULL, reply); +#ifndef DLMS_IGNORE_MALLOC + if (ret == 0) + { + mes_push(packets, reply); + } + else + { + gxfree(reply); + } +#endif //DLMS_IGNORE_MALLOC + } + break; +#endif //DLMS_IGNORE_HDLC +#ifndef DLMS_IGNORE_PLC + case DLMS_INTERFACE_TYPE_PLC: +#ifndef DLMS_IGNORE_MALLOC + gxfree(reply); +#endif //DLMS_IGNORE_MALLOC + break; + case DLMS_INTERFACE_TYPE_PLC_HDLC: + { + ret = dlms_getMacHdlcFrame(settings, DLMS_COMMAND_DISC, 0, NULL, reply); +#ifndef DLMS_IGNORE_MALLOC + if (ret == 0) + { + mes_push(packets, reply); + } + else + { + gxfree(reply); + } +#endif //DLMS_IGNORE_MALLOC + } + break; +#endif //DLMS_IGNORE_PLC +#ifndef DLMS_IGNORE_WRAPPER + case DLMS_INTERFACE_TYPE_WRAPPER: + { + BYTE_BUFFER_INIT(&bb); + bb_setUInt8(&bb, DLMS_COMMAND_RELEASE_REQUEST); + bb_setUInt8(&bb, 0x0); + ret = dlms_getWrapperFrame(settings, DLMS_COMMAND_NONE, &bb, reply); +#ifndef DLMS_IGNORE_MALLOC + if (ret == 0) + { + mes_push(packets, reply); + } + else + { + gxfree(reply); + } +#endif //DLMS_IGNORE_MALLOC + bb_clear(&bb); + } + break; +#endif //DLMS_IGNORE_WRAPPER + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } +#ifndef DLMS_IGNORE_HDLC + if (dlms_useHdlc(settings->interfaceType)) + { + //Restore default HDLC values. + settings->maxInfoTX = settings->initializeMaxInfoTX; + settings->maxInfoRX = settings->initializeMaxInfoRX; + settings->windowSizeTX = settings->initializeWindowSizeTX; + settings->windowSizeRX = settings->initializeWindowSizeRX; + } +#endif //DLMS_IGNORE_HDLC + //Restore default values. + settings->maxPduSize = settings->initializePduSize; + resetFrameSequence(settings); + return ret; +} + +int cl_write( + dlmsSettings* settings, + gxObject* object, + unsigned char index, + message* messages) +{ + unsigned int ret; + gxValueEventArg e; + ve_init(&e); + e.target = object; + e.index = index; + if ((ret = cosem_getValue(settings, &e)) != 0) + { + return ret; + } + if (settings->useLogicalNameReferencing) + { + ret = cl_writeLN( + settings, + object->logicalName, + object->objectType, + index, + &e.value, + e.byteArray, + messages); + } + else + { +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + ret = cl_writeSN( + settings, + object->shortName, + index, + &e.value, + messages); +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + } + ve_clear(&e); + return ret; +} + +int cl_writeList( + dlmsSettings* settings, + gxArray* list, + message* reply) +{ + gxListItem* it; + uint16_t pos; + gxValueEventArg e; + gxByteBuffer data; + ve_init(&e); + gxByteBuffer* pdu; + int ret; +#ifdef DLMS_IGNORE_MALLOC + if (settings->serializedPdu == NULL) + { + //Invalid parameter + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + pdu = settings->serializedPdu; + //Use same buffer for header and data. Header size is 10 bytes. + BYTE_BUFFER_INIT(&data); + bb_clear(pdu); +#else + gxByteBuffer bb; + BYTE_BUFFER_INIT(&bb); + pdu = &bb; + BYTE_BUFFER_INIT(&data); +#endif //DLMS_IGNORE_MALLOC + if (list->size == 0) + { + //Invalid parameter + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + resetBlockIndex(settings); + if (settings->useLogicalNameReferencing) + { + gxLNParameters p; + params_initLN(&p, settings, 0, DLMS_COMMAND_SET_REQUEST, DLMS_SET_COMMAND_TYPE_WITH_LIST, + pdu, &data, 0xff, DLMS_COMMAND_NONE, 0, 0); + // Add length. + hlp_setObjectCount(list->size, pdu); + for (pos = 0; pos != list->size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(list, pos, (void**)&it, sizeof(gxListItem*))) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(list, pos, (void**)&it)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + // CI. + bb_setUInt16(pdu, it->key->objectType); + bb_set(pdu, it->key->logicalName, 6); + // Attribute ID. + bb_setUInt8(pdu, it->value); + // Attribute selector is not used. + bb_setUInt8(pdu, 0); + } + // Add length. + if (ret == 0) + { + hlp_setObjectCount(list->size, pdu); + for (pos = 0; pos != list->size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(list, pos, (void**)&it, sizeof(gxListItem*))) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(list, pos, (void**)&it)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + e.target = it->key; + e.index = it->value; + if ((ret = cosem_getValue(settings, &e)) != 0) + { + break; + } +#ifdef DLMS_IGNORE_MALLOC + if (e.byteArray != 0) + { + bb_set2(pdu, e.value.byteArr, 0, bb_size(e.value.byteArr)); + } + else + { + if ((ret = dlms_setData(pdu, e.value.vt, &e.value)) != 0) + { + return ret; + } + } +#else + if (e.byteArray != 0) + { + bb_set2(&data, e.value.byteArr, 0, e.value.byteArr->size); + } + else + { + if ((ret = dlms_setData(&data, e.value.vt, &e.value)) != 0) + { + return ret; + } + } +#endif //DLMS_IGNORE_MALLOC + } + if (ret == 0) + { + ret = dlms_getLnMessages(&p, reply); + } + } + } + else + { +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + uint16_t sn; + gxSNParameters p; + for (pos = 0; pos != list->size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(list, pos, (void**)&it, sizeof(gxListItem))) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(list, pos, (void**)&it)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + // Add variable type. + bb_setUInt8(pdu, 2); + sn = ((gxObject*)it->key)->shortName; + sn += ((uint16_t)it->value - 1) * 8; + bb_setUInt16(pdu, sn); + } + if (ret == 0) + { + // Add length. + hlp_setObjectCount(list->size, pdu); + for (pos = 0; pos != list->size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(list, pos, (void**)&it, sizeof(gxListItem*))) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(list, pos, (void**)&it)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + e.target = it->key; + e.index = it->value; + if ((ret = cosem_getValue(settings, &e)) != 0) + { + break; + } +#ifdef DLMS_IGNORE_MALLOC + if (e.byteArray != 0) + { + bb_set2(pdu, value->byteArr, 0, value->byteArr->size); + } + else + { + if ((ret = dlms_setData(pdu, value->vt, value)) != 0) + { + break; + } + } +#else + if (e.byteArray != 0) + { + bb_set2(&data, e.value.byteArr, 0, e.value.byteArr->size); + } + else + { + if ((ret = dlms_setData(&data, e.value.vt, &e.value)) != 0) + { + break; + } + } + } +#endif //DLMS_IGNORE_MALLOC + if (ret == 0) + { + params_initSN(&p, settings, DLMS_COMMAND_WRITE_REQUEST, list->size, 0xFF, pdu, &data, DLMS_COMMAND_NONE); + ret = dlms_getSnMessages(&p, reply); + } + } +#else + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + } + ve_clear(&e); + bb_clear(pdu); + bb_clear(&data); + return ret; +} + +int cl_writeLN( + dlmsSettings* settings, + const unsigned char* name, + DLMS_OBJECT_TYPE objectType, + unsigned char index, + dlmsVARIANT* value, + unsigned char byteArray, + message* messages) +{ + int ret; + gxLNParameters p; + gxByteBuffer* pdu; + gxByteBuffer data; + if (index < 1) + { + //Invalid parameter + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } +#ifdef DLMS_IGNORE_MALLOC + if (settings->serializedPdu == NULL) + { + //Invalid parameter + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + pdu = settings->serializedPdu; + //Use same buffer for header and data. Header size is 10 bytes. + BYTE_BUFFER_INIT(&data); + bb_clear(pdu); +#else + gxByteBuffer bb; + BYTE_BUFFER_INIT(&bb); + pdu = &bb; + BYTE_BUFFER_INIT(&data); +#endif //DLMS_IGNORE_MALLOC + resetBlockIndex(settings); + // Add CI. + bb_setUInt16(pdu, objectType); + // Add LN + bb_set(pdu, name, 6); + // Attribute ID. + bb_setUInt8(pdu, index); + // Access selection is not used. + bb_setUInt8(pdu, 0); +#ifdef DLMS_IGNORE_MALLOC + if (byteArray != 0) + { + bb_set2(pdu, value->byteArr, 0, value->byteArr->size); + } + else + { + if ((ret = dlms_setData(pdu, value->vt, value)) != 0) + { + return ret; + } + } +#else + if (byteArray != 0) + { + bb_set2(&data, value->byteArr, 0, value->byteArr->size); + } + else + { + if ((ret = dlms_setData(&data, value->vt, value)) != 0) + { + return ret; + } + } +#endif //DLMS_IGNORE_MALLOC + + params_initLN(&p, settings, 0, + DLMS_COMMAND_SET_REQUEST, DLMS_SET_COMMAND_TYPE_NORMAL, + pdu, &data, 0xff, DLMS_COMMAND_NONE, 0, 0); + ret = dlms_getLnMessages(&p, messages); + bb_clear(&data); + bb_clear(pdu); + return ret; +} + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME +int cl_writeSN( + dlmsSettings* settings, + uint16_t address, + int index, + dlmsVARIANT* value, + message* messages) +{ + int ret; + gxSNParameters p; + gxByteBuffer bb, data; + if (index < 1) + { + //Invalid parameter + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + resetBlockIndex(settings); + BYTE_BUFFER_INIT(&bb); + BYTE_BUFFER_INIT(&data); + if ((ret = dlms_setData(&data, value->vt, value)) != 0) + { + return ret; + } + + // Add name. + address += (uint16_t)((index - 1) * 8); + bb_setUInt16(&bb, address); + // Add data count. + bb_setUInt8(&bb, 1); + params_initSN(&p, settings, + DLMS_COMMAND_WRITE_REQUEST, 1, + DLMS_VARIABLE_ACCESS_SPECIFICATION_VARIABLE_NAME, + &bb, &data, DLMS_COMMAND_NONE); + ret = dlms_getSnMessages(&p, messages); + bb_clear(&data); + bb_clear(&bb); + return ret; +} + +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + +int cl_method( + dlmsSettings* settings, + gxObject* object, + unsigned char index, + dlmsVARIANT* data, + message* messages) +{ + int ret; + if (settings->useLogicalNameReferencing) + { + ret = cl_methodLN(settings, object->logicalName, object->objectType, index, data, messages); + } + else + { +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + ret = cl_methodSN(settings, object->shortName, object->objectType, index, data, messages); +#else + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + } + return ret; +} + +int cl_method2( + dlmsSettings* settings, + gxObject* object, + unsigned char index, + unsigned char* value, + uint32_t length, + message* messages) +{ + int ret; + if (settings->useLogicalNameReferencing) + { + ret = cl_methodLN2(settings, object->logicalName, object->objectType, index, value, length, messages); + } + else + { +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + ret = cl_methodSN2(settings, object->shortName, object->objectType, index, value, length, messages); +#else + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + } + return ret; +} + +int cl_methodLN( + dlmsSettings* settings, + const unsigned char* name, + DLMS_OBJECT_TYPE objectType, + unsigned char index, + dlmsVARIANT* value, + message* messages) +{ + int ret = 0; + gxLNParameters p; + gxByteBuffer* pdu; + gxByteBuffer data; + if (index < 1) + { + //Invalid parameter + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } +#ifdef DLMS_IGNORE_MALLOC + if (settings->serializedPdu == NULL) + { + //Invalid parameter + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + pdu = settings->serializedPdu; + //Use same buffer for header and data. Header size is 10 bytes. + BYTE_BUFFER_INIT(&data); + bb_clear(pdu); +#else + gxByteBuffer bb; + unsigned char GX_METHOD_PDU[10]; + bb_attach(&bb, GX_METHOD_PDU, 0, sizeof(GX_METHOD_PDU)); + pdu = &bb; + BYTE_BUFFER_INIT(&data); +#endif //DLMS_IGNORE_MALLOC + resetBlockIndex(settings); + // CI + if ((ret = bb_setUInt16(pdu, objectType)) == 0 && + // Add LN + (ret = bb_set(pdu, name, 6)) == 0 && + // Attribute ID. + (ret = bb_setUInt8(pdu, index)) == 0 && + // Is Method Invocation Parameters used. + (ret = bb_setUInt8(pdu, value == NULL || value->vt == DLMS_DATA_TYPE_NONE ? 0 : 1)) == 0) + { +#ifdef DLMS_IGNORE_MALLOC + if (value != NULL && value->vt != DLMS_DATA_TYPE_NONE) + { + if (value->vt == DLMS_DATA_TYPE_OCTET_STRING) + { + ret = bb_set(pdu, value->byteArr->data, value->byteArr->size); + } + else + { + ret = dlms_setData(pdu, value->vt, value); + } + } +#else + if (value != NULL && value->vt != DLMS_DATA_TYPE_NONE) + { + if ((value->vt == DLMS_DATA_TYPE_ARRAY || value->vt == DLMS_DATA_TYPE_STRUCTURE) && + value->vt == DLMS_DATA_TYPE_OCTET_STRING) + { + ret = bb_set(&data, value->byteArr->data, value->byteArr->size); + } + else + { + if (value->vt == DLMS_DATA_TYPE_OCTET_STRING) + { + //Space is allocated for type and size + bb_capacity(&data, 5 + bb_size(value->byteArr)); + } + ret = dlms_setData(&data, value->vt, value); + } + } +#endif //DLMS_IGNORE_MALLOC + } + if (ret == 0) + { + params_initLN(&p, settings, 0, + DLMS_COMMAND_METHOD_REQUEST, DLMS_ACTION_COMMAND_TYPE_NORMAL, + pdu, &data, 0xff, DLMS_COMMAND_NONE, 0, 0); + ret = dlms_getLnMessages(&p, messages); + } + bb_clear(&data); + bb_clear(pdu); + return ret; +} + +int cl_methodLN2( + dlmsSettings* settings, + unsigned char* name, + DLMS_OBJECT_TYPE objectType, + unsigned char index, + unsigned char* value, + uint32_t length, + message* messages) +{ + int ret = 0; + gxLNParameters p; + gxByteBuffer* pdu; + gxByteBuffer data; + if (index < 1) + { + //Invalid parameter + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } +#ifdef DLMS_IGNORE_MALLOC + if (settings->serializedPdu == NULL) + { + //Invalid parameter + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + pdu = settings->serializedPdu; + //Use same buffer for header and data. Header size is 10 bytes. + BYTE_BUFFER_INIT(&data); + bb_clear(pdu); +#else + gxByteBuffer bb; + BYTE_BUFFER_INIT(&bb); + pdu = &bb; + BYTE_BUFFER_INIT(&data); +#endif //DLMS_IGNORE_MALLOC + resetBlockIndex(settings); + // CI + if ((ret = bb_setUInt16(pdu, objectType)) == 0 && + // Add LN + (ret = bb_set(pdu, name, 6)) == 0 && + // Attribute ID. + (ret = bb_setUInt8(pdu, index)) == 0 && + // Is Method Invocation Parameters used. + (ret = bb_setUInt8(pdu, 1)) == 0) + { + ret = bb_set(pdu, value, length); + } + if (ret == 0) + { + params_initLN(&p, settings, 0, + DLMS_COMMAND_METHOD_REQUEST, DLMS_ACTION_COMMAND_TYPE_NORMAL, + pdu, &data, 0xff, DLMS_COMMAND_NONE, 0, 0); + ret = dlms_getLnMessages(&p, messages); + } + bb_clear(&data); + bb_clear(pdu); + return ret; +} + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME +int cl_methodSN( + dlmsSettings* settings, + uint16_t address, + DLMS_OBJECT_TYPE objectType, + int index, + dlmsVARIANT* value, + message* messages) +{ + int ret; + unsigned char v, count; + gxSNParameters p; + unsigned char requestType; + gxByteBuffer bb, data; + if (index < 1) + { + //Invalid parameter + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + resetBlockIndex(settings); + BYTE_BUFFER_INIT(&data); + if (value != NULL && value->vt != DLMS_DATA_TYPE_NONE) + { + if (value->vt == DLMS_DATA_TYPE_OCTET_STRING) + { + bb_set(&data, value->byteArr->data, value->byteArr->size); + } + else + { + dlms_setData(&data, value->vt, value); + } + } + BYTE_BUFFER_INIT(&bb); + if (value == NULL || value->vt == DLMS_DATA_TYPE_NONE) + { + requestType = DLMS_VARIABLE_ACCESS_SPECIFICATION_VARIABLE_NAME; + } + else + { + requestType = DLMS_VARIABLE_ACCESS_SPECIFICATION_PARAMETERISED_ACCESS; + } + if ((ret = dlms_getActionInfo(objectType, &v, &count)) != 0) + { + return ret; + } + if (index > count) + { + //Invalid parameter + bb_clear(&data); + bb_clear(&bb); + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + index = (v + (index - 1) * 0x8); + address += (uint16_t)index; + // Add SN count. + bb_setUInt8(&bb, 1); + // Add name length. + bb_setUInt8(&bb, 4); + // Add name. + bb_setUInt16(&bb, address); + // Method Invocation Parameters is not used. + if (value == NULL || value->vt == DLMS_DATA_TYPE_NONE) + { + bb_setUInt8(&bb, 0); + } + else + { + bb_setUInt8(&bb, 1); + } + params_initSN(&p, settings, DLMS_COMMAND_READ_REQUEST, 1, + requestType, &bb, &data, DLMS_COMMAND_NONE); + ret = dlms_getSnMessages(&p, messages); + bb_clear(&data); + bb_clear(&bb); + return ret; +} + +int cl_methodSN2( + dlmsSettings* settings, + uint16_t address, + DLMS_OBJECT_TYPE objectType, + int index, + unsigned char* value, + uint32_t length, + message* messages) +{ + int ret; + unsigned char v, count; + gxSNParameters p; + gxByteBuffer bb, data; + if (index < 1) + { + //Invalid parameter + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + resetBlockIndex(settings); + BYTE_BUFFER_INIT(&data); + ret = bb_set(&data, value, length); + BYTE_BUFFER_INIT(&bb); + if ((ret = dlms_getActionInfo(objectType, &v, &count)) != 0) + { + return ret; + } + if (index > count) + { + //Invalid parameter + bb_clear(&data); + bb_clear(&bb); + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + index = (v + (index - 1) * 0x8); + address += (uint16_t)index; + // Add SN count. + bb_setUInt8(&bb, 1); + // Add name length. + bb_setUInt8(&bb, 4); + // Add name. + bb_setUInt16(&bb, address); + bb_setUInt8(&bb, 1); + params_initSN(&p, settings, DLMS_COMMAND_READ_REQUEST, 1, + DLMS_VARIABLE_ACCESS_SPECIFICATION_PARAMETERISED_ACCESS, &bb, &data, DLMS_COMMAND_NONE); + ret = dlms_getSnMessages(&p, messages); + bb_clear(&data); + bb_clear(&bb); + return ret; +} +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + +uint16_t cl_getServerAddress(uint16_t logicalAddress, uint16_t physicalAddress, unsigned char addressSize) +{ + uint16_t value; + if (addressSize < 4 && physicalAddress < 0x80 && logicalAddress < 0x80) + { + value = (uint16_t)(logicalAddress << 7 | physicalAddress); + } + else if (physicalAddress < 0x4000 && logicalAddress < 0x4000) + { + value = (uint16_t)(logicalAddress << 14 | physicalAddress); + } + else + { + value = 0; + } + return value; +} +#endif //!defined(DLMS_IGNORE_CLIENT) diff --git a/components/xt211/client.h b/components/xt211/client.h new file mode 100644 index 0000000..03a2189 --- /dev/null +++ b/components/xt211/client.h @@ -0,0 +1,446 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef CLIENT_H +#define CLIENT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "gxignore.h" +#if !(defined(DLMS_IGNORE_CLIENT) && defined(DLMS_IGNORE_MALLOC)) +#ifdef DLMS_DEBUG +#include "serverevents.h" +#endif //DLMS_DEBUG + +#include "dlms.h" + + int cl_getData( + dlmsSettings* settings, + gxByteBuffer* reply, + gxReplyData* data); + + int cl_getData2( + dlmsSettings* settings, + gxByteBuffer* reply, + gxReplyData* data, + gxReplyData* notify, + unsigned char* isNotify); + +// Get size of the frame. +// size: Size of received bytes on the frame. +// Returns: Zero if succeeded, or rccurred error code. + int cl_getFrameSize(dlmsSettings* settings, gxByteBuffer* data, uint32_t* size); + +#ifndef DLMS_IGNORE_HDLC + int cl_snrmRequest( + dlmsSettings* settings, + message* messages); + + int cl_parseUAResponse( + dlmsSettings* settings, + gxByteBuffer* data); + + // Returns the number of bytes to read before the frame is complete. + // When WRAPPER is used this method can be used to check how many bytes we need to read. + // data: Received data. + // size: Size of received bytes on the frame. + // Returns: Zero if succeeded, or rccurred error code. + int cl_getRemainingFrameSize(dlmsSettings* settings, gxByteBuffer* data, uint32_t* size); +#endif //DLMS_IGNORE_HDLC + + int cl_aarqRequest( + dlmsSettings* settings, + message* messages); + + int cl_parseAAREResponse( + dlmsSettings* settings, + gxByteBuffer* data); + + int cl_getApplicationAssociationRequest( + dlmsSettings* settings, + message* messages); + + int cl_parseApplicationAssociationResponse( + dlmsSettings* settings, + gxByteBuffer* reply); + + /*Read association view. Association view is not available if malloc is not used.*/ + int cl_getObjectsRequest( + dlmsSettings* settings, + message* messages); + +#ifndef DLMS_IGNORE_MALLOC + /*Parse association view. Association view is not available if malloc is not used.*/ + int cl_parseObjects( + dlmsSettings* settings, + gxByteBuffer* data); +#endif //DLMS_IGNORE_MALLOC + + //Get objects count in association view. + int cl_parseObjectCount( + gxByteBuffer* data, + uint16_t* count); + + /*Parse next association view object. + This method can be used when malloc is not used or there is a limited amount of the memory in use.*/ + int cl_parseNextObject( + dlmsSettings* settings, + gxByteBuffer* data, + gxObject* object); + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + int cl_readSN( + dlmsSettings* settings, + uint16_t address, + unsigned char attributeOrdinal, + gxByteBuffer* data, + message* messages); +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + + int cl_readLN( + dlmsSettings* settings, + const unsigned char* name, + DLMS_OBJECT_TYPE interfaceClass, + unsigned char attributeOrdinal, + gxByteBuffer* data, + message* messages); + + /*This method is used to read list of objects.*/ + int cl_readList( + dlmsSettings* settings, + gxArray* list, + message* messages); + + int cl_read( + dlmsSettings* settings, + gxObject* object, + unsigned char attributeOrdinal, + message* messages); + + int cl_getKeepAlive( + dlmsSettings* settings, + message* messages); + +#ifndef DLMS_IGNORE_PROFILE_GENERIC + int cl_readRowsByEntry( + dlmsSettings* settings, + gxProfileGeneric* object, + uint32_t index, + uint32_t count, + message* messages); + + int cl_readRowsByEntry2( + dlmsSettings* settings, + gxProfileGeneric* object, + uint32_t index, + uint32_t count, + uint16_t colStart, + uint16_t colEnd, + message* messages); + + +#ifdef DLMS_USE_EPOCH_TIME + int cl_readRowsByRange( + dlmsSettings* settings, + gxProfileGeneric* object, + uint32_t start, + uint32_t end, + message* messages); +#else + int cl_readRowsByRange( + dlmsSettings* settings, + gxProfileGeneric* object, + struct tm* start, + struct tm* end, + message* messages); +#endif //DLMS_USE_EPOCH_TIME + + ///////////////////////////////////////////////////////////////////////// + //Read profile generic using start and end times. + int cl_readRowsByRange2( + dlmsSettings* settings, + gxProfileGeneric* object, + gxtime* start, + gxtime* end, + message* messages); + + ///////////////////////////////////////////////////////////////////////// + //Read profile generic using Indonesia standard. +#ifdef DLMS_INDONESIA_STANDARD + int cl_readRowsByRange3( + dlmsSettings* settings, + gxProfileGeneric* object, + gxtime* start, + gxtime* end, + unsigned char startRegister, + unsigned char numberOfRegisters, + message* messages) +#endif //DLMS_INDONESIA_STANDARD + +#endif //DLMS_IGNORE_PROFILE_GENERIC + + /*This method is used to write object.*/ + int cl_write( + dlmsSettings* settings, + gxObject* object, + unsigned char index, + message* messages); + + /*This method is used to write list of objects.*/ + int cl_writeList( + dlmsSettings* settings, + gxArray* list, + message* messages); + + int cl_writeLN( + dlmsSettings* settings, + const unsigned char* name, + DLMS_OBJECT_TYPE interfaceClass, + unsigned char index, + dlmsVARIANT* data, + unsigned char byteArray, + message* messages); + + int cl_writeSN( + dlmsSettings* settings, + uint16_t address, + int index, + dlmsVARIANT* data, + message* messages); + + int cl_changeType( + gxByteBuffer* value, + DLMS_DATA_TYPE type, + dlmsVARIANT* newValue); + + int cl_updateValue( + dlmsSettings* settings, + gxObject* object, + unsigned char attributeOrdinal, + dlmsVARIANT* value); + + /** + * Update list of values. + * + * @param list + * read objects. + * @param data + * Received reply from the meter. + */ + int cl_updateValues( + dlmsSettings* settings, + gxArray* list, + gxByteBuffer* data); + + int cl_receiverReady( + dlmsSettings* settings, + DLMS_DATA_REQUEST_TYPES type, + gxByteBuffer* message); + + + /** + * Generates a release request. + * + * @return Release request, as byte array. + */ + int cl_releaseRequest( + dlmsSettings* settings, + message* packets); + + /** +* Generates a release request. +* +* @return Release request, as byte array. +*/ + int cl_releaseRequest2( + dlmsSettings* settings, + message* packets, + unsigned char useProtectedRelease); + + + int cl_disconnectRequest( + dlmsSettings* settings, + message* messages); + + /** + * Generate Method (Action) request. + * + * @param object + * Method object. + * @param index + * Method index. + * @param data + * Method data. + * @param messages DLMS action messages. + */ + int cl_method( + dlmsSettings* settings, + gxObject* object, + unsigned char index, + dlmsVARIANT* data, + message* messages); + + /** + * Generate Method (Action) request. + * + * @param object + * Method object. + * @param index + * Method index. + * @param data + * Method data. + * @param bytearray + * Is data bytearray. + * @param messages DLMS action messages. + */ + int cl_method2( + dlmsSettings* settings, + gxObject* object, + unsigned char index, + unsigned char* value, + uint32_t length, + message* messages); + + /** + * Generate Method (Action) request.. + * + * @param name + * Method object short name or Logical Name. + * @param objectType + * Object type. + * @param index + * Method index. + * @param value + * Method data. + * @param dataType + * Data type. + * @return DLMS action message. + */ + int cl_methodLN( + dlmsSettings* settings, + const unsigned char* name, + DLMS_OBJECT_TYPE objectType, + unsigned char index, + dlmsVARIANT* data, + message* messages); + + /** + * Generate Method (Action) request.. + * + * @param name + * Method object short name or Logical Name. + * @param objectType + * Object type. + * @param index + * Method index. + * @param value + * byte array. + * @param length + * Length of byte array. + * @return DLMS action message. + */ + int cl_methodLN2( + dlmsSettings* settings, + unsigned char* name, + DLMS_OBJECT_TYPE objectType, + unsigned char index, + unsigned char* value, + uint32_t length, + message* messages); + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + /** + * Generate Method (Action) request. + * + * @param name + * Method object short name or Logical Name. + * @param objectType + * Object type. + * @param index + * Method index. + * @param value + * Method data. + * @param dataType + * Data type. + * @return DLMS action message. + */ + int cl_methodSN( + dlmsSettings* settings, + uint16_t address, + DLMS_OBJECT_TYPE objectType, + int index, + dlmsVARIANT* data, + message* messages); + + + /** + * Generate Method (Action) request. + * + * @param name + * Method object short name or Logical Name. + * @param objectType + * Object type. + * @param index + * Method index. + * @param value + * byte array. + * @param lenght + * Length of the byte array. + * @return DLMS action message. + */ + int cl_methodSN2( + dlmsSettings* settings, + uint16_t address, + DLMS_OBJECT_TYPE objectType, + int index, + unsigned char* value, + uint32_t length, + message* messages); +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + + ///////////////////////////////////////////////////////////////////////// + // Convert physical address and logical address to server address. + // logicalAddress: Server logical address. + // physicalAddress: Server physical address. + // addressSize: Address size in bytes. + // Returns Server address. + uint16_t cl_getServerAddress( + uint16_t logicalAddress, + uint16_t physicalAddress, + unsigned char addressSize); +#ifdef __cplusplus +} +#endif +#endif //!defined(DLMS_IGNORE_CLIENT) && !defined(DLMS_IGNORE_MALLOC) +#endif //CLIENT_H diff --git a/components/xt211/converters.c b/components/xt211/converters.c new file mode 100644 index 0000000..e6cfc6e --- /dev/null +++ b/components/xt211/converters.c @@ -0,0 +1,4119 @@ +// +// -------------------------------------------------------------------------- +// 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) +#include +#endif +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) +#include +#include //printf needs this or error is generated. +#endif +#if _MSC_VER > 1400 +#include +#endif +#include "gxignore.h" +#include "converters.h" +#include "gxobjects.h" +#ifndef DLMS_IGNORE_MALLOC +#include "gxmem.h" +#ifndef DLMS_IGNORE_STRING_CONVERTER +#include +#include "objectarray.h" +#include "gxkey.h" +#endif //DLMS_IGNORE_STRING_CONVERTER +#else +#include "enums.h" +#endif //DLMS_IGNORE_MALLOC +#include +#include "helpers.h" + +int obj_typeToString(DLMS_OBJECT_TYPE type, char* buff) +{ + const char* str = obj_typeToString2(type); + if (str != NULL) + { + memcpy(buff, str, strlen(str)); + } + else + { + buff[0] = '\0'; + } + return 0; +} + +#ifdef DLMS_IGNORE_MALLOC +int obj_UInt16ArrayToString(gxByteBuffer* bb, gxArray* arr) +{ + int ret = 0; + uint16_t pos; + uint16_t* it; + for (pos = 0; pos != arr->size; ++pos) + { + if (pos != 0) + { + bb_addString(bb, ", "); + } +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + if ((ret = arr_getByIndex2(arr, pos, (void**)&it, sizeof(uint16_t))) != 0 || + (ret = bb_addIntAsString(bb, *it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(arr, pos, (void**)&it)) != 0 || + (ret = bb_addIntAsString(bb, *it)) != 0) + { + break; + } +#endif //defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + } + return ret; +} +#else +int obj_UInt16ArrayToString(gxByteBuffer* bb, gxArray* arr) +{ + int ret = 0; + uint16_t pos; + uint16_t* it; + for (pos = 0; pos != arr->size; ++pos) + { + if (pos != 0) + { + bb_addString(bb, ", "); + } +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + if ((ret = arr_getByIndex2(arr, pos, (void**)&it, sizeof(uint16_t))) != 0 || + (ret = bb_addIntAsString(bb, *it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(arr, pos, (void**)&it)) != 0 || + (ret = bb_addIntAsString(bb, *it)) != 0) + { + break; + } +#endif //defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + } + return ret; +} +#endif //DLMS_IGNORE_MALLOC + +const char* obj_typeToString2(DLMS_OBJECT_TYPE type) +{ + const char* ret; + switch (type) + { + case DLMS_OBJECT_TYPE_NONE: + ret = GET_STR_FROM_EEPROM(""); + break; + case DLMS_OBJECT_TYPE_DATA: + ret = GET_STR_FROM_EEPROM("Data"); + break; + case DLMS_OBJECT_TYPE_REGISTER: + ret = GET_STR_FROM_EEPROM("Register"); + break; + case DLMS_OBJECT_TYPE_CLOCK: + ret = GET_STR_FROM_EEPROM("Clock"); + break; + case DLMS_OBJECT_TYPE_ACTION_SCHEDULE: + ret = GET_STR_FROM_EEPROM("ActionSchedule"); + break; + case DLMS_OBJECT_TYPE_ACTIVITY_CALENDAR: + ret = GET_STR_FROM_EEPROM("ActivityCalendar"); + break; + case DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME: + ret = GET_STR_FROM_EEPROM("AssociationLogicalName"); + break; + case DLMS_OBJECT_TYPE_ASSOCIATION_SHORT_NAME: + ret = GET_STR_FROM_EEPROM("AssociationShortName"); + break; + case DLMS_OBJECT_TYPE_AUTO_ANSWER: + ret = GET_STR_FROM_EEPROM("AutoAnswer"); + break; + case DLMS_OBJECT_TYPE_AUTO_CONNECT: + ret = GET_STR_FROM_EEPROM("AutoConnect"); + break; + case DLMS_OBJECT_TYPE_DEMAND_REGISTER: + ret = GET_STR_FROM_EEPROM("DemandRegister"); + break; + case DLMS_OBJECT_TYPE_MAC_ADDRESS_SETUP: + ret = GET_STR_FROM_EEPROM("MACAddressSetup"); + break; + case DLMS_OBJECT_TYPE_EXTENDED_REGISTER: + ret = GET_STR_FROM_EEPROM("ExtendedRegister"); + break; + case DLMS_OBJECT_TYPE_GPRS_SETUP: + ret = GET_STR_FROM_EEPROM("GPRSSetup"); + break; + case DLMS_OBJECT_TYPE_SECURITY_SETUP: + ret = GET_STR_FROM_EEPROM("SecuritySetup"); + break; + case DLMS_OBJECT_TYPE_IEC_HDLC_SETUP: + ret = GET_STR_FROM_EEPROM("IECHDLCSetup"); + break; + case DLMS_OBJECT_TYPE_IEC_LOCAL_PORT_SETUP: + ret = GET_STR_FROM_EEPROM("IECLocalPortSetup"); + break; + case DLMS_OBJECT_TYPE_IEC_TWISTED_PAIR_SETUP: + ret = GET_STR_FROM_EEPROM("IECTwistedPairSetup"); + break; + case DLMS_OBJECT_TYPE_IP4_SETUP: + ret = GET_STR_FROM_EEPROM("IP4Setup"); + break; + case DLMS_OBJECT_TYPE_IP6_SETUP: + ret = GET_STR_FROM_EEPROM("IP6Setup"); + break; + case DLMS_OBJECT_TYPE_MBUS_SLAVE_PORT_SETUP: + ret = GET_STR_FROM_EEPROM("MBUSSlavePortSetup"); + break; + case DLMS_OBJECT_TYPE_IMAGE_TRANSFER: + ret = GET_STR_FROM_EEPROM("ImageTransfer"); + break; + case DLMS_OBJECT_TYPE_DISCONNECT_CONTROL: + ret = GET_STR_FROM_EEPROM("DisconnectControl"); + break; + case DLMS_OBJECT_TYPE_LIMITER: + ret = GET_STR_FROM_EEPROM("Limiter"); + break; + case DLMS_OBJECT_TYPE_MBUS_CLIENT: + ret = GET_STR_FROM_EEPROM("MBUSClient"); + break; + case DLMS_OBJECT_TYPE_MODEM_CONFIGURATION: + ret = GET_STR_FROM_EEPROM("ModemConfiguration"); + break; + case DLMS_OBJECT_TYPE_PPP_SETUP: + ret = GET_STR_FROM_EEPROM("PPPSetup"); + break; + case DLMS_OBJECT_TYPE_PROFILE_GENERIC: + ret = GET_STR_FROM_EEPROM("ProfileGeneric"); + break; + case DLMS_OBJECT_TYPE_REGISTER_ACTIVATION: + ret = GET_STR_FROM_EEPROM("RegisterActivation"); + break; + case DLMS_OBJECT_TYPE_REGISTER_MONITOR: + ret = GET_STR_FROM_EEPROM("RegisterMonitor"); + break; + case DLMS_OBJECT_TYPE_REGISTER_TABLE: + ret = GET_STR_FROM_EEPROM("RegisterTable"); + break; + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_STARTUP: + ret = GET_STR_FROM_EEPROM("ZigBeeSASStartup"); + break; + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_JOIN: + ret = GET_STR_FROM_EEPROM("ZigBeeSASJoin"); + break; + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_APS_FRAGMENTATION: + ret = GET_STR_FROM_EEPROM("ZigBeeSASAPSFragmentation"); + break; + case DLMS_OBJECT_TYPE_ZIG_BEE_NETWORK_CONTROL: + ret = GET_STR_FROM_EEPROM("ZigBeeNetworkControl"); + break; + case DLMS_OBJECT_TYPE_SAP_ASSIGNMENT: + ret = GET_STR_FROM_EEPROM("SAPAssignment"); + break; +#ifndef DLMS_IGNORE_SCHEDULE + case DLMS_OBJECT_TYPE_SCHEDULE: + ret = GET_STR_FROM_EEPROM("Schedule"); + break; +#endif //DLMS_IGNORE_SCHEDULE +#ifndef DLMS_IGNORE_SCRIPT_TABLE + case DLMS_OBJECT_TYPE_SCRIPT_TABLE: + ret = GET_STR_FROM_EEPROM("ScriptTable"); + break; +#endif //DLMS_IGNORE_SCRIPT_TABLE + case DLMS_OBJECT_TYPE_SMTP_SETUP: + ret = GET_STR_FROM_EEPROM("SMTPSetup"); + break; + case DLMS_OBJECT_TYPE_SPECIAL_DAYS_TABLE: + ret = GET_STR_FROM_EEPROM("SpecialDaysTable"); + break; + case DLMS_OBJECT_TYPE_STATUS_MAPPING: + ret = GET_STR_FROM_EEPROM("StatusMapping"); + break; + case DLMS_OBJECT_TYPE_TCP_UDP_SETUP: + ret = GET_STR_FROM_EEPROM("TCPUDPSetup"); + break; +#ifndef DLMS_IGNORE_MBUS_DIAGNOSTIC + case DLMS_OBJECT_TYPE_MBUS_DIAGNOSTIC: + ret = GET_STR_FROM_EEPROM("MBusDiagnostic"); + break; +#endif //DLMS_IGNORE_MBUS_DIAGNOSTIC +#ifndef DLMS_IGNORE_MBUS_PORT_SETUP + case DLMS_OBJECT_TYPE_MBUS_PORT_SETUP: + ret = GET_STR_FROM_EEPROM("MBusPortSetup"); + break; +#endif //DLMS_IGNORE_MBUS_PORT_SETUP +#ifndef DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS + case DLMS_OBJECT_TYPE_G3_PLC_MAC_LAYER_COUNTERS: + ret = GET_STR_FROM_EEPROM("G3PlcMacLayerCounters"); + break; +#endif //DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS +#ifndef DLMS_IGNORE_G3_PLC_MAC_SETUP + case DLMS_OBJECT_TYPE_G3_PLC_MAC_SETUP: + ret = GET_STR_FROM_EEPROM("G3PlcMacSetup"); + break; +#endif //DLMS_IGNORE_G3_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_G3_PLC_6LO_WPAN + case DLMS_OBJECT_TYPE_G3_PLC_6LO_WPAN: + ret = GET_STR_FROM_EEPROM("G3Plc6LoWPAN"); + break; +#endif //DLMS_IGNORE_G3_PLC_6LO_WPAN +#ifndef DLMS_IGNORE_FUNCTION_CONTROL + case DLMS_OBJECT_TYPE_FUNCTION_CONTROL: + ret = GET_STR_FROM_EEPROM("FunctionControl"); + break; +#endif //DLMS_IGNORE_FUNCTION_CONTROL +#ifndef DLMS_IGNORE_ARRAY_MANAGER + case DLMS_OBJECT_TYPE_ARRAY_MANAGER: + ret = GET_STR_FROM_EEPROM("ArrayManager"); + break; +#endif //DLMS_IGNORE_ARRAY_MANAGER + case DLMS_OBJECT_TYPE_UTILITY_TABLES: + ret = GET_STR_FROM_EEPROM("UtilityTables"); + break; + case DLMS_OBJECT_TYPE_MBUS_MASTER_PORT_SETUP: + ret = GET_STR_FROM_EEPROM("MBUSMasterPortSetup"); + break; + case DLMS_OBJECT_TYPE_PUSH_SETUP: + ret = GET_STR_FROM_EEPROM("PushSetup"); + break; + case DLMS_OBJECT_TYPE_DATA_PROTECTION: + ret = GET_STR_FROM_EEPROM("DataProtection"); + break; + case DLMS_OBJECT_TYPE_ACCOUNT: + ret = GET_STR_FROM_EEPROM("Account"); + break; + case DLMS_OBJECT_TYPE_CREDIT: + ret = GET_STR_FROM_EEPROM("Credit"); + break; + case DLMS_OBJECT_TYPE_CHARGE: + ret = GET_STR_FROM_EEPROM("Charge"); + break; + case DLMS_OBJECT_TYPE_TOKEN_GATEWAY: + ret = GET_STR_FROM_EEPROM("TokenGateway"); + break; + case DLMS_OBJECT_TYPE_LLC_SSCS_SETUP: + ret = GET_STR_FROM_EEPROM("LLCSSCSSetup"); + break; + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS: + ret = GET_STR_FROM_EEPROM("PrimeNbOfdmPLCphysicalLayerCounters"); + break; + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_SETUP: + ret = GET_STR_FROM_EEPROM("PrimeNbOfdmPLCMacSetup"); + break; + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS: + ret = GET_STR_FROM_EEPROM("PrimeNbOfdmPLCMacFunctionalParameters"); + break; + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_COUNTERS: + ret = GET_STR_FROM_EEPROM("PrimeNbOfdmPLCMacCounters"); + break; + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA: + ret = GET_STR_FROM_EEPROM("PrimeNbOfdmPLCMacNetworkAdministrationData"); + break; + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION: + ret = GET_STR_FROM_EEPROM("PrimeNbOfdmPLCApplicationsIdentification"); + break; + case DLMS_OBJECT_TYPE_PARAMETER_MONITOR: + ret = GET_STR_FROM_EEPROM("ParameterMonitor"); + break; + case DLMS_OBJECT_TYPE_COMPACT_DATA: + ret = GET_STR_FROM_EEPROM("CompactData"); + break; + case DLMS_OBJECT_TYPE_GSM_DIAGNOSTIC: + ret = GET_STR_FROM_EEPROM("GsmDiagnostic"); + break; +#ifndef DLMS_IGNORE_ARBITRATOR + case DLMS_OBJECT_TYPE_ARBITRATOR: + ret = GET_STR_FROM_EEPROM("Arbitrator"); + break; +#endif //DLMS_IGNORE_ARBITRATOR +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE1_SETUP: + ret = GET_STR_FROM_EEPROM("Iec8802LlcType1Setup"); + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE2_SETUP: + ret = GET_STR_FROM_EEPROM("Iec8802LlcType2Setup"); + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE3_SETUP: + ret = GET_STR_FROM_EEPROM("Iec8802LlcType3Setup"); + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP +#ifndef DLMS_IGNORE_SFSK_ACTIVE_INITIATOR + case DLMS_OBJECT_TYPE_SFSK_ACTIVE_INITIATOR: + ret = GET_STR_FROM_EEPROM("SFSKActiveInitiator"); + break; +#endif //DLMS_IGNORE_SFSK_ACTIVE_INITIATOR +#ifndef DLMS_IGNORE_SFSK_MAC_COUNTERS + case DLMS_OBJECT_TYPE_SFSK_MAC_COUNTERS: + ret = GET_STR_FROM_EEPROM("FSKMacCounters"); + break; +#endif //DLMS_IGNORE_SFSK_MAC_COUNTERS +#ifndef DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS + case DLMS_OBJECT_TYPE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS: + ret = GET_STR_FROM_EEPROM("SFSKMacSynchronizationTimeouts"); + break; +#endif //DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS +#ifndef DLMS_IGNORE_SFSK_PHY_MAC_SETUP + case DLMS_OBJECT_TYPE_SFSK_PHY_MAC_SETUP: + ret = GET_STR_FROM_EEPROM("SFSKPhyMacSetUp"); + break; +#endif //DLMS_IGNORE_SFSK_PHY_MAC_SETUP +#ifndef DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST + case DLMS_OBJECT_TYPE_SFSK_REPORTING_SYSTEM_LIST: + ret = GET_STR_FROM_EEPROM("SFSKReportingSystemList"); + break; +#endif //DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST +#ifdef DLMS_ITALIAN_STANDARD + case DLMS_OBJECT_TYPE_TARIFF_PLAN: + ret = GET_STR_FROM_EEPROM("TariffPlan"); + break; +#endif //DLMS_ITALIAN_STANDARD + default: //Unknown type. + ret = NULL; + break; + } + return ret; +} + +#ifndef DLMS_IGNORE_MALLOC +#ifndef DLMS_IGNORE_STRING_CONVERTER + +const char* obj_getUnitAsString(unsigned char unit) +{ + const char* ret; + switch (unit) + { + case DLMS_UNIT_NONE: + ret = GET_STR_FROM_EEPROM("None"); + break; + case DLMS_UNIT_YEAR: + ret = GET_STR_FROM_EEPROM("Year"); + break; + case DLMS_UNIT_MONTH: + ret = GET_STR_FROM_EEPROM("Month"); + break; + case DLMS_UNIT_WEEK: + ret = GET_STR_FROM_EEPROM("Week"); + break; + case DLMS_UNIT_DAY: + ret = GET_STR_FROM_EEPROM("Day"); + break; + case DLMS_UNIT_HOUR: + ret = GET_STR_FROM_EEPROM("Hour"); + break; + case DLMS_UNIT_MINUTE: + ret = GET_STR_FROM_EEPROM("Minute"); + break; + case DLMS_UNIT_SECOND: + ret = GET_STR_FROM_EEPROM("Second"); + break; + case DLMS_UNIT_PHASE_ANGLE_DEGREE: + ret = GET_STR_FROM_EEPROM("PhaseAngle"); + break; + case DLMS_UNIT_TEMPERATURE: + ret = GET_STR_FROM_EEPROM("Temperature"); + break; + case DLMS_UNIT_LOCAL_CURRENCY: + ret = GET_STR_FROM_EEPROM("LocalCurrency"); + break; + case DLMS_UNIT_LENGTH: + ret = GET_STR_FROM_EEPROM("Length"); + break; + case DLMS_UNIT_SPEED: + ret = GET_STR_FROM_EEPROM("Speed"); + break; + case DLMS_UNIT_VOLUME_CUBIC_METER: + ret = GET_STR_FROM_EEPROM("Volume Cubic Meter"); + break; + case DLMS_UNIT_CORRECTED_VOLUME: + ret = GET_STR_FROM_EEPROM("Corrected volume"); + break; + case DLMS_UNIT_VOLUME_FLUX_HOUR: + ret = GET_STR_FROM_EEPROM("Volume flux hour"); + break; + case DLMS_UNIT_CORRECTED_VOLUME_FLUX_HOUR: + ret = GET_STR_FROM_EEPROM("Corrected volume flux hour"); + break; + case DLMS_UNIT_VOLUME_FLUX_DAY: + ret = GET_STR_FROM_EEPROM("Volume flux day"); + break; + case DLMS_UNIT_CORRECTED_VOLUME_FLUX_DAY: + ret = GET_STR_FROM_EEPROM("Corrected volume flux day"); + break; + case DLMS_UNIT_VOLUME_LITER: + ret = GET_STR_FROM_EEPROM("Volume liter"); + break; + case DLMS_UNIT_MASS_KG: + ret = GET_STR_FROM_EEPROM("Mass Kg"); + break; + case DLMS_UNIT_FORCE: + ret = GET_STR_FROM_EEPROM("Force"); + break; + case DLMS_UNIT_ENERGY: + ret = GET_STR_FROM_EEPROM("Energy"); + break; + case DLMS_UNIT_PRESSURE_PASCAL: + ret = GET_STR_FROM_EEPROM("Pressure pascal"); + break; + case DLMS_UNIT_PRESSURE_BAR: + ret = GET_STR_FROM_EEPROM("Pressure Bar"); + break; + case DLMS_UNIT_ENERGY_JOULE: + ret = GET_STR_FROM_EEPROM("Energy joule"); + break; + case DLMS_UNIT_THERMAL_POWER: + ret = GET_STR_FROM_EEPROM("Thermal power"); + break; + case DLMS_UNIT_ACTIVE_POWER: + ret = GET_STR_FROM_EEPROM("Active power"); + break; + case DLMS_UNIT_APPARENT_POWER: + ret = GET_STR_FROM_EEPROM("Apparent power"); + break; + case DLMS_UNIT_REACTIVE_POWER: + ret = GET_STR_FROM_EEPROM("Reactive power"); + break; + case DLMS_UNIT_ACTIVE_ENERGY: + ret = GET_STR_FROM_EEPROM("Active energy"); + break; + case DLMS_UNIT_APPARENT_ENERGY: + ret = GET_STR_FROM_EEPROM("Apparent energy"); + break; + case DLMS_UNIT_REACTIVE_ENERGY: + ret = GET_STR_FROM_EEPROM("Reactive energy"); + break; + case DLMS_UNIT_CURRENT: + ret = GET_STR_FROM_EEPROM("Current"); + break; + case DLMS_UNIT_ELECTRICAL_CHARGE: + ret = GET_STR_FROM_EEPROM("ElectricalCharge"); + break; + case DLMS_UNIT_VOLTAGE: + ret = GET_STR_FROM_EEPROM("Voltage"); + break; + case DLMS_UNIT_ELECTRICAL_FIELD_STRENGTH: + ret = GET_STR_FROM_EEPROM("Electrical field strength E V/m"); + break; + case DLMS_UNIT_CAPACITY: + ret = GET_STR_FROM_EEPROM("Capacity C farad C/V = As/V"); + break; + case DLMS_UNIT_RESISTANCE: + ret = GET_STR_FROM_EEPROM("Resistance"); + break; + case DLMS_UNIT_RESISTIVITY: + ret = GET_STR_FROM_EEPROM("Resistivity"); + break; + case DLMS_UNIT_MAGNETIC_FLUX: + ret = GET_STR_FROM_EEPROM("Magnetic flux F weber Wb = Vs"); + break; + case DLMS_UNIT_INDUCTION: + ret = GET_STR_FROM_EEPROM("Induction T tesla Wb/m2"); + break; + case DLMS_UNIT_MAGNETIC: + ret = GET_STR_FROM_EEPROM("Magnetic field strength H A/m"); + break; + case DLMS_UNIT_INDUCTIVITY: + ret = GET_STR_FROM_EEPROM("Inductivity L henry H = Wb/A"); + break; + case DLMS_UNIT_FREQUENCY: + ret = GET_STR_FROM_EEPROM("Frequency"); + break; + case DLMS_UNIT_ACTIVE: + ret = GET_STR_FROM_EEPROM("Active energy"); + break; + case DLMS_UNIT_REACTIVE: + ret = GET_STR_FROM_EEPROM("Reactive energy"); + break; + case DLMS_UNIT_APPARENT: + ret = GET_STR_FROM_EEPROM("Apparent energy"); + break; + case DLMS_UNIT_V260: + ret = GET_STR_FROM_EEPROM("V260*60s"); + break; + case DLMS_UNIT_A260: + ret = GET_STR_FROM_EEPROM("A260*60s"); + break; + case DLMS_UNIT_MASS_KG_PER_SECOND: + ret = GET_STR_FROM_EEPROM("Mass"); + break; + case DLMS_UNIT_CONDUCTANCE: + ret = GET_STR_FROM_EEPROM("Conductance siemens"); + break; + case DLMS_UNIT_KELVIN: + ret = GET_STR_FROM_EEPROM("Kelvin"); + break; + case DLMS_UNIT_RU2H: + ret = GET_STR_FROM_EEPROM("RU2h"); + break; + case DLMS_UNIT_RI2H: + ret = GET_STR_FROM_EEPROM("RI2h"); + break; + case DLMS_UNIT_CUBIC_METER_RV: + ret = GET_STR_FROM_EEPROM("Cubic meter RV"); + break; + case DLMS_UNIT_PERCENTAGE: + ret = GET_STR_FROM_EEPROM("Percentage"); + break; + case DLMS_UNIT_AMPERE_HOURS: + ret = GET_STR_FROM_EEPROM("Ampere hours"); + break; + case DLMS_UNIT_ENERGY_PER_VOLUME: + ret = GET_STR_FROM_EEPROM("Energy per volume"); + break; + case DLMS_UNIT_WOBBE: + ret = GET_STR_FROM_EEPROM("Wobbe"); + break; + case DLMS_UNIT_MOLE_PERCENT: + ret = GET_STR_FROM_EEPROM("Mole percent"); + break; + case DLMS_UNIT_MASS_DENSITY: + ret = GET_STR_FROM_EEPROM("Mass density"); + break; + case DLMS_UNIT_PASCAL_SECOND: + ret = GET_STR_FROM_EEPROM("Pascal second"); + break; + case DLMS_UNIT_JOULE_KILOGRAM: + ret = GET_STR_FROM_EEPROM("Joule kilogram"); + break; + case DLMS_UNIT_PRESSURE_GRAM_PER_SQUARE_CENTIMETER: + ret = GET_STR_FROM_EEPROM("Pressure, gram per square centimeter."); + break; + case DLMS_UNIT_PRESSURE_ATMOSPHERE: + ret = GET_STR_FROM_EEPROM("Pressure, atmosphere."); + break; + case DLMS_UNIT_SIGNAL_STRENGTH_MILLI_WATT: + ret = GET_STR_FROM_EEPROM("Signal strength, dB milliwatt"); + break; + case DLMS_UNIT_SIGNAL_STRENGTH_MICRO_VOLT: + //logarithmic unit that expresses the ratio between two values of a physical quantity + ret = GET_STR_FROM_EEPROM("Signal strength, dB microvolt"); + break; + case DLMS_UNIT_DB: + ret = GET_STR_FROM_EEPROM("dB"); + break; + case DLMS_UNIT_INCH: + ret = GET_STR_FROM_EEPROM("Inch"); + break; + case DLMS_UNIT_FOOT: + ret = GET_STR_FROM_EEPROM("Foot"); + break; + case DLMS_UNIT_POUND: + ret = GET_STR_FROM_EEPROM("Pound"); + break; + case DLMS_UNIT_FAHRENHEIT: + ret = GET_STR_FROM_EEPROM("Fahrenheit"); + break; + case DLMS_UNIT_RANKINE: + ret = GET_STR_FROM_EEPROM("Rankine"); + break; + case DLMS_UNIT_SQUARE_INCH: + ret = GET_STR_FROM_EEPROM("Square inch"); + break; + case DLMS_UNIT_SQUARE_FOOT: + ret = GET_STR_FROM_EEPROM("Square foot"); + break; + case DLMS_UNIT_ACRE: + ret = GET_STR_FROM_EEPROM("Acre"); + break; + case DLMS_UNIT_CUBIC_INCH: + ret = GET_STR_FROM_EEPROM("Cubic inch"); + break; + case DLMS_UNIT_CUBIC_FOOT: + ret = GET_STR_FROM_EEPROM("Cubic foot"); + break; + case DLMS_UNIT_ACRE_FOOT: + ret = GET_STR_FROM_EEPROM("Acre foot"); + break; + case DLMS_UNIT_GALLON_IMPERIAL: + ret = GET_STR_FROM_EEPROM("Gallon Imperial"); + break; + case DLMS_UNIT_GALLON_US: + ret = GET_STR_FROM_EEPROM("GallonUS"); + break; + case DLMS_UNIT_POUND_FORCE: + ret = GET_STR_FROM_EEPROM("Pound force"); + break; + case DLMS_UNIT_POUND_FORCE_PER_SQUARE_INCH: + ret = GET_STR_FROM_EEPROM("Pound force per square inch"); + break; + case DLMS_UNIT_POUND_PER_CUBIC_FOOT: + ret = GET_STR_FROM_EEPROM("Pound per cubic foot"); + break; + case DLMS_UNIT_POUND_PER_FOOT_SECOND: + ret = GET_STR_FROM_EEPROM("Pound per foot second"); + break; + case DLMS_UNIT_BRITISH_THERMAL_UNIT: + ret = GET_STR_FROM_EEPROM("British thermal unit"); + break; + case DLMS_UNIT_THERM_EU: + ret = GET_STR_FROM_EEPROM("Therm EU"); + break; + case DLMS_UNIT_THERM_US: + ret = GET_STR_FROM_EEPROM("Therm US"); + break; + case DLMS_UNIT_BRITISH_THERMAL_UNIT_PER_POUND: + ret = GET_STR_FROM_EEPROM("British thermal unit per pound"); + break; + case DLMS_UNIT_BRITISH_THERMAL_UNIT_PER_CUBIC_FOOT: + ret = GET_STR_FROM_EEPROM("British thermal unit per cubic foot"); + break; + case DLMS_UNIT_CUBIC_FEET: + ret = GET_STR_FROM_EEPROM("Cubic feet"); + break; + case DLMS_UNIT_FOOT_PER_SECOND: + ret = GET_STR_FROM_EEPROM("Foot per second"); + break; + case DLMS_UNIT_CUBIC_FOOT_PER_MIN: + ret = GET_STR_FROM_EEPROM("Foot per min"); + break; + case DLMS_UNIT_CUBIC_FOOT_PER_DAY: + ret = GET_STR_FROM_EEPROM("Foot per day"); + break; + case DLMS_UNIT_ACRE_FOOT_PER_SECOND: + ret = GET_STR_FROM_EEPROM("Acre foot per second"); + break; + case DLMS_UNIT_ACRE_FOOT_PER_MIN: + ret = GET_STR_FROM_EEPROM("Acre foot per min"); + break; + case DLMS_UNIT_ACRE_FOOT_PER_HOUR: + ret = GET_STR_FROM_EEPROM("Acre foot per hour"); + break; + case DLMS_UNIT_ACRE_FOOT_PER_DAY: + ret = GET_STR_FROM_EEPROM("Acre foot per day"); + break; + case DLMS_UNIT_IMPERIAL_GALLON: + ret = GET_STR_FROM_EEPROM("Imperial gallon"); + break; + case DLMS_UNIT_IMPERIAL_GALLON_PER_SECOND: + ret = GET_STR_FROM_EEPROM("Imperial gallon per second"); + break; + case DLMS_UNIT_IMPERIAL_GALLON_PER_MIN: + ret = GET_STR_FROM_EEPROM("Imperial gallon per min"); + break; + case DLMS_UNIT_IMPERIAL_GALLON_PER_HOUR: + ret = GET_STR_FROM_EEPROM("Imperial gallon per hour"); + break; + case DLMS_UNIT_IMPERIAL_GALLON_PER_DAY: + ret = GET_STR_FROM_EEPROM("Imperial gallon per day"); + break; + case DLMS_UNIT_US_GALLON: + ret = GET_STR_FROM_EEPROM("US Gallon"); + break; + case DLMS_UNIT_US_GALLON_PER_SECOND: + ret = GET_STR_FROM_EEPROM("US gallon per second"); + break; + case DLMS_UNIT_US_GALLON_PER_MIN: + ret = GET_STR_FROM_EEPROM("US gallon per min"); + break; + case DLMS_UNIT_US_GALLON_PER_HOUR: + ret = GET_STR_FROM_EEPROM("US gallon per hour"); + break; + case DLMS_UNIT_US_GALLON_PER_DAY: + ret = GET_STR_FROM_EEPROM("US gallon per day"); + break; + case DLMS_UNIT_BRITISH_THERMAL_UNIT_PER_SECOND: + ret = GET_STR_FROM_EEPROM("British thermal unit per second"); + break; + case DLMS_UNIT_BRITISH_THERMAL_UNIT_PER_MIN: + ret = GET_STR_FROM_EEPROM("British thermal unit per min"); + break; + case DLMS_UNIT_BRITISH_THERMAL_UNIT_PER_HOUR: + ret = GET_STR_FROM_EEPROM("British thermal unit per hour"); + break; + case DLMS_UNIT_BRITISH_THERMAL_UNIT_PER_DAY: + ret = GET_STR_FROM_EEPROM("British thermal unit per day"); + break; + case DLMS_UNIT_OTHER: + ret = GET_STR_FROM_EEPROM("Other unit"); + break; + case DLMS_UNIT_NO_UNIT: + ret = GET_STR_FROM_EEPROM("NoUnit"); + break; + default: + ret = NULL; + break; + } + return ret; +} + +#ifndef DLMS_IGNORE_DATA +int obj_DataToString(gxData* object, char** buff) +{ + int ret; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + if ((ret = bb_addString(&ba, GET_STR_FROM_EEPROM("Index: 2 Value: "))) == 0 && + (ret = var_toString(&object->value, &ba)) == 0 && + (ret = bb_addString(&ba, GET_STR_FROM_EEPROM("\n"))) == 0) + { + *buff = bb_toString(&ba); + } + bb_clear(&ba); + return ret; +} +#endif //DLMS_IGNORE_DATA +#ifndef DLMS_IGNORE_REGISTER +int obj_RegisterToString(gxRegister* object, char** buff) +{ + int ret; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + if ((ret = bb_addString(&ba, GET_STR_FROM_EEPROM("Index: 3 Value: Scaler: "))) == 0 && + (ret = bb_addDoubleAsString(&ba, hlp_getScaler(object->scaler))) == 0 && + (ret = bb_addString(&ba, GET_STR_FROM_EEPROM(" Unit: "))) == 0 && + (ret = bb_addString(&ba, obj_getUnitAsString(object->unit))) == 0 && + (ret = bb_addString(&ba, GET_STR_FROM_EEPROM("\nIndex: 2 Value: "))) == 0 && + (ret = var_toString(&object->value, &ba)) == 0 && + (ret = bb_addString(&ba, GET_STR_FROM_EEPROM("\n"))) == 0) + { + *buff = bb_toString(&ba); + } + bb_clear(&ba); + return ret; +} +#endif //DLMS_IGNORE_REGISTER +#ifndef DLMS_IGNORE_CLOCK +int obj_clockToString(gxClock* object, char** buff) +{ + int ret; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + if ((ret = bb_addString(&ba, GET_STR_FROM_EEPROM("Index: 2 Value: "))) == 0 && + (ret = time_toString(&object->time, &ba)) == 0 && + (ret = bb_addString(&ba, GET_STR_FROM_EEPROM("\nIndex: 3 Value: "))) == 0 && + (ret = bb_addIntAsString(&ba, object->timeZone)) == 0 && + (ret = bb_addString(&ba, GET_STR_FROM_EEPROM("\nIndex: 4 Value: "))) == 0 && + (ret = bb_addIntAsString(&ba, object->status)) == 0 && + (ret = bb_addString(&ba, GET_STR_FROM_EEPROM("\nIndex: 5 Value: "))) == 0 && + (ret = time_toString(&object->begin, &ba)) == 0 && + (ret = bb_addString(&ba, GET_STR_FROM_EEPROM("\nIndex: 6 Value: "))) == 0 && + (ret = time_toString(&object->end, &ba)) == 0 && + (ret = bb_addString(&ba, GET_STR_FROM_EEPROM("\nIndex: 7 Value: "))) == 0 && + (ret = bb_addIntAsString(&ba, object->deviation)) == 0 && + (ret = bb_addString(&ba, GET_STR_FROM_EEPROM("\nIndex: 8 Value: "))) == 0 && + (ret = bb_addIntAsString(&ba, object->enabled)) == 0 && + (ret = bb_addString(&ba, GET_STR_FROM_EEPROM("\nIndex: 9 Value: "))) == 0 && + (ret = bb_addIntAsString(&ba, object->clockBase)) == 0 && + (ret = bb_addString(&ba, GET_STR_FROM_EEPROM("\n"))) == 0) + { + *buff = bb_toString(&ba); + } + bb_clear(&ba); + return ret; +} +#endif //DLMS_IGNORE_CLOCK +#ifndef DLMS_IGNORE_SCRIPT_TABLE +int obj_ScriptTableToString(gxScriptTable* object, char** buff) +{ + int ret; + uint16_t pos, pos2; + gxByteBuffer ba; + gxScript* s; + gxScriptAction* sa; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: ["); + for (pos = 0; pos != object->scripts.size; ++pos) + { + if (pos != 0) + { + bb_addString(&ba, ", "); + } + ret = arr_getByIndex(&object->scripts, pos, (void**)&s); + if (ret != 0) + { + return ret; + } + bb_addIntAsString(&ba, s->id); + bb_addString(&ba, "\n"); + for (pos2 = 0; pos2 != s->actions.size; ++pos2) + { + ret = arr_getByIndex(&s->actions, pos2, (void**)&sa); + if (ret != 0) + { + return ret; + } + if (pos2 != 0) + { + bb_addString(&ba, ", "); + } + bb_addIntAsString(&ba, sa->type); + bb_addString(&ba, " "); +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if (sa->target == NULL) + { + bb_addIntAsString(&ba, 0); + bb_addString(&ba, " "); + hlp_appendLogicalName(&ba, EMPTY_LN); + } + else + { + bb_addIntAsString(&ba, sa->target->objectType); + bb_addString(&ba, " "); + hlp_appendLogicalName(&ba, sa->target->logicalName); + } +#else + bb_addIntAsString(&ba, sa->objectType); + bb_addString(&ba, " "); + hlp_appendLogicalName(&ba, sa->logicalName); +#endif //DLMS_IGNORE_OBJECT_POINTERS + + bb_addString(&ba, " "); + bb_addIntAsString(&ba, sa->index); + bb_addString(&ba, " "); + ret = var_toString(&sa->parameter, &ba); + if (ret != 0) + { + return ret; + } + } + } + bb_addString(&ba, "]\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_SCRIPT_TABLE +#ifndef DLMS_IGNORE_SPECIAL_DAYS_TABLE +int obj_specialDaysTableToString(gxSpecialDaysTable* object, char** buff) +{ + int ret; + uint16_t pos; + gxSpecialDay* sd; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: ["); + for (pos = 0; pos != object->entries.size; ++pos) + { + if (pos != 0) + { + bb_addString(&ba, ", "); + } + ret = arr_getByIndex(&object->entries, pos, (void**)&sd); + if (ret != 0) + { + return ret; + } + bb_addIntAsString(&ba, sd->index); + bb_addString(&ba, " "); + ret = time_toString(&sd->date, &ba); + if (ret != 0) + { + return ret; + } + bb_addString(&ba, " "); + bb_addIntAsString(&ba, sd->dayId); + } + bb_addString(&ba, "]\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_SPECIAL_DAYS_TABLE +#ifndef DLMS_IGNORE_TCP_UDP_SETUP +int obj_TcpUdpSetupToString(gxTcpUdpSetup* object, char** buff) +{ + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + bb_addIntAsString(&ba, object->port); + bb_addString(&ba, "\nIndex: 3 Value: "); +#ifndef DLMS_IGNORE_OBJECT_POINTERS + bb_addLogicalName(&ba, obj_getLogicalName((gxObject*)object->ipSetup)); +#else + bb_addLogicalName(&ba, object->ipReference); +#endif //DLMS_IGNORE_OBJECT_POINTERS + + bb_addString(&ba, "\nIndex: 4 Value: "); + bb_addIntAsString(&ba, object->maximumSegmentSize); + bb_addString(&ba, "\nIndex: 5 Value: "); + bb_addIntAsString(&ba, object->maximumSimultaneousConnections); + bb_addString(&ba, "\nIndex: 6 Value: "); + bb_addIntAsString(&ba, object->inactivityTimeout); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_TCP_UDP_SETUP +#ifndef DLMS_IGNORE_MBUS_MASTER_PORT_SETUP +int obj_mBusMasterPortSetupToString(gxMBusMasterPortSetup* object, char** buff) +{ + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + bb_addIntAsString(&ba, object->commSpeed); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_MBUS_MASTER_PORT_SETUP + +int obj_timeWindowToString(gxArray* arr, gxByteBuffer* bb) +{ + gxKey* it; + int ret = 0; + uint16_t pos; + for (pos = 0; pos != arr->size; ++pos) + { + if ((ret = arr_getByIndex(arr, pos, (void**)&it)) != 0) + { + break; + } + if (pos != 0) + { + bb_addString(bb, ", "); + } + if ((ret = time_toString((gxtime*)it->key, bb)) != 0 || + (ret = bb_addString(bb, " ")) != 0 || + (ret = time_toString((gxtime*)it->value, bb)) != 0) + { + break; + } + } + return ret; +} + +int obj_CaptureObjectsToString(gxByteBuffer* ba, gxArray* objects) +{ + uint16_t pos; + int ret = DLMS_ERROR_CODE_OK; +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + gxTarget* it; +#else + gxKey* it; +#endif //#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + for (pos = 0; pos != objects->size; ++pos) + { + if ((ret = arr_getByIndex(objects, pos, (void**)&it)) != DLMS_ERROR_CODE_OK) + { + break; + } + if (pos != 0) + { + bb_addString(ba, ", "); + } +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + if ((ret = bb_addString(ba, obj_typeToString2((DLMS_OBJECT_TYPE)it->target->objectType))) != 0 || + (ret = bb_addString(ba, " ")) != 0 || + (ret = hlp_appendLogicalName(ba, it->target->logicalName)) != 0) + { + break; + } +#else + if ((ret = bb_addString(ba, obj_typeToString2(((gxObject*)it->key)->objectType))) != 0 || + (ret = bb_addString(ba, " ")) != 0 || + (ret = hlp_appendLogicalName(ba, ((gxObject*)it->key)->logicalName)) != 0) + { + break; + } +#endif //#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + } + return ret; +} + +#ifndef DLMS_IGNORE_PUSH_SETUP +int obj_pushSetupToString(gxPushSetup* object, char** buff) +{ + int ret; + gxByteBuffer ba; + if ((ret = BYTE_BUFFER_INIT(&ba)) == 0 && + (ret = bb_addString(&ba, "Index: 2 Value: ")) == 0 && + (ret = obj_CaptureObjectsToString(&ba, &object->pushObjectList)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 3 Value: ")) == 0 && + (ret = bb_set(&ba, object->destination.data, object->destination.size)) == 0 && + (ret = bb_addString(&ba, " ")) == 0 && + (ret = bb_addIntAsString(&ba, object->message)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 4 Value: ")) == 0 && + (ret = obj_timeWindowToString(&object->communicationWindow, &ba)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 5 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->randomisationStartInterval)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 6 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->numberOfRetries)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 7 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->repetitionDelay)) == 0 && + (ret = bb_addString(&ba, "\n")) == 0) + { + *buff = bb_toString(&ba); + } + bb_clear(&ba); + return ret; +} +#endif //DLMS_IGNORE_PUSH_SETUP +#ifndef DLMS_IGNORE_AUTO_CONNECT +int obj_autoConnectToString(gxAutoConnect* object, char** buff) +{ + gxKey* k; + int ret; + uint16_t pos; + gxByteBuffer ba, * dest; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + bb_addIntAsString(&ba, object->mode); + bb_addString(&ba, "\nIndex: 3 Value: "); + bb_addIntAsString(&ba, object->repetitions); + bb_addString(&ba, "\nIndex: 4 Value: "); + bb_addIntAsString(&ba, object->repetitionDelay); + bb_addString(&ba, "\nIndex: 5 Value: ["); + for (pos = 0; pos != object->callingWindow.size; ++pos) + { + if (pos != 0) + { + bb_addString(&ba, ", "); + } + ret = arr_getByIndex(&object->callingWindow, pos, (void**)&k); + if (ret != 0) + { + return ret; + } + time_toString((gxtime*)k->key, &ba); + bb_addString(&ba, " "); + time_toString((gxtime*)k->value, &ba); + } + bb_addString(&ba, "]"); + bb_addString(&ba, "\nIndex: 6 Value: "); + for (pos = 0; pos != object->destinations.size; ++pos) + { + if (pos != 0) + { + bb_addString(&ba, ", "); + } + ret = arr_getByIndex(&object->destinations, pos, (void**)&dest); + if (ret != 0) + { + return ret; + } + bb_set2(&ba, dest, 0, bb_size(dest)); + } + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_AUTO_CONNECT +#ifndef DLMS_IGNORE_ACTIVITY_CALENDAR +int obj_seasonProfileToString(gxArray* arr, gxByteBuffer* ba) +{ + gxSeasonProfile* it; + int ret; + uint16_t pos; + bb_addString(ba, "["); + for (pos = 0; pos != arr->size; ++pos) + { + if (pos != 0) + { + bb_addString(ba, ", "); + } + ret = arr_getByIndex(arr, pos, (void**)&it); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + bb_addString(ba, "{"); + bb_attachString(ba, bb_toHexString(&it->name)); + bb_addString(ba, ", "); + time_toString(&it->start, ba); + bb_addString(ba, ", "); + bb_attachString(ba, bb_toHexString(&it->weekName)); + bb_addString(ba, "}"); + } + bb_addString(ba, "]"); + return 0; +} +int obj_weekProfileToString(gxArray* arr, gxByteBuffer* ba) +{ + gxWeekProfile* it; + int ret; + uint16_t pos; + bb_addString(ba, "["); + for (pos = 0; pos != arr->size; ++pos) + { + if (pos != 0) + { + bb_addString(ba, ", "); + } + ret = arr_getByIndex(arr, pos, (void**)&it); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + bb_attachString(ba, bb_toString(&it->name)); + bb_addString(ba, " "); + bb_addIntAsString(ba, it->monday); + bb_addString(ba, " "); + bb_addIntAsString(ba, it->tuesday); + bb_addString(ba, " "); + bb_addIntAsString(ba, it->wednesday); + bb_addString(ba, " "); + bb_addIntAsString(ba, it->thursday); + bb_addString(ba, " "); + bb_addIntAsString(ba, it->friday); + bb_addString(ba, " "); + bb_addIntAsString(ba, it->saturday); + bb_addString(ba, " "); + bb_addIntAsString(ba, it->sunday); + } + bb_addString(ba, "]"); + return 0; +} + +int obj_dayProfileToString(gxArray* arr, gxByteBuffer* ba) +{ + gxDayProfile* dp; + gxDayProfileAction* it; + int ret; + uint16_t pos, pos2; + bb_addString(ba, "["); + for (pos = 0; pos != arr->size; ++pos) + { + if (pos != 0) + { + bb_addString(ba, ", "); + } + ret = arr_getByIndex(arr, pos, (void**)&dp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + bb_addIntAsString(ba, dp->dayId); + bb_addString(ba, "["); + for (pos2 = 0; pos2 != dp->daySchedules.size; ++pos2) + { + if (pos2 != 0) + { + bb_addString(ba, ", "); + } + ret = arr_getByIndex(&dp->daySchedules, pos2, (void**)&it); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if (it->script == NULL) + { + hlp_appendLogicalName(ba, EMPTY_LN); + } + else + { + hlp_appendLogicalName(ba, it->script->logicalName); + } +#else + hlp_appendLogicalName(ba, it->scriptLogicalName); +#endif //DLMS_IGNORE_OBJECT_POINTERS + bb_addString(ba, " "); + bb_addIntAsString(ba, it->scriptSelector); + bb_addString(ba, " "); + time_toString(&it->startTime, ba); + } + bb_addString(ba, "]"); + } + bb_addString(ba, "]"); + return 0; +} + +int obj_activityCalendarToString(gxActivityCalendar* object, char** buff) +{ + int ret; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + if ((ret = bb_addString(&ba, "Index: 2 Value: ")) == 0 && + (ret = bb_attachString(&ba, bb_toString(&object->calendarNameActive))) == 0 && + (ret = bb_addString(&ba, "\nIndex: 3 Value: ")) == 0 && + (ret = obj_seasonProfileToString(&object->seasonProfileActive, &ba)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 4 Value: ")) == 0 && + (ret = obj_weekProfileToString(&object->weekProfileTableActive, &ba)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 5 Value: ")) == 0 && + (ret = obj_dayProfileToString(&object->dayProfileTableActive, &ba)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 6 Value: ")) == 0 && + (ret = bb_attachString(&ba, bb_toString(&object->calendarNamePassive))) == 0 && + (ret = bb_addString(&ba, "\nIndex: 7 Value: ")) == 0 && + (ret = obj_seasonProfileToString(&object->seasonProfilePassive, &ba)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 8 Value: ")) == 0 && + (ret = obj_weekProfileToString(&object->weekProfileTablePassive, &ba)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 9 Value: ")) == 0 && + (ret = obj_dayProfileToString(&object->dayProfileTablePassive, &ba)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 10 Value: ")) == 0 && + (ret = time_toString(&object->time, &ba)) == 0 && + (ret = bb_addString(&ba, "\n")) == 0) + { + *buff = bb_toString(&ba); + } + bb_clear(&ba); + return ret; +} +#endif //DLMS_IGNORE_ACTIVITY_CALENDAR +#ifndef DLMS_IGNORE_SECURITY_SETUP +int obj_securitySetupToString(gxSecuritySetup* object, char** buff) +{ + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + bb_addIntAsString(&ba, object->securityPolicy); + bb_addString(&ba, "\nIndex: 3 Value: "); + bb_addIntAsString(&ba, object->securitySuite); + bb_addString(&ba, "\nIndex: 4 Value: "); + bb_attachString(&ba, bb_toHexString(&object->serverSystemTitle)); + bb_addString(&ba, "\nIndex: 5 Value: "); + bb_attachString(&ba, bb_toHexString(&object->clientSystemTitle)); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_SECURITY_SETUP +#ifndef DLMS_IGNORE_IEC_HDLC_SETUP +int obj_hdlcSetupToString(gxIecHdlcSetup* object, char** buff) +{ + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + bb_addIntAsString(&ba, object->communicationSpeed); + bb_addString(&ba, "\nIndex: 3 Value: "); + bb_addIntAsString(&ba, object->windowSizeTransmit); + bb_addString(&ba, "\nIndex: 4 Value: "); + bb_addIntAsString(&ba, object->windowSizeReceive); + bb_addString(&ba, "\nIndex: 5 Value: "); + bb_addIntAsString(&ba, object->maximumInfoLengthTransmit); + bb_addString(&ba, "\nIndex: 6 Value: "); + bb_addIntAsString(&ba, object->maximumInfoLengthReceive); + bb_addString(&ba, "\nIndex: 7 Value: "); + bb_addIntAsString(&ba, object->interCharachterTimeout); + bb_addString(&ba, "\nIndex: 8 Value: "); + bb_addIntAsString(&ba, object->inactivityTimeout); + bb_addString(&ba, "\nIndex: 9 Value: "); + bb_addIntAsString(&ba, object->deviceAddress); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_IEC_HDLC_SETUP +#ifndef DLMS_IGNORE_IEC_LOCAL_PORT_SETUP +int obj_localPortSetupToString(gxLocalPortSetup* object, char** buff) +{ + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + bb_addIntAsString(&ba, object->defaultMode); + bb_addString(&ba, "\nIndex: 3 Value: "); + bb_addIntAsString(&ba, object->defaultBaudrate); + bb_addString(&ba, "\nIndex: 4 Value: "); + bb_addIntAsString(&ba, object->proposedBaudrate); + bb_addString(&ba, "\nIndex: 5 Value: "); + bb_addIntAsString(&ba, object->responseTime); + bb_addString(&ba, "\nIndex: 6 Value: "); + bb_attachString(&ba, bb_toString(&object->deviceAddress)); + bb_addString(&ba, "\nIndex: 7 Value: "); + bb_attachString(&ba, bb_toString(&object->password1)); + bb_addString(&ba, "\nIndex: 8 Value: "); + bb_attachString(&ba, bb_toString(&object->password2)); + bb_addString(&ba, "\nIndex: 9 Value: "); + bb_attachString(&ba, bb_toString(&object->password5)); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_IEC_LOCAL_PORT_SETUP + +#ifndef DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP +int obj_IecTwistedPairSetupToString(gxIecTwistedPairSetup* object, char** buff) +{ + int pos, ret; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + if ((ret = bb_addString(&ba, "Index: 2 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->mode)) == 0 && + (ret = bb_addString(&ba, "Index: 3 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, (int)object->speed)) == 0) + { + bb_addString(&ba, "Index: 4 Value: ["); + for (pos = 0; pos != object->primaryAddresses.size; ++pos) + { + if (pos != 0) + { + bb_addString(&ba, ", "); + } + if ((ret = bb_addIntAsString(&ba, object->primaryAddresses.data[pos])) != 0) + { + break; + } + } + if (ret == 0 && + (ret = bb_addString(&ba, "]\n")) == 0 && + (ret = bb_addString(&ba, "Index: 5 Value: [")) == 0) + { + for (pos = 0; pos != object->tabis.size; ++pos) + { + if (pos != 0) + { + bb_addString(&ba, ", "); + } + if ((ret = bb_addIntAsString(&ba, object->tabis.data[pos])) != 0) + { + break; + } + } + if (ret == 0) + { + ret = bb_addString(&ba, "]\n"); + } + } + } + if (ret == 0) + { + *buff = bb_toString(&ba); + } + bb_clear(&ba); + return ret; +} +#endif //DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP + +#ifndef DLMS_IGNORE_DEMAND_REGISTER +int obj_demandRegisterToString(gxDemandRegister* object, char** buff) +{ + int ret; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + if ((ret = bb_addString(&ba, "Index: 2 Value: ")) == 0 && + (ret = var_toString(&object->currentAverageValue, &ba)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 3 Value: ")) == 0 && + (ret = var_toString(&object->lastAverageValue, &ba)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 4 Value: Scaler: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->scaler)) == 0 && + (ret = bb_addString(&ba, " Unit: ")) == 0 && + (ret = bb_addString(&ba, obj_getUnitAsString(object->unit))) == 0 && + (ret = bb_addString(&ba, "\nIndex: 5 Value: ")) == 0 && + (ret = var_toString(&object->status, &ba)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 6 Value: ")) == 0 && + (ret = time_toString(&object->captureTime, &ba)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 7 Value: ")) == 0 && + (ret = time_toString(&object->startTimeCurrent, &ba)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 8 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->period)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 9 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->numberOfPeriods)) == 0 && + (ret = bb_addString(&ba, "\n")) == 0) + { + *buff = bb_toString(&ba); + } + bb_clear(&ba); + return ret; +} +#endif //DLMS_IGNORE_DEMAND_REGISTER +#ifndef DLMS_IGNORE_REGISTER_ACTIVATION +int obj_registerActivationToString(gxRegisterActivation* object, char** buff) +{ + int ret = 0; + uint16_t pos; +#ifdef DLMS_IGNORE_OBJECT_POINTERS + gxObjectDefinition* od; + gxKey* it; +#else + gxObject* od; +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + gxRegisterActivationMask* it; +#else + gxKey* it; +#endif //defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) +#endif //DLMS_IGNORE_OBJECT_POINTERS + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: ["); + for (pos = 0; pos != object->registerAssignment.size; ++pos) + { +#if !defined(DLMS_IGNORE_OBJECT_POINTERS) && !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + ret = oa_getByIndex(&object->registerAssignment, pos, &od); +#else + ret = arr_getByIndex(&object->registerAssignment, pos, (void**)&od); +#endif //DLMS_IGNORE_OBJECT_POINTERS + if (ret != 0) + { + break; + } + if (pos != 0) + { + bb_addString(&ba, ", "); + } + if ((ret = bb_addIntAsString(&ba, od->objectType)) != 0 || + (ret = bb_addString(&ba, " ")) != 0 || + (ret = hlp_appendLogicalName(&ba, od->logicalName)) != 0) + { + break; + } + } + if (ret == 0) + { + if ((ret = bb_addString(&ba, "]\n")) == 0 && + (ret = bb_addString(&ba, "Index: 3 Value: [")) == 0) + { + for (pos = 0; pos != object->maskList.size; ++pos) + { + ret = arr_getByIndex(&object->maskList, pos, (void**)&it); + if (ret != 0) + { + break; + } + if (pos != 0) + { + bb_addString(&ba, ", "); + } +#if !defined(DLMS_IGNORE_OBJECT_POINTERS) && !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + bb_attachString(&ba, bb_toString((gxByteBuffer*)it->key)); + bb_addString(&ba, " "); + bb_attachString(&ba, bb_toString((gxByteBuffer*)it->value)); +#else + if ((ret = bb_attachString(&ba, bb_toHexString(&it->name))) != 0 || + (ret = bb_addString(&ba, ": ")) != 0 || + (ret = bb_attachString(&ba, bb_toHexString(&it->indexes))) != 0) + { + break; + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + bb_addString(&ba, "]\n"); + *buff = bb_toString(&ba); + } + } + bb_clear(&ba); + return ret; +} +#endif //DLMS_IGNORE_REGISTER_ACTIVATION +#if !(defined(DLMS_IGNORE_REGISTER_MONITOR) && defined(DLMS_IGNORE_LIMITER)) +void actionItemToString(gxActionItem* item, gxByteBuffer* ba) +{ +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if (item->script == NULL) + { + hlp_appendLogicalName(ba, EMPTY_LN); + } + else + { + hlp_appendLogicalName(ba, item->script->base.logicalName); + } +#else + hlp_appendLogicalName(ba, item->logicalName); +#endif //DLMS_IGNORE_OBJECT_POINTERS + bb_addString(ba, " "); + bb_addIntAsString(ba, item->scriptSelector); +} +#endif //!(defined(DLMS_IGNORE_REGISTER_MONITOR) && defined(DLMS_IGNORE_LIMITER)) + +#ifndef DLMS_IGNORE_REGISTER_MONITOR +int obj_registerMonitorToString(gxRegisterMonitor* object, char** buff) +{ + int ret; + uint16_t pos; + dlmsVARIANT* tmp; + gxByteBuffer ba; + gxActionSet* as; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: ["); + for (pos = 0; pos != object->thresholds.size; ++pos) + { + ret = va_getByIndex(&object->thresholds, pos, &tmp); + if (ret != 0) + { + return ret; + } + if (pos != 0) + { + bb_addString(&ba, ", "); + } + ret = var_toString(tmp, &ba); +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(ret == 0); +#endif + } + bb_addString(&ba, "]\nIndex: 3 Value: "); +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if (object->monitoredValue.target == NULL) + { + hlp_appendLogicalName(&ba, EMPTY_LN); + bb_addString(&ba, " "); + bb_addString(&ba, obj_typeToString2(0)); + } + else + { + hlp_appendLogicalName(&ba, object->monitoredValue.target->logicalName); + bb_addString(&ba, " "); + bb_addString(&ba, obj_typeToString2(object->monitoredValue.target->objectType)); + } +#else + hlp_appendLogicalName(&ba, object->monitoredValue.logicalName); + bb_addString(&ba, " "); + bb_addString(&ba, obj_typeToString2(object->monitoredValue.objectType)); +#endif //DLMS_IGNORE_OBJECT_POINTERS + bb_addString(&ba, " "); + bb_addIntAsString(&ba, object->monitoredValue.attributeIndex); + + bb_addString(&ba, "\nIndex: 4 Value: ["); + for (pos = 0; pos != object->actions.size; ++pos) + { + ret = arr_getByIndex(&object->actions, pos, (void**)&as); + if (ret != 0) + { + return ret; + } + if (pos != 0) + { + bb_addString(&ba, ", "); + } + actionItemToString(&as->actionUp, &ba); + bb_addString(&ba, " "); + actionItemToString(&as->actionDown, &ba); + } + bb_addString(&ba, "]\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_REGISTER_MONITOR +#ifndef DLMS_IGNORE_ACTION_SCHEDULE +int obj_actionScheduleToString(gxActionSchedule* object, char** buff) +{ + int ret; + uint16_t pos; + gxtime* tm; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if (object->executedScript == NULL) + { + hlp_appendLogicalName(&ba, EMPTY_LN); + } + else + { + hlp_appendLogicalName(&ba, object->executedScript->base.logicalName); + } +#else + hlp_appendLogicalName(&ba, object->executedScriptLogicalName); +#endif //DLMS_IGNORE_OBJECT_POINTERS + + bb_addString(&ba, " "); + bb_addIntAsString(&ba, object->executedScriptSelector); + bb_addString(&ba, "\nIndex: 3 Value: "); + bb_addIntAsString(&ba, object->type); + + bb_addString(&ba, "\nIndex: 4 Value: ["); + for (pos = 0; pos != object->executionTime.size; ++pos) + { + ret = arr_getByIndex(&object->executionTime, pos, (void**)&tm); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + else + { + if (pos != 0) + { + bb_addString(&ba, ", "); + } + ret = time_toString(tm, &ba); + if (ret != 0) + { + return ret; + } + } + } + bb_addString(&ba, "]\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return DLMS_ERROR_CODE_OK; +} +#endif //DLMS_IGNORE_ACTION_SCHEDULE +#ifndef DLMS_IGNORE_SAP_ASSIGNMENT +int obj_sapAssignmentToString(gxSapAssignment* object, char** buff) +{ + int ret; + uint16_t pos; + gxSapItem* it; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: ["); + for (pos = 0; pos != object->sapAssignmentList.size; ++pos) + { + ret = arr_getByIndex(&object->sapAssignmentList, pos, (void**)&it); + if (ret != 0) + { + return ret; + } + if (pos != 0) + { + bb_addString(&ba, ", "); + } + bb_addIntAsString(&ba, it->id); + bb_addString(&ba, ": "); + bb_set2(&ba, &it->name, 0, bb_size(&it->name)); + } + bb_addString(&ba, "]\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_SAP_ASSIGNMENT +#ifndef DLMS_IGNORE_AUTO_ANSWER +int obj_autoAnswerToString(gxAutoAnswer* object, char** buff) +{ + int ret; + gxByteBuffer ba; + if ((ret = BYTE_BUFFER_INIT(&ba)) == 0 && + (ret = bb_addString(&ba, "Index: 2 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->mode)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 3 Value: [")) == 0 && + (ret = obj_timeWindowToString(&object->listeningWindow, &ba)) == 0 && + (ret = bb_addString(&ba, "]\nIndex: 4 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->status)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 5 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->numberOfCalls)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 6 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->numberOfRingsInListeningWindow)) == 0 && + (ret = bb_addString(&ba, " ")) == 0 && + (ret = bb_addIntAsString(&ba, object->numberOfRingsOutListeningWindow)) == 0 && + (ret = bb_addString(&ba, "\n")) == 0) + { + *buff = bb_toString(&ba); + } + bb_clear(&ba); + return ret; +} +#endif //DLMS_IGNORE_AUTO_ANSWER +#ifndef DLMS_IGNORE_IP4_SETUP +int obj_ip4SetupToString(gxIp4Setup* object, char** buff) +{ + int ret; + uint16_t pos; +#if !defined(DLMS_IGNORE_OBJECT_POINTERS) && !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + dlmsVARIANT* tmp; +#else + uint32_t* tmp; +#endif + gxip4SetupIpOption* ip; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if (object->dataLinkLayer != NULL) + { + bb_addLogicalName(&ba, object->dataLinkLayer->logicalName); + } +#else + bb_addLogicalName(&ba, object->dataLinkLayerReference); +#endif //DLMS_IGNORE_OBJECT_POINTERS + bb_addString(&ba, "\nIndex: 3 Value: "); + bb_addIntAsString(&ba, object->ipAddress); + bb_addString(&ba, "\nIndex: 4 Value: ["); + for (pos = 0; pos != object->multicastIPAddress.size; ++pos) + { +#if !defined(DLMS_IGNORE_OBJECT_POINTERS) && !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + ret = va_getByIndex(&object->multicastIPAddress, pos, &tmp); +#else + ret = arr_getByIndex2(&object->multicastIPAddress, pos, (void**)&tmp, sizeof(uint32_t)); +#endif + if (ret != 0) + { + return ret; + } + if (pos != 0) + { + bb_addString(&ba, ", "); + } +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + ret = bb_addIntAsString(&ba, *tmp); +#else + ret = var_toString(tmp, &ba); +#endif //defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + if (ret != 0) + { + return ret; + } + } + bb_addString(&ba, "]\nIndex: 5 Value: ["); + for (pos = 0; pos != object->ipOptions.size; ++pos) + { + ret = arr_getByIndex(&object->ipOptions, pos, (void**)&ip); + if (ret != 0) + { + return ret; + } + if (pos != 0) + { + bb_addString(&ba, ", "); + } + bb_addIntAsString(&ba, ip->type); + bb_addString(&ba, " "); + bb_attachString(&ba, bb_toString(&ip->data)); + } + bb_addString(&ba, "]\nIndex: 6 Value: "); + bb_addIntAsString(&ba, object->subnetMask); + bb_addString(&ba, "\nIndex: 7 Value: "); + bb_addIntAsString(&ba, object->gatewayIPAddress); + bb_addString(&ba, "\nIndex: 8 Value: "); + bb_addIntAsString(&ba, object->useDHCP); + bb_addString(&ba, "\nIndex: 9 Value: "); + bb_addIntAsString(&ba, object->primaryDNSAddress); + bb_addString(&ba, "\nIndex: 10 Value: "); + bb_addIntAsString(&ba, object->secondaryDNSAddress); + bb_addString(&ba, "\nIndex: 11 Value: "); + var_toString(&object->value, &ba); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_IP4_SETUP + +#ifndef DLMS_IGNORE_IP6_SETUP + +int obj_getIPAddress(gxByteBuffer* ba, gxArray* arr) +{ + char tmp[64]; + int ret; + uint16_t pos; + IN6_ADDR* ip; + if ((ret = bb_addString(ba, "{")) == 0) + { + for (pos = 0; pos != arr->size; ++pos) + { + if ((ret = arr_getByIndex(arr, pos, (void**)&ip)) != 0) + { + break; + } + if (pos != 0) + { + bb_addString(ba, ", "); + } + //Add Ws2_32.lib for LabWindows/CVI. + inet_ntop(AF_INET6, &ip, tmp, sizeof(tmp)); + bb_addString(ba, tmp); + } + if (ret == 0) + { + ret = bb_addString(ba, "}"); + } + } + return ret; +} + +int obj_getNeighborDiscoverySetupAsString(gxByteBuffer* ba, gxArray* arr) +{ + int ret; + uint16_t pos; + gxNeighborDiscoverySetup* it; + if ((ret = bb_addString(ba, "{")) == 0) + { + for (pos = 0; pos != arr->size; ++pos) + { + if ((ret = arr_getByIndex(arr, pos, (void**)&it)) != 0) + { + break; + } + if (pos != 0) + { + bb_addString(ba, ", "); + } + if ((ret = bb_addString(ba, "[")) != 0 || + (ret = bb_addIntAsString(ba, it->maxRetry)) != 0 || + (ret = bb_addString(ba, ", ")) != 0 || + (ret = bb_addIntAsString(ba, it->retryWaitTime)) != 0 || + (ret = bb_addString(ba, ", ")) != 0 || + (ret = bb_addIntAsString(ba, it->sendPeriod)) != 0 || + (ret = bb_addString(ba, "]")) != 0) + { + break; + } + } + if (ret == 0) + { + ret = bb_addString(ba, "}"); + } + } + return ret; +} + +int obj_ip6SetupToString(gxIp6Setup* object, char** buff) +{ + char tmp[64]; + int ret; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if (object->dataLinkLayer != NULL) + { + bb_addLogicalName(&ba, object->dataLinkLayer->logicalName); + } +#else + bb_addLogicalName(&ba, object->dataLinkLayerReference); +#endif //DLMS_IGNORE_OBJECT_POINTERS + if ((ret = bb_addString(&ba, "\nIndex: 3 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->addressConfigMode)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 4 Value: [")) == 0 && + (ret = obj_getIPAddress(&ba, &object->unicastIPAddress)) == 0 && + (ret = bb_addString(&ba, "]\nIndex: 5 Value: [")) == 0 && + (ret = obj_getIPAddress(&ba, &object->multicastIPAddress)) == 0 && + (ret = bb_addString(&ba, "]\nIndex: 6 Value: [")) == 0 && + (ret = obj_getIPAddress(&ba, &object->gatewayIPAddress)) == 0 && + (ret = bb_addString(&ba, "]\nIndex: 7 Value: ")) == 0) + { + //Add Ws2_32.lib for LabWindows/CVI. + + inet_ntop(AF_INET6, &object->primaryDNSAddress, tmp, sizeof(tmp)); + bb_addString(&ba, tmp); + inet_ntop(AF_INET6, &object->secondaryDNSAddress, tmp, sizeof(tmp)); + bb_addString(&ba, tmp); + if ((ret = bb_addIntAsString(&ba, object->trafficClass)) == 0 && + (ret = obj_getNeighborDiscoverySetupAsString(&ba, &object->neighborDiscoverySetup)) == 0 && + (ret = bb_addString(&ba, "\n")) == 0) + { + } + } + if (ret == 0) + { + *buff = bb_toString(&ba); + } + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_IP6_SETUP + +#ifndef DLMS_IGNORE_MBUS_DIAGNOSTIC +int obj_MBusDiagnosticToString(gxMbusDiagnostic* object, char** buff) +{ + int ret, pos; + gxBroadcastFrameCounter* it; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + bb_addIntAsString(&ba, object->receivedSignalStrength); + bb_addString(&ba, "\nIndex: 3 Value: "); + bb_addIntAsString(&ba, object->channelId); + bb_addString(&ba, "\nIndex: 4 Value: "); + bb_addIntAsString(&ba, object->linkStatus); + bb_addString(&ba, "\nIndex: 5 Value: {"); + for (pos = 0; pos != object->broadcastFrames.size; ++pos) + { + ret = arr_getByIndex(&object->broadcastFrames, pos, (void**)&it); + if (ret != 0) + { + return ret; + } + if (pos != 0) + { + bb_addString(&ba, ", "); + } + bb_addString(&ba, "["); + bb_addIntAsString(&ba, it->clientId); + bb_addString(&ba, ", "); + bb_addIntAsString(&ba, it->counter); + bb_addString(&ba, ", "); + time_toString(&it->timeStamp, &ba); + bb_addString(&ba, "]"); + } + bb_addString(&ba, "}\nIndex: 6 Value: "); + bb_addIntAsString(&ba, object->transmissions); + bb_addString(&ba, "\nIndex: 7 Value: "); + bb_addIntAsString(&ba, object->receivedFrames); + bb_addString(&ba, "\nIndex: 8 Value: "); + bb_addIntAsString(&ba, object->failedReceivedFrames); + bb_addString(&ba, "\nIndex: 9 Value: "); + bb_addIntAsString(&ba, object->captureTime.attributeId); + bb_addString(&ba, ":"); + time_toString(&object->captureTime.timeStamp, &ba); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_MBUS_DIAGNOSTIC + +#ifndef DLMS_IGNORE_MBUS_PORT_SETUP +int obj_MBusPortSetupToString(gxMBusPortSetup* object, char** buff) +{ + int ret; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + if ((ret = bb_addString(&ba, "Index: 2 Value: ")) == 0 && + (ret = hlp_appendLogicalName(&ba, object->profileSelection)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 3 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->portCommunicationStatus)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 4 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->dataHeaderType)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 5 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->primaryAddress)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 6 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->identificationNumber)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 7 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->manufacturerId)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 8 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->mBusVersion)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 9 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->deviceType)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 10 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->maxPduSize)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 11 Value: ")) == 0 && + (ret = obj_timeWindowToString(&object->listeningWindow, &ba)) == 0) + { + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + } + bb_clear(&ba); + return ret; +} +#endif //DLMS_IGNORE_MBUS_PORT_SETUP + +#ifndef DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS +int obj_G3PlcMacLayerCounters(gxG3PlcMacLayerCounters* object, char** buff) +{ + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + bb_addIntAsString(&ba, object->txDataPacketCount); + bb_addString(&ba, "\nIndex: 3 Value: "); + bb_addIntAsString(&ba, object->rxDataPacketCount); + bb_addString(&ba, "\nIndex: 4 Value: "); + bb_addIntAsString(&ba, object->txCmdPacketCount); + bb_addString(&ba, "\nIndex: 5 Value: "); + bb_addIntAsString(&ba, object->rxCmdPacketCount); + bb_addString(&ba, "\nIndex: 6 Value: "); + bb_addIntAsString(&ba, object->cSMAFailCount); + bb_addString(&ba, "\nIndex: 7 Value: "); + bb_addIntAsString(&ba, object->cSMANoAckCount); + bb_addString(&ba, "\nIndex: 8 Value: "); + bb_addIntAsString(&ba, object->badCrcCount); + bb_addString(&ba, "\nIndex: 9 Value: "); + bb_addIntAsString(&ba, object->txDataBroadcastCount); + bb_addString(&ba, "\nIndex: 10 Value: "); + bb_addIntAsString(&ba, object->rxDataBroadcastCount); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS + +#ifndef DLMS_IGNORE_G3_PLC_MAC_SETUP + +int obj_G3PlcMacSetupKeyTableToString(gxG3PlcMacSetup* object, gxByteBuffer* ba) +{ + int pos, ret = 0; + gxG3MacKeyTable* it; + bb_addString(ba, "\nIndex: 5 Value: [\r\n"); + for (pos = 0; pos != object->keyTable.size; ++pos) + { + if ((ret = arr_getByIndex(&object->keyTable, pos, (void**)&it)) != 0) + { + return ret; + } + bb_addString(ba, "{ "); + bb_addIntAsString(ba, it->id); + bb_addString(ba, ","); + //Add MAC keys as a hex string. + if (bb_getCapacity(ba) - ba->size < 3 * MAX_G3_MAC_KEY_TABLE_KEY_SIZE) + { + bb_capacity(ba, bb_size(ba) + 3 * MAX_G3_MAC_KEY_TABLE_KEY_SIZE); + } + if ((ret = hlp_bytesToHex2(it->key, MAX_G3_MAC_KEY_TABLE_KEY_SIZE, + (char*)ba->data + ba->size, (uint16_t)bb_available(ba))) != 0) + { + return ret; + } + ba->size += 3 * MAX_G3_MAC_KEY_TABLE_KEY_SIZE; + --ba->size; + bb_addString(ba, "}\n"); + } + bb_addString(ba, "]\n"); + return ret; +} + +int obj_G3PlcMacSetupNeighbourTableToString(gxG3PlcMacSetup* object, gxByteBuffer* ba) +{ + int pos, ret = 0; + gxNeighbourTable* it; + bb_addString(ba, "\nIndex: 11 Value: [\r"); + for (pos = 0; pos != object->neighbourTable.size; ++pos) + { + if ((ret = arr_getByIndex(&object->neighbourTable, pos, (void**)&it)) != 0) + { + return ret; + } + bb_addString(ba, "{shortAddress: "); + bb_addIntAsString(ba, it->shortAddress); + bb_addString(ba, ", scheme: "); + bb_addIntAsString(ba, it->payloadModulationScheme); + bb_addString(ba, ", tone map: "); + ba_toString2(ba, &it->toneMap); + bb_addString(ba, ", modulation: "); + bb_addIntAsString(ba, it->modulation); + bb_addString(ba, ", txGain: "); + bb_addIntAsString(ba, it->txGain); + bb_addString(ba, ", txRes: "); + bb_addIntAsString(ba, it->txRes); + bb_addString(ba, ", txCoeff: "); + ba_toString2(ba, &it->txCoeff); + bb_addString(ba, ", lqi: "); + bb_addIntAsString(ba, it->lqi); + bb_addString(ba, ", phaseDifferential: "); + bb_addIntAsString(ba, it->phaseDifferential); + bb_addString(ba, ", tmrValidTime: "); + bb_addIntAsString(ba, it->tmrValidTime); + bb_addString(ba, ", noData: "); + bb_addIntAsString(ba, it->noData); + } + bb_addString(ba, "]\n"); + return ret; +} + +int obj_G3PlcMacSetupMacPosTableToString(gxG3PlcMacSetup* object, gxByteBuffer* ba) +{ + int pos, ret = 0; + gxMacPosTable* it; + bb_addString(ba, "\nIndex: 25 Value: [\r"); + for (pos = 0; pos != object->macPosTable.size; ++pos) + { + if ((ret = arr_getByIndex(&object->macPosTable, pos, (void**)&it)) != 0) + { + break; + } + bb_addString(ba, "{shortAddress: "); + bb_addIntAsString(ba, it->shortAddress); + bb_addString(ba, ", lqi: "); + bb_addIntAsString(ba, it->lqi); + bb_addString(ba, ", validTime: "); + bb_addIntAsString(ba, it->validTime); + } + bb_addString(ba, "]\n"); + return ret; +} + +int obj_G3PlcMacSetupToString(gxG3PlcMacSetup* object, char** buff) +{ + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + bb_addIntAsString(&ba, object->shortAddress); + bb_addString(&ba, "\nIndex: 3 Value: "); + bb_addIntAsString(&ba, object->rcCoord); + bb_addString(&ba, "\nIndex: 4 Value: "); + bb_addIntAsString(&ba, object->panId); + obj_G3PlcMacSetupKeyTableToString(object, &ba); + bb_addString(&ba, "Index: 6 Value: "); + bb_addIntAsString(&ba, object->frameCounter); + bb_addString(&ba, "\nIndex: 7 Value: "); + ba_toString2(&ba, &object->toneMask); + bb_addString(&ba, "\nIndex: 8 Value: "); + bb_addIntAsString(&ba, object->tmrTtl); + bb_addString(&ba, "\nIndex: 9 Value: "); + bb_addIntAsString(&ba, object->maxFrameRetries); + bb_addString(&ba, "\nIndex: 10 Value: "); + bb_addIntAsString(&ba, object->neighbourTableEntryTtl); + obj_G3PlcMacSetupNeighbourTableToString(object, &ba); + bb_addString(&ba, "\nIndex: 12 Value: "); + bb_addIntAsString(&ba, object->highPriorityWindowSize); + bb_addString(&ba, "\nIndex: 13 Value: "); + bb_addIntAsString(&ba, object->cscmFairnessLimit); + bb_addString(&ba, "\nIndex: 14 Value: "); + bb_addIntAsString(&ba, object->beaconRandomizationWindowLength); + bb_addString(&ba, "\nIndex: 15 Value: "); + bb_addIntAsString(&ba, object->macA); + bb_addString(&ba, "\nIndex: 16 Value: "); + bb_addIntAsString(&ba, object->macK); + bb_addString(&ba, "\nIndex: 17 Value: "); + bb_addIntAsString(&ba, object->minCwAttempts); + bb_addString(&ba, "\nIndex: 18 Value: "); + bb_addIntAsString(&ba, object->cenelecLegacyMode); + bb_addString(&ba, "\nIndex: 19 Value: "); + bb_addIntAsString(&ba, object->fccLegacyMode); + bb_addString(&ba, "\nIndex: 20 Value: "); + bb_addIntAsString(&ba, object->maxBe); + bb_addString(&ba, "\nIndex: 21 Value: "); + bb_addIntAsString(&ba, object->maxCsmaBackoffs); + bb_addString(&ba, "\nIndex: 22 Value: "); + bb_addIntAsString(&ba, object->minBe); + bb_addString(&ba, "\nIndex: 23 Value: "); + bb_addIntAsString(&ba, object->macBroadcastMaxCwEnabled); + bb_addString(&ba, "\nIndex: 24 Value: "); + bb_addIntAsString(&ba, object->macTransmitAtten); + obj_G3PlcMacSetupMacPosTableToString(object, &ba); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_G3_PLC_MAC_SETUP + +#ifndef DLMS_IGNORE_G3_PLC_6LO_WPAN + +int obj_G3Plc6RoutingConfigurationToString(gxArray* table, gxByteBuffer* ba) +{ + int pos, ret = 0; + gxRoutingConfiguration* it; + bb_addString(ba, "\nIndex: 6 Value: [\r"); + for (pos = 0; pos != table->size; ++pos) + { + if ((ret = arr_getByIndex(table, pos, (void**)&it)) != 0) + { + break; + } + bb_addString(ba, "{netTraversalTime: "); + bb_addIntAsString(ba, it->netTraversalTime); + bb_addString(ba, ", routingTableEntryTtl: "); + bb_addIntAsString(ba, it->routingTableEntryTtl); + bb_addString(ba, ", kr: "); + bb_addIntAsString(ba, it->kr); + bb_addString(ba, ", km: "); + bb_addIntAsString(ba, it->km); + bb_addString(ba, ", kc: "); + bb_addIntAsString(ba, it->kc); + bb_addString(ba, ", kq: "); + bb_addIntAsString(ba, it->kq); + bb_addString(ba, ", kh: "); + bb_addIntAsString(ba, it->kh); + bb_addString(ba, ", krt: "); + bb_addIntAsString(ba, it->krt); + bb_addString(ba, ", rReqRetries: "); + bb_addIntAsString(ba, it->rReqRetries); + bb_addString(ba, ", rReqReqWait: "); + bb_addIntAsString(ba, it->rReqReqWait); + bb_addString(ba, ", blacklistTableEntryTtl: "); + bb_addIntAsString(ba, it->blacklistTableEntryTtl); + bb_addString(ba, ", unicastRreqGenEnable: "); + bb_addIntAsString(ba, it->unicastRreqGenEnable); + bb_addString(ba, ", rlcEnabled: "); + bb_addIntAsString(ba, it->rlcEnabled); + bb_addString(ba, ", addRevLinkCost: "); + bb_addIntAsString(ba, it->addRevLinkCost); + } + bb_addString(ba, "]\n"); + return ret; +} + +int obj_G3Plc6RoutingTableToString(gxArray* table, gxByteBuffer* ba) +{ + int pos, ret = 0; + gxRoutingTable* it; + bb_addString(ba, "\nIndex: 8 Value: [\r"); + for (pos = 0; pos != table->size; ++pos) + { + if ((ret = arr_getByIndex(table, pos, (void**)&it)) != 0) + { + break; + } + bb_addString(ba, "{destination address: "); + bb_addIntAsString(ba, it->destinationAddress); + bb_addString(ba, ", next hop address: "); + bb_addIntAsString(ba, it->nextHopAddress); + bb_addString(ba, ", route cost: "); + bb_addIntAsString(ba, it->routeCost); + bb_addString(ba, ", hop count: "); + bb_addIntAsString(ba, it->hopCount); + bb_addString(ba, ", weak link count: "); + bb_addIntAsString(ba, it->weakLinkCount); + bb_addString(ba, ", valid time: "); + bb_addIntAsString(ba, it->validTime); + } + bb_addString(ba, "]\n"); + return ret; +} + +int obj_G3Plc6ContextInformationTableToString(gxArray* table, gxByteBuffer* ba) +{ + int pos, ret = 0; + gxContextInformationTable* it; + bb_addString(ba, "\nIndex: 9 Value: [\r"); + for (pos = 0; pos != table->size; ++pos) + { + if ((ret = arr_getByIndex(table, pos, (void**)&it)) != 0) + { + break; + } + bb_addString(ba, "{CID: "); + bb_addIntAsString(ba, it->cid); + bb_addString(ba, ", context: "); + bb_attachString(ba, hlp_bytesToHex(it->context, 16)); + bb_addString(ba, ", compression: "); + bb_addIntAsString(ba, it->compression); + bb_addString(ba, ", valid life time: "); + bb_addIntAsString(ba, it->validLifetime); + } + bb_addString(ba, "]\n"); + return ret; +} + +int obj_G3Plc6BlacklistTableToString(gxArray* table, gxByteBuffer* ba) +{ + int pos, ret = 0; + gxBlacklistTable* it; + bb_addString(ba, "\nIndex: 10 Value: [\r"); + for (pos = 0; pos != table->size; ++pos) + { + if ((ret = arr_getByIndex(table, pos, (void**)&it)) != 0) + { + break; + } + bb_addString(ba, "{neighbour address: "); + bb_addIntAsString(ba, it->neighbourAddress); + bb_addString(ba, ", valid time: "); + bb_addIntAsString(ba, it->validTime); + } + bb_addString(ba, "]\n"); + return ret; +} + +int obj_G3Plc6BroadcastLogTableToString(gxArray* table, gxByteBuffer* ba) +{ + int pos, ret = 0; + gxBroadcastLogTable* it; + bb_addString(ba, "\nIndex: 11 Value: [\r"); + for (pos = 0; pos != table->size; ++pos) + { + if ((ret = arr_getByIndex(table, pos, (void**)&it)) != 0) + { + break; + } + bb_addString(ba, "{sourceAddress: "); + bb_addIntAsString(ba, it->sourceAddress); + bb_addString(ba, ", sequenceNumber: "); + bb_addIntAsString(ba, it->sequenceNumber); + bb_addString(ba, ", validTime: "); + bb_addIntAsString(ba, it->validTime); + } + bb_addString(ba, "]\n"); + return ret; +} + +int obj_G3Plc6LoWPANToString(gxG3Plc6LoWPAN* object, char** buff) +{ + int ret; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + bb_addIntAsString(&ba, object->maxHops); + bb_addString(&ba, "\nIndex: 3 Value: "); + bb_addIntAsString(&ba, object->weakLqiValue); + bb_addString(&ba, "\nIndex: 4 Value: "); + bb_addIntAsString(&ba, object->securityLevel); + obj_G3Plc6RoutingConfigurationToString(&object->routingConfiguration, &ba); + bb_addString(&ba, "\nIndex: 7 Value: "); + bb_addIntAsString(&ba, object->broadcastLogTableEntryTtl); + obj_G3Plc6RoutingTableToString(&object->routingTable, &ba); + obj_G3Plc6ContextInformationTableToString(&object->contextInformationTable, &ba); + obj_G3Plc6BlacklistTableToString(&object->blacklistTable, &ba); + obj_G3Plc6BroadcastLogTableToString(&object->broadcastLogTable, &ba); + bb_addString(&ba, "\nIndex: 12 Value: "); +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + if ((ret = obj_UInt16ArrayToString(&ba, &object->groupTable)) != 0) + { + return ret; + } +#else + if ((ret = va_toString(&object->groupTable, &ba)) != 0) + { + return ret; + } +#endif //defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + bb_addString(&ba, "\nIndex: 13 Value: "); + bb_addIntAsString(&ba, object->maxJoinWaitTime); + bb_addString(&ba, "\nIndex: 14 Value: "); + bb_addIntAsString(&ba, object->pathDiscoveryTime); + bb_addString(&ba, "\nIndex: 15 Value: "); + bb_addIntAsString(&ba, object->activeKeyIndex); + bb_addString(&ba, "\nIndex: 16 Value: "); + bb_addIntAsString(&ba, object->metricType); + bb_addString(&ba, "\nIndex: 17 Value: "); + bb_addIntAsString(&ba, object->coordShortAddress); + bb_addString(&ba, "\nIndex: 18 Value: "); + bb_addIntAsString(&ba, object->disableDefaultRouting); + bb_addString(&ba, "\nIndex: 19 Value: "); + bb_addIntAsString(&ba, object->deviceType); + bb_addString(&ba, "\nIndex: 20 Value: "); + bb_addIntAsString(&ba, object->defaultCoordRouteEnabled); + bb_addString(&ba, "\nIndex: 21 Value: "); +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + if ((ret = obj_UInt16ArrayToString(&ba, &object->destinationAddress)) != 0) + { + bb_clear(&ba); + return ret; + } +#else + if ((ret = va_toString(&object->destinationAddress, &ba)) != 0) + { + bb_clear(&ba); + return ret; + } +#endif //defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + bb_addString(&ba, "\nIndex: 22 Value: "); + bb_addIntAsString(&ba, object->lowLQI); + bb_addString(&ba, "\nIndex: 23 Value: "); + bb_addIntAsString(&ba, object->highLQI); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return ret; +} +#endif //DLMS_IGNORE_G3_PLC_6LO_WPAN + + +int obj_objectsToString(gxByteBuffer* ba, objectArray* objects) +{ + uint16_t pos; + int ret = DLMS_ERROR_CODE_OK; + gxObject* it; + for (pos = 0; pos != objects->size; ++pos) + { + ret = oa_getByIndex(objects, pos, &it); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + if (pos != 0) + { + bb_addString(ba, ", "); + } + bb_addString(ba, obj_typeToString2((DLMS_OBJECT_TYPE)it->objectType)); +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(ret == 0); +#endif + bb_addString(ba, " "); + hlp_appendLogicalName(ba, it->logicalName); + } + return ret; +} + +#ifndef DLMS_IGNORE_FUNCTION_CONTROL + +int obj_FunctionControlActivationStatusToString(gxArray* table, gxByteBuffer* ba) +{ + int pos, ret = 0; + functionStatus* it; + bb_addString(ba, "\nIndex: 1 Value: [\r"); + for (pos = 0; pos != table->size; ++pos) + { + if ((ret = arr_getByIndex(table, pos, (void**)&it)) != 0) + { + break; + } + bb_addString(ba, "{Name: "); + bb_attachString(ba, bb_toHexString(&it->name)); + bb_addString(ba, ", Status: "); + bb_addIntAsString(ba, it->status); + } + bb_addString(ba, "]\n"); + return ret; +} + + +int obj_FunctionControlFunctionsToString(gxArray* table, gxByteBuffer* ba) +{ + int pos, ret = 0; + functionalBlock* it; + bb_addString(ba, "\nIndex: 1 Value: [\r"); + for (pos = 0; pos != table->size; ++pos) + { + if ((ret = arr_getByIndex(table, pos, (void**)&it)) != 0 || + (ret = bb_addString(ba, "{Name: ")) != 0 || + (ret = bb_attachString(ba, bb_toHexString(&it->name))) != 0 || + (ret = bb_addString(ba, ", specifications: ")) != 0 || + (ret = obj_objectsToString(ba, &it->functionSpecifications)) != 0) + { + break; + } + } + bb_addString(ba, "]\n"); + return ret; +} + +int obj_FunctionControlToString(gxFunctionControl* object, char** buff) +{ + int ret; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + if ((ret = obj_FunctionControlActivationStatusToString(&object->activationStatus, &ba)) == 0 && + (ret = obj_FunctionControlFunctionsToString(&object->functions, &ba)) == 0) + { + + } + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return ret; +} +#endif //DLMS_IGNORE_FUNCTION_CONTROL + + +#ifndef DLMS_IGNORE_ARRAY_MANAGER + +int obj_ArrayManagerToString(gxArrayManager* object, char** buff) +{ + int pos, ret = 0; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value:[ "); + gxArrayManagerItem* it; + for (pos = 0; pos != object->elements.size; ++pos) + { + if ((ret = arr_getByIndex(&object->elements, pos, (void**)&it)) != 0 || + (ret = bb_addString(&ba, "{ID: ")) != 0 || + (ret = bb_addIntAsString(&ba, it->id)) != 0 || + (ret = bb_addString(&ba, ", Target: ")) != 0 || + (ret = hlp_appendLogicalName(&ba, it->element.target->logicalName)) != 0 || + (ret = bb_addString(&ba, ":")) != 0 || + (ret = bb_addIntAsString(&ba, it->element.attributeIndex)) != 0 || + (ret = bb_addString(&ba, "}")) != 0) + { + break; + } + } + bb_addString(&ba, "]\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return ret; +} +#endif //DLMS_IGNORE_ARRAY_MANAGER + +#ifndef DLMS_IGNORE_UTILITY_TABLES +int obj_UtilityTablesToString(gxUtilityTables* object, char** buff) +{ + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + bb_addIntAsString(&ba, object->tableId); + bb_addString(&ba, "\nIndex: 3 Value: "); + bb_addIntAsString(&ba, bb_size(&object->buffer)); + bb_addString(&ba, "\nIndex: 4 Value: "); + bb_attachString(&ba, bb_toHexString(&object->buffer)); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_UTILITY_TABLES + +#ifndef DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP +int obj_mbusSlavePortSetupToString(gxMbusSlavePortSetup* object, char** buff) +{ + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + bb_addIntAsString(&ba, object->defaultBaud); + bb_addString(&ba, "\nIndex: 3 Value: "); + bb_addIntAsString(&ba, object->availableBaud); + bb_addString(&ba, "\nIndex: 4 Value: "); + bb_addIntAsString(&ba, object->addressState); + bb_addString(&ba, "\nIndex: 5 Value: "); + bb_addIntAsString(&ba, object->busAddress); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP +#ifndef DLMS_IGNORE_IMAGE_TRANSFER +int obj_imageTransferToString(gxImageTransfer* object, char** buff) +{ + uint16_t pos; + int ret; + gxImageActivateInfo* it; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + bb_addIntAsString(&ba, object->imageBlockSize); + bb_addString(&ba, "\nIndex: 3 Value: "); + bb_attachString(&ba, ba_toString(&object->imageTransferredBlocksStatus)); + bb_addString(&ba, "\nIndex: 4 Value: "); + bb_addIntAsString(&ba, object->imageFirstNotTransferredBlockNumber); + bb_addString(&ba, "\nIndex: 5 Value: "); + bb_addIntAsString(&ba, object->imageTransferEnabled); + bb_addString(&ba, "\nIndex: 6 Value: "); + bb_addIntAsString(&ba, object->imageTransferStatus); + bb_addString(&ba, "\nIndex: 7 Value: ["); + for (pos = 0; pos != object->imageActivateInfo.size; ++pos) + { + ret = arr_getByIndex(&object->imageActivateInfo, pos, (void**)&it); + if (ret != 0) + { + return ret; + } + if (pos != 0) + { + bb_addString(&ba, ", "); + } + bb_addIntAsString(&ba, it->size); + bb_addString(&ba, " "); + bb_attachString(&ba, bb_toHexString(&it->identification)); + bb_addString(&ba, " "); + bb_attachString(&ba, bb_toHexString(&it->signature)); + } + bb_addString(&ba, "]\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_IMAGE_TRANSFER +#ifndef DLMS_IGNORE_DISCONNECT_CONTROL +int obj_disconnectControlToString(gxDisconnectControl* object, char** buff) +{ + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + bb_addIntAsString(&ba, object->outputState); + bb_addString(&ba, "\nIndex: 3 Value: "); + bb_addIntAsString(&ba, object->controlState); + bb_addString(&ba, "\nIndex: 4 Value: "); + bb_addIntAsString(&ba, object->controlMode); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_DISCONNECT_CONTROL +#ifndef DLMS_IGNORE_LIMITER +int obj_limiterToString(gxLimiter* object, char** buff) +{ + int ret; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + bb_addString(&ba, " "); + if (object->monitoredValue != NULL) + { + hlp_appendLogicalName(&ba, object->monitoredValue->logicalName); + bb_addString(&ba, ": "); + bb_addIntAsString(&ba, object->selectedAttributeIndex); + } + bb_addString(&ba, "\nIndex: 3 Value: "); + ret = var_toString(&object->thresholdActive, &ba); + if (ret != 0) + { + return ret; + } + bb_addString(&ba, "\nIndex: 4 Value: "); + ret = var_toString(&object->thresholdNormal, &ba); + if (ret != 0) + { + return ret; + } + bb_addString(&ba, "\nIndex: 5 Value: "); + ret = var_toString(&object->thresholdEmergency, &ba); + if (ret != 0) + { + return ret; + } + bb_addString(&ba, "\nIndex: 6 Value: "); + bb_addIntAsString(&ba, object->minOverThresholdDuration); + bb_addString(&ba, "\nIndex: 7 Value: "); + bb_addIntAsString(&ba, object->minUnderThresholdDuration); + bb_addString(&ba, "\nIndex: 8 Value: "); + bb_addIntAsString(&ba, object->emergencyProfile.id); + bb_addString(&ba, " "); + time_toString(&object->emergencyProfile.activationTime, &ba); + bb_addString(&ba, " "); + bb_addIntAsString(&ba, object->emergencyProfile.duration); + + bb_addString(&ba, "\nIndex: 9 Value: "); +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + if ((ret = obj_UInt16ArrayToString(&ba, &object->emergencyProfileGroupIDs)) != 0) + { + return ret; + } +#else + if ((ret = va_toString(&object->emergencyProfileGroupIDs, &ba)) != 0) + { + return ret; + } +#endif //defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + bb_addString(&ba, "\nIndex: 10 Value: "); + bb_addIntAsString(&ba, object->emergencyProfileActive); + bb_addString(&ba, "\nIndex: 11 Value: "); + actionItemToString(&object->actionOverThreshold, &ba); + bb_addString(&ba, "\nIndex: 12 Value: "); + actionItemToString(&object->actionUnderThreshold, &ba); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_LIMITER +#ifndef DLMS_IGNORE_MBUS_CLIENT +int obj_mBusClientToString(gxMBusClient* object, char** buff) +{ + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + bb_addIntAsString(&ba, object->capturePeriod); + bb_addString(&ba, "\nIndex: 3 Value: "); + bb_addIntAsString(&ba, object->primaryAddress); + bb_addString(&ba, "\nIndex: 4 Value: "); +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if (object->mBusPort != NULL) + { + bb_addLogicalName(&ba, object->mBusPort->logicalName); + } +#else + bb_addLogicalName(&ba, object->mBusPortReference); +#endif //DLMS_IGNORE_OBJECT_POINTERS + bb_addString(&ba, "\nIndex: 5 Value: "); + //TODO: bb_addIntAsString(&ba, object->captureDefinition); + bb_addString(&ba, "\nIndex: 6 Value: "); + bb_addIntAsString(&ba, object->identificationNumber); + bb_addString(&ba, "\nIndex: 7 Value: "); + bb_addIntAsString(&ba, object->manufacturerID); + bb_addString(&ba, "\nIndex: 8 Value: "); + bb_addIntAsString(&ba, object->dataHeaderVersion); + bb_addString(&ba, "\nIndex: 9 Value: "); + bb_addIntAsString(&ba, object->deviceType); + bb_addString(&ba, "\nIndex: 10 Value: "); + bb_addIntAsString(&ba, object->accessNumber); + bb_addString(&ba, "\nIndex: 11 Value: "); + bb_addIntAsString(&ba, object->status); + bb_addString(&ba, "\nIndex: 12 Value: "); + bb_addIntAsString(&ba, object->alarm); + bb_addString(&ba, "\nIndex: 13 Value: "); + bb_addIntAsString(&ba, object->configuration); + bb_addString(&ba, "\nIndex: 14 Value: "); + bb_addIntAsString(&ba, object->encryptionKeyStatus); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_MBUS_CLIENT +#ifndef DLMS_IGNORE_MODEM_CONFIGURATION +int obj_modemConfigurationToString(gxModemConfiguration* object, char** buff) +{ + uint16_t pos; + int ret; + gxModemInitialisation* mi; + gxByteBuffer ba, * it; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + bb_addIntAsString(&ba, object->communicationSpeed); + bb_addString(&ba, "\nIndex: 3 Value: ["); + for (pos = 0; pos != object->initialisationStrings.size; ++pos) + { + ret = arr_getByIndex(&object->initialisationStrings, pos, (void**)&mi); + if (ret != 0) + { + return ret; + } + if (pos != 0) + { + bb_addString(&ba, ", "); + } + bb_attachString(&ba, bb_toString(&mi->request)); + bb_addString(&ba, " "); + bb_attachString(&ba, bb_toString(&mi->response)); + bb_addString(&ba, " "); + bb_addIntAsString(&ba, mi->delay); + } + bb_addString(&ba, "]\nIndex: 4 Value: ["); + for (pos = 0; pos != object->modemProfile.size; ++pos) + { + ret = arr_getByIndex(&object->modemProfile, pos, (void**)&it); + if (ret != 0) + { + return ret; + } + if (pos != 0) + { + bb_addString(&ba, ", "); + } + bb_attachString(&ba, bb_toString(it)); + } + bb_addString(&ba, "]\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_MODEM_CONFIGURATION +#ifndef DLMS_IGNORE_MAC_ADDRESS_SETUP +int obj_macAddressSetupToString(gxMacAddressSetup* object, char** buff) +{ + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + bb_attachString(&ba, bb_toString(&object->macAddress)); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_MAC_ADDRESS_SETUP + +#ifndef DLMS_IGNORE_GPRS_SETUP +void qualityOfServiceToString(gxQualityOfService* target, gxByteBuffer* ba) +{ + bb_addIntAsString(ba, target->precedence); + bb_addString(ba, " "); + bb_addIntAsString(ba, target->delay); + bb_addString(ba, " "); + bb_addIntAsString(ba, target->reliability); + bb_addString(ba, " "); + bb_addIntAsString(ba, target->peakThroughput); + bb_addString(ba, " "); + bb_addIntAsString(ba, target->meanThroughput); + bb_addString(ba, " "); +} + +int obj_GPRSSetupToString(gxGPRSSetup* object, char** buff) +{ + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + bb_attachString(&ba, bb_toString(&object->apn)); + bb_addString(&ba, "\nIndex: 3 Value: "); + bb_addIntAsString(&ba, object->pinCode); + bb_addString(&ba, "\nIndex: 4 Value: ["); + qualityOfServiceToString(&object->defaultQualityOfService, &ba); + bb_addString(&ba, "]\nIndex: 5 Value: ["); + qualityOfServiceToString(&object->requestedQualityOfService, &ba); + bb_addString(&ba, "]\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_GPRS_SETUP +#ifndef DLMS_IGNORE_EXTENDED_REGISTER +int obj_extendedRegisterToString(gxExtendedRegister* object, char** buff) +{ + int ret; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + ret = var_toString(&object->value, &ba); + if (ret != 0) + { + return ret; + } + bb_addString(&ba, "\nIndex: 3 Value: Scaler: "); + bb_addIntAsString(&ba, object->scaler); + bb_addString(&ba, " Unit: "); + bb_addString(&ba, obj_getUnitAsString(object->unit)); + bb_addString(&ba, "\nIndex: 4 Value: "); + ret = var_toString(&object->status, &ba); + if (ret != 0) + { + return ret; + } + bb_addString(&ba, "\nIndex: 5 Value: "); + time_toString(&object->captureTime, &ba); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_EXTENDED_REGISTER + +int obj_rowsToString(gxByteBuffer* ba, gxArray* buffer) +{ + dlmsVARIANT* tmp; + variantArray* va; + int ret; + uint16_t r, c; + for (r = 0; r != buffer->size; ++r) + { + ret = arr_getByIndex(buffer, r, (void**)&va); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + for (c = 0; c != va->size; ++c) + { + if (c != 0) + { + bb_addString(ba, " | "); + } + ret = va_getByIndex(va, c, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = var_toString(tmp, ba); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + } + bb_addString(ba, "\n"); + } + return 0; +} + +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME +void obj_applicationContextNameToString(gxByteBuffer* ba, gxApplicationContextName* object) +{ + hlp_appendLogicalName(ba, object->logicalName); + bb_addString(ba, " "); + bb_addIntAsString(ba, object->jointIsoCtt); + bb_addString(ba, " "); + bb_addIntAsString(ba, object->country); + bb_addString(ba, " "); + bb_addIntAsString(ba, object->countryName); + bb_addString(ba, " "); + bb_addIntAsString(ba, object->identifiedOrganization); + bb_addString(ba, " "); + bb_addIntAsString(ba, object->dlmsUA); + bb_addString(ba, " "); + bb_addIntAsString(ba, object->applicationContext); + bb_addString(ba, " "); + bb_addIntAsString(ba, object->contextId); +} + +void obj_xDLMSContextTypeToString(gxByteBuffer* ba, gxXDLMSContextType* object) +{ + bb_addIntAsString(ba, object->conformance); + bb_addString(ba, " "); + bb_addIntAsString(ba, object->maxReceivePduSize); + bb_addString(ba, " "); + bb_addIntAsString(ba, object->maxSendPduSize); + bb_addString(ba, " "); + bb_addIntAsString(ba, object->qualityOfService); + bb_addString(ba, " "); + bb_attachString(ba, bb_toString(&object->cypheringInfo)); +} + +void obj_authenticationMechanismNameToString(gxByteBuffer* ba, gxAuthenticationMechanismName* object) +{ + bb_addIntAsString(ba, object->jointIsoCtt); + bb_addString(ba, " "); + bb_addIntAsString(ba, object->country); + bb_addString(ba, " "); + bb_addIntAsString(ba, object->countryName); + bb_addIntAsString(ba, object->identifiedOrganization); + bb_addString(ba, " "); + bb_addIntAsString(ba, object->dlmsUA); + bb_addString(ba, " "); + bb_addIntAsString(ba, object->authenticationMechanismName); + bb_addString(ba, " "); + bb_addIntAsString(ba, object->mechanismId); +} + +int obj_associationLogicalNameToString(gxAssociationLogicalName* object, char** buff) +{ + uint16_t pos; + int ret = 0; + gxKey2* it; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: ["); + obj_objectsToString(&ba, &object->objectList); + bb_addString(&ba, "]\nIndex: 3 Value: "); + bb_addIntAsString(&ba, object->clientSAP); + bb_addString(&ba, "/"); + bb_addIntAsString(&ba, object->serverSAP); + bb_addString(&ba, "\nIndex: 4 Value: "); + obj_applicationContextNameToString(&ba, &object->applicationContextName); + bb_addString(&ba, "\nIndex: 5 Value: "); + obj_xDLMSContextTypeToString(&ba, &object->xDLMSContextInfo); + bb_addString(&ba, "\nIndex: 6 Value: "); + obj_authenticationMechanismNameToString(&ba, &object->authenticationMechanismName); + bb_addString(&ba, "\nIndex: 7 Value: "); + bb_attachString(&ba, bb_toString(&object->secret)); + bb_addString(&ba, "\nIndex: 8 Value: "); + bb_addIntAsString(&ba, object->associationStatus); + //Security Setup Reference is from version 1. + if (object->base.version > 0) + { + bb_addString(&ba, "\nIndex: 9 Value: "); +#ifndef DLMS_IGNORE_SECURITY_SETUP +#ifndef DLMS_IGNORE_OBJECT_POINTERS + bb_addLogicalName(&ba, obj_getLogicalName((gxObject*)object->securitySetup)); +#else + bb_addLogicalName(&ba, object->securitySetupReference); +#endif //DLMS_IGNORE_OBJECT_POINTERS +#endif //DLMS_IGNORE_SECURITY_SETUP + } + if (object->base.version > 1) + { + bb_addString(&ba, "\nIndex: 10 Value: [\n"); + for (pos = 0; pos != object->userList.size; ++pos) + { + if ((ret = arr_getByIndex(&object->userList, pos, (void**)&it)) != 0) + { + return ret; + } + bb_addString(&ba, "ID: "); + bb_addIntAsString(&ba, it->key); + bb_addString(&ba, " Name: "); + bb_addString(&ba, (char*)it->value); + } + bb_addString(&ba, "]\n"); + } + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} + +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME +int obj_associationShortNameToString(gxAssociationShortName* object, char** buff) +{ + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: ["); + obj_objectsToString(&ba, &object->objectList); + bb_addString(&ba, "]\nIndex: 3 Value: "); + //TODO: Show access rights. +#ifndef DLMS_IGNORE_SECURITY_SETUP + bb_addString(&ba, "\nIndex: 4 Value: "); +#ifndef DLMS_IGNORE_OBJECT_POINTERS + bb_addLogicalName(&ba, obj_getLogicalName((gxObject*)object->securitySetup)); +#else + hlp_appendLogicalName(&ba, object->securitySetupReference); +#endif //DLMS_IGNORE_OBJECT_POINTERS +#endif //DLMS_IGNORE_SECURITY_SETUP + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} + +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME +#ifndef DLMS_IGNORE_PPP_SETUP +int obj_pppSetupToString(gxPppSetup* object, char** buff) +{ + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: ["); + //TODO: ipcpOptions + bb_addString(&ba, "]\nIndex: 3 Value: "); +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if (object->phy != NULL) + { + bb_addLogicalName(&ba, object->phy->logicalName); + } +#else + bb_addLogicalName(&ba, object->PHYReference); +#endif //DLMS_IGNORE_OBJECT_POINTERS + bb_addString(&ba, "\nIndex: 4 Value: ["); + //TODO: lcpOptions + bb_addString(&ba, "]\nIndex: 5 Value: "); + bb_attachString(&ba, bb_toString(&object->userName)); + bb_addString(&ba, "\nIndex: 6 Value: "); + bb_attachString(&ba, bb_toString(&object->password)); + bb_addString(&ba, "\nIndex: 7 Value: "); + bb_addIntAsString(&ba, object->authentication); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_PPP_SETUP + +#ifndef DLMS_IGNORE_PROFILE_GENERIC + +int obj_ProfileGenericToString(gxProfileGeneric* object, char** buff) +{ + int ret; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: [\n"); + obj_rowsToString(&ba, &object->buffer); + bb_addString(&ba, "]\nIndex: 3 Value: ["); + obj_CaptureObjectsToString(&ba, &object->captureObjects); + bb_addString(&ba, "]\nIndex: 4 Value: "); + bb_addIntAsString(&ba, object->capturePeriod); + bb_addString(&ba, "\nIndex: 5 Value: "); + bb_addIntAsString(&ba, object->sortMethod); + bb_addString(&ba, "\nIndex: 6 Value: "); + if (object->sortObject != NULL) + { + ret = hlp_appendLogicalName(&ba, object->sortObject->logicalName); + if (ret != 0) + { + return ret; + } + } + bb_addString(&ba, "\nIndex: 7 Value: "); + bb_addIntAsString(&ba, object->entriesInUse); + bb_addString(&ba, "\nIndex: 8 Value: "); + bb_addIntAsString(&ba, object->profileEntries); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_PROFILE_GENERIC +#ifndef DLMS_IGNORE_ACCOUNT +int obj_appendReferences(gxByteBuffer* ba, gxArray* list) +{ + uint16_t pos; + int ret = 0; + unsigned char* it; + for (pos = 0; pos != list->size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(list, pos, (void**)&it, 6)) != 0 || +#else + if ((ret = arr_getByIndex(list, pos, (void**)&it)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = hlp_appendLogicalName(ba, it)) != 0) + { + break; + } + } + return ret; +} +int obj_accountToString(gxAccount* object, char** buff) +{ + int ret; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + if ((ret = bb_addString(&ba, "Index: 2 Value: [\n")) == 0 && + (ret = bb_addIntAsString(&ba, object->paymentMode)) == 0 && + (ret = bb_addString(&ba, "\n")) == 0 && + (ret = bb_addIntAsString(&ba, object->accountStatus)) == 0 && + (ret = bb_addString(&ba, "]")) == 0 && + (ret = bb_addString(&ba, "\nIndex: 3 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->currentCreditInUse)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 4 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->currentCreditStatus)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 5 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->availableCredit)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 6 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->amountToClear)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 7 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->clearanceThreshold)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 8 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->aggregatedDebt)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 9 Value: ")) == 0 && + (ret = obj_appendReferences(&ba, &object->creditReferences)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 10 Value: ")) == 0 && + (ret = obj_appendReferences(&ba, &object->chargeReferences)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 11 Value: ")) == 0 && + //bb_addIntAsString(&ba, &object->creditChargeConfigurations)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 12 Value: ")) == 0 && + // bb_addIntAsString(&ba, object->tokenGatewayConfigurations)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 13 Value: ")) == 0 && + (ret = time_toString(&object->accountActivationTime, &ba)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 14 Value: ")) == 0 && + (ret = time_toString(&object->accountClosureTime, &ba)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 15 Value: ")) == 0 && + (ret = bb_set(&ba, object->currency.name.data, object->currency.name.size)) == 0 && + (ret = bb_addIntAsString(&ba, object->currency.scale)) == 0 && + (ret = bb_addIntAsString(&ba, object->currency.unit)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 16 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->lowCreditThreshold)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 17 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->nextCreditAvailableThreshold)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 18 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->maxProvision)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 19 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->maxProvisionPeriod)) == 0 && + (ret = bb_addString(&ba, "\n")) == 0) + { + *buff = bb_toString(&ba); + } + bb_clear(&ba); + return ret; +} +#endif //DLMS_IGNORE_ACCOUNT +#ifndef DLMS_IGNORE_CREDIT +int obj_creditToString(gxCredit* object, char** buff) +{ + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + bb_addIntAsString(&ba, object->currentCreditAmount); + bb_addString(&ba, "\nIndex: 3 Value: "); + bb_addIntAsString(&ba, object->type); + bb_addString(&ba, "\nIndex: 4 Value: "); + bb_addIntAsString(&ba, object->priority); + bb_addString(&ba, "\nIndex: 5 Value: "); + bb_addIntAsString(&ba, object->warningThreshold); + bb_addString(&ba, "\nIndex: 6 Value: "); + bb_addIntAsString(&ba, object->limit); + bb_addString(&ba, "\nIndex: 7 Value: "); + // bb_addIntAsString(&ba, object->creditConfiguration); + bb_addString(&ba, "\nIndex: 8 Value: "); + bb_addIntAsString(&ba, object->status); + bb_addString(&ba, "\nIndex: 9 Value: "); + bb_addIntAsString(&ba, object->presetCreditAmount); + bb_addString(&ba, "\nIndex: 10 Value: "); + bb_addIntAsString(&ba, object->creditAvailableThreshold); + bb_addString(&ba, "\nIndex: 11 Value: "); + time_toString(&object->period, &ba); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_CREDIT +#ifndef DLMS_IGNORE_CHARGE +int obj_chargeToString(gxCharge* object, char** buff) +{ + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + bb_addIntAsString(&ba, object->totalAmountPaid); + bb_addString(&ba, "\nIndex: 3 Value: "); + bb_addIntAsString(&ba, object->chargeType); + bb_addString(&ba, "\nIndex: 4 Value: "); + bb_addIntAsString(&ba, object->priority); + bb_addString(&ba, "\nIndex: 5 Value: "); + //TODO: +// bb_addIntAsString(&ba, object->unitChargeActive); + bb_addString(&ba, "\nIndex: 6 Value: "); + // bb_addIntAsString(&ba, object->unitChargePassive); + bb_addString(&ba, "\nIndex: 7 Value: "); + time_toString(&object->unitChargeActivationTime, &ba); + bb_addString(&ba, "\nIndex: 8 Value: "); + bb_addIntAsString(&ba, object->period); + bb_addString(&ba, "\nIndex: 9 Value: "); + // bb_addIntAsString(&ba, object->chargeConfiguration); + bb_addString(&ba, "\nIndex: 10 Value: "); + time_toString(&object->lastCollectionTime, &ba); + bb_addString(&ba, "\nIndex: 11 Value: "); + bb_addIntAsString(&ba, object->lastCollectionAmount); + bb_addString(&ba, "\nIndex: 12 Value: "); + bb_addIntAsString(&ba, object->totalAmountRemaining); + bb_addString(&ba, "\nIndex: 13 Value: "); + bb_addIntAsString(&ba, object->proportion); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_CHARGE +#ifndef DLMS_IGNORE_TOKEN_GATEWAY +int obj_tokenGatewayToString( + gxTokenGateway* object, + char** buff) +{ + char* tmp; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + tmp = bb_toHexString(&object->token); + bb_addString(&ba, tmp); + gxfree(tmp); + bb_addString(&ba, "\nIndex: 3 Value: "); + time_toString(&object->time, &ba); + bb_addString(&ba, "\nIndex: 5 Value: "); + bb_addIntAsString(&ba, object->deliveryMethod); + bb_addString(&ba, "\nIndex: 6 Value: "); + bb_addIntAsString(&ba, object->status); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_TOKEN_GATEWAY +#ifndef DLMS_IGNORE_GSM_DIAGNOSTIC +int obj_GsmDiagnosticToString(gxGsmDiagnostic* object, char** buff) +{ + int ret; + uint16_t pos; + gxAdjacentCell* it; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + bb_set(&ba, object->operatorName.data, object->operatorName.size); +#else + bb_addString(&ba, object->operatorName); +#endif //defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + bb_addString(&ba, "\nIndex: 3 Value: "); + bb_addIntAsString(&ba, object->status); + bb_addString(&ba, "\nIndex: 4 Value: "); + bb_addIntAsString(&ba, object->circuitSwitchStatus); + bb_addString(&ba, "\nIndex: 5 Value: "); + bb_addIntAsString(&ba, object->packetSwitchStatus); + bb_addString(&ba, "\nIndex: 6 Value: ["); + bb_addString(&ba, "Cell ID: "); + bb_addIntAsString(&ba, object->cellInfo.cellId); + bb_addString(&ba, "Location ID: "); + bb_addIntAsString(&ba, object->cellInfo.locationId); + bb_addString(&ba, "Signal Quality: "); + bb_addIntAsString(&ba, object->cellInfo.signalQuality); + bb_addString(&ba, "BER: "); + bb_addIntAsString(&ba, object->cellInfo.ber); + bb_addString(&ba, "]"); + + bb_addString(&ba, "\nIndex: 7 Value:[\n"); + for (pos = 0; pos != object->adjacentCells.size; ++pos) + { + ret = arr_getByIndex(&object->adjacentCells, pos, (void**)&it); + if (ret != 0) + { + return ret; + } + if (pos != 0) + { + bb_addString(&ba, ", "); + } + bb_addIntAsString(&ba, it->cellId); + bb_addString(&ba, ":"); + bb_addIntAsString(&ba, it->signalQuality); + } + bb_addString(&ba, "]\n"); + bb_addString(&ba, "\nIndex: 8 Value: "); + time_toString(&object->captureTime, &ba); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_GSM_DIAGNOSTIC + +#ifndef DLMS_IGNORE_COMPACT_DATA +int obj_CompactDataToString(gxCompactData* object, char** buff) +{ + gxByteBuffer ba; + char* tmp; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + tmp = bb_toHexString(&object->buffer); + bb_addString(&ba, tmp); + gxfree(tmp); + bb_addString(&ba, "\nIndex: 3 Value: "); + obj_CaptureObjectsToString(&ba, &object->captureObjects); + bb_addString(&ba, "\nIndex: 4 Value: "); + bb_addIntAsString(&ba, object->templateId); + bb_addString(&ba, "\nIndex: 5 Value: "); + tmp = bb_toHexString(&object->templateDescription); + bb_addString(&ba, tmp); + gxfree(tmp); + bb_addString(&ba, "\nIndex: 6 Value: "); + bb_addIntAsString(&ba, object->captureMethod); + *buff = bb_toString(&ba); + bb_clear(&ba); + return 0; +} +#endif //DLMS_IGNORE_COMPACT_DATA + +#ifndef DLMS_IGNORE_LLC_SSCS_SETUP +int obj_LlcSscsSetupToString(gxLlcSscsSetup* object, char** buff) +{ + int ret; + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + if ((ret = bb_addString(&ba, "Index: 2 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->serviceNodeAddress)) == 0 && + (ret = bb_addString(&ba, "\nIndex: 3 Value: ")) == 0 && + (ret = bb_addIntAsString(&ba, object->baseNodeAddress)) == 0) + { + *buff = bb_toString(&ba); + } + bb_clear(&ba); + return ret; +} +#endif //DLMS_IGNORE_LLC_SSCS_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +int obj_PrimeNbOfdmPlcPhysicalLayerCountersToString(gxPrimeNbOfdmPlcPhysicalLayerCounters* object, char** buff) +{ + return 0; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +int obj_PrimeNbOfdmPlcMacSetupToString(gxPrimeNbOfdmPlcMacSetup* object, char** buff) +{ + return 0; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +int obj_PrimeNbOfdmPlcMacFunctionalParametersToString(gxPrimeNbOfdmPlcMacFunctionalParameters* object, char** buff) +{ + return 0; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +int obj_PrimeNbOfdmPlcMacCountersToString(gxPrimeNbOfdmPlcMacCounters* object, char** buff) +{ + return 0; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA +int obj_PrimeNbOfdmPlcMacNetworkAdministrationDataToString(gxPrimeNbOfdmPlcMacNetworkAdministrationData* object, char** buff) +{ + return 0; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION +int obj_PrimeNbOfdmPlcApplicationsIdentificationToString(gxPrimeNbOfdmPlcApplicationsIdentification* object, char** buff) +{ + return 0; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION + +#ifndef DLMS_IGNORE_SCHEDULE +int obj_scheduleToString(gxSchedule* object, char** buff) +{ + return 0; +} +#endif //DLMS_IGNORE_SCHEDULE + +#ifndef DLMS_IGNORE_PARAMETER_MONITOR + +int obj_ParameterMonitorToString(gxParameterMonitor* object, char** buff) +{ + return 0; +} +#endif //DLMS_IGNORE_PARAMETER_MONITOR + +#ifndef DLMS_IGNORE_ARBITRATOR +int obj_ArbitratorToString(gxArbitrator* object, char** buff) +{ + uint16_t pos; + int ret = 0; + gxByteBuffer bb; + gxActionItem* it; + bitArray* ba; + BYTE_BUFFER_INIT(&bb); + bb_addString(&bb, "Index: 2 Value:{"); + for (pos = 0; pos != object->actions.size; ++pos) + { + if (pos != 0) + { + bb_addString(&bb, ", "); + } + if ((ret = arr_getByIndex(&object->actions, pos, (void**)&it)) != 0) + { + break; + } + bb_addString(&bb, "["); + hlp_appendLogicalName(&bb, it->script->base.logicalName); + bb_addString(&bb, ", "); + bb_addIntAsString(&bb, it->scriptSelector); + bb_addString(&bb, "]"); + } + bb_addString(&bb, "}"); + bb_addString(&bb, "\nIndex: 3 Value:{"); + for (pos = 0; pos != object->permissionsTable.size; ++pos) + { + if (pos != 0) + { + bb_addString(&bb, ", "); + } + if ((ret = arr_getByIndex(&object->permissionsTable, pos, (void**)&ba)) != 0 || + (ret = ba_toString2(&bb, ba)) != 0) + { + break; + } + } + ret = bb_addString(&bb, "}"); + *buff = bb_toString(&bb); + bb_clear(&bb); + return 0; +} +#endif //DLMS_IGNORE_ARBITRATOR +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +int obj_Iec8802LlcType1SetupToString(gxIec8802LlcType1Setup* object, char** buff) +{ + int ret; + gxByteBuffer bb; + BYTE_BUFFER_INIT(&bb); + if ((ret = bb_addString(&bb, "Index: 2 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->maximumOctetsUiPdu)) == 0) + { + *buff = bb_toString(&bb); + } + bb_clear(&bb); + return ret; +} +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP +int obj_Iec8802LlcType2SetupToString(gxIec8802LlcType2Setup* object, char** buff) +{ + int ret; + gxByteBuffer bb; + BYTE_BUFFER_INIT(&bb); + if ((ret = bb_addString(&bb, "Index: 2 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->transmitWindowSizeK)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 3 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->transmitWindowSizeRW)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 4 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->maximumOctetsPdu)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 5 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->maximumNumberTransmissions)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 6 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->acknowledgementTimer)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 7 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->bitTimer)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 8 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->rejectTimer)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 9 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->busyStateTimer)) == 0) + { + *buff = bb_toString(&bb); + } + bb_clear(&bb); + return ret; +} +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP +int obj_Iec8802LlcType3SetupToString(gxIec8802LlcType3Setup* object, char** buff) +{ + int ret; + gxByteBuffer bb; + BYTE_BUFFER_INIT(&bb); + if ((ret = bb_addString(&bb, "\nIndex: 2 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->maximumOctetsACnPdu)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 3 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->maximumTransmissions)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 4 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->acknowledgementTime)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 5 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->receiveLifetime)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 6 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->transmitLifetime)) == 0) + { + *buff = bb_toString(&bb); + } + bb_clear(&bb); + return ret; +} +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP +#ifndef DLMS_IGNORE_SFSK_ACTIVE_INITIATOR +int obj_SFSKActiveInitiatorToString(gxSFSKActiveInitiator* object, char** buff) +{ + int ret; + gxByteBuffer bb; + BYTE_BUFFER_INIT(&bb); + if ((ret = bb_addString(&bb, "\nIndex: 2 Value: ")) == 0 && + (ret = bb_attachString(&bb, bb_toHexString(&object->systemTitle))) == 0 && + (ret = bb_addString(&bb, "\nIndex: 3 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->macAddress)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 4 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->lSapSelector)) == 0) + { + *buff = bb_toString(&bb); + } + bb_clear(&bb); + return ret; +} +#endif //DLMS_IGNORE_SFSK_ACTIVE_INITIATOR +#ifndef DLMS_IGNORE_SFSK_MAC_COUNTERS + + +int obj_getArrayAsString(gxByteBuffer* bb, gxArray* arr) +{ + uint16_t pos; + int ret = 0; + gxUint16PairUint32* it; + for (pos = 0; pos != arr->size; ++pos) + { + if (pos != 0) + { + bb_addString(bb, ", "); + } + if ((ret = arr_getByIndex(arr, pos, (void**)&it)) != 0 || + (ret = bb_addIntAsString(bb, it->first)) != 0 || + (ret = bb_addString(bb, ": ")) != 0 || + (ret = bb_addIntAsString(bb, it->second)) != 0) + { + break; + } + } + return ret; +} + +int obj_FSKMacCountersToString(gxFSKMacCounters* object, char** buff) +{ + int ret; + gxByteBuffer bb; + BYTE_BUFFER_INIT(&bb); + if ((ret = bb_addString(&bb, "\nIndex: 2 Value:{")) == 0 && + (ret = obj_getArrayAsString(&bb, &object->synchronizationRegister)) == 0 && + (ret = bb_addString(&bb, "}\nIndex: 3 Value:[")) == 0 && + (ret = bb_addIntAsString(&bb, object->physicalLayerDesynchronization)) == 0 && + (ret = bb_addString(&bb, ", ")) == 0 && + (ret = bb_addIntAsString(&bb, object->timeOutNotAddressedDesynchronization)) == 0 && + (ret = bb_addString(&bb, ", ")) == 0 && + (ret = bb_addIntAsString(&bb, object->timeOutFrameNotOkDesynchronization)) == 0 && + (ret = bb_addString(&bb, ", ")) == 0 && + (ret = bb_addIntAsString(&bb, object->writeRequestDesynchronization)) == 0 && + (ret = bb_addString(&bb, ", ")) == 0 && + (ret = bb_addIntAsString(&bb, object->wrongInitiatorDesynchronization)) == 0 && + (ret = bb_addString(&bb, "]\nIndex: 3 Value:{")) == 0 && + (ret = obj_getArrayAsString(&bb, &object->broadcastFramesCounter)) == 0 && + (ret = bb_addString(&bb, "}\nIndex: 4 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->repetitionsCounter)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 5 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->transmissionsCounter)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 6 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->crcOkFramesCounter)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 7 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->crcNOkFramesCounter)) == 0) + { + *buff = bb_toString(&bb); + } + bb_clear(&bb); + return ret; +} +#endif //DLMS_IGNORE_SFSK_MAC_COUNTERS +#ifndef DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS +int obj_SFSKMacSynchronizationTimeoutsToString(gxSFSKMacSynchronizationTimeouts* object, char** buff) +{ + int ret; + gxByteBuffer bb; + BYTE_BUFFER_INIT(&bb); + if ((ret = bb_addString(&bb, "\nIndex: 2 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->searchInitiatorTimeout)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 3 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->synchronizationConfirmationTimeout)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 4 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->timeOutNotAddressed)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 5 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->timeOutFrameNotOK)) == 0) + { + *buff = bb_toString(&bb); + } + bb_clear(&bb); + return ret; +} +#endif //DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS +#ifndef DLMS_IGNORE_SFSK_PHY_MAC_SETUP + +int obj_SFSKPhyMacSetUpToString(gxSFSKPhyMacSetUp* object, char** buff) +{ + int ret = 0; + gxByteBuffer bb; + BYTE_BUFFER_INIT(&bb); + if ((ret = bb_addString(&bb, "\nIndex: 2 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->initiatorElectricalPhase)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 3 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->deltaElectricalPhase)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 4 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->maxReceivingGain)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 5 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->maxTransmittingGain)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 6 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->searchInitiatorThreshold)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 7 Value:[")) == 0 && + (ret = bb_addIntAsString(&bb, object->markFrequency)) == 0 && + (ret = bb_addString(&bb, ", ")) == 0 && + (ret = bb_addIntAsString(&bb, object->spaceFrequency)) == 0 && + (ret = bb_addString(&bb, "]\nIndex: 8 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->macAddress)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 9 Value:{")) == 0 && + (ret = obj_UInt16ArrayToString(&bb, &object->macGroupAddresses)) == 0 && + (ret = bb_addString(&bb, "}\nIndex: 10 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->repeater)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 11 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->repeaterStatus)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 12 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->minDeltaCredit)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 13 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->initiatorMacAddress)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 14 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->synchronizationLocked)) == 0 && + (ret = bb_addString(&bb, "\nIndex: 15 Value: ")) == 0 && + (ret = bb_addIntAsString(&bb, object->transmissionSpeed)) == 0) + { + *buff = bb_toString(&bb); + } + bb_clear(&bb); + return ret; +} +#endif //DLMS_IGNORE_SFSK_PHY_MAC_SETUP +#ifndef DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST +int obj_SFSKReportingSystemListToString(gxSFSKReportingSystemList* object, char** buff) +{ + uint16_t pos; + int ret = 0; + gxByteBuffer* it; + gxByteBuffer bb; + BYTE_BUFFER_INIT(&bb); + if ((ret = bb_addString(&bb, "\nIndex: 2 Value:{")) == 0) + { + for (pos = 0; pos != object->reportingSystemList.size; ++pos) + { + if (pos != 0) + { + bb_addString(&bb, ", "); + } + if ((ret = arr_getByIndex(&object->reportingSystemList, pos, (void**)&it)) != 0 || + (ret = bb_attachString(&bb, bb_toHexString(it))) != 0) + { + break; + } + } + if (ret == 0) + { + if ((ret = bb_addString(&bb, "\n}")) == 0) + { + *buff = bb_toString(&bb); + } + } + } + bb_clear(&bb); + return ret; +} +#endif //DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST + +#ifdef DLMS_ITALIAN_STANDARD +int obj_TariffPlanToString(gxTariffPlan* object, char** buff) +{ + gxByteBuffer ba; + BYTE_BUFFER_INIT(&ba); + bb_addString(&ba, "Index: 2 Value: "); + bb_addString(&ba, object->calendarName); + bb_addString(&ba, "\nIndex: 3 Value: "); + bb_addIntAsString(&ba, object->enabled); + bb_addString(&ba, "\nIndex: 5 Value: "); + time_toString(&object->activationTime, &ba); + bb_addString(&ba, "\n"); + *buff = bb_toString(&ba); + bb_clear(&ba); + return DLMS_ERROR_CODE_OK; +} +#endif //DLMS_ITALIAN_STANDARD + +int obj_toString(gxObject* object, char** buff) +{ + int ret = 0; + switch (object->objectType) + { +#ifndef DLMS_IGNORE_DATA + case DLMS_OBJECT_TYPE_DATA: + ret = obj_DataToString((gxData*)object, buff); + break; +#endif //DLMS_IGNORE_DATA +#ifndef DLMS_IGNORE_REGISTER + case DLMS_OBJECT_TYPE_REGISTER: + ret = obj_RegisterToString((gxRegister*)object, buff); + break; +#endif //DLMS_IGNORE_REGISTER +#ifndef DLMS_IGNORE_CLOCK + case DLMS_OBJECT_TYPE_CLOCK: + ret = obj_clockToString((gxClock*)object, buff); + break; +#endif //DLMS_IGNORE_CLOCK +#ifndef DLMS_IGNORE_ACTION_SCHEDULE + case DLMS_OBJECT_TYPE_ACTION_SCHEDULE: + ret = obj_actionScheduleToString((gxActionSchedule*)object, buff); + break; +#endif //DLMS_IGNORE_ACTION_SCHEDULE +#ifndef DLMS_IGNORE_ACTIVITY_CALENDAR + case DLMS_OBJECT_TYPE_ACTIVITY_CALENDAR: + ret = obj_activityCalendarToString((gxActivityCalendar*)object, buff); + break; +#endif //DLMS_IGNORE_ACTIVITY_CALENDAR +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + case DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME: + ret = obj_associationLogicalNameToString((gxAssociationLogicalName*)object, buff); + break; +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + case DLMS_OBJECT_TYPE_ASSOCIATION_SHORT_NAME: +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + ret = obj_associationShortNameToString((gxAssociationShortName*)object, buff); +#else + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + break; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME +#ifndef DLMS_IGNORE_AUTO_ANSWER + case DLMS_OBJECT_TYPE_AUTO_ANSWER: + ret = obj_autoAnswerToString((gxAutoAnswer*)object, buff); + break; +#endif //DLMS_IGNORE_AUTO_ANSWER +#ifndef DLMS_IGNORE_AUTO_CONNECT + case DLMS_OBJECT_TYPE_AUTO_CONNECT: + ret = obj_autoConnectToString((gxAutoConnect*)object, buff); + break; +#endif //DLMS_IGNORE_AUTO_CONNECT +#ifndef DLMS_IGNORE_DEMAND_REGISTER + case DLMS_OBJECT_TYPE_DEMAND_REGISTER: + ret = obj_demandRegisterToString((gxDemandRegister*)object, buff); + break; +#endif //DLMS_IGNORE_DEMAND_REGISTER +#ifndef DLMS_IGNORE_MAC_ADDRESS_SETUP + case DLMS_OBJECT_TYPE_MAC_ADDRESS_SETUP: + ret = obj_macAddressSetupToString((gxMacAddressSetup*)object, buff); + break; +#endif //DLMS_IGNORE_MAC_ADDRESS_SETUP +#ifndef DLMS_IGNORE_EXTENDED_REGISTER + case DLMS_OBJECT_TYPE_EXTENDED_REGISTER: + ret = obj_extendedRegisterToString((gxExtendedRegister*)object, buff); + break; +#endif //DLMS_IGNORE_EXTENDED_REGISTER +#ifndef DLMS_IGNORE_GPRS_SETUP + case DLMS_OBJECT_TYPE_GPRS_SETUP: +#ifndef DLMS_IGNORE_GPRS_SETUP + ret = obj_GPRSSetupToString((gxGPRSSetup*)object, buff); +#endif //DLMS_IGNORE_GPRS_SETUP + break; +#endif //DLMS_IGNORE_GPRS_SETUP +#ifndef DLMS_IGNORE_SECURITY_SETUP + case DLMS_OBJECT_TYPE_SECURITY_SETUP: + ret = obj_securitySetupToString((gxSecuritySetup*)object, buff); + break; +#endif //DLMS_IGNORE_SECURITY_SETUP +#ifndef DLMS_IGNORE_IEC_HDLC_SETUP + case DLMS_OBJECT_TYPE_IEC_HDLC_SETUP: + ret = obj_hdlcSetupToString((gxIecHdlcSetup*)object, buff); + break; +#endif //DLMS_IGNORE_IEC_HDLC_SETUP +#ifndef DLMS_IGNORE_IEC_LOCAL_PORT_SETUP + case DLMS_OBJECT_TYPE_IEC_LOCAL_PORT_SETUP: + ret = obj_localPortSetupToString((gxLocalPortSetup*)object, buff); + break; +#endif //DLMS_IGNORE_IEC_LOCAL_PORT_SETUP +#ifndef DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP + case DLMS_OBJECT_TYPE_IEC_TWISTED_PAIR_SETUP: + ret = obj_IecTwistedPairSetupToString((gxIecTwistedPairSetup*)object, buff); + break; +#endif //DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP +#ifndef DLMS_IGNORE_IP4_SETUP + case DLMS_OBJECT_TYPE_IP4_SETUP: + ret = obj_ip4SetupToString((gxIp4Setup*)object, buff); + break; +#endif //DLMS_IGNORE_IP4_SETUP +#ifndef DLMS_IGNORE_IP6_SETUP + case DLMS_OBJECT_TYPE_IP6_SETUP: + ret = obj_ip6SetupToString((gxIp6Setup*)object, buff); + break; +#endif //DLMS_IGNORE_IP4_SETUP +#ifndef DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP + case DLMS_OBJECT_TYPE_MBUS_SLAVE_PORT_SETUP: + ret = obj_mbusSlavePortSetupToString((gxMbusSlavePortSetup*)object, buff); + break; +#endif //DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP +#ifndef DLMS_IGNORE_IMAGE_TRANSFER + case DLMS_OBJECT_TYPE_IMAGE_TRANSFER: + ret = obj_imageTransferToString((gxImageTransfer*)object, buff); + break; +#endif //DLMS_IGNORE_IMAGE_TRANSFER +#ifndef DLMS_IGNORE_DISCONNECT_CONTROL + case DLMS_OBJECT_TYPE_DISCONNECT_CONTROL: + ret = obj_disconnectControlToString((gxDisconnectControl*)object, buff); + break; +#endif //DLMS_IGNORE_DISCONNECT_CONTROL +#ifndef DLMS_IGNORE_LIMITER + case DLMS_OBJECT_TYPE_LIMITER: + ret = obj_limiterToString((gxLimiter*)object, buff); + break; +#endif //DLMS_IGNORE_LIMITER +#ifndef DLMS_IGNORE_MBUS_CLIENT + case DLMS_OBJECT_TYPE_MBUS_CLIENT: + ret = obj_mBusClientToString((gxMBusClient*)object, buff); + break; +#endif //DLMS_IGNORE_MBUS_CLIENT +#ifndef DLMS_IGNORE_MODEM_CONFIGURATION + case DLMS_OBJECT_TYPE_MODEM_CONFIGURATION: + ret = obj_modemConfigurationToString((gxModemConfiguration*)object, buff); + break; +#endif //DLMS_IGNORE_MODEM_CONFIGURATION +#ifndef DLMS_IGNORE_PPP_SETUP + case DLMS_OBJECT_TYPE_PPP_SETUP: + ret = obj_pppSetupToString((gxPppSetup*)object, buff); + break; +#endif //DLMS_IGNORE_PPP_SETUP +#ifndef DLMS_IGNORE_PROFILE_GENERIC + case DLMS_OBJECT_TYPE_PROFILE_GENERIC: + ret = obj_ProfileGenericToString((gxProfileGeneric*)object, buff); + break; +#endif //DLMS_IGNORE_PROFILE_GENERIC +#ifndef DLMS_IGNORE_REGISTER_ACTIVATION + case DLMS_OBJECT_TYPE_REGISTER_ACTIVATION: + ret = obj_registerActivationToString((gxRegisterActivation*)object, buff); + break; +#endif //DLMS_IGNORE_REGISTER_ACTIVATION +#ifndef DLMS_IGNORE_REGISTER_MONITOR + case DLMS_OBJECT_TYPE_REGISTER_MONITOR: + ret = obj_registerMonitorToString((gxRegisterMonitor*)object, buff); + break; +#endif //DLMS_IGNORE_REGISTER_MONITOR +#ifndef DLMS_IGNORE_REGISTER_TABLE + case DLMS_OBJECT_TYPE_REGISTER_TABLE: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_REGISTER_TABLE +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_STARTUP + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_STARTUP: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_ZIG_BEE_SAS_STARTUP +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_JOIN + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_JOIN: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_ZIG_BEE_SAS_JOIN +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_APS_FRAGMENTATION + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_APS_FRAGMENTATION: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_ZIG_BEE_SAS_APS_FRAGMENTATION +#ifndef DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL + case DLMS_OBJECT_TYPE_ZIG_BEE_NETWORK_CONTROL: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL +#ifndef DLMS_IGNORE_SAP_ASSIGNMENT + case DLMS_OBJECT_TYPE_SAP_ASSIGNMENT: + ret = obj_sapAssignmentToString((gxSapAssignment*)object, buff); + break; +#endif //DLMS_IGNORE_SAP_ASSIGNMENT +#ifndef DLMS_IGNORE_SCHEDULE + case DLMS_OBJECT_TYPE_SCHEDULE: + ret = obj_scheduleToString((gxSchedule*)object, buff); + break; +#endif //DLMS_IGNORE_SCHEDULE +#ifndef DLMS_IGNORE_SCRIPT_TABLE + case DLMS_OBJECT_TYPE_SCRIPT_TABLE: + ret = obj_ScriptTableToString((gxScriptTable*)object, buff); + break; +#endif //DLMS_IGNORE_SCRIPT_TABLE +#ifndef DLMS_IGNORE_SMTP_SETUP + case DLMS_OBJECT_TYPE_SMTP_SETUP: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_SMTP_SETUP +#ifndef DLMS_IGNORE_SPECIAL_DAYS_TABLE + case DLMS_OBJECT_TYPE_SPECIAL_DAYS_TABLE: + ret = obj_specialDaysTableToString((gxSpecialDaysTable*)object, buff); + break; +#endif //DLMS_IGNORE_SPECIAL_DAYS_TABLE +#ifndef DLMS_IGNORE_STATUS_MAPPING + case DLMS_OBJECT_TYPE_STATUS_MAPPING: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_STATUS_MAPPING +#ifndef DLMS_IGNORE_TCP_UDP_SETUP + case DLMS_OBJECT_TYPE_TCP_UDP_SETUP: + ret = obj_TcpUdpSetupToString((gxTcpUdpSetup*)object, buff); + break; +#endif //DLMS_IGNORE_TCP_UDP_SETUP +#ifndef DLMS_IGNORE_MBUS_DIAGNOSTIC + case DLMS_OBJECT_TYPE_MBUS_DIAGNOSTIC: + ret = obj_MBusDiagnosticToString((gxMbusDiagnostic*)object, buff); + break; +#endif //DLMS_IGNORE_MBUS_DIAGNOSTIC +#ifndef DLMS_IGNORE_MBUS_PORT_SETUP + case DLMS_OBJECT_TYPE_MBUS_PORT_SETUP: + ret = obj_MBusPortSetupToString((gxMBusPortSetup*)object, buff); + break; +#endif //DLMS_IGNORE_MBUS_PORT_SETUP +#ifndef DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS + case DLMS_OBJECT_TYPE_G3_PLC_MAC_LAYER_COUNTERS: + ret = obj_G3PlcMacLayerCounters((gxG3PlcMacLayerCounters*)object, buff); + break; +#endif //DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS +#ifndef DLMS_IGNORE_G3_PLC_MAC_SETUP + case DLMS_OBJECT_TYPE_G3_PLC_MAC_SETUP: + ret = obj_G3PlcMacSetupToString((gxG3PlcMacSetup*)object, buff); + break; +#endif //DLMS_IGNORE_G3_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_G3_PLC_6LO_WPAN + case DLMS_OBJECT_TYPE_G3_PLC_6LO_WPAN: + ret = obj_G3Plc6LoWPANToString((gxG3Plc6LoWPAN*)object, buff); + break; +#endif //DLMS_IGNORE_G3_PLC_6LO_WPAN +#ifndef DLMS_IGNORE_FUNCTION_CONTROL + case DLMS_OBJECT_TYPE_FUNCTION_CONTROL: + ret = obj_FunctionControlToString((gxFunctionControl*)object, buff); + break; +#endif //DLMS_IGNORE_FUNCTION_CONTROL +#ifndef DLMS_IGNORE_ARRAY_MANAGER + case DLMS_OBJECT_TYPE_ARRAY_MANAGER: + ret = obj_ArrayManagerToString((gxArrayManager*)object, buff); + break; +#endif //DLMS_IGNORE_ARRAY_MANAGER +#ifndef DLMS_IGNORE_UTILITY_TABLES + case DLMS_OBJECT_TYPE_UTILITY_TABLES: + ret = obj_UtilityTablesToString((gxUtilityTables*)object, buff); + break; +#endif //DLMS_IGNORE_UTILITY_TABLES +#ifndef DLMS_IGNORE_MBUS_MASTER_PORT_SETUP + case DLMS_OBJECT_TYPE_MBUS_MASTER_PORT_SETUP: + ret = obj_mBusMasterPortSetupToString((gxMBusMasterPortSetup*)object, buff); + break; +#endif //DLMS_IGNORE_MBUS_MASTER_PORT_SETUP +#ifndef DLMS_IGNORE_PUSH_SETUP + case DLMS_OBJECT_TYPE_PUSH_SETUP: + ret = obj_pushSetupToString((gxPushSetup*)object, buff); + break; +#endif //DLMS_IGNORE_PUSH_SETUP +#ifndef DLMS_IGNORE_DATA_PROTECTION + case DLMS_OBJECT_TYPE_DATA_PROTECTION: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_DATA_PROTECTION +#ifndef DLMS_IGNORE_ACCOUNT + case DLMS_OBJECT_TYPE_ACCOUNT: + ret = obj_accountToString((gxAccount*)object, buff); + break; +#endif //DLMS_IGNORE_ACCOUNT +#ifndef DLMS_IGNORE_CREDIT + case DLMS_OBJECT_TYPE_CREDIT: + ret = obj_creditToString((gxCredit*)object, buff); + break; +#endif //DLMS_IGNORE_CREDIT +#ifndef DLMS_IGNORE_CHARGE + case DLMS_OBJECT_TYPE_CHARGE: + ret = obj_chargeToString((gxCharge*)object, buff); + break; +#endif //DLMS_IGNORE_CHARGE +#ifndef DLMS_IGNORE_TOKEN_GATEWAY + case DLMS_OBJECT_TYPE_TOKEN_GATEWAY: + ret = obj_tokenGatewayToString((gxTokenGateway*)object, buff); + break; +#endif //DLMS_IGNORE_TOKEN_GATEWAY +#ifndef DLMS_IGNORE_GSM_DIAGNOSTIC + case DLMS_OBJECT_TYPE_GSM_DIAGNOSTIC: + ret = obj_GsmDiagnosticToString((gxGsmDiagnostic*)object, buff); + break; +#endif //DLMS_IGNORE_GSM_DIAGNOSTIC +#ifndef DLMS_IGNORE_COMPACT_DATA + case DLMS_OBJECT_TYPE_COMPACT_DATA: + ret = obj_CompactDataToString((gxCompactData*)object, buff); + break; +#endif //DLMS_IGNORE_COMPACT_DATA +#ifndef DLMS_IGNORE_LLC_SSCS_SETUP + case DLMS_OBJECT_TYPE_LLC_SSCS_SETUP: + ret = obj_LlcSscsSetupToString((gxLlcSscsSetup*)object, buff); + break; +#endif //DLMS_IGNORE_LLC_SSCS_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS: + ret = obj_PrimeNbOfdmPlcPhysicalLayerCountersToString((gxPrimeNbOfdmPlcPhysicalLayerCounters*)object, buff); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_SETUP: + ret = obj_PrimeNbOfdmPlcMacSetupToString((gxPrimeNbOfdmPlcMacSetup*)object, buff); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS: + ret = obj_PrimeNbOfdmPlcMacFunctionalParametersToString((gxPrimeNbOfdmPlcMacFunctionalParameters*)object, buff); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_COUNTERS: + ret = obj_PrimeNbOfdmPlcMacCountersToString((gxPrimeNbOfdmPlcMacCounters*)object, buff); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA: + ret = obj_PrimeNbOfdmPlcMacNetworkAdministrationDataToString((gxPrimeNbOfdmPlcMacNetworkAdministrationData*)object, buff); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION: + ret = obj_PrimeNbOfdmPlcApplicationsIdentificationToString((gxPrimeNbOfdmPlcApplicationsIdentification*)object, buff); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION +#ifndef DLMS_IGNORE_PARAMETER_MONITOR + case DLMS_OBJECT_TYPE_PARAMETER_MONITOR: + ret = obj_ParameterMonitorToString((gxParameterMonitor*)object, buff); + break; +#endif //DLMS_IGNORE_PARAMETER_MONITOR +#ifndef DLMS_IGNORE_ARBITRATOR + case DLMS_OBJECT_TYPE_ARBITRATOR: + ret = obj_ArbitratorToString((gxArbitrator*)object, buff); + break; +#endif //DLMS_IGNORE_ARBITRATOR +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE1_SETUP: + ret = obj_Iec8802LlcType1SetupToString((gxIec8802LlcType1Setup*)object, buff); + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE2_SETUP: + ret = obj_Iec8802LlcType2SetupToString((gxIec8802LlcType2Setup*)object, buff); + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE3_SETUP: + ret = obj_Iec8802LlcType3SetupToString((gxIec8802LlcType3Setup*)object, buff); + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP +#ifndef DLMS_IGNORE_SFSK_ACTIVE_INITIATOR + case DLMS_OBJECT_TYPE_SFSK_ACTIVE_INITIATOR: + ret = obj_SFSKActiveInitiatorToString((gxSFSKActiveInitiator*)object, buff); + break; +#endif //DLMS_IGNORE_SFSK_ACTIVE_INITIATOR +#ifndef DLMS_IGNORE_SFSK_MAC_COUNTERS + case DLMS_OBJECT_TYPE_SFSK_MAC_COUNTERS: + ret = obj_FSKMacCountersToString((gxFSKMacCounters*)object, buff); + break; +#endif //DLMS_IGNORE_SFSK_MAC_COUNTERS +#ifndef DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS + case DLMS_OBJECT_TYPE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS: + ret = obj_SFSKMacSynchronizationTimeoutsToString((gxSFSKMacSynchronizationTimeouts*)object, buff); + break; +#endif //DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS +#ifndef DLMS_IGNORE_SFSK_PHY_MAC_SETUP + case DLMS_OBJECT_TYPE_SFSK_PHY_MAC_SETUP: + ret = obj_SFSKPhyMacSetUpToString((gxSFSKPhyMacSetUp*)object, buff); + break; +#endif //DLMS_IGNORE_SFSK_PHY_MAC_SETUP +#ifndef DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST + case DLMS_OBJECT_TYPE_SFSK_REPORTING_SYSTEM_LIST: + ret = obj_SFSKReportingSystemListToString((gxSFSKReportingSystemList*)object, buff); + break; +#endif //DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST +#ifdef DLMS_ITALIAN_STANDARD + case DLMS_OBJECT_TYPE_TARIFF_PLAN: + ret = obj_TariffPlanToString((gxTariffPlan*)object, buff); + break; +#endif //DLMS_ITALIAN_STANDARD + default: //Unknown type. + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} + +#endif //DLMS_IGNORE_STRING_CONVERTER + +const char* err_toString(int err) +{ + return hlp_getErrorMessage(err); +} +#endif //DLMS_IGNORE_MALLOC diff --git a/components/xt211/converters.h b/components/xt211/converters.h new file mode 100644 index 0000000..090c8bc --- /dev/null +++ b/components/xt211/converters.h @@ -0,0 +1,84 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef CONVERTERRS_H +#define CONVERTERRS_H +#include "gxignore.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DLMS_IGNORE_MALLOC +#include "errorcodes.h" +#include "variant.h" +#include "gxarray.h" +#include "gxobjects.h" +#endif //DLMS_IGNORE_MALLOC +#include "enums.h" + + //Get object type as string. + int obj_typeToString( + DLMS_OBJECT_TYPE type, + char* buff); + + //Get object type as string. + const char* obj_typeToString2( + DLMS_OBJECT_TYPE type); + + //Get object type as string. + const char* obj_typeToString2( + DLMS_OBJECT_TYPE type); + +#ifndef DLMS_IGNORE_MALLOC +#ifndef DLMS_IGNORE_STRING_CONVERTER + + const char* obj_getUnitAsString( + unsigned char unit); + + int obj_rowsToString( + gxByteBuffer* ba, + gxArray* buffer); + + //Convert object's attributes to string. + //This can be used in debugging purposes. + int obj_toString( + gxObject* object, + char** buff); +#endif //DLMS_IGNORE_STRING_CONVERTER + const char* err_toString(int err); + +#endif //DLMS_IGNORE_MALLOC +#ifdef __cplusplus +} +#endif +#endif //CONVERTERRS_H diff --git a/components/xt211/cosem.c b/components/xt211/cosem.c new file mode 100644 index 0000000..ece43f8 --- /dev/null +++ b/components/xt211/cosem.c @@ -0,0 +1,1968 @@ +// +// -------------------------------------------------------------------------- +// 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 +#endif + +#include "gxmem.h" +#if _MSC_VER > 1400 +#include +#endif +#include +#include "datainfo.h" +#include "dlms.h" +#include "cosem.h" +#include "helpers.h" +#include "lnparameters.h" +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME +#include "snparameters.h" +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + +//cosem_getObjectSize returns zero if object is not supported. +uint16_t cosem_getObjectSize(DLMS_OBJECT_TYPE type) +{ + int size = 0; + switch (type) + { +#ifndef DLMS_IGNORE_DATA + case DLMS_OBJECT_TYPE_DATA: + size = sizeof(gxData); + break; +#endif //DLMS_IGNORE_DATA +#ifndef DLMS_IGNORE_REGISTER + case DLMS_OBJECT_TYPE_REGISTER: + size = sizeof(gxRegister); + break; +#endif //DLMS_IGNORE_REGISTER +#ifndef DLMS_IGNORE_CLOCK + case DLMS_OBJECT_TYPE_CLOCK: + size = sizeof(gxClock); + break; +#endif //DLMS_IGNORE_CLOCK +#ifndef DLMS_IGNORE_ACTION_SCHEDULE + case DLMS_OBJECT_TYPE_ACTION_SCHEDULE: + size = sizeof(gxActionSchedule); + break; +#endif //DLMS_IGNORE_ACTION_SCHEDULE +#ifndef DLMS_IGNORE_ACTIVITY_CALENDAR + case DLMS_OBJECT_TYPE_ACTIVITY_CALENDAR: + size = sizeof(gxActivityCalendar); + break; +#endif //DLMS_IGNORE_ACTIVITY_CALENDAR +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + case DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME: + size = sizeof(gxAssociationLogicalName); + break; +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + case DLMS_OBJECT_TYPE_ASSOCIATION_SHORT_NAME: + size = sizeof(gxAssociationShortName); + break; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME +#ifndef DLMS_IGNORE_AUTO_ANSWER + case DLMS_OBJECT_TYPE_AUTO_ANSWER: + size = sizeof(gxAutoAnswer); + break; +#endif //DLMS_IGNORE_AUTO_ANSWER +#ifndef DLMS_IGNORE_AUTO_CONNECT + case DLMS_OBJECT_TYPE_AUTO_CONNECT: + size = sizeof(gxAutoConnect); + break; +#endif //DLMS_IGNORE_AUTO_CONNECT +#ifndef DLMS_IGNORE_DEMAND_REGISTER + case DLMS_OBJECT_TYPE_DEMAND_REGISTER: + size = sizeof(gxDemandRegister); + break; +#endif //DLMS_IGNORE_DEMAND_REGISTER +#ifndef DLMS_IGNORE_MAC_ADDRESS_SETUP + case DLMS_OBJECT_TYPE_MAC_ADDRESS_SETUP: + size = sizeof(gxMacAddressSetup); + break; +#endif //DLMS_IGNORE_MAC_ADDRESS_SETUP +#ifndef DLMS_IGNORE_EXTENDED_REGISTER + case DLMS_OBJECT_TYPE_EXTENDED_REGISTER: + size = sizeof(gxExtendedRegister); + break; +#endif //DLMS_IGNORE_EXTENDED_REGISTER +#ifndef DLMS_IGNORE_GPRS_SETUP + case DLMS_OBJECT_TYPE_GPRS_SETUP: + size = sizeof(gxGPRSSetup); + break; +#endif //DLMS_IGNORE_GPRS_SETUP +#ifndef DLMS_IGNORE_SECURITY_SETUP + case DLMS_OBJECT_TYPE_SECURITY_SETUP: + size = sizeof(gxSecuritySetup); + break; +#endif //DLMS_IGNORE_SECURITY_SETUP +#ifndef DLMS_IGNORE_IEC_HDLC_SETUP + case DLMS_OBJECT_TYPE_IEC_HDLC_SETUP: + size = sizeof(gxIecHdlcSetup); + break; +#endif //DLMS_IGNORE_IEC_HDLC_SETUP +#ifndef DLMS_IGNORE_IEC_LOCAL_PORT_SETUP + case DLMS_OBJECT_TYPE_IEC_LOCAL_PORT_SETUP: + size = sizeof(gxLocalPortSetup); + break; +#endif //DLMS_IGNORE_IEC_LOCAL_PORT_SETUP +#ifndef DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP + case DLMS_OBJECT_TYPE_IEC_TWISTED_PAIR_SETUP: + size = sizeof(gxIecTwistedPairSetup); + break; +#endif //DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP +#ifndef DLMS_IGNORE_IP4_SETUP + case DLMS_OBJECT_TYPE_IP4_SETUP: + size = sizeof(gxIp4Setup); + break; +#endif //DLMS_IGNORE_IP4_SETUP +#ifndef DLMS_IGNORE_IP6_SETUP + case DLMS_OBJECT_TYPE_IP6_SETUP: + size = sizeof(gxIp6Setup); + break; +#endif //DLMS_IGNORE_IP6_SETUP +#ifndef DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP + case DLMS_OBJECT_TYPE_MBUS_SLAVE_PORT_SETUP: + size = sizeof(gxMbusSlavePortSetup); + break; +#endif //DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP +#ifndef DLMS_IGNORE_IMAGE_TRANSFER + case DLMS_OBJECT_TYPE_IMAGE_TRANSFER: + size = sizeof(gxImageTransfer); + break; +#endif //DLMS_IGNORE_IMAGE_TRANSFER +#ifndef DLMS_IGNORE_DISCONNECT_CONTROL + case DLMS_OBJECT_TYPE_DISCONNECT_CONTROL: + size = sizeof(gxDisconnectControl); + break; +#endif //DLMS_IGNORE_DISCONNECT_CONTROL +#ifndef DLMS_IGNORE_LIMITER + case DLMS_OBJECT_TYPE_LIMITER: + size = sizeof(gxLimiter); + break; +#endif //DLMS_IGNORE_LIMITER +#ifndef DLMS_IGNORE_MBUS_CLIENT + case DLMS_OBJECT_TYPE_MBUS_CLIENT: + size = sizeof(gxMBusClient); + break; +#endif // +#ifndef DLMS_IGNORE_MODEM_CONFIGURATION + case DLMS_OBJECT_TYPE_MODEM_CONFIGURATION: + size = sizeof(gxModemConfiguration); + break; +#endif //DLMS_IGNORE_MODEM_CONFIGURATION +#ifndef DLMS_IGNORE_PPP_SETUP + case DLMS_OBJECT_TYPE_PPP_SETUP: + size = sizeof(gxPppSetup); + break; +#endif //DLMS_IGNORE_PPP_SETUP +#ifndef DLMS_IGNORE_PROFILE_GENERIC + case DLMS_OBJECT_TYPE_PROFILE_GENERIC: + size = sizeof(gxProfileGeneric); + break; +#endif //DLMS_IGNORE_PROFILE_GENERIC +#ifndef DLMS_IGNORE_REGISTER_ACTIVATION + case DLMS_OBJECT_TYPE_REGISTER_ACTIVATION: + size = sizeof(gxRegisterActivation); + break; +#endif //DLMS_IGNORE_REGISTER_ACTIVATION +#ifndef DLMS_IGNORE_REGISTER_MONITOR + case DLMS_OBJECT_TYPE_REGISTER_MONITOR: + size = sizeof(gxRegisterMonitor); + break; +#endif //DLMS_IGNORE_REGISTER_MONITOR +#ifndef DLMS_IGNORE_REGISTER_TABLE + case DLMS_OBJECT_TYPE_REGISTER_TABLE: + size = sizeof(gxRegisterTable); + break; +#endif //DLMS_IGNORE_REGISTER_TABLE +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_STARTUP + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_STARTUP: + size = sizeof(gxZigBeeSasStartup); + break; +#endif //DLMS_IGNORE_ZIG_BEE_SAS_STARTUP +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_JOIN + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_JOIN: + size = sizeof(gxZigBeeSasJoin); + break; +#endif //ZIG_BEE_SAS_JOIN +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_APS_FRAGMENTATION + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_APS_FRAGMENTATION: + size = sizeof(gxZigBeeSasApsFragmentation); + break; +#endif //DLMS_IGNORE_ZIG_BEE_SAS_APS_FRAGMENTATION +#ifndef DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL + case DLMS_OBJECT_TYPE_ZIG_BEE_NETWORK_CONTROL: + size = sizeof(gxZigBeeNetworkControl); + break; +#endif //DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL +#ifndef DLMS_IGNORE_SAP_ASSIGNMENT + case DLMS_OBJECT_TYPE_SAP_ASSIGNMENT: + size = sizeof(gxSapAssignment); + break; +#endif //DLMS_IGNORE_SAP_ASSIGNMENT +#ifndef DLMS_IGNORE_SCHEDULE + case DLMS_OBJECT_TYPE_SCHEDULE: + size = sizeof(gxSchedule); + break; +#endif //DLMS_IGNORE_SCHEDULE +#ifndef DLMS_IGNORE_SCRIPT_TABLE + case DLMS_OBJECT_TYPE_SCRIPT_TABLE: + size = sizeof(gxScriptTable); + break; +#endif //DLMS_IGNORE_SCRIPT_TABLE +#ifndef DLMS_IGNORE_SMTP_SETUP + case DLMS_OBJECT_TYPE_SMTP_SETUP: + size = sizeof(gxSmtpSetup); + break; +#endif //DLMS_IGNORE_SMTP_SETUP +#ifndef DLMS_IGNORE_SPECIAL_DAYS_TABLE + case DLMS_OBJECT_TYPE_SPECIAL_DAYS_TABLE: + size = sizeof(gxSpecialDaysTable); + break; +#endif //DLMS_IGNORE_SPECIAL_DAYS_TABLE +#ifndef DLMS_IGNORE_STATUS_MAPPING + case DLMS_OBJECT_TYPE_STATUS_MAPPING: + size = sizeof(gxStatusMapping); + break; +#endif //DLMS_IGNORE_STATUS_MAPPING +#ifndef DLMS_IGNORE_TCP_UDP_SETUP + case DLMS_OBJECT_TYPE_TCP_UDP_SETUP: + size = sizeof(gxTcpUdpSetup); + break; +#endif //DLMS_IGNORE_TCP_UDP_SETUP +#ifndef DLMS_IGNORE_MBUS_DIAGNOSTIC + case DLMS_OBJECT_TYPE_MBUS_DIAGNOSTIC: + size = sizeof(gxMbusDiagnostic); + break; +#endif //DLMS_IGNORE_MBUS_DIAGNOSTIC +#ifndef DLMS_IGNORE_MBUS_PORT_SETUP + case DLMS_OBJECT_TYPE_MBUS_PORT_SETUP: + size = sizeof(gxMBusPortSetup); + break; +#endif //DLMS_IGNORE_MBUS_PORT_SETUP +#ifndef DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS + case DLMS_OBJECT_TYPE_G3_PLC_MAC_LAYER_COUNTERS: + size = sizeof(gxG3PlcMacLayerCounters); + break; +#endif //DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS +#ifndef DLMS_IGNORE_G3_PLC_MAC_SETUP + case DLMS_OBJECT_TYPE_G3_PLC_MAC_SETUP: + size = sizeof(gxG3PlcMacSetup); + break; +#endif //DLMS_IGNORE_G3_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_G3_PLC_6LO_WPAN + case DLMS_OBJECT_TYPE_G3_PLC_6LO_WPAN: + size = sizeof(gxG3Plc6LoWPAN); + break; +#endif //DLMS_IGNORE_G3_PLC_6LO_WPAN +#ifndef DLMS_IGNORE_FUNCTION_CONTROL + case DLMS_OBJECT_TYPE_FUNCTION_CONTROL: + size = sizeof(gxFunctionControl); + break; +#endif //DLMS_IGNORE_FUNCTION_CONTROL +#ifndef DLMS_IGNORE_ARRAY_MANAGER + case DLMS_OBJECT_TYPE_ARRAY_MANAGER: + size = sizeof(gxArrayManager); + break; +#endif //DLMS_IGNORE_ARRAY_MANAGER +#ifndef DLMS_IGNORE_UTILITY_TABLES + case DLMS_OBJECT_TYPE_UTILITY_TABLES: + size = sizeof(gxUtilityTables); + break; +#endif //DLMS_IGNORE_UTILITY_TABLES +#ifndef DLMS_IGNORE_MBUS_MASTER_PORT_SETUP + case DLMS_OBJECT_TYPE_MBUS_MASTER_PORT_SETUP: + size = sizeof(gxMBusMasterPortSetup); + break; +#endif //DLMS_IGNORE_MBUS_MASTER_PORT_SETUP +#ifndef DLMS_IGNORE_PUSH_SETUP + case DLMS_OBJECT_TYPE_PUSH_SETUP: + size = sizeof(gxPushSetup); + break; +#endif //DLMS_IGNORE_PUSH_SETUP +#ifndef DLMS_IGNORE_DATA_PROTECTION + case DLMS_OBJECT_TYPE_DATA_PROTECTION: + size = sizeof(gxDataProtection); + break; +#endif //DLMS_IGNORE_DATA_PROTECTION +#ifndef DLMS_IGNORE_ACCOUNT + case DLMS_OBJECT_TYPE_ACCOUNT: + size = sizeof(gxAccount); + break; +#endif //DLMS_IGNORE_ACCOUNT +#ifndef DLMS_IGNORE_CREDIT + case DLMS_OBJECT_TYPE_CREDIT: + size = sizeof(gxCredit); + break; +#endif //DLMS_IGNORE_CREDIT +#ifndef DLMS_IGNORE_CHARGE + case DLMS_OBJECT_TYPE_CHARGE: + size = sizeof(gxCharge); + break; +#endif //DLMS_IGNORE_CHARGE +#ifndef DLMS_IGNORE_TOKEN_GATEWAY + case DLMS_OBJECT_TYPE_TOKEN_GATEWAY: + size = sizeof(gxTokenGateway); + break; +#endif //DLMS_IGNORE_TOKEN_GATEWAY +#ifndef DLMS_IGNORE_GSM_DIAGNOSTIC + case DLMS_OBJECT_TYPE_GSM_DIAGNOSTIC: + size = sizeof(gxGsmDiagnostic); + break; +#endif //DLMS_IGNORE_GSM_DIAGNOSTIC +#ifndef DLMS_IGNORE_COMPACT_DATA + case DLMS_OBJECT_TYPE_COMPACT_DATA: + size = sizeof(gxCompactData); + break; +#endif //DLMS_IGNORE_COMPACT_DATA +#ifndef DLMS_IGNORE_PARAMETER_MONITOR + case DLMS_OBJECT_TYPE_PARAMETER_MONITOR: + size = sizeof(gxParameterMonitor); + break; +#endif //DLMS_IGNORE_PARAMETER_MONITOR +#ifndef DLMS_IGNORE_LLC_SSCS_SETUP + case DLMS_OBJECT_TYPE_LLC_SSCS_SETUP: + size = sizeof(gxLlcSscsSetup); + break; +#endif //DLMS_IGNORE_LLC_SSCS_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS: + size = sizeof(gxPrimeNbOfdmPlcPhysicalLayerCounters); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_SETUP: + size = sizeof(gxPrimeNbOfdmPlcMacSetup); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS: + size = sizeof(gxPrimeNbOfdmPlcMacFunctionalParameters); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_COUNTERS: + size = sizeof(gxPrimeNbOfdmPlcMacCounters); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA: + size = sizeof(gxPrimeNbOfdmPlcMacNetworkAdministrationData); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION: + size = sizeof(gxPrimeNbOfdmPlcApplicationsIdentification); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION +#ifndef DLMS_IGNORE_ARBITRATOR + case DLMS_OBJECT_TYPE_ARBITRATOR: + size = sizeof(gxArbitrator); + break; +#endif //DLMS_IGNORE_ARBITRATOR +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE1_SETUP: + size = sizeof(gxIec8802LlcType1Setup); + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE2_SETUP: + size = sizeof(gxIec8802LlcType2Setup); + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE3_SETUP: + size = sizeof(gxIec8802LlcType3Setup); + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP +#ifndef DLMS_IGNORE_SFSK_ACTIVE_INITIATOR + case DLMS_OBJECT_TYPE_SFSK_ACTIVE_INITIATOR: + size = sizeof(gxSFSKActiveInitiator); + break; +#endif //DLMS_IGNORE_SFSK_ACTIVE_INITIATOR +#ifndef DLMS_IGNORE_SFSK_MAC_COUNTERS + case DLMS_OBJECT_TYPE_SFSK_MAC_COUNTERS: + size = sizeof(gxFSKMacCounters); + break; +#endif //DLMS_IGNORE_SFSK_MAC_COUNTERS +#ifndef DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS + case DLMS_OBJECT_TYPE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS: + size = sizeof(gxSFSKMacSynchronizationTimeouts); + break; +#endif //DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS +#ifndef DLMS_IGNORE_SFSK_PHY_MAC_SETUP + case DLMS_OBJECT_TYPE_SFSK_PHY_MAC_SETUP: + size = sizeof(gxSFSKPhyMacSetUp); + break; +#endif //DLMS_IGNORE_SFSK_PHY_MAC_SETUP +#ifndef DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST + case DLMS_OBJECT_TYPE_SFSK_REPORTING_SYSTEM_LIST: + size = sizeof(gxSFSKReportingSystemList); + break; +#endif //DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST +#ifdef DLMS_ITALIAN_STANDARD + case DLMS_OBJECT_TYPE_TARIFF_PLAN: + size = sizeof(gxTariffPlan); + break; +#endif //DLMS_ITALIAN_STANDARD + default: + return 0; + } +#if _MSC_VER > 1400 + { + /* + printf("Object %s size: %d\r\n", obj_typeToString2(type), size); + */ + } +#endif + return size; +} + +#ifndef DLMS_IGNORE_MALLOC +int cosem_createObject(DLMS_OBJECT_TYPE type, gxObject** object) +{ + int ret; + static unsigned char ln[] = { 0,0,40,0,0,255 }; + uint16_t size = cosem_getObjectSize(type); + if (size == 0) + { + return DLMS_ERROR_CODE_UNAVAILABLE_OBJECT; + } + *object = (gxObject*)gxcalloc(1, size); + if (*object == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + (*object)->objectType = type; + /* + #if _MSC_VER > 1400 + { + printf("Object %s size: %d\r\n", obj_typeToString2(type), (int)_msize(*object)); + } + #endif + */ + + if (type == DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME) + { + } +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + else if (type == DLMS_OBJECT_TYPE_ASSOCIATION_SHORT_NAME) + { + } + else + { + memset(ln, 0, 6); + } +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + ret = cosem_init2(*object, type, ln); + return ret; +} + +int cosem_createObject2( + DLMS_OBJECT_TYPE type, + const char* ln, + gxObject** object) +{ + int ret = cosem_createObject(type, object); + if (ret != 0) + { + return ret; + } + hlp_setLogicalName((*object)->logicalName, ln); + return 0; +} +#endif //DLMS_IGNORE_MALLOC + +int cosem_setLogicalName( + gxObject* object, + const unsigned char* value) +{ + memcpy(object->logicalName, value, 6); + return 0; +} + +#ifndef DLMS_IGNORE_MALLOC +int cosem_init( + gxObject* object, + DLMS_OBJECT_TYPE type, + const char* logicalNameString) +{ + unsigned char ln[6]; + hlp_setLogicalName(ln, logicalNameString); + return cosem_init2(object, type, ln); +} +#endif //DLMS_IGNORE_MALLOC + +int cosem_init2( + gxObject* object, + DLMS_OBJECT_TYPE type, + const unsigned char* ln) +{ + return cosem_init3(object, 0, type, ln); +} + +int cosem_init3( + gxObject* object, + const uint16_t expectedSize, + DLMS_OBJECT_TYPE type, + const unsigned char* ln) +{ + return cosem_init4((void*)object, expectedSize, type, ln); +} + +int cosem_init4( + void* object, + const uint16_t expectedSize, + DLMS_OBJECT_TYPE type, + const unsigned char* ln) +{ + uint16_t size = cosem_getObjectSize(type); + if (size == 0) + { + return DLMS_ERROR_CODE_UNAVAILABLE_OBJECT; + } + if (expectedSize != 0 && size != expectedSize) + { + return DLMS_ERROR_CODE_UNMATCH_TYPE; + } + memset(object, 0, size); + ((gxObject*)object)->objectType = type; + ((gxObject*)object)->logicalName[0] = ln[0]; + ((gxObject*)object)->logicalName[1] = ln[1]; + ((gxObject*)object)->logicalName[2] = ln[2]; + ((gxObject*)object)->logicalName[3] = ln[3]; + ((gxObject*)object)->logicalName[4] = ln[4]; + ((gxObject*)object)->logicalName[5] = ln[5]; + //Set default values, if any. + switch (type) + { + case DLMS_OBJECT_TYPE_DATA: + break; + case DLMS_OBJECT_TYPE_REGISTER: + break; + case DLMS_OBJECT_TYPE_CLOCK: + break; + case DLMS_OBJECT_TYPE_ACTION_SCHEDULE: + break; + case DLMS_OBJECT_TYPE_ACTIVITY_CALENDAR: + break; +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + case DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME: + { + gxAssociationLogicalName* it = (gxAssociationLogicalName*)object; + ((gxObject*)object)->version = 2; + it->xDLMSContextInfo.dlmsVersionNumber = 6; + it->applicationContextName.jointIsoCtt = 2; + it->applicationContextName.country = 16; + it->applicationContextName.countryName = 756; + it->applicationContextName.identifiedOrganization = 5; + it->applicationContextName.dlmsUA = 8; + it->applicationContextName.applicationContext = 1; + it->applicationContextName.contextId = DLMS_APPLICATION_CONTEXT_NAME_LOGICAL_NAME; + it->authenticationMechanismName.jointIsoCtt = 2; + it->authenticationMechanismName.country = 16; + it->authenticationMechanismName.countryName = 756; + it->authenticationMechanismName.identifiedOrganization = 5; + it->authenticationMechanismName.dlmsUA = 8; + it->authenticationMechanismName.authenticationMechanismName = 2; + it->serverSAP = 1; + } + break; +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + case DLMS_OBJECT_TYPE_ASSOCIATION_SHORT_NAME: + { + ((gxObject*)object)->shortName = 0xFA00; + ((gxObject*)object)->version = 2; + } + break; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + case DLMS_OBJECT_TYPE_AUTO_ANSWER: + break; + case DLMS_OBJECT_TYPE_AUTO_CONNECT: + ((gxObject*)object)->version = 2; + break; + case DLMS_OBJECT_TYPE_DEMAND_REGISTER: + break; + case DLMS_OBJECT_TYPE_MAC_ADDRESS_SETUP: + break; + case DLMS_OBJECT_TYPE_EXTENDED_REGISTER: + break; + case DLMS_OBJECT_TYPE_GPRS_SETUP: + break; + case DLMS_OBJECT_TYPE_SECURITY_SETUP: + break; +#ifndef DLMS_IGNORE_IEC_HDLC_SETUP + case DLMS_OBJECT_TYPE_IEC_HDLC_SETUP: + ((gxObject*)object)->version = 1; + ((gxIecHdlcSetup*)object)->communicationSpeed = DLMS_BAUD_RATE_9600; + ((gxIecHdlcSetup*)object)->windowSizeTransmit = 1; + ((gxIecHdlcSetup*)object)->windowSizeReceive = 1; + ((gxIecHdlcSetup*)object)->maximumInfoLengthTransmit = 128; + ((gxIecHdlcSetup*)object)->maximumInfoLengthReceive = 128; + ((gxIecHdlcSetup*)object)->interCharachterTimeout = 25; + ((gxIecHdlcSetup*)object)->inactivityTimeout = 120; + ((gxIecHdlcSetup*)object)->deviceAddress = 0x10; + break; +#endif //DLMS_IGNORE_IEC_HDLC_SETUP + case DLMS_OBJECT_TYPE_IEC_LOCAL_PORT_SETUP: + ((gxObject*)object)->version = 1; + break; + case DLMS_OBJECT_TYPE_IEC_TWISTED_PAIR_SETUP: + ((gxObject*)object)->version = 1; + break; + case DLMS_OBJECT_TYPE_IP4_SETUP: + break; + case DLMS_OBJECT_TYPE_IP6_SETUP: + break; + case DLMS_OBJECT_TYPE_MBUS_SLAVE_PORT_SETUP: + break; + case DLMS_OBJECT_TYPE_IMAGE_TRANSFER: + break; + case DLMS_OBJECT_TYPE_DISCONNECT_CONTROL: + break; + case DLMS_OBJECT_TYPE_LIMITER: + break; + case DLMS_OBJECT_TYPE_MBUS_CLIENT: + ((gxObject*)object)->version = 1; + break; + case DLMS_OBJECT_TYPE_MODEM_CONFIGURATION: + ((gxObject*)object)->version = 1; + break; + case DLMS_OBJECT_TYPE_PPP_SETUP: + break; +#ifndef DLMS_IGNORE_PROFILE_GENERIC + case DLMS_OBJECT_TYPE_PROFILE_GENERIC: + break; +#endif //DLMS_IGNORE_PROFILE_GENERIC + case DLMS_OBJECT_TYPE_REGISTER_ACTIVATION: + break; + case DLMS_OBJECT_TYPE_REGISTER_MONITOR: + break; + case DLMS_OBJECT_TYPE_REGISTER_TABLE: + break; + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_STARTUP: + break; + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_JOIN: + break; + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_APS_FRAGMENTATION: + break; + case DLMS_OBJECT_TYPE_ZIG_BEE_NETWORK_CONTROL: + break; + case DLMS_OBJECT_TYPE_SAP_ASSIGNMENT: + break; +#ifndef DLMS_IGNORE_SCHEDULE + case DLMS_OBJECT_TYPE_SCHEDULE: + break; +#endif //DLMS_IGNORE_SCHEDULE +#ifndef DLMS_IGNORE_SCRIPT_TABLE + case DLMS_OBJECT_TYPE_SCRIPT_TABLE: + break; +#endif //DLMS_IGNORE_SCRIPT_TABLE + case DLMS_OBJECT_TYPE_SMTP_SETUP: + break; + case DLMS_OBJECT_TYPE_SPECIAL_DAYS_TABLE: + break; + case DLMS_OBJECT_TYPE_STATUS_MAPPING: + break; +#ifndef DLMS_IGNORE_TCP_UDP_SETUP + case DLMS_OBJECT_TYPE_TCP_UDP_SETUP: + ((gxTcpUdpSetup*)object)->maximumSimultaneousConnections = 1; + ((gxTcpUdpSetup*)object)->maximumSegmentSize = 40; + ((gxTcpUdpSetup*)object)->inactivityTimeout = 180; + break; +#endif //DLMS_IGNORE_TCP_UDP_SETUP + case DLMS_OBJECT_TYPE_MBUS_DIAGNOSTIC: + break; + case DLMS_OBJECT_TYPE_UTILITY_TABLES: + break; + case DLMS_OBJECT_TYPE_MBUS_MASTER_PORT_SETUP: + break; + case DLMS_OBJECT_TYPE_PUSH_SETUP: + break; + case DLMS_OBJECT_TYPE_DATA_PROTECTION: + break; + case DLMS_OBJECT_TYPE_ACCOUNT: + break; + case DLMS_OBJECT_TYPE_CREDIT: + break; + case DLMS_OBJECT_TYPE_CHARGE: + break; + case DLMS_OBJECT_TYPE_TOKEN_GATEWAY: + break; + case DLMS_OBJECT_TYPE_GSM_DIAGNOSTIC: + ((gxObject*)object)->version = 1; + break; + case DLMS_OBJECT_TYPE_G3_PLC_MAC_LAYER_COUNTERS: + ((gxObject*)object)->version = 1; + break; + case DLMS_OBJECT_TYPE_G3_PLC_MAC_SETUP: + ((gxObject*)object)->version = 3; + break; + case DLMS_OBJECT_TYPE_G3_PLC_6LO_WPAN: + ((gxObject*)object)->version = 3; + break; + case DLMS_OBJECT_TYPE_FUNCTION_CONTROL: + break; + default: + break; + } + return 0; +} + +int cosem_checkStructure(gxByteBuffer* bb, uint16_t expectedItemCount) +{ + int ret; + uint16_t cnt; + if ((ret = cosem_getStructure(bb, &cnt)) == 0) + { + if (cnt != expectedItemCount) + { + ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } + } + return ret; +} + +int cosem_getStructure(gxByteBuffer* bb, uint16_t* count) +{ + int ret; + unsigned char value; + uint16_t cnt; + if ((ret = bb_getUInt8(bb, &value)) != 0) + { + return ret; + } + if (value != DLMS_DATA_TYPE_STRUCTURE) + { + return DLMS_ERROR_CODE_UNMATCH_TYPE; + } + //Get structure count. + if ((ret = hlp_getObjectCount2(bb, &cnt)) != 0) + { + return ret; + } + *count = cnt; + return 0; +} + +int cosem_checkArray(gxByteBuffer* bb, uint16_t* count) +{ + return cosem_checkArray2(bb, count, 1); +} + +int cosem_checkArray2(gxByteBuffer* bb, uint16_t* count, unsigned char checkDataType) +{ + int ret; + unsigned char ch; + uint16_t cnt; + if (checkDataType) + { + if ((ret = bb_getUInt8(bb, &ch)) != 0) + { + return ret; + } + if (ch != DLMS_DATA_TYPE_ARRAY) + { + return DLMS_ERROR_CODE_UNMATCH_TYPE; + } + } + //Get array count. + if ((ret = hlp_getObjectCount2(bb, &cnt)) != 0) + { + return ret; + } +#ifndef DLMS_COSEM_EXACT_DATA_TYPES + if (*count < cnt) + { + return DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } +#endif //DLMS_COSEM_EXACT_DATA_TYPES + * count = cnt; + return 0; +} + +int cosem_getUInt8(gxByteBuffer* bb, unsigned char* value) +{ + int ret; + unsigned char tmp; + if ((ret = bb_getUInt8(bb, &tmp)) != 0) + { + return ret; + } + if (tmp != DLMS_DATA_TYPE_UINT8) + { + return DLMS_ERROR_CODE_UNMATCH_TYPE; + } + if ((ret = bb_getUInt8(bb, value)) != 0) + { + return ret; + } + return 0; +} + +int cosem_getUInt16(gxByteBuffer* bb, uint16_t* value) +{ + int ret; + unsigned char tmp; + if ((ret = bb_getUInt8(bb, &tmp)) != 0) + { + return ret; + } + if (tmp != DLMS_DATA_TYPE_UINT16) + { + return DLMS_ERROR_CODE_UNMATCH_TYPE; + } + if ((ret = bb_getUInt16(bb, value)) != 0) + { + return ret; + } + return 0; +} + +int cosem_getUInt32(gxByteBuffer* bb, uint32_t* value) +{ + int ret; + unsigned char tmp; + if ((ret = bb_getUInt8(bb, &tmp)) != 0) + { + return ret; + } + if (tmp != DLMS_DATA_TYPE_UINT32) + { + return DLMS_ERROR_CODE_UNMATCH_TYPE; + } + if ((ret = bb_getUInt32(bb, value)) != 0) + { + return ret; + } + return 0; +} + +int cosem_getInt8(gxByteBuffer* bb, signed char* value) +{ + int ret; + unsigned char tmp; + if ((ret = bb_getUInt8(bb, &tmp)) != 0) + { + return ret; + } + if (tmp != DLMS_DATA_TYPE_INT8) + { + return DLMS_ERROR_CODE_UNMATCH_TYPE; + } + if ((ret = bb_getInt8(bb, value)) != 0) + { + return ret; + } + return 0; +} + +int cosem_getInt16(gxByteBuffer* bb, int16_t* value) +{ + int ret; + unsigned char tmp; + if ((ret = bb_getUInt8(bb, &tmp)) != 0) + { + return ret; + } + if (tmp != DLMS_DATA_TYPE_INT16) + { + return DLMS_ERROR_CODE_UNMATCH_TYPE; + } + if ((ret = bb_getInt16(bb, value)) != 0) + { + return ret; + } + return 0; +} + +int cosem_getInt32(gxByteBuffer* bb, int32_t* value) +{ + int ret; + unsigned char tmp; + if ((ret = bb_getUInt8(bb, &tmp)) != 0) + { + return ret; + } + if (tmp != DLMS_DATA_TYPE_INT32) + { + return DLMS_ERROR_CODE_UNMATCH_TYPE; + } + if ((ret = bb_getInt32(bb, value)) != 0) + { + return ret; + } + return 0; +} + +int cosem_getOctetStringBase(gxByteBuffer* bb, gxByteBuffer* value, unsigned char type, unsigned char exact) +{ + int ret; + unsigned char tmp; + uint16_t count; + if ((ret = bb_getUInt8(bb, &tmp)) != 0) + { + return ret; + } + if (tmp != type) + { + return DLMS_ERROR_CODE_UNMATCH_TYPE; + } + if ((ret = hlp_getObjectCount2(bb, &count)) != 0) + { + return ret; + } + if (exact && count != bb_getCapacity(value)) + { + return DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } + if ((ret = bb_clear(value)) != 0 || + (ret = bb_set2(value, bb, bb->position, count)) != 0) + { + return ret; + } + return 0; +} + +int cosem_getOctetStringBase2(gxByteBuffer* bb, unsigned char* value, uint16_t capacity, uint16_t* size, unsigned char type) +{ + int ret; + unsigned char tmp; + uint16_t count; + memset(value, 0, capacity); + if ((ret = bb_getUInt8(bb, &tmp)) != 0) + { + return ret; + } + if (tmp != type) + { + return DLMS_ERROR_CODE_UNMATCH_TYPE; + } + if ((ret = hlp_getObjectCount2(bb, &count)) != 0) + { + return ret; + } + if (count > capacity) + { + return DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } + if (size != NULL) + { + *size = count; + } + return bb_get(bb, value, count); +} + +int cosem_getOctetString(gxByteBuffer* bb, gxByteBuffer* value) +{ + return cosem_getOctetStringBase(bb, value, DLMS_DATA_TYPE_OCTET_STRING, 0); +} + +int cosem_getString(gxByteBuffer* bb, gxByteBuffer* value) +{ + return cosem_getOctetStringBase(bb, value, DLMS_DATA_TYPE_STRING, 0); +} + +int cosem_getOctetString2(gxByteBuffer* bb, unsigned char* value, uint16_t capacity, uint16_t* size) +{ + return cosem_getOctetStringBase2(bb, value, capacity, size, DLMS_DATA_TYPE_OCTET_STRING); +} + +int cosem_getOctetString3(gxByteBuffer* bb, gxByteBuffer* value, unsigned char exact) +{ + return cosem_getOctetStringBase(bb, value, DLMS_DATA_TYPE_OCTET_STRING, exact); +} + +int cosem_getString2(gxByteBuffer* bb, char* value, uint16_t capacity) +{ + uint16_t size; + if (capacity != 0) + { + --capacity; + } + int ret = cosem_getOctetStringBase2(bb, (unsigned char*)value, capacity, &size, DLMS_DATA_TYPE_STRING); + if (ret == 0) + { + value[size] = 0; + } + return ret; +} + +int cosem_getDateTimeBase( + gxByteBuffer* bb, + gxtime* value, + unsigned char type, + unsigned char checkDataType) +{ + int ret; + unsigned char ch; + gxDataInfo info; + dlmsVARIANT tmp; + time_clear(value); + if (checkDataType) + { + if ((ret = bb_getUInt8(bb, &ch)) != 0) + { + return ret; + } + if (ch != type) + { + return DLMS_ERROR_CODE_UNMATCH_TYPE; + } + } +#ifdef DLMS_IGNORE_MALLOC + GX_DATETIME(tmp) = value; +#else + var_init(&tmp); +#endif //DLMS_IGNORE_MALLOC + di_init(&info); + info.type = (DLMS_DATA_TYPE)type; + ret = dlms_getData(bb, &info, &tmp); +#ifndef DLMS_IGNORE_MALLOC + if (ret == 0) + { + *value = *tmp.dateTime; + var_clear(&tmp); + } +#endif //DLMS_IGNORE_MALLOC + return ret; +} + +//Get date time value from octect string. +int cosem_getDateTimeFromOctetStringBase( + gxByteBuffer* bb, + gxtime* value, + unsigned char type, + unsigned char checkDataType) +{ + int ret; + unsigned char ch; + uint16_t count; + gxDataInfo info; + dlmsVARIANT tmp; + time_clear(value); + GX_DATETIME(tmp) = value; + if (checkDataType) + { + if ((ret = bb_getUInt8(bb, &ch)) != 0) + { + return ret; + } + if (ch != DLMS_DATA_TYPE_OCTET_STRING) + { + return DLMS_ERROR_CODE_UNMATCH_TYPE; + } + } + if ((ret = hlp_getObjectCount2(bb, &count)) != 0) + { + return ret; + } + if (type == DLMS_DATA_TYPE_DATETIME) + { + if (count != 12) + { + return DLMS_ERROR_CODE_UNMATCH_TYPE; + } + } + else if (type == DLMS_DATA_TYPE_DATE) + { + if (count != 5) + { + return DLMS_ERROR_CODE_UNMATCH_TYPE; + } + } + else if (type == DLMS_DATA_TYPE_TIME) + { + if (count != 4) + { + return DLMS_ERROR_CODE_UNMATCH_TYPE; + } + } + di_init(&info); + info.type = (DLMS_DATA_TYPE)type; + return dlms_getData(bb, &info, &tmp); +} + +int cosem_getDateTimeFromOctetString(gxByteBuffer* bb, gxtime* value) +{ + return cosem_getDateTimeFromOctetStringBase(bb, value, DLMS_DATA_TYPE_DATETIME, 1); +} + +int cosem_getDateFromOctetString(gxByteBuffer* bb, gxtime* value) +{ + return cosem_getDateTimeFromOctetStringBase(bb, value, DLMS_DATA_TYPE_DATE, 1); +} + +int cosem_getTimeFromOctetString(gxByteBuffer* bb, gxtime* value) +{ + return cosem_getDateTimeFromOctetStringBase(bb, value, DLMS_DATA_TYPE_TIME, 1); +} + +int cosem_getDateTimeFromOctetString2(gxByteBuffer* bb, gxtime* value, unsigned char checkDataType) +{ + return cosem_getDateTimeFromOctetStringBase(bb, value, DLMS_DATA_TYPE_DATETIME, checkDataType); +} + +int cosem_getDateFromOctetString2(gxByteBuffer* bb, gxtime* value, unsigned char checkDataType) +{ + return cosem_getDateTimeFromOctetStringBase(bb, value, DLMS_DATA_TYPE_DATE, checkDataType); +} + +int cosem_getTimeFromOctetString2(gxByteBuffer* bb, gxtime* value, unsigned char checkDataType) +{ + return cosem_getDateTimeFromOctetStringBase(bb, value, DLMS_DATA_TYPE_TIME, checkDataType); +} + +int cosem_getBitString2(gxByteBuffer* bb, unsigned char* value, uint16_t capacity, uint16_t* size) +{ + int ret; + unsigned char ch; + uint16_t count; + bitArray tmp; + ba_attach(&tmp, value, 0, capacity); + if ((ret = bb_getUInt8(bb, &ch)) != 0) + { + return ret; + } + if (ch != DLMS_DATA_TYPE_BIT_STRING) + { + return DLMS_ERROR_CODE_UNMATCH_TYPE; + } + if ((ret = hlp_getObjectCount2(bb, &count)) != 0) + { + return ret; + } + ret = hlp_add(&tmp, bb, count); + if (ret == 0) + { + *size = (unsigned short)bb->size; + } + return ret; +} + +int cosem_getBitString(gxByteBuffer* bb, bitArray* value) +{ + int ret; + unsigned char ch; + uint16_t count; + ba_clear(value); + if ((ret = bb_getUInt8(bb, &ch)) != 0) + { + return ret; + } + if (ch != DLMS_DATA_TYPE_BIT_STRING) + { + return DLMS_ERROR_CODE_UNMATCH_TYPE; + } + if ((ret = hlp_getObjectCount2(bb, &count)) != 0) + { + return ret; + } + return hlp_add(value, bb, count); +} + +int cosem_getIntegerFromBitString(gxByteBuffer* bb, uint32_t* value) +{ + int ret; + unsigned char ch; + uint16_t count; + bitArray ba; + if ((ret = bb_getUInt8(bb, &ch)) != 0) + { + return ret; + } + if (ch != DLMS_DATA_TYPE_BIT_STRING) + { + return DLMS_ERROR_CODE_UNMATCH_TYPE; + } + if ((ret = hlp_getObjectCount2(bb, &count)) != 0) + { + return ret; + } + ba_attach(&ba, bb->data + bb->position, count, count); + bb->position += ba_getByteCount(count); + return ba_toInteger(&ba, value); +} + +int cosem_getVariant(gxByteBuffer* bb, dlmsVARIANT* value) +{ + int ret; + unsigned char ch; + gxDataInfo info; + var_clear(value); + if ((ret = bb_getUInt8(bb, &ch)) == 0) + { + if (ch != DLMS_DATA_TYPE_NONE) + { + di_init(&info); + --bb->position; + ret = dlms_getData(bb, &info, value); + } + } + return ret; +} + +int cosem_getEnum(gxByteBuffer* bb, unsigned char* value) +{ + int ret; + unsigned char tmp; + if ((ret = bb_getUInt8(bb, &tmp)) != 0) + { + return ret; + } + if (tmp != DLMS_DATA_TYPE_ENUM) + { + return DLMS_ERROR_CODE_UNMATCH_TYPE; + } + if ((ret = bb_getUInt8(bb, value)) != 0) + { + return ret; + } + return 0; +} + +int cosem_getBoolean(gxByteBuffer* bb, unsigned char* value) +{ + int ret; + unsigned char tmp; + if ((ret = bb_getUInt8(bb, &tmp)) != 0) + { + return ret; + } + if (tmp != DLMS_DATA_TYPE_BOOLEAN) + { + return DLMS_ERROR_CODE_UNMATCH_TYPE; + } + if ((ret = bb_getUInt8(bb, value)) != 0) + { + return ret; + } + return 0; +} + +int cosem_getUtf8String(gxByteBuffer* bb, gxByteBuffer* value) +{ + return cosem_getOctetStringBase(bb, value, DLMS_DATA_TYPE_STRING_UTF8, 0); +} + +int cosem_getUtf8String2(gxByteBuffer* bb, char* value, uint16_t capacity, uint16_t* size) +{ + return cosem_getOctetStringBase2(bb, (unsigned char*)value, capacity, size, DLMS_DATA_TYPE_STRING_UTF8); +} + +int cosem_setDateTimeAsOctetString(gxByteBuffer* bb, gxtime* value) +{ + int ret; + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(bb, 12)) != 0 || + (ret = var_getDateTime2(value, bb)) != 0) + { + //Error code is returned at the end of the function. + } + return ret; +} + +int cosem_setDateAsOctetString(gxByteBuffer* bb, gxtime* value) +{ + int ret; + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(bb, 5)) != 0 || + (ret = var_getDate(value, bb)) != 0) + { + //Error code is returned at the end of the function. + } + return ret; +} + +int cosem_setBitString(gxByteBuffer* bb, uint32_t value, uint16_t count) +{ + int ret = 0; + uint16_t pos; + uint16_t capacity = count == 0 ? 2 : (3 + (count / 8)); + capacity += (uint16_t)bb_size(bb); + if (bb_getCapacity(bb) < capacity) + { + ret = bb_capacity(bb, capacity); + } + if (ret == 0 && + (ret = bb_setUInt8(bb, DLMS_DATA_TYPE_BIT_STRING)) == 0 && + (ret = hlp_setObjectCount(count, bb)) == 0) + { + bitArray ba; + ba_attach(&ba, bb->data + bb->size, 0, (uint16_t)(8 * (bb->size - bb->size))); + for (pos = 0; pos != count; ++pos) + { + if ((ret = ba_setByIndex(&ba, pos, value & 01)) != 0) + { + break; + } + value >>= 1; + } + bb->size += ba_getByteCount(count); + } + return ret; +} + + +int cosem_setTimeAsOctetString(gxByteBuffer* bb, gxtime* value) +{ + int ret; + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(bb, 4)) != 0 || + (ret = var_getTime(value, bb)) != 0) + { + //Error code is returned at the end of the function. + } + return ret; +} + +int cosem_setOctetString(gxByteBuffer* bb, gxByteBuffer* value) +{ + int ret; + if (value == NULL) + { + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(bb, 0)) != 0) + { + //Error code is returned at the end of the function. + } + } + else if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(bb, (unsigned char)value->size)) != 0 || + (ret = bb_set(bb, value->data, (uint16_t)value->size)) != 0) + { + //Error code is returned at the end of the function. + } + return ret; +} + +int cosem_setString(gxByteBuffer* bb, const char* value, uint16_t len) +{ + int ret; + if (value == NULL || len == 0) + { + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_STRING)) != 0 || + (ret = bb_setUInt8(bb, 0)) != 0) + { + //Error code is returned at the end of the function. + } + } + else + { + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_STRING)) != 0 || + (ret = hlp_setObjectCount(len, bb)) != 0 || + (ret = bb_set(bb, (unsigned char*)value, len)) != 0) + { + //Error code is returned at the end of the function. + } + } + return ret; +} + + +int cosem_setString2(gxByteBuffer* bb, gxByteBuffer* value) +{ + int ret; + uint16_t len = (uint16_t)bb_size(value); + if (bb_size(value) == 0) + { + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_STRING)) != 0 || + (ret = bb_setUInt8(bb, 0)) != 0) + { + //Error code is returned at the end of the function. + } + } + else + { + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_STRING)) != 0 || + (ret = hlp_setObjectCount(len, bb)) != 0 || + (ret = bb_set(bb, value->data, len)) != 0) + { + //Error code is returned at the end of the function. + } + } + return ret; +} + +int cosem_setDateTime(gxByteBuffer* bb, gxtime* value) +{ + int ret; + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_DATETIME)) != 0 || + (ret = var_getDateTime2(value, bb)) != 0) + { + //Error code is returned at the end of the function. + } + return ret; +} + +int cosem_setDate(gxByteBuffer* bb, gxtime* value) +{ + int ret; + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_DATE)) != 0 || + (ret = var_getDate(value, bb)) != 0) + { + //Error code is returned at the end of the function. + } + return ret; +} + +int cosem_setTime(gxByteBuffer* bb, gxtime* value) +{ + int ret; + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_TIME)) != 0 || + (ret = var_getTime(value, bb)) != 0) + { + //Error code is returned at the end of the function. + } + return ret; +} + + +int cosem_setOctetString2( + gxByteBuffer* bb, + const unsigned char* value, + uint16_t size) +{ + int ret; + if (value == NULL || size == 0) + { + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(bb, 0)) != 0) + { + //Error code is returned at the end of the function. + } + } + else if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(bb, (unsigned char)size)) != 0 || + (ret = bb_set(bb, value, size)) != 0) + { + //Error code is returned at the end of the function. + } + return ret; +} + +int cosem_getDateTime(gxByteBuffer* bb, gxtime* value) +{ + return cosem_getDateTimeBase(bb, value, DLMS_DATA_TYPE_DATETIME, 1); +} + +int cosem_getDate(gxByteBuffer* bb, gxtime* value) +{ + return cosem_getDateTimeBase(bb, value, DLMS_DATA_TYPE_DATE, 1); +} + +int cosem_getTime(gxByteBuffer* bb, gxtime* value) +{ + return cosem_getDateTimeBase(bb, value, DLMS_DATA_TYPE_TIME, 1); +} + +int cosem_getDateTime2(gxByteBuffer* bb, gxtime* value, unsigned char checkDataType) +{ + return cosem_getDateTimeBase(bb, value, DLMS_DATA_TYPE_DATETIME, checkDataType); +} + +int cosem_getDate2(gxByteBuffer* bb, gxtime* value, unsigned char checkDataType) +{ + return cosem_getDateTimeBase(bb, value, DLMS_DATA_TYPE_DATE, checkDataType); +} + +int cosem_getTime2(gxByteBuffer* bb, gxtime* value, unsigned char checkDataType) +{ + return cosem_getDateTimeBase(bb, value, DLMS_DATA_TYPE_TIME, checkDataType); +} + +int cosem_setUInt8(gxByteBuffer* bb, unsigned char value) +{ + int ret; + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_UINT8)) != 0 || + (ret = bb_setUInt8(bb, value)) != 0) + { + //Error code is returned at the end of the function. + } + return ret; +} + +int cosem_setUInt16(gxByteBuffer* bb, uint16_t value) +{ + int ret; + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(bb, value)) != 0) + { + //Error code is returned at the end of the function. + } + return ret; +} + +int cosem_setUInt32(gxByteBuffer* bb, uint32_t value) +{ + int ret; + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_UINT32)) != 0 || + (ret = bb_setUInt32(bb, value)) != 0) + { + //Error code is returned at the end of the function. + } + return ret; +} + +int cosem_setUInt64(gxByteBuffer* bb, uint64_t* value) +{ + int ret; + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_UINT64)) != 0 || + (ret = bb_setUInt64(bb, *value)) != 0) + { + //Error code is returned at the end of the function. + } + return ret; +} + +int cosem_setInt8(gxByteBuffer* bb, char value) +{ + int ret; + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_INT8)) != 0 || + (ret = bb_setInt8(bb, value)) != 0) + { + //Error code is returned at the end of the function. + } + return ret; +} + +int cosem_setInt16(gxByteBuffer* bb, int16_t value) +{ + int ret; + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_INT16)) != 0 || + (ret = bb_setInt16(bb, value)) != 0) + { + //Error code is returned at the end of the function. + } + return ret; +} + +int cosem_setInt32(gxByteBuffer* bb, int32_t value) +{ + int ret; + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_INT32)) != 0 || + (ret = bb_setInt32(bb, value)) != 0) + { + //Error code is returned at the end of the function. + } + return ret; +} + +int cosem_setInt64(gxByteBuffer* bb, int64_t* value) +{ + int ret; + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_INT64)) != 0 || + (ret = bb_setInt64(bb, *value)) != 0) + { + //Error code is returned at the end of the function. + } + return ret; +} + +int cosem_setVariant(gxByteBuffer* bb, dlmsVARIANT* value) +{ + if (value->vt == DLMS_DATA_TYPE_NONE) + { + return bb_setUInt8(bb, 0); + } + return dlms_setData(bb, value->vt, value); +} + +int cosem_setStructure(gxByteBuffer* bb, uint16_t count) +{ + int ret; + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = hlp_setObjectCount(count, bb)) != 0) + { + //Error code is returned at the end of the function. + } + return ret; +} + +int cosem_setArray(gxByteBuffer* bb, uint16_t count) +{ + int ret; + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_ARRAY)) != 0 || + (ret = hlp_setObjectCount(count, bb)) != 0) + { + //Error code is returned at the end of the function. + } + return ret; +} + +int cosem_setEnum(gxByteBuffer* bb, unsigned char value) +{ + int ret; + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_ENUM)) != 0 || + (ret = bb_setInt8(bb, value)) != 0) + { + //Error code is returned at the end of the function. + } + return ret; +} + +int cosem_setBoolean(gxByteBuffer* bb, unsigned char value) +{ + int ret; + if ((ret = bb_setUInt8(bb, DLMS_DATA_TYPE_BOOLEAN)) != 0 || + (ret = bb_setInt8(bb, value)) != 0) + { + //Error code is returned at the end of the function. + } + return ret; +} + +#ifndef DLMS_IGNORE_PROFILE_GENERIC + +/** + * Get selected columns. + * + * @param cols + * selected columns. + * @param columns + * Selected columns. + */ +#ifndef DLMS_IGNORE_MALLOC +int getSelectedColumns( + gxArray* captureObjects, + variantArray* cols, + gxArray* columns) +{ + gxKey* c; + dlmsVARIANT* it, * it2; + unsigned char* ln; + DLMS_OBJECT_TYPE ot; + int ret, dataIndex; + uint16_t pos, pos2; + unsigned char attributeIndex; + for (pos = 0; pos != cols->size; ++pos) + { + if ((ret = va_getByIndex(cols, pos, &it)) != 0 || + //Get object type. + (ret = va_getByIndex(it->Arr, 0, &it2)) != 0) + { + break; + } + ot = (DLMS_OBJECT_TYPE)var_toInteger(it2); + //Get logical name. + if ((ret = va_getByIndex(it->Arr, 1, &it2)) != 0) + { + break; + } + ln = it2->byteArr->data; + //Get attribute index. + if ((ret = va_getByIndex(it->Arr, 2, &it2)) != 0) + { + break; + } + attributeIndex = (char)var_toInteger(it2); + //Get data index. + if ((ret = va_getByIndex(it->Arr, 3, &it2)) != 0) + { + break; + } + dataIndex = var_toInteger(it2); + // Find columns and update only them. + for (pos2 = 0; pos2 != captureObjects->size; ++pos2) + { + if ((ret = arr_getByIndex(captureObjects, pos2, (void**)&c)) != 0) + { + return ret; + } + if (((gxObject*)c->key)->objectType == ot && + ((gxTarget*)c->value)->attributeIndex == attributeIndex && + ((gxTarget*)c->value)->dataIndex == dataIndex && + memcmp(((gxObject*)c->key)->logicalName, ln, 6) == 0) + { + if ((ret = arr_push(columns, c)) != 0) + { + return ret; + } + break; + } + } + } + return 0; +} +#endif //DLMS_IGNORE_MALLOC + +int cosem_getColumns( + gxArray* captureObjects, + unsigned char selector, + dlmsVARIANT* parameters, + gxArray* columns) +{ + uint16_t pos, start = 0, count = 0; + int ret = 0; + arr_empty(columns); +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + int index = 0; + gxTarget* k; + gxTarget* k2; + if (selector == 1) //Read by range + { + count = arr_getCapacity(columns); + if ((ret = cosem_checkArray(parameters->byteArr, &count)) != 0) + { + return ret; + } + //Add all. + if (count == 0) + { + count = captureObjects->size; + columns->size = count; + for (pos = 0; pos != count; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(captureObjects, pos, (void**)&k)) != 0 || + (ret = arr_getByIndex(columns, pos, (void**)&k2)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(captureObjects, pos, (void**)&k, sizeof(gxTarget))) != 0 || + (ret = arr_getByIndex(columns, pos, (void**)&k2, sizeof(gxTarget))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + memcpy(k2, k, sizeof(gxTarget)); + } + } + else + { + int pos2; + uint16_t ot; + unsigned char ln[6]; + signed char aIndex; + short dIndex; + columns->size = 0; + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_checkStructure(parameters->byteArr, 4)) != 0 || + (ret = cosem_getUInt16(parameters->byteArr, &ot)) != 0 || + (ret = cosem_getOctetString2(parameters->byteArr, ln, 6, NULL)) != 0 || + (ret = cosem_getInt8(parameters->byteArr, &aIndex)) != 0 || + (ret = cosem_getInt16(parameters->byteArr, &dIndex)) != 0) + { + break; + } + for (pos2 = 0; pos2 != captureObjects->size; ++pos2) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(captureObjects, pos2, (void**)&k)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(captureObjects, pos2, (void**)&k, sizeof(gxTarget))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC +#ifdef DLMS_IGNORE_OBJECT_POINTERS + if (k->objectType == ot && memcmp(k->logicalName, ln, 6) == 0) +#else + if (k->target->objectType == ot && memcmp(k->target->logicalName, ln, 6) == 0) +#endif //DLMS_IGNORE_OBJECT_POINTERS + { + if (!(columns->size < arr_getCapacity(columns))) + { + return DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } + ++columns->size; +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(columns, index, (void**)&k2)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(columns, index, (void**)&k2, sizeof(gxTarget))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + memcpy(k2, k, sizeof(gxTarget)); + ++index; + break; + } + } + } + } + } + else if (selector == 2) //Read by entry. + { + if ((ret = cosem_getUInt16(parameters->byteArr, &start)) != 0 || + (ret = cosem_getUInt16(parameters->byteArr, &count)) != 0) + { + return ret; + } + if (count == 0) + { + count = captureObjects->size - start + 1; + } + if (!(count <= captureObjects->size || start < count)) + { + return DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } + columns->size = count; + for (pos = start - 1; pos != count; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(captureObjects, pos, (void**)&k)) != 0 || + (ret = arr_getByIndex(columns, index, (void**)&k2)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(captureObjects, pos, (void**)&k, sizeof(gxTarget))) != 0 || + (ret = arr_getByIndex(columns, index, (void**)&k2, sizeof(gxTarget))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + memcpy(k2, k, sizeof(gxTarget)); + ++index; + } + } +#else + uint16_t addAllColumns = 1; + gxKey* k; + dlmsVARIANT* it; + if (parameters->vt == DLMS_DATA_TYPE_STRUCTURE) + { + if (selector == 1) //Read by range + { + if (parameters->Arr->size > 3) + { + if ((ret = va_getByIndex(parameters->Arr, 3, &it)) == 0) + { + ret = getSelectedColumns(captureObjects, it->Arr, columns); + } + addAllColumns = 0; + } + } + else if (selector == 2) //Read by entry. + { + if (parameters->Arr->size > 2) + { + if ((ret = va_getByIndex(parameters->Arr, 2, &it)) != 0) + { + return ret; + } + start = (uint16_t)var_toInteger(it); + } + if (parameters->Arr->size > 3) + { + if ((ret = va_getByIndex(parameters->Arr, 3, &it)) != 0) + { + return ret; + } + count = (uint16_t)var_toInteger(it); + } + else if (start != 1) + { + count = captureObjects->size; + } + if (start != 1 || count != 0) + { + addAllColumns = 0; + if (count == 0) + { + count = captureObjects->size - start; + } + for (pos = start - 1; pos != count; ++pos) + { + if ((ret = arr_getByIndex(captureObjects, pos, (void**)&k)) != 0 || + (ret = arr_push(columns, k)) != 0) + { + return ret; + } + } + } + } + //Add all objects. + if (addAllColumns) + { + for (pos = 0; pos != captureObjects->size; ++pos) + { + if ((ret = arr_getByIndex(captureObjects, pos, (void**)&k)) != 0 || + (ret = arr_push(columns, k)) != 0) + { + break; + } + } + } + } +#endif //DLMS_IGNORE_MALLOC + return ret; +} +#endif //DLMS_IGNORE_PROFILE_GENERIC + +int cosem_findObjectByLN( + dlmsSettings* settings, + DLMS_OBJECT_TYPE ot, + const unsigned char* ln, + gxObject** object) +{ + int ret; + if (memcmp(ln, EMPTY_LN, sizeof(EMPTY_LN)) != 0) + { + if ((ret = oa_findByLN(&settings->objects, ot, ln, object)) == 0) + { +#ifndef DLMS_IGNORE_MALLOC + if (*object == NULL) + { + if ((ret = oa_findByLN(&settings->releasedObjects, ot, ln, object)) == 0) + { + if (*object == NULL && ot != DLMS_OBJECT_TYPE_NONE) + { + if ((ret = cosem_createObject(ot, object)) == 0) + { + memcpy((*object)->logicalName, ln, 6); + oa_push(&settings->releasedObjects, *object); + } + } + } + } +#endif //DLMS_IGNORE_MALLOC + } + } + else + { + *object = NULL; + ret = 0; + } + return ret; +} \ No newline at end of file diff --git a/components/xt211/cosem.h b/components/xt211/cosem.h new file mode 100644 index 0000000..b212875 --- /dev/null +++ b/components/xt211/cosem.h @@ -0,0 +1,229 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef COSEM_H +#define COSEM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "gxobjects.h" +#include "dlmssettings.h" + +#ifndef DLMS_IGNORE_MALLOC + int cosem_createObject( + DLMS_OBJECT_TYPE type, + gxObject** object); + + int cosem_createObject2( + DLMS_OBJECT_TYPE type, + const char* ln, + gxObject** object); +#endif //DLMS_IGNORE_MALLOC + + int cosem_setLogicalName( + gxObject* object, + const unsigned char* value); + +#ifndef DLMS_IGNORE_MALLOC + int cosem_init( + gxObject* object, + DLMS_OBJECT_TYPE type, + const char* logicalNameString); +#endif //DLMS_IGNORE_MALLOC + + int cosem_init2( + gxObject* object, + DLMS_OBJECT_TYPE type, + const unsigned char* ln); + + //This initialize method will also check the size of the object type and compare it with the expected size. + int cosem_init3( + gxObject* object, + const uint16_t expectedSize, + DLMS_OBJECT_TYPE type, + const unsigned char* ln); + + //This initialize method will also check the size of the object type and compare it with the expected size. + int cosem_init4( + void* object, + const uint16_t expectedSize, + DLMS_OBJECT_TYPE type, + const unsigned char* ln); + + int cosem_checkStructure(gxByteBuffer* bb, uint16_t expectedItemCount); + + int cosem_getStructure(gxByteBuffer* bb, uint16_t* count); + + int cosem_checkArray(gxByteBuffer* bb, uint16_t* count); + + int cosem_checkArray2(gxByteBuffer* bb, uint16_t* count, unsigned char checkDataType); + + int cosem_getUInt8(gxByteBuffer* bb, unsigned char* value); + + int cosem_getUInt16(gxByteBuffer* bb, uint16_t* value); + + int cosem_getUInt32(gxByteBuffer* bb, uint32_t* value); + + int cosem_getInt8(gxByteBuffer* bb, signed char* value); + + int cosem_getInt16(gxByteBuffer* bb, int16_t* value); + + int cosem_getInt32(gxByteBuffer* bb, int32_t* value); + + int cosem_getOctetString(gxByteBuffer* bb, gxByteBuffer* value); + + + int cosem_getString(gxByteBuffer* bb, gxByteBuffer* value); + + int cosem_getOctetString2(gxByteBuffer* bb, unsigned char* value, uint16_t capacity, uint16_t* size); + + int cosem_getOctetString3(gxByteBuffer* bb, gxByteBuffer* value, unsigned char exact); + + int cosem_getString2(gxByteBuffer* bb, char* value, uint16_t capacity); + + //Get date-time value from the octet-string. + int cosem_getDateTimeFromOctetString(gxByteBuffer* bb, gxtime* value); + + //Get date-time value from the octet-string. + int cosem_getDateFromOctetString(gxByteBuffer* bb, gxtime* value); + + //Get date-time value from the octet-string. + int cosem_getTimeFromOctetString(gxByteBuffer* bb, gxtime* value); + + //Get date-time value from the octet-string. + int cosem_getDateTimeFromOctetString2(gxByteBuffer* bb, gxtime* value, unsigned char checkDataType); + + //Get date-time value from the octet-string. + int cosem_getDateFromOctetString2(gxByteBuffer* bb, gxtime* value, unsigned char checkDataType); + + //Get date-time value from the octet-string. + int cosem_getTimeFromOctetString2(gxByteBuffer* bb, gxtime* value, unsigned char checkDataType); + + //Get date-time value from the byte array. + int cosem_getDateTime(gxByteBuffer* bb, gxtime* value); + + //Get date value from the byte array. + int cosem_getDate(gxByteBuffer* bb, gxtime* value); + + //Get time value from the byte array. + int cosem_getTime(gxByteBuffer* bb, gxtime* value); + + //Get date-time value from the byte array. + int cosem_getDateTime2(gxByteBuffer* bb, gxtime* value, unsigned char checkDataType); + + //Get date value from the byte array. + int cosem_getDate2(gxByteBuffer* bb, gxtime* value, unsigned char checkDataType); + + //Get time value from the byte array. + int cosem_getTime2(gxByteBuffer* bb, gxtime* value, unsigned char checkDataType); + + //Get get bit string from the byte array. + int cosem_getBitString(gxByteBuffer* bb, bitArray* value); + //Get get bit string from the byte array. + int cosem_getBitString2(gxByteBuffer* bb, unsigned char* value, uint16_t capacity, uint16_t* size); + + //Get integer value from bit string. + int cosem_getIntegerFromBitString(gxByteBuffer* bb, uint32_t* value); + + int cosem_getVariant(gxByteBuffer* bb, dlmsVARIANT* value); + + int cosem_getEnum(gxByteBuffer* bb, unsigned char* value); + + int cosem_getBoolean(gxByteBuffer* bb, unsigned char* value); + + int cosem_getUtf8String(gxByteBuffer* bb, gxByteBuffer* value); + + int cosem_getUtf8String2(gxByteBuffer* bb, char* value, uint16_t capacity, uint16_t* size); + + int cosem_setDateTimeAsOctetString(gxByteBuffer* bb, gxtime* value); + + int cosem_setDateAsOctetString(gxByteBuffer* bb, gxtime* value); + + int cosem_setBitString(gxByteBuffer* bb, uint32_t value, uint16_t count); + + int cosem_setTimeAsOctetString(gxByteBuffer* bb, gxtime* value); + + int cosem_setDateTime(gxByteBuffer* bb, gxtime* value); + + int cosem_setDate(gxByteBuffer* bb, gxtime* value); + + int cosem_setTime(gxByteBuffer* bb, gxtime* value); + + int cosem_setOctetString(gxByteBuffer* bb, gxByteBuffer* value); + + int cosem_setString(gxByteBuffer* bb, const char* value, uint16_t len); + + int cosem_setString2(gxByteBuffer* bb, gxByteBuffer* value); + + int cosem_setOctetString2( + gxByteBuffer* bb, + const unsigned char* value, + uint16_t size); + + int cosem_setUInt8(gxByteBuffer* bb, unsigned char value); + int cosem_setUInt16(gxByteBuffer* bb, uint16_t value); + int cosem_setUInt32(gxByteBuffer* bb, uint32_t value); + int cosem_setUInt64(gxByteBuffer* bb, uint64_t* value); + + int cosem_setInt8(gxByteBuffer* bb, char value); + int cosem_setInt16(gxByteBuffer* bb, int16_t value); + int cosem_setInt32(gxByteBuffer* bb, int32_t value); + int cosem_setInt64(gxByteBuffer* bb, int64_t* value); + int cosem_setVariant(gxByteBuffer* bb, dlmsVARIANT* value); + + int cosem_setStructure(gxByteBuffer* bb, uint16_t count); + int cosem_setArray(gxByteBuffer* bb, uint16_t count); + int cosem_setEnum(gxByteBuffer* bb, unsigned char value); + int cosem_setBoolean(gxByteBuffer* bb, unsigned char value); + +#ifndef DLMS_IGNORE_PROFILE_GENERIC + int cosem_getColumns( + gxArray* captureObjects, + unsigned char selector, + dlmsVARIANT* parameters, + gxArray* columns); +#endif //DLMS_IGNORE_PROFILE_GENERIC + + //Find object from settings object and create if not found. + int cosem_findObjectByLN( + dlmsSettings* settings, + DLMS_OBJECT_TYPE ot, + const unsigned char* ln, + gxObject** object); + +#ifdef __cplusplus +} +#endif + +#endif //COSEM_H diff --git a/components/xt211/crc.h b/components/xt211/crc.h new file mode 100644 index 0000000..ea15109 --- /dev/null +++ b/components/xt211/crc.h @@ -0,0 +1,113 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef CRC_H +#define CRC_H + +#include "gxignore.h" +#ifndef DLMS_IGNORE_HDLC +#if defined(USE_AVR) || defined(ARDUINO_ARCH_AVR) +//If AVR is used. +#include +#endif //#if defined(USE_AVR) || defined(ARDUINO_ARCH_AVR) + +#ifdef __cplusplus +extern "C" { +#endif + //CRC table. +#ifndef USE_PROGMEM + static const uint16_t FCS16Table[] = { +#else + const uint16_t FCS16Table[] PROGMEM = { +#endif //USE_PROGMEM + 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, + 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, + 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, + 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, + 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, + 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, + 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, + 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, + 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, + 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, + 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, + 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, + 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, + 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, + 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, + 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, + 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, + 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, + 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, + 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, + 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, + 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, + 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, + 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, + 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, + 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, + 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, + 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, + 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, + 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, + 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, + 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 + }; + + static uint16_t countCRC(gxByteBuffer* Buff, uint32_t index, uint32_t count) + { + uint16_t tmp; + uint16_t FCS16 = 0xFFFF; + uint16_t pos; + for (pos = 0; pos < count; ++pos) + { +#ifdef ARDUINO_ARCH_AVR +//If Arduino is used data is read from flash like this. + tmp = (FCS16 ^ Buff->data[index + pos]) & 0xFF; + FCS16 = (FCS16 >> 8) ^ pgm_read_word_near(FCS16Table + tmp); +#else + FCS16 = (FCS16 >> 8) ^ FCS16Table[(FCS16 ^ ((unsigned char*)Buff->data)[index + pos]) & 0xFF]; +#endif //ARDUINO_ARCH_AVR + } + FCS16 = ~FCS16; + //CRC is in big endian byte order. + tmp = FCS16; + FCS16 = tmp >> 8; + FCS16 |= tmp << 8; + return FCS16; + } + +#ifdef __cplusplus + } +#endif +#endif //DLMS_IGNORE_HDLC +#endif //CRC_H diff --git a/components/xt211/datainfo.c b/components/xt211/datainfo.c new file mode 100644 index 0000000..a4f0b32 --- /dev/null +++ b/components/xt211/datainfo.c @@ -0,0 +1,46 @@ +// +// -------------------------------------------------------------------------- +// 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 "datainfo.h" + +void di_init(gxDataInfo *info) +{ + info->index = 0; + info->count = 0; + info->type = DLMS_DATA_TYPE_NONE; + info->complete = 1; +#ifdef DLMS_ITALIAN_STANDARD + //Some meters require that there is a array count in data. + info->appendAA = 0; +#endif //DLMS_ITALIAN_STANDARD + +} diff --git a/components/xt211/datainfo.h b/components/xt211/datainfo.h new file mode 100644 index 0000000..ac4dbfe --- /dev/null +++ b/components/xt211/datainfo.h @@ -0,0 +1,66 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- +#ifndef GXDATA_INFO_H +#define GXDATA_INFO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "gxint.h" +#include "enums.h" +#include "gxignore.h" + +typedef struct +{ + // Last array index. + uint16_t index; + + // Items count in array. + uint16_t count; + // Object data type. + DLMS_DATA_TYPE type; + // Is data parsed to the end. + unsigned char complete; +#ifdef DLMS_ITALIAN_STANDARD + //Some meters require that there is a array count in data. + unsigned char appendAA; +#endif //DLMS_ITALIAN_STANDARD +} gxDataInfo; + +void di_init(gxDataInfo *info); + +#ifdef __cplusplus +} +#endif + +#endif //GXDATA_INFO_H diff --git a/components/xt211/date.c b/components/xt211/date.c new file mode 100644 index 0000000..202947f --- /dev/null +++ b/components/xt211/date.c @@ -0,0 +1,1662 @@ +// +// -------------------------------------------------------------------------- +// 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 +#endif +#include +#include + +#ifndef DLMS_IGNORE_STRING_CONVERTER +#include //printf needs this or error is generated. +#endif //DLMS_IGNORE_STRING_CONVERTER + +#include "gxmem.h" +#if _MSC_VER > 1400 +#include +#endif +#include "date.h" +#include "helpers.h" + +#ifndef DLMS_USE_EPOCH_TIME +//Get UTC offset in minutes. +void time_getUtcOffset(short* hours, short* minutes) +{ + time_t zero = 24 * 60 * 60L; + struct tm tm; + + // local time for Jan 2, 1900 00:00 UTC +#if _MSC_VER > 1000 + localtime_s(&tm, &zero); +#else + tm = *localtime(&zero); +#endif + * hours = (short)tm.tm_hour; + + //If the local time is the "day before" the UTC, subtract 24 hours from the hours to get the UTC offset + if (tm.tm_mday < 2) + { + *hours -= 24; + } + *minutes = (short)tm.tm_min; +} + +void time_init3( + gxtime* time, + int year, + int month, + int day, + int hour, + int minute, + int second, + int millisecond) +{ + short devitation, hours, minutes; + time_getUtcOffset(&hours, &minutes); + devitation = -(hours * 60 + minutes); + time_init(time, (uint16_t)year, (unsigned char)month, (unsigned char)day, (unsigned char)hour, (unsigned char)minute, (unsigned char)second, (unsigned char)millisecond, devitation); +} +#endif //DLMS_USE_EPOCH_TIME + +#ifndef DLMS_USE_EPOCH_TIME +time_t gxmktime(struct tm* value) +{ + struct tm orig = *value; + time_t ret; + if ((ret = mktime(value)) == (time_t)-1) + { + return ret; + } + if (value->tm_isdst == 1) + { + *value = orig; + value->tm_isdst = 1; + if ((ret = mktime(value)) == (time_t)-1) + { + return ret; + } + value->tm_isdst = 0; + } + return ret; +} +#endif //DLMS_USE_EPOCH_TIME + +// Constructor. +void time_init( + gxtime* time, + uint16_t year, + unsigned char month, + unsigned char day, + unsigned char hour, + unsigned char minute, + unsigned char second, + uint16_t millisecond, + signed short devitation) +{ + if (devitation == -1) + { + devitation = 0x8000; + } +#ifdef DLMS_USE_EPOCH_TIME + //multiply to tmp variable or it'll fails for some compilers. + uint32_t tmp; + //January and February are counted as months 13 and 14 of the previous year + if (month != 0xFF && month <= 2) + { + month += 12; + if (year != 0xFFFF) + { + year -= 1; + } + } + time->skip = DATETIME_SKIPS_NONE; + time->status = DLMS_CLOCK_STATUS_OK; + time->extraInfo = 0; + //Convert years to days + time->value = 0; + if (year == 0xFFFF) + { + time->skip = (unsigned char)(DATETIME_SKIPS_YEAR | DATETIME_SKIPS_DEVITATION); + year = 1970; + } + time->value = year; + time->value *= 365L; + tmp = year; + tmp /= 4L; + time->value += tmp; + tmp = year; + tmp /= 100L; + time->value -= tmp; + tmp = year; + tmp /= 400L; + time->value += tmp; + //Convert months to days + if (month == 0xFF) + { + time->skip |= DATETIME_SKIPS_MONTH | DATETIME_SKIPS_DEVITATION; + month = 1; + } + else if (month == 0xFE) + { + time->extraInfo = DLMS_DATE_TIME_EXTRA_INFO_DST_BEGIN; + month = 1; + } + else if (month == 0xFD) + { + time->extraInfo = DLMS_DATE_TIME_EXTRA_INFO_DST_END; + month = 1; + } + if (day == 0xFF) + { + time->skip |= DATETIME_SKIPS_DAY | DATETIME_SKIPS_DEVITATION; + day = 1; + } + else if (day == 0xFE) + { + time->extraInfo = DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY; + day = 1; + } + else if (day == 0xFD) + { + time->extraInfo = DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY2; + day = 1; + } + tmp = month; + tmp *= 30L; + time->value += tmp; + tmp = 1 + month; + tmp = tmp * 3L; + tmp = tmp / 5L; + time->value += tmp; + time->value += day; + //Unix time starts on January 1st, 1970 + if (time->value < 719561) + { + time->value = 0; + } + else + { + time->value -= 719561L; + } + //Convert days to seconds + if (time->value != 0) + { + time->value *= 86400L; + } + //Add hours, minutes and seconds + if (hour != 0xFF) + { + time->value += (3600L * hour); + } + else + { + time->skip |= DATETIME_SKIPS_HOUR; + } + if (minute != 0xFF) + { + time->value += (60L * minute); + } + else + { + time->skip |= DATETIME_SKIPS_MINUTE; + } + if (second != 0xFF) + { + time->value += second; + } + else + { + time->skip |= DATETIME_SKIPS_SECOND; + } + time->skip |= DATETIME_SKIPS_MS; + if (devitation == (short)0x8000) + { + time->skip |= DATETIME_SKIPS_DEVITATION; + } + time->deviation = devitation; +#else + int skip = DATETIME_SKIPS_NONE; + memset(&time->value, 0, sizeof(time->value)); + time->extraInfo = 0; + time->status = DLMS_CLOCK_STATUS_OK; + if (year < 1 || year == 0xFFFF) + { + skip |= DATETIME_SKIPS_YEAR; + year = 2000; + } + if (month == 0xFF) + { + skip |= DATETIME_SKIPS_MONTH; + month = 0; + } + else if (month == 0xFE) + { + time->extraInfo |= DLMS_DATE_TIME_EXTRA_INFO_DST_BEGIN; + month = 0; + } + else if (month == 0xFD) + { + time->extraInfo |= DLMS_DATE_TIME_EXTRA_INFO_DST_END; + month = 0; + } + else + { + --month; + } + if (day == 0xFF) + { + skip |= DATETIME_SKIPS_DAY; + day = 1; + } + else if (day == 0xFD) + { + time->extraInfo = DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY2; + } + else if (day == 0xFE) + { + time->extraInfo = DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY; + } + if (hour == 0xFF) + { + skip |= DATETIME_SKIPS_HOUR; + hour = 1; + } + if (minute == 0xFF) + { + skip |= DATETIME_SKIPS_MINUTE; + minute = 0; + } + if (second == 0xFF) + { + skip |= DATETIME_SKIPS_SECOND; + second = 0; + } + if (millisecond == 0xFFFF) + { + skip |= DATETIME_SKIPS_MS; + millisecond = 0; + } + time->skip = (DATETIME_SKIPS)skip; + if (year != 0) + { + time->value.tm_year = year - 1900; + } + time->value.tm_mon = month; + time->value.tm_mday = day; + time->value.tm_hour = hour; + time->value.tm_min = minute; + time->value.tm_sec = second; + time->deviation = devitation; + if (gxmktime(&time->value) == (time_t)-1) + { +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + } +#endif //DLMS_USE_EPOCH_TIME +} + +void time_clearDate( + gxtime* value) +{ +#ifdef DLMS_USE_EPOCH_TIME + //Get hours, minutes and seconds + if (value->value > 60) + { + unsigned char seconds = value->value % 60; + uint32_t t = value->value; + t /= 60; + unsigned char minutes = t % 60; + t /= 60; + unsigned char hours = t % 24; + value->value = seconds; + value->value += 60 * minutes; + value->value += 3600 * hours; + } +#else + value->value.tm_year = value->value.tm_yday = + value->value.tm_wday = value->value.tm_mon = + value->value.tm_mday = value->value.tm_isdst = 0; +#endif + value->skip &= ~(DATETIME_SKIPS_YEAR | DATETIME_SKIPS_MONTH | DATETIME_SKIPS_DAY | DATETIME_SKIPS_DAYOFWEEK | DATETIME_SKIPS_DEVITATION); +} + +void time_clearTime( + gxtime* value) +{ +#ifdef DLMS_USE_EPOCH_TIME + if (value->value != 0) + { + //Remove hours, minutes and seconds + value->value -= value->value % 60; + value->value -= value->value % 3600; + value->value -= value->value % 86400; + } +#else + value->value.tm_sec = value->value.tm_min = value->value.tm_hour = 0; +#endif + value->skip &= ~(DATETIME_SKIPS_HOUR | DATETIME_SKIPS_MINUTE | DATETIME_SKIPS_SECOND | DATETIME_SKIPS_MS); +} + +void time_clearHours(gxtime* value) +{ + time_addHours(value, -time_getHours(value)); +} + +void time_clearMinutes(gxtime* value) +{ + time_addMinutes(value, -time_getMinutes(value)); +} + +void time_clearSeconds(gxtime* value) +{ + time_addSeconds(value, -time_getSeconds(value)); +} + +uint16_t time_getYears2( + uint32_t value) +{ + //remove hours, minutes and seconds + value /= 86400; + //Convert Unix time to date + uint32_t a = (uint32_t)((4 * value + 102032) / 146097 + 15); + uint32_t b = (uint32_t)(value + 2442113 + a - (a / 4)); + uint32_t c = (20 * b - 2442) / 7305; + uint32_t d = b - 365 * c - (c / 4); + uint32_t e = d * 1000 / 30601; + //January and February are counted as months 13 and 14 of the previous year + if (e <= 13) + { + c -= 4716; + } + else + { + c -= 4715; + } + return (uint16_t)c; +} + +uint16_t time_getYears( + const gxtime* value) +{ +#ifdef DLMS_USE_EPOCH_TIME + return time_getYears2(value->value); +#else + return (uint16_t)(1900 + value->value.tm_year); +#endif // DLMS_USE_EPOCH_TIME +} + +unsigned char time_getMonths2( + uint32_t value) +{ + //remove hours, minutes and seconds + value /= 86400; + //Convert Unix time to date + uint32_t a = (uint32_t)((4 * value + 102032) / 146097 + 15); + uint32_t b = (uint32_t)(value + 2442113 + a - (a / 4)); + uint32_t c = (20 * b - 2442) / 7305; + uint32_t d = b - 365 * c - (c / 4); + uint32_t e = d * 1000 / 30601; + //January and February are counted as months 13 and 14 of the previous year + if (e <= 13) + { + e -= 1; + } + else + { + e -= 13; + } + return (unsigned char)e; +} + +unsigned char time_getMonths( + const gxtime* value) +{ +#ifdef DLMS_USE_EPOCH_TIME + return time_getMonths2(value->value); +#else + return (unsigned char)(1 + value->value.tm_mon); +#endif // DLMS_USE_EPOCH_TIME +} + +unsigned char time_getDays2(uint32_t value) +{ + //remove hours, minutes and seconds + value /= 86400; + //Convert Unix time to date + uint32_t a = (uint32_t)((4 * value + 102032) / 146097 + 15); + uint32_t b = (uint32_t)(value + 2442113 + a - (a / 4)); + uint32_t c = (20 * b - 2442) / 7305; + uint32_t d = b - 365 * c - (c / 4); + uint32_t e = d * 1000 / 30601; + uint32_t f = d - e * 30 - e * 601 / 1000; + return (unsigned char)f; +} + +unsigned char time_getDays( + const gxtime* value) +{ +#ifdef DLMS_USE_EPOCH_TIME + return time_getDays2(value->value); +#else + return (unsigned char)value->value.tm_mday; +#endif // DLMS_USE_EPOCH_TIME +} + +unsigned char time_getHours( + const gxtime* value) +{ +#ifdef DLMS_USE_EPOCH_TIME + return (unsigned char)((value->value % 86400L) / 3600L); +#else + return (unsigned char)value->value.tm_hour; +#endif // DLMS_USE_EPOCH_TIME +} + +unsigned char time_getMinutes( + const gxtime* value) +{ +#ifdef DLMS_USE_EPOCH_TIME + return (unsigned char)((value->value % 3600L) / 60L); +#else + return (unsigned char)value->value.tm_min; +#endif // DLMS_USE_EPOCH_TIME +} + +unsigned char time_getSeconds( + const gxtime* value) +{ +#ifdef DLMS_USE_EPOCH_TIME + return (unsigned char)(value->value % 60); +#else + return (unsigned char)value->value.tm_sec; +#endif // DLMS_USE_EPOCH_TIME +} + +void time_addDays( + gxtime* value, + int days) +{ +#ifdef DLMS_USE_EPOCH_TIME + time_addHours(value, 24L * days); +#else + value->value.tm_mday += days; + if (gxmktime(&value->value) == (time_t)-1) + { +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + } +#endif //DLMS_USE_EPOCH_TIME +} + +void time_addHours( + gxtime* value, + int hours) +{ +#ifdef DLMS_USE_EPOCH_TIME + time_addMinutes(value, 60L * hours); +#else + value->value.tm_hour += hours; + if (gxmktime(&value->value) == (time_t)-1) + { + //If OS +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + } +#endif //DLMS_USE_EPOCH_TIME +} + +void time_addMinutes( + gxtime* value, + int minutes) +{ +#ifdef DLMS_USE_EPOCH_TIME + time_addSeconds(value, 60L * minutes); +#else + value->value.tm_min += minutes; + if (gxmktime(&value->value) == (time_t)-1) + { + //If OS +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + } +#endif //DLMS_USE_EPOCH_TIME +} + +void time_addSeconds( + gxtime* value, + int seconds) +{ +#ifdef DLMS_USE_EPOCH_TIME + value->value += seconds; +#else + value->value.tm_sec += seconds; + if (gxmktime(&value->value) == (time_t)-1) + { + //If OS +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + } +#endif //DLMS_USE_EPOCH_TIME +} + +#ifndef DLMS_USE_EPOCH_TIME +void time_init2( + gxtime* time, + struct tm* value) +{ +#ifdef DLMS_USE_EPOCH_TIME + uint16_t y; + unsigned char m, d; + //Year + y = value->tm_year; + //Month of year + m = value->tm_mon; + //Day of month + d = value->tm_mday; + + //January and February are counted as months 13 and 14 of the previous year + if (m <= 2) + { + m += 12; + y -= 1; + } + + //Convert years to days + time->value = (365 * y) + (y / 4) - (y / 100) + (y / 400); + //Convert months to days + time->value += (30 * m) + (3 * (m + 1) / 5) + d; + //Unix time starts on January 1st, 1970 + time->value -= 719561; + //Convert days to seconds + time->value *= 86400; + //Add hours, minutes and seconds + time->value += (3600 * value->tm_hour) + (60 * value->tm_min) + value->tm_sec; +#else + short devitation, hours, minutes; + time_getUtcOffset(&hours, &minutes); + devitation = -(hours * 60 + minutes); + time_init(time, (uint16_t)(value->tm_year + 1900), (unsigned char)(value->tm_mon + 1), (unsigned char)value->tm_mday, (unsigned char)value->tm_hour, (unsigned char)value->tm_min, + (unsigned char)value->tm_sec, 0, devitation); +#endif //DLMS_USE_EPOCH_TIME +} +#endif //DLMS_USE_EPOCH_TIME + +void time_initUnix( + gxtime* time, + uint32_t value) +{ + time->deviation = 0; +#ifdef DLMS_USE_EPOCH_TIME + time->value = value; +#else + time_fromUnixTime(value, &time->value); + gxmktime(&time->value); +#endif //DLMS_USE_EPOCH_TIME + time->extraInfo = 0; + time->status = DLMS_CLOCK_STATUS_OK; + time->skip = DATETIME_SKIPS_NONE; +} + +void time_clear( + gxtime* time) +{ +#ifdef DLMS_USE_EPOCH_TIME + time->value = 0; +#else + memset(&time->value, 0, sizeof(struct tm)); +#endif //DLMS_USE_EPOCH_TIME + time->skip = DATETIME_SKIPS_NONE; + time->extraInfo = 0; + time->status = DLMS_CLOCK_STATUS_OK; +} + +int date_isleap(uint16_t year) +{ + return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); +} + +unsigned char date_daysInMonth( + uint16_t year, + uint8_t month) +{ + switch (month) + { + case 0: + case 2: + case 4: + case 6: + case 7: + case 9: + case 11: + return 31; + case 3: + case 5: + case 8: + case 10: + return 30; + default: + if (date_isleap(year)) + { + return 29; + } + return 28; + } +} + +uint16_t date_getYearDay(uint8_t day, uint8_t mon, uint16_t year) +{ + static const uint16_t days[2][13] = { + {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, + {0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335} + }; + return days[date_isleap(year)][mon] + day; +} + +//Constants for different orders of date components. +typedef enum +{ + GXDLMS_DATE_FORMAT_INVALID = -1, + GXDLMS_DATE_FORMAT_DMY = 0, + GXDLMS_DATE_FORMAT_MDY = 1, + GXDLMS_DATE_FORMAT_YMD = 2, + GXDLMS_DATE_FORMAT_YDM = 3 +} GXDLMS_DATE_FORMAT; + +#if !defined(DLMS_IGNORE_STRING_CONVERTER) +int getDateFormat(GXDLMS_DATE_FORMAT* format, char* separator) +{ + //If OS is used. +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + int ret = 0, value, lastPos = 0, pos; + char buff[10]; + struct tm order = { 0 }; + order.tm_year = 0; + order.tm_mday = 1; + order.tm_mon = 1;//Month is zero based. + ret = (int)strftime(buff, 10, "%x", &order); + if (ret > 0) + { + for (pos = 0; pos != ret; ++pos) + { + //If numeric value + if (buff[pos] >= '0' && buff[pos] <= '9') + { + + } + else //If date time separator. + { + *separator = buff[pos]; +#if _MSC_VER > 1000 + if (sscanf_s(buff + lastPos, "%d", &value) == 1) +#else + if (sscanf(buff + lastPos, "%d", &value) == 1) +#endif + { + if (value == 1) + { + *format = lastPos == 0 ? GXDLMS_DATE_FORMAT_DMY : GXDLMS_DATE_FORMAT_YDM; + break; + } + else if (value == 2) + { + *format = lastPos == 0 ? GXDLMS_DATE_FORMAT_MDY : GXDLMS_DATE_FORMAT_YMD; + break; + } + } + lastPos = pos + 1; + } + } + } + return 0; +#else + * format = GXDLMS_DATE_FORMAT_MDY; + *separator = '/'; + return 0; +#endif +} + +int time_print(const char* format, gxtime* time) +{ + int ret; + char buff[50]; + if ((ret = time_toString2(time, buff, 50)) != 0) + { + return ret; + } + if (format != NULL) + { + printf(format, buff); + } + else + { + printf("%s", buff); + } + return 0; +} + +int time_toString2( + const gxtime* time, + char* buff, + uint16_t len) +{ + gxByteBuffer bb; + bb_attach(&bb, (unsigned char*)buff, 0, len); + return time_toString(time, &bb); +} + +int time_toString( + const gxtime* time, + gxByteBuffer* ba) +{ + int ret = 0; + unsigned char empty = 1; + GXDLMS_DATE_FORMAT format; + char separator; + uint16_t year = 0; + unsigned char addDate = 0; + unsigned char mon = 0, day = 0, hour = 0, min = 0, sec = 0; +#ifdef DLMS_USE_EPOCH_TIME + time_fromUnixTime2(time->value, &year, &mon, &day, &hour, &min, &sec, NULL); +#else + year = (uint16_t)time->value.tm_year; + if (year != 0xFFFF) + { + year += 1900; + } + mon = (unsigned char)time->value.tm_mon; + if (mon != 0xFF) + { + mon += 1; + } + day = (unsigned char)time->value.tm_mday; + hour = (unsigned char)time->value.tm_hour; + min = (unsigned char)time->value.tm_min; + sec = (unsigned char)time->value.tm_sec; +#endif //DLMS_USE_EPOCH_TIME + //Add year, month and date if used. + if ((time->skip & (DATETIME_SKIPS_YEAR | DATETIME_SKIPS_MONTH | DATETIME_SKIPS_DAY)) != (DATETIME_SKIPS_YEAR | DATETIME_SKIPS_MONTH | DATETIME_SKIPS_DAY)) + { + if ((ret = getDateFormat(&format, &separator)) != 0) + { + return ret; + } + switch (format) + { + case GXDLMS_DATE_FORMAT_DMY: + { + if ((time->skip & DATETIME_SKIPS_DAY) == 0) + { + empty = 0; + bb_addIntAsString2(ba, day, 2); + } + if ((time->skip & DATETIME_SKIPS_MONTH) == 0) + { + if (!empty) + { + bb_setUInt8(ba, separator); + } + else + { + empty = 0; + } + bb_addIntAsString2(ba, mon, 2); + } + else if ((time->extraInfo & (DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY | DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY2)) != 0) + { + if (!empty) + { + bb_setUInt8(ba, separator); + } + else + { + empty = 0; + } + bb_addString(ba, GET_STR_FROM_EEPROM("*")); + } + if ((time->skip & DATETIME_SKIPS_YEAR) == 0) + { + if (!empty) + { + bb_setUInt8(ba, separator); + } + else + { + empty = 0; + } + bb_addIntAsString(ba, year); + } + else if ((time->extraInfo & (DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY | DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY2)) != 0) + { + if (!empty) + { + bb_setUInt8(ba, separator); + } + else + { + empty = 0; + } + bb_addString(ba, GET_STR_FROM_EEPROM("*")); + } + } + break; + case GXDLMS_DATE_FORMAT_YMD: + { + if ((time->skip & DATETIME_SKIPS_YEAR) == 0) + { + empty = 0; + bb_addIntAsString(ba, year); + } + else if ((time->extraInfo & (DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY | DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY2)) != 0) + { + if (!empty) + { + bb_setUInt8(ba, separator); + } + else + { + empty = 0; + } + bb_addString(ba, GET_STR_FROM_EEPROM("*")); + } + if ((time->skip & DATETIME_SKIPS_MONTH) == 0) + { + if (!empty) + { + bb_setUInt8(ba, separator); + } + else + { + empty = 0; + } + bb_addIntAsString2(ba, mon, 2); + } + else if ((time->extraInfo & (DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY | DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY2)) != 0) + { + if (!empty) + { + bb_setUInt8(ba, separator); + } + else + { + empty = 0; + } + bb_addString(ba, GET_STR_FROM_EEPROM("*")); + } + if ((time->skip & DATETIME_SKIPS_DAY) == 0) + { + if (!empty) + { + bb_setUInt8(ba, separator); + } + else + { + empty = 0; + } + bb_addIntAsString2(ba, day, 2); + } + } + break; + case GXDLMS_DATE_FORMAT_YDM: + { + if ((time->skip & DATETIME_SKIPS_YEAR) == 0) + { + bb_addIntAsString(ba, year); + empty = 0; + } + else if ((time->extraInfo & (DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY | DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY2)) != 0) + { + if (!empty) + { + bb_setUInt8(ba, separator); + } + else + { + empty = 0; + } + bb_addString(ba, GET_STR_FROM_EEPROM("*")); + } + if ((time->skip & DATETIME_SKIPS_DAY) == 0) + { + if (!empty) + { + bb_setUInt8(ba, separator); + } + else + { + empty = 0; + } + bb_addIntAsString2(ba, day, 2); + } + if ((time->skip & DATETIME_SKIPS_MONTH) == 0) + { + if (!empty) + { + bb_setUInt8(ba, separator); + } + else + { + empty = 0; + } + bb_addIntAsString2(ba, mon, 2); + } + else if ((time->extraInfo & (DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY | DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY2)) != 0) + { + if (!empty) + { + bb_setUInt8(ba, separator); + } + else + { + empty = 0; + } + bb_addString(ba, GET_STR_FROM_EEPROM("*")); + } + } + break; + default: //GXDLMS_DATE_FORMAT_MDY + { + if ((time->extraInfo & DLMS_DATE_TIME_EXTRA_INFO_DST_BEGIN) != 0) + { + empty = 0; + addDate = 1; + bb_addString(ba, GET_STR_FROM_EEPROM("BEGIN")); + } + else if ((time->extraInfo & DLMS_DATE_TIME_EXTRA_INFO_DST_END) != 0) + { + empty = 0; + addDate = 1; + bb_addString(ba, GET_STR_FROM_EEPROM("END")); + } + else if ((time->skip & DATETIME_SKIPS_MONTH) == 0) + { + empty = 0; + bb_addIntAsString2(ba, mon, 2); + } + else if ((time->extraInfo & (DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY | DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY2)) != 0) + { + if (!empty) + { + bb_setUInt8(ba, separator); + } + else + { + empty = 0; + } + bb_addString(ba, GET_STR_FROM_EEPROM("*")); + } + if ((time->skip & DATETIME_SKIPS_DAY) == 0) + { + if (!empty) + { + bb_setUInt8(ba, separator); + } + else + { + empty = 0; + } + if ((time->extraInfo & DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY) != 0) + { + bb_addString(ba, GET_STR_FROM_EEPROM("LASTDAY")); + } + else if ((time->extraInfo & DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY2) != 0) + { + bb_addString(ba, GET_STR_FROM_EEPROM("LASTDAY2")); + } + else + { + bb_addIntAsString2(ba, day, 2); + } + } + else if (addDate) + { + if (!empty) + { + bb_setUInt8(ba, separator); + } + else + { + empty = 0; + } + bb_addString(ba, GET_STR_FROM_EEPROM("*")); + } + if ((time->skip & DATETIME_SKIPS_YEAR) == 0) + { + if (!empty) + { + bb_setUInt8(ba, separator); + } + else + { + empty = 0; + } + bb_addIntAsString(ba, (time->skip & DATETIME_SKIPS_YEAR) == 0 ? year : 0); + } + else if ((time->extraInfo & (DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY | DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY2)) != 0) + { + if (!empty) + { + bb_setUInt8(ba, separator); + } + else + { + empty = 0; + } + bb_addString(ba, GET_STR_FROM_EEPROM("*")); + } + else if (addDate) + { + if (!empty) + { + bb_setUInt8(ba, separator); + } + else + { + empty = 0; + } + bb_addString(ba, GET_STR_FROM_EEPROM("*")); + } + } + break; + } + } + unsigned char addTime = (time->skip & (DATETIME_SKIPS_HOUR | DATETIME_SKIPS_MINUTE | DATETIME_SKIPS_MINUTE | DATETIME_SKIPS_SECOND)) != 0; + if (!empty) + { + bb_setUInt8(ba, ' '); + } + //Add hours. + if ((time->skip & DATETIME_SKIPS_HOUR) == 0) + { + empty = 0; + bb_addIntAsString2(ba, hour, 2); + } + else if (addTime) + { + if (!empty) + { + bb_setUInt8(ba, ':'); + } + else + { + empty = 0; + } + bb_setUInt8(ba, '*'); + } + //Add minutes. + if ((time->skip & DATETIME_SKIPS_MINUTE) == 0) + { + if (!empty) + { + bb_setUInt8(ba, ':'); + } + else + { + empty = 0; + } + bb_addIntAsString2(ba, min, 2); + } + else if (addTime) + { + if (!empty) + { + bb_setUInt8(ba, ':'); + } + else + { + empty = 0; + } + bb_setUInt8(ba, '*'); + } + //Add seconds. + if ((time->skip & DATETIME_SKIPS_SECOND) == 0) + { + if (!empty) + { + bb_setUInt8(ba, ':'); + } + empty = 0; + bb_addIntAsString2(ba, sec, 2); + } + else if (addTime) + { + if (!empty) + { + bb_setUInt8(ba, ':'); + } + else + { + empty = 0; + } + bb_setUInt8(ba, '*'); + } + if (time->deviation != (short)0x8000 && (time->skip & DATETIME_SKIPS_DEVITATION) == 0) + { + short tmp = time->deviation; +#ifndef DLMS_USE_UTC_TIME_ZONE + tmp = -tmp; +#endif //DLMS_USE_UTC_TIME_ZONE + bb_addString(ba, " UTC"); + if (tmp < 0) + { + bb_addString(ba, "-"); + } + else + { + bb_addString(ba, "+"); + } + bb_addIntAsString2(ba, (int)(tmp / 60), 2); + bb_addString(ba, ":"); + bb_addIntAsString2(ba, (int)(tmp % 60), 2); + } + //Add end of string, but that is not added to the length. + bb_setUInt8(ba, '\0'); + --ba->size; + return 0; +} +#endif //!defined(GX_DLMS_MICROCONTROLLER) + +void time_copy( + gxtime* trg, + gxtime* src) +{ + trg->extraInfo = src->extraInfo; + trg->skip = src->skip; + trg->status = src->status; + trg->value = src->value; + trg->deviation = src->deviation; +} + +void time_addTime( + gxtime* time, + int hours, + int minutes, + int seconds) +{ +#ifdef DLMS_USE_EPOCH_TIME + time_addHours(time, hours); + time_addMinutes(time, minutes); + time_addSeconds(time, seconds); +#else + time->value.tm_hour += hours; + time->value.tm_min += minutes; + time->value.tm_sec += seconds; + gxmktime(&time->value); +#endif // DLMS_USE_EPOCH_TIME +} + +int time_compareWithDiff( + gxtime* value1, + uint32_t value2, + short deviationDiff) +{ + if (value2 == 0xFFFFFFFF) + { + return 1; + } + uint16_t year1; + unsigned char month1, day1, hour1, minute1, second1; + uint16_t year2; + unsigned char month2, day2, hour2, minute2, second2; +#ifdef DLMS_USE_EPOCH_TIME + time_fromUnixTime2(time_toUnixTime2(value1), &year1, &month1, + &day1, &hour1, &minute1, &second1, NULL); +#else + year1 = (uint16_t)(1900 + value1->value.tm_year); + month1 = (unsigned char)(1 + value1->value.tm_mon); + day1 = (unsigned char)(value1->value.tm_mday); + hour1 = (unsigned char)(value1->value.tm_hour); + minute1 = (unsigned char)(value1->value.tm_min); + second1 = (unsigned char)(value1->value.tm_sec); +#endif //DLMS_USE_EPOCH_TIME + + if (deviationDiff != (short)0x8000) + { +#ifndef DLMS_USE_UTC_TIME_ZONE + value2 += (60 * deviationDiff); +#else + value2 -= (60 * deviationDiff); +#endif //DLMS_USE_UTC_TIME_ZONE + } + time_fromUnixTime2(value2, &year2, &month2, + &day2, &hour2, &minute2, &second2, NULL); + if ((value1->skip & (DATETIME_SKIPS_SECOND | DATETIME_SKIPS_MINUTE | DATETIME_SKIPS_HOUR | DATETIME_SKIPS_DAY | DATETIME_SKIPS_MONTH | DATETIME_SKIPS_YEAR)) != 0) + { + uint32_t val1 = 0, val2 = 0; + if ((value1->skip & DATETIME_SKIPS_SECOND) == 0) + { + val1 = second1; + val2 = second2; + } + if ((value1->skip & DATETIME_SKIPS_MINUTE) == 0) + { + val1 += 60L * minute1; + val2 += 60L * minute2; + } + if ((value1->skip & DATETIME_SKIPS_HOUR) == 0) + { + val1 += 3600L * hour1; + val2 += 3600L * hour2; + } + if ((value1->skip & DATETIME_SKIPS_DAY) == 0) + { + val1 += 24L * 3600L * day1; + val2 += 24L * 3600L * day2; + } + if ((value1->skip & DATETIME_SKIPS_MONTH) == 0) + { + if ((value1->skip & DATETIME_SKIPS_YEAR) == 0) + { + if (year1 != year2) + { + return year1 < year2 ? -1 : 1; + } + if (month1 != month2) + { + return month1 < month2 ? -1 : 1; + } + } + else if (month1 != month2) + { + return month1 < month2 ? -1 : 1; + } + } + else if ((value1->skip & DATETIME_SKIPS_YEAR) == 0) + { + if (year1 != year2) + { + return year1 < year2 ? -1 : 1; + } + } + if (val1 != val2) + { + return val1 < val2 ? -1 : 1; + } + return 0; + } + if (time_toUnixTime2(value1) == value2) + { + return 0; + } + return time_toUnixTime2(value1) < value2 ? -1 : 1; +} + +int time_compare2( + gxtime* value1, + uint32_t value2) +{ + return time_compareWithDiff(value1, value2, value1->deviation); +} + +int time_compare( + gxtime* value1, + gxtime* value2) +{ + //Compare using UTC times. + return time_compareWithDiff(value1, time_toUnixTime2(value2), value1->deviation); +} + +int time_fromUnixTime2( + uint32_t epoch, + uint16_t* year, + unsigned char* month, + unsigned char* day, + unsigned char* hour, + unsigned char* minute, + unsigned char* second, + unsigned char* dayOfWeek) +{ + //Retrieve hours, minutes and seconds + if (second != NULL) + { + *second = epoch % 60; + } + epoch /= 60; + if (minute != NULL) + { + *minute = epoch % 60; + } + epoch /= 60; + if (hour != NULL) + { + *hour = epoch % 24; + } + epoch /= 24; + //Convert Unix time to date + uint32_t a = (uint32_t)((4 * epoch + 102032) / 146097 + 15); + uint32_t b = (uint32_t)(epoch + 2442113 + a - (a / 4)); + uint32_t c = (20 * b - 2442) / 7305; + uint32_t d = b - 365 * c - (c / 4); + uint32_t e = d * 1000 / 30601; + uint32_t f = d - e * 30 - e * 601 / 1000; + //January and February are counted as months 13 and 14 of the previous year + if (e <= 13) + { + c -= 4716; + e -= 1; + } + else + { + c -= 4715; + e -= 13; + } + //Retrieve year, month and day + if (year != NULL) + { + *year = (uint16_t)c; + } + if (month != NULL) + { + *month = (unsigned char)e; + } + if (day != NULL) + { + *day = (unsigned char)f; + } + if (dayOfWeek != NULL && year != NULL && month != NULL && day != NULL) + { + //Calculate day of week + *dayOfWeek = time_dayOfWeek(*year, *month, *day); + } + return 0; +} + +int time_fromUnixTime3( + const gxtime* time, + uint16_t* year, + unsigned char* month, + unsigned char* day, + unsigned char* hour, + unsigned char* minute, + unsigned char* second, + unsigned char* dayOfWeek) +{ +#ifdef DLMS_USE_EPOCH_TIME + return time_fromUnixTime2(time->value, year, month, + day, hour, minute, second, dayOfWeek); +#else + if (year != NULL) + { + *year = (uint16_t)(1900 + time->value.tm_year); + } + if (month != NULL) + { + *month = (unsigned char)(1 + time->value.tm_mon); + } + if (day != NULL) + { + *day = (unsigned char)(time->value.tm_mday); + } + if (hour != NULL) + { + *hour = (unsigned char)(time->value.tm_hour); + } + if (minute != NULL) + { + *minute = (unsigned char)(time->value.tm_min); + } + if (second != NULL) + { + *second = (unsigned char)(time->value.tm_sec); + } + if (dayOfWeek != NULL) + { + *dayOfWeek = (unsigned char)(time->value.tm_year); + } + return 0; +#endif //DLMS_USE_EPOCH_TIME +} + +//https://en.wikipedia.org/wiki/Zeller%27s_congruence +unsigned char time_dayOfWeek( + uint16_t year, + unsigned char month, + unsigned char day) +{ + uint16_t h, j, k; + if (month <= 2) + { + month += 12; + year -= 1; + } + j = year / 100; + k = year % 100; + h = day + (26 * (month + 1) / 10) + k + (k / 4) + (5 * j) + (j / 4); + return ((h + 5) % 7) + 1; +} + +#ifndef DLMS_USE_EPOCH_TIME +//Get date time from Epoch time. +int time_fromUnixTime(uint32_t epoch, struct tm* time) +{ + uint16_t year; + unsigned char month, day, hour, minute, second, dayOfWeek; + time_fromUnixTime2(epoch, &year, &month, + &day, &hour, &minute, &second, &dayOfWeek); + memset(time, 0, sizeof(struct tm)); + time->tm_sec = second; + time->tm_min = minute; + time->tm_hour = hour; + time->tm_year = year - 1900; + time->tm_mon = month - 1; + time->tm_mday = day; + time->tm_wday = dayOfWeek; + return 0; +} + +// Convert date time to Epoch time. +uint32_t time_toUnixTime(struct tm* time) +{ + return (uint32_t)gxmktime(time); +} +#endif //DLMS_USE_EPOCH_TIME + +// Convert date time to Epoch time. +uint32_t time_toUnixTime2(gxtime* time) +{ + gxtime tmp = *time; + if ((time->extraInfo & DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY) != 0) + { + unsigned char days = time_getDays(time); + unsigned char max = date_daysInMonth(time_getYears(time), time_getMonths(time)); + time_addDays(&tmp, max - days); + } + uint32_t value; +#ifdef DLMS_USE_EPOCH_TIME + value = tmp.value; + if (tmp.deviation != 0 && time->deviation != (short)0x8000) + { +#ifdef DLMS_USE_UTC_TIME_ZONE + value -= 60 * tmp.deviation; +#else + value += 60 * tmp.deviation; +#endif //DLMS_USE_UTC_TIME_ZONE + } +#else + value = (uint32_t)gxmktime(&tmp.value); +#endif //DLMS_USE_EPOCH_TIME + return value; +} + +int time_getDeviation(gxtime* value1) +{ +#ifdef DLMS_USE_UTC_TIME_ZONE + return -value1->deviation; +#else + return value1->deviation; +#endif //DLMS_USE_UTC_TIME_ZONE +} + +int time_toUTC(gxtime* value) +{ + //Convert time to UCT if time zone is given. + if (value->deviation != 0 && value->deviation != (short)0x8000) + { + time_addMinutes(value, time_getDeviation(value)); + value->deviation = 0; + //DST deviation is included to deviation. Remove status. + value->status &= ~DLMS_CLOCK_STATUS_DAYLIGHT_SAVE_ACTIVE; + } + return 0; +} + +// Get next scheduled date in UTC time. +uint32_t time_getNextScheduledDate(uint32_t start, gxtime* value) +{ + if ((value->skip & (DATETIME_SKIPS_SECOND | DATETIME_SKIPS_MINUTE | DATETIME_SKIPS_HOUR | DATETIME_SKIPS_DAY | DATETIME_SKIPS_MONTH | DATETIME_SKIPS_YEAR)) == 0) + { + //If time is in the past. + if (time_toUnixTime2(value) < start) + { + start = 0xFFFFFFFF; + } + else + { + start = time_toUnixTime2(value); + } + } + else + { + uint32_t offset; + if ((value->skip & DATETIME_SKIPS_SECOND) == 0) + { + offset = ((60 + (time_toUnixTime2(value) % 60)) - (start % 60)); + if (offset % 60 == 0) + { + start += 60; + } + else + { + start += offset % 60; + } + } + if ((value->skip & DATETIME_SKIPS_MINUTE) == 0) + { + offset = ((3600L + (time_toUnixTime2(value) % 3600L)) - (start % 3600L)); + if (offset % 3600L == 0) + { + start += 3600L; + } + else + { + start += offset % 3600L; + } + } + if ((value->skip & DATETIME_SKIPS_HOUR) == 0) + { + offset = ((24 * 3600L + (time_toUnixTime2(value) % (24 * 3600L))) - (start % (24 * 3600L))); + if (offset % (24L * 3600L) == 0) + { + start += 24L * 3600L; + } + else + { + start += offset % (24L * 3600L); + } + } + if ((value->skip & DATETIME_SKIPS_DAY) == 0) + { + //Get current time. + unsigned char currentMonth = time_getMonths2(start); + uint16_t currentYear = time_getYears2(start); + uint16_t currentDay = date_getYearDay(time_getDays2(start), currentMonth, currentYear); + //Get executed time. + uint16_t executed; + unsigned char month; + uint16_t year; + //If year is not given it's count from the current date. + if ((value->skip & DATETIME_SKIPS_YEAR) == 0) + { + year = time_getYears(value); + } + else + { + year = time_getYears2(start); + } + //If month is not given it's count from the current date. + if ((value->skip & DATETIME_SKIPS_MONTH) == 0) + { + month = time_getMonths(value); + } + else + { + month = time_getMonths2(start); + if (date_getYearDay(time_getDays(value), month, year) < currentDay) + { + ++month; + } + } + executed = date_getYearDay(time_getDays(value), month, year); + if (executed < currentDay) + { + if (date_isleap(year)) + { + executed += 366; + } + else + { + executed += 365; + } + } + if (executed != currentDay) + { + offset = (executed - currentDay); + offset *= 24; + offset *= 3600; + start += offset; + } + } + else if ((value->skip & DATETIME_SKIPS_MONTH) == 0) + { + uint16_t year = time_getYears2(start); + uint32_t offset; + if (date_isleap(year)) + { + offset = 367; + } + else + { + offset = 366; + } + offset -= date_getYearDay(time_getDays2(start), time_getMonths2(start), year); + offset *= 24; + offset *= 3600; + start += offset; + } + } + return start; +} \ No newline at end of file diff --git a/components/xt211/date.h b/components/xt211/date.h new file mode 100644 index 0000000..38e7921 --- /dev/null +++ b/components/xt211/date.h @@ -0,0 +1,380 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- +#ifndef DATE_H +#define DATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "enums.h" + +#include "bytebuffer.h" + +#ifndef DLMS_USE_EPOCH_TIME +#include +#endif + +#ifndef DLMS_USE_EPOCH_TIME + //Get UTC offset in minutes. + void time_getUtcOffset(short* hours, short* minutes); +#endif //DLMS_USE_EPOCH_TIME + + // DataType enumerates skipped fields from date time. + typedef enum + { + // Nothing is skipped from date time. + DATETIME_SKIPS_NONE = 0x0, + // Year part of date time is skipped. + DATETIME_SKIPS_YEAR = 0x1, + // Month part of date time is skipped. + DATETIME_SKIPS_MONTH = 0x2, + // Day part is skipped. + DATETIME_SKIPS_DAY = 0x4, + // Day of week part of date time is skipped. + DATETIME_SKIPS_DAYOFWEEK = 0x8, + // Hours part of date time is skipped. + DATETIME_SKIPS_HOUR = 0x10, + // Minute part of date time is skipped. + DATETIME_SKIPS_MINUTE = 0x20, + // Seconds part of date time is skipped. + DATETIME_SKIPS_SECOND = 0x40, + // Hundreds of seconds part of date time is skipped. + DATETIME_SKIPS_MS = 0x80, + //Devitation is skipped. + DATETIME_SKIPS_DEVITATION = 0x100, + //Status is skipped. + DATETIME_SKIPS_STATUS = 0x200 + } DATETIME_SKIPS; + + typedef struct + { +#ifdef DLMS_USE_EPOCH_TIME + uint32_t value; +#else + struct tm value; +#endif + int16_t deviation; + DATETIME_SKIPS skip : 16; + DLMS_DATE_TIME_EXTRA_INFO extraInfo : 8; + DLMS_CLOCK_STATUS status : 8; + } gxtime; + + // Constructor. + void time_init( + gxtime* time, + uint16_t year, + unsigned char month, + unsigned char day, + unsigned char hour, + unsigned char minute, + unsigned char second, + uint16_t millisecond, + int16_t devitation); + +#ifndef DLMS_USE_EPOCH_TIME + void time_init2( + gxtime* time, + struct tm* value); + + // Constructor. + void time_init3( + gxtime* time, + int year, + int month, + int day, + int hour, + int minute, + int second, + int millisecond); +#endif //DLMS_USE_EPOCH_TIME + + //Constructor from Unix time. + void time_initUnix( + gxtime* time, + uint32_t value); + + void time_clear( + gxtime* time); + + void time_copy( + gxtime* trg, + gxtime* src); + + //Returns the approximate processor time in ms. + extern uint32_t time_elapsed(void); + + /* + Get years from time. + */ + uint16_t time_getYears( + const gxtime* value); + /* + Get months from time. + */ + unsigned char time_getMonths( + const gxtime* value); + /* + Get days from time. + */ + unsigned char time_getDays( + const gxtime* value); + + /* + Get hours from time. + */ + unsigned char time_getHours( + const gxtime* value); + + /* + Get minutes from time. + */ + unsigned char time_getMinutes( + const gxtime* value); + + /* + Get seconds from time. + */ + unsigned char time_getSeconds( + const gxtime* value); + + /* +Get years from time. +*/ + uint16_t time_getYears2( + uint32_t value); + /* + Get months from time. + */ + unsigned char time_getMonths2( + uint32_t value); + /* + Get days from time. + */ + unsigned char time_getDays2( + uint32_t value); + + /* + Get hours from time. + */ + unsigned char time_getHours2( + uint32_t value); + + /* + Get minutes from time. + */ + unsigned char time_getMinutes2( + uint32_t value); + + /* + Get seconds from time. + */ + unsigned char time_getSeconds2( + uint32_t value); + + /* + Adds amount of days to current time. + */ + void time_addDays( + gxtime* value, + int days); + + /* + Adds amount of hours to current time. + */ + void time_addHours( + gxtime* value, + int hours); + + /* + Adds amount of minutes to current time. + */ + void time_addMinutes( + gxtime* value, + int minutes); + + /* + Adds amount of seconds to current time. + */ + void time_addSeconds( + gxtime* value, + int seconds); + + /* + Clears date part. + */ + void time_clearDate( + gxtime* value); + + /* + Clears time part. + */ + void time_clearTime( + gxtime* value); + + /* + Clears hours. + */ + void time_clearHours( + gxtime* value); + + /* + Clears minutes. + */ + void time_clearMinutes( + gxtime* value); + + /* + Clears seconds. + */ + void time_clearSeconds( + gxtime* value); + + unsigned char date_daysInMonth( + uint16_t year, + uint8_t month); + +#if !defined(DLMS_IGNORE_STRING_CONVERTER) && !defined(DLMS_IGNORE_MALLOC) + //Print time to cout. + int time_print( + //Format. + const char* format, + gxtime* time); +#endif //!defined(DLMS_IGNORE_STRING_CONVERTER) && !defined(DLMS_IGNORE_MALLOC) + + //Save time to char buffer. + int time_toString2( + const gxtime* time, + char* buff, + uint16_t len); + + //Save time to bytebuffer. + int time_toString( + const gxtime* time, + gxByteBuffer* arr); + + void time_addTime( + gxtime* time, + int hours, + int minutes, + int seconds); + + ///////////////////////////////////////////////////////////////////////// + // Compare times. + // + // if Return value < 0 then it indicates value1 is less than value2. + // if Return value > 0 then it indicates value2 is less than value1. + // if Return value = 0 then it indicates value1 is equal to value2. + int time_compare( + gxtime* value1, + gxtime* value2); + + ///////////////////////////////////////////////////////////////////////// + // Compare time and EPOCH time. + // + // if Return value < 0 then it indicates value1 is less than value2. + // if Return value > 0 then it indicates value2 is less than value1. + // if Return value = 0 then it indicates value1 is equal to value2. + int time_compare2( + gxtime* value1, + uint32_t value2); + + + int time_compareWithDiff( + gxtime* value1, + uint32_t value2, + short deviationDiff); + +#ifndef DLMS_USE_EPOCH_TIME + //Get date-time from EPOCH time. + int time_fromUnixTime( + uint32_t epoch, + struct tm* time); +#endif //DLMS_USE_EPOCH_TIME + + //Get date-time from EPOCH time. + int time_fromUnixTime2( + uint32_t epoch, + uint16_t* year, + unsigned char* month, + unsigned char* day, + unsigned char* hour, + unsigned char* minute, + unsigned char* second, + unsigned char* dayOfWeek); + + //Get date-time from EPOCH time. + int time_fromUnixTime3( + const gxtime* time, + uint16_t* year, + unsigned char* month, + unsigned char* day, + unsigned char* hour, + unsigned char* minute, + unsigned char* second, + unsigned char* dayOfWeek); + +#ifndef DLMS_USE_EPOCH_TIME + // Convert date time to Epoch time. + uint32_t time_toUnixTime( + struct tm* time); +#endif //DLMS_USE_EPOCH_TIME + + // Convert date time to Epoch time. + uint32_t time_toUnixTime2( + gxtime* time); + + //Get day of week. + unsigned char time_dayOfWeek( + uint16_t year, + unsigned char month, + unsigned char day); + + //Get deviation. + int time_getDeviation( + gxtime* value1); + + //Convert date time to UTC date time. + int time_toUTC(gxtime* value); + + // Get next scheduled date in UTC time. + uint32_t time_getNextScheduledDate( + //Start time. + uint32_t start, + //Compared time. + gxtime* value); + +#ifdef __cplusplus +} +#endif + +#endif //DATE_H diff --git a/components/xt211/dlms.c b/components/xt211/dlms.c new file mode 100644 index 0000000..03b494a --- /dev/null +++ b/components/xt211/dlms.c @@ -0,0 +1,6833 @@ +// +// -------------------------------------------------------------------------- +// 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" +#include "serverevents.h" +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) +#include +#endif +#include "gxmem.h" +#if _MSC_VER > 1400 +#include +#endif +#include /* memset */ +#include "enums.h" +#include "dlms.h" +#ifndef DLMS_IGNORE_HIGH_GMAC +#include "ciphering.h" +#endif //DLMS_IGNORE_HIGH_GMAC +#include "crc.h" +#include "cosem.h" +#include "gxobjects.h" +#include "date.h" +#ifndef DLMS_IGNORE_HIGH_MD5 +#include "gxmd5.h" +#endif //DLMS_IGNORE_HIGH_MD5 +#ifndef DLMS_IGNORE_HIGH_SHA256 +#include "gxsha256.h" +#endif //DLMS_IGNORE_HIGH_SHA256 +#ifndef DLMS_IGNORE_HIGH_SHA1 +#include "gxsha1.h" +#endif //DLMS_IGNORE_HIGH_SHA1 +#ifndef DLMS_IGNORE_HIGH_AES +#include "gxaes.h" +#endif //DLMS_IGNORE_HIGH_AES + +unsigned char pduAttributes[PDU_MAX_HEADER_SIZE]; +static const unsigned char LLC_SEND_BYTES[3] = { 0xE6, 0xE6, 0x00 }; +static const unsigned char LLC_REPLY_BYTES[3] = { 0xE6, 0xE7, 0x00 }; +static const unsigned char HDLC_FRAME_START_END = 0x7E; + +unsigned char dlms_useHdlc(DLMS_INTERFACE_TYPE type) +{ +#ifndef DLMS_IGNORE_HDLC + return type == DLMS_INTERFACE_TYPE_HDLC || + type == DLMS_INTERFACE_TYPE_HDLC_WITH_MODE_E || + type == DLMS_INTERFACE_TYPE_PLC_HDLC; +#else + return 0; +#endif //DLMS_IGNORE_HDLC +} + +//Makes sure that the basic settings are set. +int dlms_checkInit(dlmsSettings* settings) +{ + if (settings->clientAddress == 0) + { + return DLMS_ERROR_CODE_INVALID_CLIENT_ADDRESS; + } + if (settings->serverAddress == 0) + { + return DLMS_ERROR_CODE_INVALID_SERVER_ADDRESS; + } + if (settings->maxPduSize < 64) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return DLMS_ERROR_CODE_OK; +} + +#ifndef DLMS_IGNORE_HIGH_GMAC +unsigned char dlms_useDedicatedKey(dlmsSettings* settings) +{ +#ifndef DLMS_IGNORE_MALLOC + return settings->cipher.dedicatedKey != NULL; +#else + return memcmp(settings->cipher.dedicatedKey, EMPTY_KEY, 16) != 0; +#endif //DLMS_IGNORE_MALLOC +} + +unsigned char dlms_usePreEstablishedConnection(dlmsSettings* settings) +{ +#ifndef DLMS_IGNORE_MALLOC + return settings->preEstablishedSystemTitle != NULL; +#else + return memcmp(settings->preEstablishedSystemTitle, EMPTY_SYSTEM_TITLE, 8) != 0; +#endif //DLMS_IGNORE_MALLOC +} + +#ifndef DLMS_IGNORE_HIGH_GMAC +/** +* Get used glo message. +* +* @param command +* Executed DLMS command. +* @return Integer value of glo message. +*/ +unsigned char dlms_getGloMessage(dlmsSettings* settings, DLMS_COMMAND command, DLMS_COMMAND encryptedCommand) +{ + unsigned char cmd; + unsigned glo = settings->negotiatedConformance & DLMS_CONFORMANCE_GENERAL_PROTECTION || + dlms_usePreEstablishedConnection(settings); + unsigned ded = dlms_useDedicatedKey(settings) && (settings->connected & DLMS_CONNECTION_STATE_DLMS) != 0; + if (encryptedCommand == DLMS_COMMAND_GENERAL_GLO_CIPHERING || + encryptedCommand == DLMS_COMMAND_GENERAL_DED_CIPHERING) + { + cmd = encryptedCommand; + } + else if (glo && encryptedCommand == DLMS_COMMAND_NONE) + { + if (ded) + { + cmd = DLMS_COMMAND_GENERAL_DED_CIPHERING; + } + else + { + cmd = DLMS_COMMAND_GENERAL_GLO_CIPHERING; + } + } + else + { + switch (command) + { +#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + case DLMS_COMMAND_READ_REQUEST: + if (ded) + { + cmd = DLMS_COMMAND_DED_READ_REQUEST; + } + else + { + cmd = DLMS_COMMAND_GLO_READ_REQUEST; + } + break; +#endif //!defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + case DLMS_COMMAND_GET_REQUEST: + if (ded) + { + cmd = DLMS_COMMAND_DED_GET_REQUEST; + } + else + { + cmd = DLMS_COMMAND_GLO_GET_REQUEST; + } + break; +#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + case DLMS_COMMAND_WRITE_REQUEST: + if (ded) + { + cmd = DLMS_COMMAND_DED_WRITE_REQUEST; + } + else + { + cmd = DLMS_COMMAND_GLO_WRITE_REQUEST; + } + break; +#endif //!defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + case DLMS_COMMAND_SET_REQUEST: + if (ded) + { + cmd = DLMS_COMMAND_DED_SET_REQUEST; + } + else + { + cmd = DLMS_COMMAND_GLO_SET_REQUEST; + } + break; + case DLMS_COMMAND_METHOD_REQUEST: + if (ded) + { + cmd = DLMS_COMMAND_DED_METHOD_REQUEST; + } + else + { + cmd = DLMS_COMMAND_GLO_METHOD_REQUEST; + } + break; +#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + case DLMS_COMMAND_READ_RESPONSE: + if (ded) + { + cmd = DLMS_COMMAND_DED_READ_RESPONSE; + } + else + { + cmd = DLMS_COMMAND_GLO_READ_RESPONSE; + } + break; +#endif //!defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + case DLMS_COMMAND_GET_RESPONSE: + if (ded) + { + cmd = DLMS_COMMAND_DED_GET_RESPONSE; + } + else + { + cmd = DLMS_COMMAND_GLO_GET_RESPONSE; + } + break; +#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + case DLMS_COMMAND_WRITE_RESPONSE: + if (ded) + { + cmd = DLMS_COMMAND_DED_WRITE_RESPONSE; + } + else + { + cmd = DLMS_COMMAND_GLO_WRITE_RESPONSE; + } + break; +#endif //!defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + case DLMS_COMMAND_SET_RESPONSE: + if (ded) + { + cmd = DLMS_COMMAND_DED_SET_RESPONSE; + } + else + { + cmd = DLMS_COMMAND_GLO_SET_RESPONSE; + } + break; + case DLMS_COMMAND_METHOD_RESPONSE: + if (ded) + { + cmd = DLMS_COMMAND_DED_METHOD_RESPONSE; + } + else + { + cmd = DLMS_COMMAND_GLO_METHOD_RESPONSE; + } + break; + case DLMS_COMMAND_DATA_NOTIFICATION: + if (ded) + { + cmd = DLMS_COMMAND_GENERAL_DED_CIPHERING; + } + else + { + cmd = DLMS_COMMAND_GENERAL_GLO_CIPHERING; + } + break; + case DLMS_COMMAND_RELEASE_REQUEST: + cmd = DLMS_COMMAND_RELEASE_REQUEST; + break; + case DLMS_COMMAND_RELEASE_RESPONSE: + cmd = DLMS_COMMAND_RELEASE_RESPONSE; + break; + case DLMS_COMMAND_GENERAL_DED_CIPHERING: + cmd = DLMS_COMMAND_GENERAL_DED_CIPHERING; + break; + case DLMS_COMMAND_GENERAL_GLO_CIPHERING: + cmd = DLMS_COMMAND_GENERAL_GLO_CIPHERING; + break; + default: + cmd = DLMS_COMMAND_NONE; + } + } + return cmd; +} +#endif //DLMS_IGNORE_HIGH_GMAC +#endif //DLMS_IGNORE_HIGH_GMAC + +unsigned char dlms_getInvokeIDPriority(dlmsSettings* settings, unsigned char increase) +{ + unsigned char value = 0; + if (settings->priority == DLMS_PRIORITY_HIGH) + { + value |= 0x80; + } + if (settings->serviceClass == DLMS_SERVICE_CLASS_CONFIRMED) + { + value |= 0x40; + } + if (increase) + { + settings->invokeID = (unsigned char)((1 + settings->invokeID) & 0xF); + } + value |= settings->invokeID; + return value; +} + +/** +* Generates Invoke ID and priority. +* +* @param settings +* DLMS settings-> +* @return Invoke ID and priority. +*/ +int32_t dlms_getLongInvokeIDPriority(dlmsSettings* settings) +{ + int32_t value = 0; + if (settings->priority == DLMS_PRIORITY_HIGH) + { + value = 0x80000000; + } + if (settings->serviceClass == DLMS_SERVICE_CLASS_CONFIRMED) + { + value |= 0x40000000; + } + value |= (settings->longInvokeID & 0xFFFFFF); + ++settings->longInvokeID; + return value; +} + +int dlms_getMaxPduSize( + dlmsSettings* settings, + gxByteBuffer* data, + gxByteBuffer* bb) +{ + int offset = 0; + int size = data->size - data->position; + if (bb != NULL) + { + offset = bb->size; + } + if (size + offset > settings->maxPduSize) + { + size = settings->maxPduSize - offset; + size -= hlp_getObjectCountSizeInBytes(size); + } + else if (size + hlp_getObjectCountSizeInBytes(size) > settings->maxPduSize) + { + size = (size - hlp_getObjectCountSizeInBytes(size)); + } + return size; +} + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +int dlms_setData2( + unsigned char* buff, + uint32_t length, + DLMS_DATA_TYPE type, + dlmsVARIANT* value) +#else +int dlms_setData2( + unsigned char* buff, + uint16_t length, + DLMS_DATA_TYPE type, + dlmsVARIANT* value) +#endif +{ + gxByteBuffer bb; + bb_attach(&bb, buff, length, length); + return dlms_setData(&bb, type, value); +} + +int dlms_setData(gxByteBuffer* buff, DLMS_DATA_TYPE type, dlmsVARIANT* value) +{ +#ifndef DLMS_IGNORE_MALLOC + int ret; + ret = var_changeType(value, type); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } +#endif //DLMS_IGNORE_MALLOC + return var_getBytes2(value, type, buff); +} + +#ifndef DLMS_IGNORE_MALLOC +int getCount(gxByteBuffer* buff, gxDataInfo* info, dlmsVARIANT* value) +{ + if (hlp_getObjectCount2(buff, &info->count) != 0) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + value->Arr = (variantArray*)gxmalloc(sizeof(variantArray)); + if (value->Arr == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + va_init(value->Arr); + va_capacity(value->Arr, info->count); + value->vt = DLMS_DATA_TYPE_ARRAY; + return 0; +} + +/** +* Get array from DLMS data. +* +* buff +* Received DLMS data. +* info +* Data info. +* index +* starting index. +* Returns CGXDLMSVariant array. +*/ +int getArray(gxByteBuffer* buff, gxDataInfo* info, uint16_t index, dlmsVARIANT* value) +{ + dlmsVARIANT* tmp; + gxDataInfo info2; + uint32_t size; + uint16_t pos, startIndex; + int ret; + if (info->count == 0) + { + if ((ret = getCount(buff, info, value)) != 0) + { + return ret; + } + } + size = buff->size - buff->position; + if (info->count != 0 && size < 1) + { + info->complete = 0; + return 0; + } + startIndex = index; + // Position where last row was found. Cache uses this info. + for (pos = info->index; pos != info->count; ++pos) + { + tmp = (dlmsVARIANT*)gxmalloc(sizeof(dlmsVARIANT)); + if (tmp == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + var_init(tmp); + di_init(&info2); + if ((ret = dlms_getData(buff, &info2, tmp)) != 0) + { + var_clear(tmp); + gxfree(tmp); + return ret; + } + if (!info2.complete) + { + var_clear(tmp); + gxfree(tmp); + buff->position = startIndex; + info->complete = 0; + break; + } + else + { + if (info2.count == info2.index) + { + startIndex = (uint16_t)buff->position; + va_push(value->Arr, tmp); + } + } + } + info->index = pos; + return DLMS_ERROR_CODE_OK; +} +#endif //DLMS_IGNORE_MALLOC + +/** +* Get UInt32 value from DLMS data. +* +* buff +* Received DLMS data. +* info +* Data info. +* Returns parsed UInt32 value. +*/ +int getUInt32(gxByteBuffer* buff, gxDataInfo* info, dlmsVARIANT* value) +{ + int ret; + // If there is not enough data available. + if (buff->size - buff->position < 4) + { + info->complete = 0; + return 0; + } + if ((value->vt & DLMS_DATA_TYPE_BYREF) == 0) + { + value->vt = DLMS_DATA_TYPE_UINT32; + } + if ((ret = bb_getUInt32(buff, (value->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &value->ulVal : value->pulVal)) != 0) + { + return ret; + } + return DLMS_ERROR_CODE_OK; +} + +/** +* Get Int32 value from DLMS data. +* +* buff +* Received DLMS data. +* info +* Data info. +* Returns parsed Int32 value. +*/ +int getInt32(gxByteBuffer* buff, gxDataInfo* info, dlmsVARIANT* value) +{ + int ret; + // If there is not enough data available. + if (buff->size - buff->position < 4) + { + info->complete = 0; + return 0; + } + if ((value->vt & DLMS_DATA_TYPE_BYREF) == 0) + { + value->vt = DLMS_DATA_TYPE_INT32; + } + if ((ret = bb_getInt32(buff, (value->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &value->lVal : value->plVal)) != 0) + { + return ret; + } + return DLMS_ERROR_CODE_OK; +} + +/** +* Get bit std::string value from DLMS data. +* +* buff : Received DLMS data. +* info : Data info. +* Returns parsed bit std::string value. +*/ +static int getBitString(gxByteBuffer* buff, gxDataInfo* info, dlmsVARIANT* value) +{ + uint16_t cnt = 0; +#ifndef DLMS_IGNORE_MALLOC + int ret; +#endif //DLMS_IGNORE_MALLOC + if (hlp_getObjectCount2(buff, &cnt) != 0) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + uint16_t byteCnt = ba_getByteCount(cnt); + // If there is not enough data available. + if (buff->size - buff->position < byteCnt) + { + info->complete = 0; + return 0; + } +#ifdef DLMS_IGNORE_MALLOC + if (value->vt != (DLMS_DATA_TYPE_BIT_STRING | DLMS_DATA_TYPE_BYREF)) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if (value->capacity < cnt) + { + return DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } + value->size = cnt; + memcpy(value->pVal, buff->data + buff->position, byteCnt); + buff->position += byteCnt; +#else + value->bitArr = (bitArray*)gxmalloc(sizeof(bitArray)); + ba_init(value->bitArr); + if ((ret = hlp_add(value->bitArr, buff, cnt)) != 0) + { + return ret; + } +#endif //DLMS_IGNORE_MALLOC + return 0; +} + +static int getBool(gxByteBuffer* buff, gxDataInfo* info, dlmsVARIANT* value) +{ + int ret; + unsigned char ch; + // If there is not enough data available. + if (buff->size - buff->position < 1) + { + info->complete = 0; + return 0; + } + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + if ((value->vt & DLMS_DATA_TYPE_BYREF) == 0) + { + value->vt = DLMS_DATA_TYPE_BOOLEAN; + value->boolVal = ch != 0; + } + else + { + *value->pboolVal = ch != 0; + } + return 0; +} + +/** +* Get string value from DLMS data. +* +* buff +* Received DLMS data. +* info +* Data info. +* Returns parsed std::string value. +*/ +int getString(gxByteBuffer* buff, gxDataInfo* info, unsigned char knownType, dlmsVARIANT* value) +{ + int ret = 0; + uint16_t len = 0; + if (knownType) + { + len = (uint16_t)buff->size; + } + else + { + if (hlp_getObjectCount2(buff, &len) != 0) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + // If there is not enough data available. + if (buff->size - buff->position < (uint16_t)len) + { + info->complete = 0; + return 0; + } + } +#ifdef DLMS_IGNORE_MALLOC + if (value->vt != (DLMS_DATA_TYPE_STRING | DLMS_DATA_TYPE_BYREF)) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if (value->capacity < len) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + value->size = len; + memcpy(value->pVal, buff->data + buff->position, len); + buff->position += len; +#else + value->vt = DLMS_DATA_TYPE_STRING; + if (len > 0) + { + value->strVal = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + BYTE_BUFFER_INIT(value->strVal); + ret = bb_set2(value->strVal, buff, buff->position, len); + } +#endif //DLMS_IGNORE_MALLOC + return ret; +} + +#ifndef DLMS_IGNORE_MALLOC +/** +* Get UTF std::string value from DLMS data. +* +* buff +* Received DLMS data. +* info +* Data info. +* Returns parsed UTF std::string value. +*/ +int getUtfString( + gxByteBuffer* buff, + gxDataInfo* info, + unsigned char knownType, + dlmsVARIANT* value) +{ + int ret = 0; + uint16_t len = 0; + var_clear(value); + if (knownType) + { + len = (uint16_t)buff->size; + } + else + { + if (hlp_getObjectCount2(buff, &len) != 0) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + // If there is not enough data available. + if (buff->size - buff->position < len) + { + info->complete = 0; + return 0; + } + } + if (len > 0) + { + value->strUtfVal = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + BYTE_BUFFER_INIT(value->strUtfVal); + ret = bb_set2(value->strUtfVal, buff, buff->position, len); + value->vt = DLMS_DATA_TYPE_STRING_UTF8; + } + else + { + value->strUtfVal = NULL; + } + return ret; +} +#endif //DLMS_IGNORE_MALLOC + +/** +* Get octet string value from DLMS data. +* +* buff +* Received DLMS data. +* info +* Data info. +* Returns parsed octet string value. +*/ +int getOctetString(gxByteBuffer* buff, gxDataInfo* info, unsigned char knownType, dlmsVARIANT* value) +{ + uint16_t len; + int ret = 0; + if (knownType) + { + len = (uint16_t)buff->size; + } + else + { + if (hlp_getObjectCount2(buff, &len) != 0) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + // If there is not enough data available. + if (buff->size - buff->position < len) + { + info->complete = 0; + return 0; + } + } +#ifdef DLMS_IGNORE_MALLOC + if (value->vt != (DLMS_DATA_TYPE_OCTET_STRING | DLMS_DATA_TYPE_BYREF)) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if (value->capacity < len) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + value->size = len; + memcpy(value->pVal, buff->data + buff->position, len); + buff->position += len; +#else + if (len == 0) + { + var_clear(value); + } + else + { + ret = var_addBytes(value, buff->data + buff->position, len); +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + buff->position += (uint32_t)len; +#else + buff->position += (uint16_t)len; +#endif + } +#endif //DLMS_IGNORE_MALLOC + return ret; +} + +/** +* Get BCD value from DLMS data. +* +* buff +* Received DLMS data. +* info +* Data info. +* Returns parsed BCD value. +*/ +int getBcd(gxByteBuffer* buff, gxDataInfo* info, unsigned char knownType, dlmsVARIANT* value) +{ +#ifndef DLMS_IGNORE_MALLOC + unsigned char idHigh, idLow; +#endif //DLMS_IGNORE_MALLOC + static const char hexArray[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; + int ret = 0, a; + uint16_t len; + unsigned char ch; + if (knownType) + { + len = (uint16_t)buff->size; + } + else + { + if (hlp_getObjectCount2(buff, &len) != 0) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + // If there is not enough data available. + if ((buff->size - buff->position) < (uint16_t)(2 * len)) + { + info->complete = 0; + return 0; + } + } +#ifdef DLMS_IGNORE_MALLOC + value->size = 2 * len; + if (value->vt != (DLMS_DATA_TYPE_OCTET_STRING | DLMS_DATA_TYPE_BYREF)) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + else if (value->capacity < len) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + } + else + { + unsigned char* p = (unsigned char*)value->pVal; + for (a = 0; a != len; ++a) + { + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + break; + } + *p = hexArray[ch >> 4]; + p++; + *p = hexArray[ch & 0x0F]; + p++; + } + } +#else + value->strVal = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + BYTE_BUFFER_INIT(value->strVal); + value->vt = DLMS_DATA_TYPE_STRING; + bb_capacity(value->strVal, (uint16_t)(len * 2)); + for (a = 0; a != len; ++a) + { + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + break; + } + idHigh = ch >> 4; + idLow = ch & 0x0F; + bb_setInt8(value->strVal, hexArray[idHigh]); + bb_setInt8(value->strVal, hexArray[idLow]); + } +#endif //DLMS_IGNORE_MALLOC + return ret; +} + + +/** +* Get UInt8 value from DLMS data. +* +* buff +* Received DLMS data. +* info +* Data info. +* Returns parsed UInt8 value. +*/ +int getUInt8(gxByteBuffer* buff, gxDataInfo* info, dlmsVARIANT* value) +{ + int ret; + // If there is not enough data available. + if (buff->size - buff->position < 1) + { + info->complete = 0; + return 0; + } + if ((ret = bb_getUInt8(buff, (value->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &value->bVal : value->pbVal)) != 0) + { + return ret; + } + if ((value->vt & DLMS_DATA_TYPE_BYREF) == 0) + { + value->vt = DLMS_DATA_TYPE_UINT8; + } + return 0; +} + +/** +* Get Int16 value from DLMS data. +* +* buff +* Received DLMS data. +* info +* Data info. +* Returns parsed Int16 value. +*/ +int getInt16(gxByteBuffer* buff, gxDataInfo* info, dlmsVARIANT* value) +{ + int ret; + // If there is not enough data available. + if (buff->size - buff->position < 2) + { + info->complete = 0; + return 0; + } + if ((ret = bb_getInt16(buff, (value->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &value->iVal : value->piVal)) != 0) + { + return ret; + } + if ((value->vt & DLMS_DATA_TYPE_BYREF) == 0) + { + value->vt = DLMS_DATA_TYPE_INT16; + } + return 0; +} + +/** +* Get Int8 value from DLMS data. +* +* buff +* Received DLMS data. +* info +* Data info. +* Returns parsed Int8 value. +*/ +int getInt8(gxByteBuffer* buff, gxDataInfo* info, dlmsVARIANT* value) +{ + int ret; + // If there is not enough data available. + if (buff->size - buff->position < 1) + { + info->complete = 0; + return 0; + } + if ((ret = bb_getInt8(buff, (value->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &value->cVal : value->pcVal)) != 0) + { + return ret; + } + if ((value->vt & DLMS_DATA_TYPE_BYREF) == 0) + { + value->vt = DLMS_DATA_TYPE_INT8; + } + return 0; +} + + +/** +* Get UInt16 value from DLMS data. +* +* buff +* Received DLMS data. +* info +* Data info. +* Returns parsed UInt16 value. +*/ +int getUInt16(gxByteBuffer* buff, gxDataInfo* info, dlmsVARIANT* value) +{ + int ret; + // If there is not enough data available. + if (buff->size - buff->position < 2) + { + info->complete = 0; + return 0; + } + if ((ret = bb_getUInt16(buff, (value->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &value->uiVal : value->puiVal)) != 0) + { + return ret; + } + if ((value->vt & DLMS_DATA_TYPE_BYREF) == 0) + { + value->vt = DLMS_DATA_TYPE_UINT16; + } + return 0; +} + + +/** +* Get Int64 value from DLMS data. +* +* buff +* Received DLMS data. +* info +* Data info. +* Returns parsed Int64 value. +*/ +int getInt64(gxByteBuffer* buff, gxDataInfo* info, dlmsVARIANT* value) +{ + int ret; + // If there is not enough data available. + if (buff->size - buff->position < 8) + { + info->complete = 0; + return 0; + } + if ((ret = bb_getInt64(buff, (value->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &value->llVal : value->pllVal)) != 0) + { + return ret; + } + if ((value->vt & DLMS_DATA_TYPE_BYREF) == 0) + { + value->vt = DLMS_DATA_TYPE_INT64; + } + return 0; +} + + +/** +* Get UInt64 value from DLMS data. +* +* buff +* Received DLMS data. +* info +* Data info. +* Returns parsed UInt64 value. +*/ +int getUInt64(gxByteBuffer* buff, gxDataInfo* info, dlmsVARIANT* value) +{ + int ret; + // If there is not enough data available. + if (buff->size - buff->position < 8) + { + info->complete = 0; + return 0; + } + if ((ret = bb_getUInt64(buff, (value->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &value->ullVal : value->pullVal)) != 0) + { + return ret; + } + if ((value->vt & DLMS_DATA_TYPE_BYREF) == 0) + { + value->vt = DLMS_DATA_TYPE_UINT64; + } + return 0; +} + + +/** +* Get enumeration value from DLMS data. +* +* buff +* Received DLMS data. +* info +* Data info. +* Returns parsed enumeration value. +*/ +int getEnum(gxByteBuffer* buff, gxDataInfo* info, dlmsVARIANT* value) +{ + int ret; + // If there is not enough data available. + if (buff->size - buff->position < 1) + { + info->complete = 0; + return 0; + } + if ((ret = bb_getUInt8(buff, (value->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &value->bVal : value->pbVal)) != 0) + { + return ret; + } + if ((value->vt & DLMS_DATA_TYPE_BYREF) == 0) + { + value->vt = DLMS_DATA_TYPE_ENUM; + } + return 0; +} + +#ifndef DLMS_IGNORE_FLOAT64 +/** +* Get double value from DLMS data. +* +* buff +* Received DLMS data. +* info +* Data info. +* Returns Parsed double value. +*/ +int getDouble(gxByteBuffer* buff, gxDataInfo* info, dlmsVARIANT* value) +{ + int ret; + // If there is not enough data available. + if (buff->size - buff->position < 8) + { + info->complete = 0; + return 0; + } + if ((ret = bb_getDouble(buff, (value->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &value->dblVal : value->pdblVal)) != 0) + { + return ret; + } + if ((value->vt & DLMS_DATA_TYPE_BYREF) == 0) + { + value->vt = DLMS_DATA_TYPE_FLOAT64; + } + return 0; +} +#endif //#endif //DLMS_IGNORE_FLOAT32 + +#ifndef DLMS_IGNORE_FLOAT32 +/** +* Get float value from DLMS data. +* +* buff +* Received DLMS data. +* info +* Data info. +* Returns Parsed float value. +*/ +int getFloat(gxByteBuffer* buff, gxDataInfo* info, dlmsVARIANT* value) +{ + int ret; + // If there is not enough data available. + if (buff->size - buff->position < 4) + { + info->complete = 0; + return 0; + } + if ((ret = bb_getFloat(buff, (value->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &value->fltVal : value->pfltVal)) != 0) + { + return ret; + } + if ((value->vt & DLMS_DATA_TYPE_BYREF) == 0) + { + value->vt = DLMS_DATA_TYPE_FLOAT32; + } + return 0; +} + +#endif //DLMS_IGNORE_FLOAT32 + +/** +* Get time from DLMS data. +* +* buff +* Received DLMS data. +* info +* Data info. +* Returns Parsed time. +*/ +int getTime(gxByteBuffer* buff, gxDataInfo* info, dlmsVARIANT* value) +{ + int ret; + unsigned char ch, hour, minute, second; + uint16_t ms = 0xFFFF; + if (buff->size - buff->position < 4) + { + // If there is not enough data available. + info->complete = 0; + return 0; + } + // Get time. + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + hour = ch; + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + minute = ch; + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + second = ch; + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + if (ch != 0xFF) + { + ms = ch * 10; + } +#if !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + if ((value->vt & DLMS_DATA_TYPE_BYREF) == 0) + { + value->dateTime = (gxtime*)gxmalloc(sizeof(gxtime)); + } + time_init(value->dateTime, (uint16_t)-1, 0xFF, 0xFF, hour, minute, second, ms, 0x8000); + value->vt = DLMS_DATA_TYPE_TIME; +#else + time_init((gxtime*)value->pVal, -1, -1, -1, hour, minute, second, ms, 0x8000); +#endif //DLMS_IGNORE_MALLOC + return 0; +} + +/** +* Get date from DLMS data. +* +* buff +* Received DLMS data. +* info +* Data info. +* Returns Parsed date. +*/ +int getDate(gxByteBuffer* buff, gxDataInfo* info, dlmsVARIANT* value) +{ + int ret; + unsigned char month, day; + uint16_t year; + unsigned char ch; + if (buff->size - buff->position < 5) + { + // If there is not enough data available. + info->complete = 0; + return 0; + } + // Get year. + if ((ret = bb_getUInt16(buff, &year)) != 0) + { + return ret; + } + // Get month + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + month = ch; + // Get day. + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + day = ch; + // Skip week day + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + +#if !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + if ((value->vt & DLMS_DATA_TYPE_BYREF) == 0) + { + value->dateTime = (gxtime*)gxmalloc(sizeof(gxtime)); + } + time_init(value->dateTime, year, month, day, 0xFF, 0xFF, 0xFF, 0xFF, 0x8000); + if (ch > 7) + { + value->dateTime->skip |= DATETIME_SKIPS_DAYOFWEEK; + } + value->vt = DLMS_DATA_TYPE_DATE; +#else + time_init((gxtime*)value->pVal, year, month, day, -1, -1, -1, -1, 0x8000); + if (ch > 7) + { + ((gxtime*)value->pVal)->skip |= DATETIME_SKIPS_DAYOFWEEK; + } +#endif //DLMS_IGNORE_MALLOC + return 0; +} + +/** +* Get date and time from DLMS data. +* +* buff +* Received DLMS data. +* info +* Data info. +* Returns Parsed date and time. +*/ +int getDateTime(gxByteBuffer* buff, gxDataInfo* info, dlmsVARIANT* value) +{ + uint16_t year; +#ifdef DLMS_USE_EPOCH_TIME + int ret, status; +#else + int ret, ms, status; +#endif // DLMS_USE_EPOCH_TIME + unsigned char ch; + // If there is not enough data available. + if (buff->size - buff->position < 12) + { + info->complete = 0; + return 0; + } + // Get year. + if ((ret = bb_getUInt16(buff, &year)) != 0) + { + return ret; + } + gxtime* t; +#if defined(DLMS_IGNORE_MALLOC) + t = value->pVal; +#else + if ((value->vt & DLMS_DATA_TYPE_BYREF) != 0) + { + t = value->pVal; + } + else + { + t = value->dateTime = (gxtime*)gxmalloc(sizeof(gxtime)); + value->vt = DLMS_DATA_TYPE_DATETIME; + } +#endif //DLMS_IGNORE_MALLOC +#ifdef DLMS_USE_EPOCH_TIME + short deviation; + unsigned char mon = 0, day = 0, hour = 0, min = 0, sec = 0, wday = 0, skip = 0; + // Get month + if ((ret = bb_getUInt8(buff, &mon)) != 0) + { + return ret; + } + // Get day + if ((ret = bb_getUInt8(buff, &day)) != 0) + { + return ret; + } + // Skip week day + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + // Get time. + if ((ret = bb_getUInt8(buff, &hour)) != 0) + { + return ret; + } + if ((ret = bb_getUInt8(buff, &min)) != 0) + { + return ret; + } + if ((ret = bb_getUInt8(buff, &sec)) != 0) + { + return ret; + } + //Get ms. + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + if ((ret = bb_getInt16(buff, &deviation)) != 0) + { + return ret; + } + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + status = ch; + t->status = (DLMS_CLOCK_STATUS)status; + skip = DATETIME_SKIPS_MS; + if (year < 1 || year == 0xFFFF) + { + skip |= DATETIME_SKIPS_YEAR; + year = 1970; + } + if (wday > 7) + { + wday = 0; + skip |= DATETIME_SKIPS_DAYOFWEEK; + } + if ((mon < 1 || mon > 12) && mon != 0xFE && mon != 0xFD) + { + skip |= DATETIME_SKIPS_MONTH; + mon = 1; + } + if ((day < 1 || day > 31) && day != 0xFE && day != 0xFD) + { + skip |= DATETIME_SKIPS_DAY; + day = 1; + } + if (hour > 24) + { + skip |= DATETIME_SKIPS_HOUR; + hour = 0; + } + if (min > 60) + { + skip |= DATETIME_SKIPS_MINUTE; + min = 0; + } + if (sec > 60) + { + skip |= DATETIME_SKIPS_SECOND; + sec = 0; + } + time_init(t, year, mon, day, hour, min, sec, 0, deviation); + t->skip = skip; + t->status = status; + if (status == 0xFF) + { + t->skip = (DATETIME_SKIPS)(t->skip | DATETIME_SKIPS_STATUS); + t->status = 0; + } +#else + t->value.tm_yday = 0; + t->value.tm_year = year; + // Get month + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + t->value.tm_mon = ch; + // Get day + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + t->value.tm_mday = ch; + // Skip week day + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + t->value.tm_wday = ch; + // Get time. + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + t->value.tm_hour = ch; + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + t->value.tm_min = ch; + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + t->value.tm_sec = ch; + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + t->extraInfo = DLMS_DATE_TIME_EXTRA_INFO_NONE; + t->skip = DATETIME_SKIPS_NONE; + ms = ch; + if (ms != 0xFF) + { + ms *= 10; + } + else + { + t->skip = (DATETIME_SKIPS)(t->skip | DATETIME_SKIPS_MS); + } + if ((ret = bb_getInt16(buff, &t->deviation)) != 0) + { + return ret; + } + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + if (ch == 0xFF) + { + t->skip = (DATETIME_SKIPS)(t->skip | DATETIME_SKIPS_STATUS); + ch = 0; + } + status = ch; + t->status = (DLMS_CLOCK_STATUS)status; + if (year < 1 || year == 0xFFFF) + { + t->skip = (DATETIME_SKIPS)(t->skip | DATETIME_SKIPS_YEAR); + t->value.tm_year = 1; + } + else + { + t->value.tm_year -= 1900; + } + if (t->value.tm_wday < 0 || t->value.tm_wday > 7) + { + t->value.tm_wday = 0; + t->skip = (DATETIME_SKIPS)(t->skip | DATETIME_SKIPS_DAYOFWEEK); + } + if (t->value.tm_mon == 0xFE) + { + t->extraInfo |= DLMS_DATE_TIME_EXTRA_INFO_DST_BEGIN; + t->value.tm_mon = 0; + } + else if (t->value.tm_mon == 0xFD) + { + t->extraInfo |= DLMS_DATE_TIME_EXTRA_INFO_DST_END; + t->value.tm_mon = 0; + } + else if (t->value.tm_mon < 1 || t->value.tm_mon > 12) + { + t->skip = (DATETIME_SKIPS)(t->skip | DATETIME_SKIPS_MONTH); + t->value.tm_mon = 0; + } + else + { + t->value.tm_mon -= 1; + } + if (t->value.tm_mday == 0xFD) + { + // 2nd last day of month. + t->value.tm_mday = 1; + t->extraInfo |= DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY2; + } + else if (t->value.tm_mday == 0xFE) + { + //Last day of month + t->value.tm_mday = 1; + t->extraInfo |= DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY; + } + else if (t->value.tm_mday == -1 || t->value.tm_mday == 0 || t->value.tm_mday > 31) + { + t->skip = (DATETIME_SKIPS)(t->skip | DATETIME_SKIPS_DAY); + t->value.tm_mday = 1; + } + if (t->value.tm_hour < 0 || t->value.tm_hour > 24) + { + t->skip = (DATETIME_SKIPS)(t->skip | DATETIME_SKIPS_HOUR); + t->value.tm_hour = 0; + } + if (t->value.tm_min < 0 || t->value.tm_min > 60) + { + t->skip = (DATETIME_SKIPS)(t->skip | DATETIME_SKIPS_MINUTE); + t->value.tm_min = 0; + } + if (t->value.tm_sec < 0 || t->value.tm_sec > 60) + { + t->skip = (DATETIME_SKIPS)(t->skip | DATETIME_SKIPS_SECOND); + t->value.tm_sec = 0; + } + t->value.tm_isdst = (status & DLMS_CLOCK_STATUS_DAYLIGHT_SAVE_ACTIVE); + mktime(&t->value); +#endif //DLMS_USE_EPOCH_TIME + return 0; +} + +#ifndef DLMS_IGNORE_MALLOC + +int getCompactArrayItem( + gxByteBuffer* buff, + DLMS_DATA_TYPE dt, + variantArray* list, + uint32_t len) +{ + int ret; + gxDataInfo tmp; + di_init(&tmp); + tmp.type = dt; + uint32_t start = buff->position; + dlmsVARIANT* value = gxmalloc(sizeof(dlmsVARIANT)); + if (value == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + var_init(value); + if (dt == DLMS_DATA_TYPE_STRING) + { + while (buff->position - start < len) + { + var_clear(value); + di_init(&tmp); + tmp.type = dt; + if ((ret = getString(buff, &tmp, 0, value)) != 0) + { + return ret; + } + va_push(list, value); + if (!tmp.complete) + { + break; + } + } + } + else if (dt == DLMS_DATA_TYPE_OCTET_STRING) + { + while (buff->position - start < len) + { + var_clear(value); + di_init(&tmp); + tmp.type = dt; + if ((ret = getOctetString(buff, &tmp, 0, value)) != 0) + { + return ret; + } + va_push(list, value); + if (!tmp.complete) + { + break; + } + } + } + else + { + while (buff->position - start < len) + { + var_clear(value); + di_init(&tmp); + tmp.type = dt; + if ((ret = dlms_getData(buff, &tmp, value)) != 0) + { + return ret; + } + va_push(list, value); + if (!tmp.complete) + { + break; + } + } + } + return 0; +} + +int getCompactArrayItem2( + gxByteBuffer* buff, + variantArray* dt, + variantArray* list, + int len) +{ + int ret, pos; + dlmsVARIANT* tmp = gxmalloc(sizeof(dlmsVARIANT)); + if (tmp == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + dlmsVARIANT* it; + var_init(tmp); + tmp->vt = DLMS_DATA_TYPE_ARRAY; + tmp->Arr = (variantArray*)gxmalloc(sizeof(variantArray)); + if (tmp->Arr == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + va_init(tmp->Arr); + for (pos = 0; pos != dt->size; ++pos) + { + if ((ret = va_getByIndex(dt, pos, &it)) != 0) + { + var_clear(tmp); + gxfree(tmp); + return ret; + } + if (it->vt == DLMS_DATA_TYPE_ARRAY || it->vt == DLMS_DATA_TYPE_STRUCTURE) + { + if ((ret = getCompactArrayItem2(buff, it->Arr, tmp->Arr, 1)) != 0) + { + var_clear(tmp); + gxfree(tmp); + return ret; + } + } + else + { + if ((ret = getCompactArrayItem(buff, (DLMS_DATA_TYPE)it->bVal, tmp->Arr, 1)) != 0) + { + var_clear(tmp); + gxfree(tmp); + return ret; + } + } + } + va_push(list, tmp); + return 0; +} + +int getDataTypes( + gxByteBuffer* buff, + variantArray* cols, + int len) +{ + int ret; + unsigned char ch; + uint16_t cnt; + DLMS_DATA_TYPE dt; + if (cols->size == 0) + { + va_capacity(cols, (uint16_t)len); + } + for (int pos = 0; pos != len; ++pos) + { + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + dt = (DLMS_DATA_TYPE)ch; + if (dt == DLMS_DATA_TYPE_ARRAY) + { + if ((ret = bb_getUInt16(buff, &cnt)) != 0) + { + return ret; + } + dlmsVARIANT tmp; + dlmsVARIANT* it; + var_init(&tmp); + tmp.Arr = (variantArray*)gxmalloc(sizeof(variantArray)); + tmp.vt = DLMS_DATA_TYPE_ARRAY; + if (tmp.Arr == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + va_init(tmp.Arr); + getDataTypes(buff, tmp.Arr, 1); + if ((ret = va_getByIndex(tmp.Arr, 0, &it)) != 0) + { + va_clear(cols); + return ret; + } + dlmsVARIANT* tmp2 = (dlmsVARIANT*)gxmalloc(sizeof(dlmsVARIANT)); + if (tmp2 == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + var_init(tmp2); + tmp2->vt = DLMS_DATA_TYPE_ARRAY; + tmp2->Arr = (variantArray*)gxmalloc(sizeof(variantArray)); + if (tmp2->Arr == NULL) + { + var_clear(tmp2); + gxfree(tmp2); + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + va_init(tmp2->Arr); + for (int i = 0; i != cnt; ++i) + { + dlmsVARIANT* tmp3 = (dlmsVARIANT*)gxmalloc(sizeof(dlmsVARIANT)); + if (tmp3 == NULL) + { + var_clear(tmp2); + gxfree(tmp2); + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + var_init(tmp3); + if ((ret = var_copy(tmp3, it)) != 0) + { + var_clear(tmp3); + gxfree(tmp3); + var_clear(tmp2); + gxfree(tmp2); + return ret; + } + va_push(tmp2->Arr, tmp3); + } + var_clear(&tmp); + va_push(cols, tmp2); + } + else if (dt == DLMS_DATA_TYPE_STRUCTURE) + { + dlmsVARIANT* tmp = gxmalloc(sizeof(dlmsVARIANT)); + if (tmp == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + var_init(tmp); + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + va_clear(cols); + var_clear(tmp); + gxfree(tmp); + return ret; + } + tmp->vt = DLMS_DATA_TYPE_STRUCTURE; + tmp->Arr = (variantArray*)gxmalloc(sizeof(variantArray)); + if (tmp->Arr == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + va_init(tmp->Arr); + getDataTypes(buff, tmp->Arr, ch); + va_push(cols, tmp); + } + else + { + dlmsVARIANT* tmp = gxmalloc(sizeof(dlmsVARIANT)); + if (tmp == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + var_init(tmp); + if (cols->size == 0) + { + va_capacity(cols, 1); + } + var_setUInt8(tmp, dt); + va_push(cols, tmp); + } + } + return 0; +} + +//Get compact array value from DLMS data. +int getCompactArray( + dlmsSettings* settings, + gxByteBuffer* buff, + gxDataInfo* info, + dlmsVARIANT* value, + unsigned char onlyDataTypes) +{ + int ret, pos; + uint16_t len; + unsigned char ch; + var_clear(value); + // If there is not enough data available. + if (buff->size - buff->position < 2) + { + info->complete = 0; + return 0; + } + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + DLMS_DATA_TYPE dt = (DLMS_DATA_TYPE)ch; + if (dt == DLMS_DATA_TYPE_ARRAY) + { + //Invalid compact array data. + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if ((ret = hlp_getObjectCount2(buff, &len)) != 0) + { + return ret; + } + value->Arr = (variantArray*)gxmalloc(sizeof(variantArray)); + value->vt = DLMS_DATA_TYPE_ARRAY; + if (value->Arr == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + va_init(value->Arr); + if (dt == DLMS_DATA_TYPE_STRUCTURE) + { + // Get data types. + variantArray cols; + va_init(&cols); + if ((ret = getDataTypes(buff, &cols, len)) != 0) + { + va_clear(&cols); + return ret; + } + if (onlyDataTypes) + { + va_attach2(value->Arr, &cols); + return 0; + } + if (buff->position == buff->size) + { + len = 0; + } + else + { + if ((ret = hlp_getObjectCount2(buff, &len)) != 0) + { + va_clear(&cols); + return ret; + } + } + int start = buff->position; + while (buff->position - start < len) + { + dlmsVARIANT* it, * it2, * it3, * it4; + variantArray* row = (variantArray*)gxmalloc(sizeof(variantArray)); + if (row == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + va_init(row); + for (pos = 0; pos != cols.size; ++pos) + { + if ((ret = va_getByIndex(&cols, pos, &it)) != 0) + { + va_clear(&cols); + va_clear(row); + gxfree(row); + return ret; + } + if (it->vt == DLMS_DATA_TYPE_STRUCTURE) + { + if ((ret = getCompactArrayItem2(buff, it->Arr, row, 1)) != 0) + { + va_clear(&cols); + va_clear(row); + gxfree(row); + return ret; + } + } + else if (it->vt == DLMS_DATA_TYPE_ARRAY) + { + int pos1; + variantArray tmp2; + va_init(&tmp2); +#ifdef DLMS_ITALIAN_STANDARD + //Some Italy meters require that there is a array count in data. + if (info->appendAA) + { + if ((ret = hlp_getObjectCount2(buff, &len)) != 0) + { + va_clear(&cols); + return ret; + } + if (it->Arr->size != len) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + } +#endif //DLMS_ITALIAN_STANDARD + + if ((ret = getCompactArrayItem2(buff, it->Arr, &tmp2, 1)) != 0 || + (ret = va_getByIndex(&tmp2, 0, &it2)) != 0) + { + va_clear(&tmp2); + va_clear(&cols); + va_clear(row); + gxfree(row); + return ret; + } + for (pos1 = 0; pos1 != it2->Arr->size; ++pos1) + { + if ((ret = va_getByIndex(it2->Arr, pos1, &it3)) != 0) + { + va_clear(&tmp2); + va_clear(&cols); + va_clear(row); + gxfree(row); + return ret; + } + it4 = (dlmsVARIANT*)gxmalloc(sizeof(dlmsVARIANT)); + if (it4 == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + var_init(it4); + if ((ret = var_copy(it4, it3)) != 0) + { + return ret; + } + va_push(row, it4); + } + va_clear(&tmp2); + } + else + { + if ((ret = getCompactArrayItem(buff, (DLMS_DATA_TYPE)it->bVal, row, 1)) != 0) + { + va_clear(&cols); + va_clear(row); + gxfree(row); + return ret; + } + } + if (buff->position == buff->size) + { + break; + } + } + //If all columns are read. + if (row->size >= cols.size) + { + dlmsVARIANT* tmp = (dlmsVARIANT*)gxmalloc(sizeof(dlmsVARIANT)); + if (tmp == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + var_init(tmp); + tmp->Arr = row; + tmp->vt = DLMS_DATA_TYPE_ARRAY; + va_push(value->Arr, tmp); + } + else + { + break; + } + } + va_clear(&cols); + return 0; + } + return getCompactArrayItem(buff, dt, value->Arr, len); +} +#endif //DLMS_IGNORE_MALLOC + +int dlms_getData(gxByteBuffer* data, gxDataInfo* info, dlmsVARIANT* value) +{ + unsigned char ch, knownType; + int ret = 0; +#ifndef DLMS_IGNORE_MALLOC + uint32_t startIndex = data->position; + var_clear(value); +#endif //DLMS_IGNORE_MALLOC + if (data->position == data->size) + { + info->complete = 0; + return 0; + } + info->complete = 1; + knownType = info->type != DLMS_DATA_TYPE_NONE; + if (!knownType) + { + ret = bb_getUInt8(data, &ch); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + info->type = (DLMS_DATA_TYPE)ch; + } + if (info->type == DLMS_DATA_TYPE_NONE) + { + //Do nothing. + return DLMS_ERROR_CODE_OK; + } + if (data->position == data->size) + { + info->complete = 0; + return 0; + } + switch (info->type & ~DLMS_DATA_TYPE_BYREF) + { + case DLMS_DATA_TYPE_ARRAY: + case DLMS_DATA_TYPE_STRUCTURE: + { +#if !defined(DLMS_IGNORE_MALLOC) + ret = getArray(data, info, (uint16_t)startIndex, value); + value->vt = info->type; +#else + if ((value->vt & DLMS_DATA_TYPE_BYREF) != 0) + { + uint16_t count, pos; + if ((ret = hlp_getObjectCount2(data, &count)) != 0) + { + return ret; + } + //If user try to write too many items. + if (va_getCapacity(value->Arr) < count) + { + return DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } + value->Arr->size = count; + for (pos = 0; pos != count; ++pos) + { + gxDataInfo info2; + di_init(&info2); + dlmsVARIANT* value2; + if ((ret = va_getByIndex(value->Arr, pos, &value2)) != 0 || + (ret = dlms_getData(data, &info2, value2)) != 0) + { + return ret; + } + } + } + else + { + value->vt = DLMS_DATA_TYPE_OCTET_STRING; + --data->position; + value->byteArr = data; + } + return 0; +#endif //#!defined(DLMS_IGNORE_MALLOC) + break; + } + case DLMS_DATA_TYPE_BOOLEAN: + { + ret = getBool(data, info, value); + break; + } + case DLMS_DATA_TYPE_BIT_STRING: +#if !defined(DLMS_IGNORE_MALLOC) + ret = getBitString(data, info, value); +#else + if ((value->vt & DLMS_DATA_TYPE_BYREF) != 0) + { + ret = getBitString(data, info, value); + } + else + { + value->vt = DLMS_DATA_TYPE_OCTET_STRING; + --data->position; + value->byteArr = data; + return 0; + } +#endif //!defined(DLMS_IGNORE_MALLOC) + break; + case DLMS_DATA_TYPE_INT32: + ret = getInt32(data, info, value); + break; + case DLMS_DATA_TYPE_UINT32: + ret = getUInt32(data, info, value); + break; + case DLMS_DATA_TYPE_STRING: +#if !defined(DLMS_IGNORE_MALLOC) + ret = getString(data, info, knownType, value); +#else + if ((value->vt & DLMS_DATA_TYPE_BYREF) != 0) + { + ret = getString(data, info, 0, value); + } + else + { + value->vt = DLMS_DATA_TYPE_OCTET_STRING; + --data->position; + value->byteArr = data; + ret = 0; + } +#endif //!defined(DLMS_IGNORE_MALLOC) + break; + case DLMS_DATA_TYPE_STRING_UTF8: +#if !defined(DLMS_IGNORE_MALLOC) + ret = getUtfString(data, info, knownType, value); +#else + value->vt = DLMS_DATA_TYPE_OCTET_STRING; + --data->position; + value->byteArr = data; + return 0; +#endif //!defined(DLMS_IGNORE_MALLOC) + break; + case DLMS_DATA_TYPE_OCTET_STRING: +#if !defined(DLMS_IGNORE_MALLOC) + ret = getOctetString(data, info, knownType, value); +#else + if ((value->vt & DLMS_DATA_TYPE_BYREF) != 0) + { + ret = getOctetString(data, info, 0, value); + } + else + { + value->vt = DLMS_DATA_TYPE_OCTET_STRING; + --data->position; + value->byteArr = data; + ret = 0; + } +#endif // DLMS_IGNORE_MALLOC + break; + case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL: + ret = getBcd(data, info, knownType, value); + break; + case DLMS_DATA_TYPE_INT8: + ret = getInt8(data, info, value); + break; + case DLMS_DATA_TYPE_INT16: + ret = getInt16(data, info, value); + break; + case DLMS_DATA_TYPE_UINT8: + ret = getUInt8(data, info, value); + break; + case DLMS_DATA_TYPE_UINT16: + ret = getUInt16(data, info, value); + break; + case DLMS_DATA_TYPE_COMPACT_ARRAY: +#ifndef DLMS_IGNORE_MALLOC + ret = getCompactArray(NULL, data, info, value, 0); +#endif //DLMS_IGNORE_MALLOC + break; + case DLMS_DATA_TYPE_INT64: + ret = getInt64(data, info, value); + break; + case DLMS_DATA_TYPE_UINT64: + ret = getUInt64(data, info, value); + break; + case DLMS_DATA_TYPE_ENUM: + ret = getEnum(data, info, value); + break; +#ifndef DLMS_IGNORE_FLOAT32 + case DLMS_DATA_TYPE_FLOAT32: + ret = getFloat(data, info, value); + break; +#endif //DLMS_IGNORE_FLOAT32 +#ifndef DLMS_IGNORE_FLOAT64 + case DLMS_DATA_TYPE_FLOAT64: + ret = getDouble(data, info, value); + break; +#endif //DLMS_IGNORE_FLOAT64 + case DLMS_DATA_TYPE_DATETIME: +#if defined(DLMS_IGNORE_MALLOC) + if ((value->vt & DLMS_DATA_TYPE_BYREF) != 0) + { + ret = getDateTime(data, info, value); + } + else + { + value->vt = DLMS_DATA_TYPE_OCTET_STRING; + --data->position; + value->byteArr = data; + ret = 0; + } +#else + ret = getDateTime(data, info, value); +#endif //DLMS_IGNORE_MALLOC + break; + case DLMS_DATA_TYPE_DATE: +#if defined(DLMS_IGNORE_MALLOC) + if ((value->vt & DLMS_DATA_TYPE_BYREF) != 0) + { + ret = getDate(data, info, value); + } + else + { + value->vt = DLMS_DATA_TYPE_OCTET_STRING; + --data->position; + value->byteArr = data; + ret = 0; + } +#else + ret = getDate(data, info, value); +#endif //DLMS_IGNORE_MALLOC + break; + case DLMS_DATA_TYPE_TIME: +#if defined(DLMS_IGNORE_MALLOC) + if ((value->vt & DLMS_DATA_TYPE_BYREF) != 0) + { + ret = getTime(data, info, value); + } + else + { + value->vt = DLMS_DATA_TYPE_OCTET_STRING; + --data->position; + value->byteArr = data; + ret = 0; + } +#else + ret = getTime(data, info, value); +#endif //DLMS_IGNORE_MALLOC + break; + default: +#ifdef _DEBUG + //Assert in debug version. +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif +#endif + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } +#ifdef DLMS_IGNORE_MALLOC + if (ret == 0 && (value->vt & DLMS_DATA_TYPE_BYREF) == 0) + { + value->vt = info->type; + } +#else + if (ret == 0 && (value->vt & DLMS_DATA_TYPE_BYREF) == 0) + { + value->vt = info->type; + } +#endif //DLMS_IGNORE_MALLOC + return ret; +} + +#ifndef DLMS_IGNORE_HDLC + +//Return DLMS_ERROR_CODE_FALSE if LLC bytes are not included. +int dlms_checkLLCBytes(dlmsSettings* settings, gxByteBuffer* data) +{ + if (settings->server) + { + //Check LLC bytes. + if (memcmp(data->data + data->position, LLC_SEND_BYTES, 3) != 0) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + } + else + { + //Check LLC bytes. + if (memcmp(data->data + data->position, LLC_REPLY_BYTES, 3) != 0) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + } + data->position += 3; + return DLMS_ERROR_CODE_OK; +} + +int dlms_getHDLCAddress( + gxByteBuffer* buff, + uint32_t* address, + unsigned char checkClientAddress) +{ + unsigned char ch; + uint16_t s, pos; + uint32_t l; + int ret, size = 0; + for (pos = (uint16_t)buff->position; pos != (uint16_t)buff->size; ++pos) + { + ++size; + if ((ret = bb_getUInt8ByIndex(buff, pos, &ch)) != 0) + { + return ret; + } + if ((ch & 0x1) == 1) + { + break; + } + } + //DLMS CCT test requires that client size is one byte. + if (checkClientAddress && size != 1) + { + return DLMS_ERROR_CODE_INVALID_CLIENT_ADDRESS; + } + + if (size == 1) + { + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + *address = ((ch & 0xFE) >> 1); + } + else if (size == 2) + { + if ((ret = bb_getUInt16(buff, &s)) != 0) + { + return ret; + } + *address = ((s & 0xFE) >> 1) | ((s & 0xFE00) >> 2); + } + else if (size == 4) + { + if ((ret = bb_getUInt32(buff, &l)) != 0) + { + return ret; + } + *address = ((l & 0xFE) >> 1) | ((l & 0xFE00) >> 2) + | ((l & 0xFE0000) >> 3) | ((l & 0xFE000000) >> 4); + } + else + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return DLMS_ERROR_CODE_OK; +} + +void dlms_getServerAddress(uint32_t address, uint32_t* logical, uint32_t* physical) +{ + if (address < 0x4000) + { + *logical = address >> 7; + *physical = address & 0x7F; + } + else + { + *logical = address >> 14; + *physical = address & 0x3FFF; + } +} + +/** +* Check that client and server address match. +* +* @param server +* Is server. +* @param settings +* DLMS settings. +* @param reply +* Received data. +* @param index +* Position. +* @return True, if client and server address match. +*/ +int dlms_checkHdlcAddress( + unsigned char server, + dlmsSettings* settings, + gxByteBuffer* reply, + uint16_t index) +{ + unsigned char ch; + int ret; + uint32_t source, target; + // Get destination and source addresses. + if ((ret = dlms_getHDLCAddress(reply, &target, 0)) != 0) + { + return ret; + } + if ((ret = dlms_getHDLCAddress(reply, &source, server)) != 0) + { + return ret; + } + if (server) + { + // Check that server addresses match. + if (settings->serverAddress != 0 && settings->serverAddress != target) + { + // Get frame command. + if (bb_getUInt8ByIndex(reply, reply->position, &ch) != 0) + { + return DLMS_ERROR_CODE_INVALID_SERVER_ADDRESS; + } + return DLMS_ERROR_CODE_INVALID_SERVER_ADDRESS; + } + else + { + settings->serverAddress = target; + } + + // Check that client addresses match. + if (settings->clientAddress != 0 && settings->clientAddress != source) + { + // Get frame command. + if (bb_getUInt8ByIndex(reply, reply->position, &ch) != 0) + { + return DLMS_ERROR_CODE_INVALID_CLIENT_ADDRESS; + } + //If SNRM and client has not call disconnect and changes client ID. + if (ch == DLMS_COMMAND_SNRM) + { + settings->clientAddress = (uint16_t)source; + } + else + { + return DLMS_ERROR_CODE_INVALID_CLIENT_ADDRESS; + } + } + else + { + settings->clientAddress = (uint16_t)source; + } + } + else + { + // Check that client addresses match. + if (settings->clientAddress != target) + { + // If echo. + if (settings->clientAddress == source && settings->serverAddress == target) + { + reply->position = index + 1; + } + return DLMS_ERROR_CODE_FALSE; + } + // Check that server addresses match. + if (settings->serverAddress != source && + // If All-station (Broadcast). + (settings->serverAddress & 0x7F) != 0x7F && (settings->serverAddress & 0x3FFF) != 0x3FFF) + { + //Check logical and physical address separately. + //This is done because some meters might send four bytes + //when only two bytes are needed. + uint32_t readLogical, readPhysical, logical, physical; + dlms_getServerAddress(source, &readLogical, &readPhysical); + dlms_getServerAddress(settings->serverAddress, &logical, &physical); + if (readLogical != logical || readPhysical != physical) + { + return DLMS_ERROR_CODE_FALSE; + } + } + } + return DLMS_ERROR_CODE_OK; +} + +int dlms_getAddress(int32_t value, uint32_t* address, int* size) +{ + if (value < 0x80) + { + *address = (unsigned char)(value << 1 | 1); + *size = 1; + return 0; + } + else if (value < 0x4000) + { + *address = (uint16_t)((value & 0x3F80) << 2 | (value & 0x7F) << 1 | 1); + *size = 2; + } + else if (value < 0x10000000) + { + *address = (uint32_t)((value & 0xFE00000) << 4 | (value & 0x1FC000) << 3 + | (value & 0x3F80) << 2 | (value & 0x7F) << 1 | 1); + *size = 4; + } + else + { + //Invalid address + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return DLMS_ERROR_CODE_OK; +} + +/** +* Get HDLC address as bytes. +*/ +int dlms_getAddressBytes( + uint32_t value, + gxByteBuffer* bytes) +{ + int ret, size; + uint32_t address; + if ((ret = dlms_getAddress(value, &address, &size)) != 0) + { + return ret; + } + if (size == 1) + { + bb_setUInt8(bytes, (unsigned char)address); + } + else if (size == 2) + { + bb_setUInt16(bytes, (uint16_t)address); + } + else if (size == 4) + { + bb_setUInt32(bytes, address); + } + else + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return DLMS_ERROR_CODE_OK; +} + +int dlms_getHdlcFrame( + dlmsSettings* settings, + int frame, + gxByteBuffer* data, + gxByteBuffer* reply) +{ + unsigned char tmp[4], tmp2[4]; + uint16_t crc; + int ret; + uint16_t frameSize; +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + uint32_t len = 0; +#else + uint16_t len = 0; +#endif + gxByteBuffer primaryAddress, secondaryAddress; + bb_clear(reply); + bb_attach(&primaryAddress, tmp, 0, 4); + bb_attach(&secondaryAddress, tmp2, 0, 4); + if (settings->server) + { + if ((ret = bb_capacity(&primaryAddress, 1)) == 0 && + (ret = bb_capacity(&secondaryAddress, 4)) == 0) + { + if ((frame == 0x13 || frame == 0x3) && ((dlmsServerSettings*)settings)->pushClientAddress != 0) + { + ret = dlms_getAddressBytes(((dlmsServerSettings*)settings)->pushClientAddress, &primaryAddress); + } + else + { + ret = dlms_getAddressBytes(settings->clientAddress, &primaryAddress); + } + if (ret == 0) + { + ret = dlms_getAddressBytes(settings->serverAddress, &secondaryAddress); + } + } + } + else + { + ret = bb_capacity(&primaryAddress, 4); + if (ret == 0) + { + ret = bb_capacity(&secondaryAddress, 1); + } + if (ret == 0 && (ret = dlms_getAddressBytes(settings->serverAddress, &primaryAddress)) == 0) + { + ret = dlms_getAddressBytes(settings->clientAddress, &secondaryAddress); + } + } + + // Add BOP + if (ret == 0 && (ret = bb_capacity(reply, 8)) == 0) + { + ret = bb_setUInt8(reply, HDLC_FRAME_START_END); + } + + frameSize = settings->maxInfoTX; + if (data != NULL && data->position == 0) + { + frameSize -= 3; + } + // If no data + if (ret == 0 && (data == NULL || data->size == 0)) + { + len = 0; + ret = bb_setUInt8(reply, 0xA0); + } + else if (ret == 0 && data->size - data->position <= frameSize) + { + // Is last packet. + len = bb_available(data); + ret = bb_setUInt8(reply, (unsigned char)(0xA0 | (((7 + primaryAddress.size + secondaryAddress.size + len) >> 8) & 0x7))); + } + else if (ret == 0) + { + // More data to left. + len = frameSize; + ret = bb_setUInt8(reply, (unsigned char)(0xA8 | (((7 + primaryAddress.size + secondaryAddress.size + len) >> 8) & 0x7))); + } + // Frame len. + if (ret == 0 && len == 0) + { + ret = bb_setUInt8(reply, (unsigned char)(5 + primaryAddress.size + secondaryAddress.size + len)); + } + else if (ret == 0) + { + if ((ret = bb_capacity(reply, (uint16_t)(11 + len))) == 0) + { + ret = bb_setUInt8(reply, (unsigned char)(7 + primaryAddress.size + secondaryAddress.size + len)); + } + } + // Add primary address. + if (ret == 0 && (ret = bb_set2(reply, &primaryAddress, 0, primaryAddress.size)) == 0) + { + // Add secondary address. + ret = bb_set2(reply, &secondaryAddress, 0, secondaryAddress.size); + } + + // Add frame ID. + if (ret == 0 && frame == 0) + { + ret = bb_setUInt8(reply, getNextSend(settings, 1)); + } + else if (ret == 0) + { + ret = bb_setUInt8(reply, (unsigned char)frame); + } + if (ret == 0) + { + // Add header CRC. + crc = countCRC(reply, 1, (reply->size - 1)); + ret = bb_setUInt16(reply, crc); + } + if (ret == 0 && len != 0) + { + // Add data. + if ((ret = bb_set2(reply, data, data->position, len)) == 0) + { + // Add data CRC. + crc = countCRC(reply, 1, (reply->size - 1)); + ret = bb_setUInt16(reply, crc); + } + } + // Add EOP + if (ret == 0) + { + ret = bb_setUInt8(reply, HDLC_FRAME_START_END); + } + // Remove sent data in server side. + if (ret == 0 && settings->server) + { + if (data != NULL) + { + //If all data is sent. + if (data->size == data->position) + { + ret = bb_clear(data); + } + else + { + //Remove sent data. + ret = bb_move(data, data->position, 0, data->size - data->position); + data->position = 0; + } + } + } + bb_clear(&primaryAddress); + bb_clear(&secondaryAddress); + return ret; +} +#endif //DLMS_IGNORE_HDLC + +#ifndef DLMS_IGNORE_PLC +int dlms_getPlcFrame( + dlmsSettings* settings, + unsigned char creditFields, + gxByteBuffer* data, + gxByteBuffer* reply) +{ + int frameSize = bb_available(data); + //Max frame size is 124 bytes. + if (frameSize > 134) + { + frameSize = 134; + } + //PAD Length. + unsigned char padLen = (unsigned char)((36 - ((11 + frameSize) % 36)) % 36); + bb_capacity(reply, 15 + frameSize + padLen); + //Add STX + bb_setUInt8(reply, 2); + //Length. + bb_setUInt8(reply, (unsigned char)(11 + frameSize)); + //Length. + bb_setUInt8(reply, 0x50); + //Add Credit fields. + bb_setUInt8(reply, creditFields); + //Add source and target MAC addresses. + bb_setUInt8(reply, (unsigned char)(settings->plcSettings.macSourceAddress >> 4)); + int val = settings->plcSettings.macSourceAddress << 12; + val |= settings->plcSettings.macDestinationAddress & 0xFFF; + bb_setUInt16(reply, (uint16_t)val); + bb_setUInt8(reply, padLen); + //Control byte. + bb_setUInt8(reply, DLMS_PLC_DATA_LINK_DATA_REQUEST); + bb_setUInt8(reply, (unsigned char)settings->serverAddress); + bb_setUInt8(reply, (unsigned char)settings->clientAddress); + bb_set(reply, data->data + data->position, frameSize); + data->position += frameSize; + //Add padding. + while (padLen != 0) + { + bb_setUInt8(reply, 0); + --padLen; + } + //Checksum. + uint16_t crc = countCRC(reply, 0, reply->size); + bb_setUInt16(reply, crc); + //Remove sent data in server side. + if (settings->server) + { + if (data->size == data->position) + { + bb_clear(data); + } + else + { + bb_move(data, data->position, 0, data->size - data->position); + data->position = 0; + } + } + return 0; +} + +// Reserved for internal use. +const uint32_t CRCPOLY = 0xD3B6BA00; +uint32_t dlms_countFCS24(unsigned char* buff, int index, int count) +{ + unsigned char i, j; + uint32_t crcreg = 0; + for (j = 0; j < count; ++j) + { + unsigned char b = buff[index + j]; + for (i = 0; i < 8; ++i) + { + crcreg >>= 1; + if ((b & 0x80) != 0) + { + crcreg |= 0x80000000; + } + if ((crcreg & 0x80) != 0) + { + crcreg = crcreg ^ CRCPOLY; + } + b <<= 1; + } + } + return crcreg >> 8; +} + +int dlms_getMacHdlcFrame( + dlmsSettings* settings, + unsigned char frame, + unsigned char creditFields, + gxByteBuffer* data, + gxByteBuffer* reply) +{ + if (settings->maxInfoTX > 126) + { + settings->maxInfoTX = 86; + }; + int ret; + gxByteBuffer tmp; + BYTE_BUFFER_INIT(&tmp); + //Lenght is updated last. + bb_setUInt16(reply, 0); + //Add Credit fields. + bb_setUInt8(reply, creditFields); + //Add source and target MAC addresses. + bb_setUInt8(reply, (unsigned char)(settings->plcSettings.macSourceAddress >> 4)); + int val = settings->plcSettings.macSourceAddress << 12; + val |= settings->plcSettings.macDestinationAddress & 0xFFF; + bb_setUInt16(reply, (uint16_t)val); + if ((ret = dlms_getHdlcFrame(settings, frame, data, &tmp)) == 0) + { + unsigned char padLen = (unsigned char)((36 - ((10 + tmp.size) % 36)) % 36); + bb_setUInt8(reply, padLen); + bb_set(reply, tmp.data, tmp.size); + //Add padding. + while (padLen != 0) + { + bb_setUInt8(reply, 0); + --padLen; + } + //Checksum. + uint32_t crc = dlms_countFCS24(reply->data, 2, reply->size - 2 - padLen); + bb_setUInt8(reply, (unsigned char)(crc >> 16)); + bb_setUInt16(reply, (uint16_t)crc); + //Add NC + val = reply->size / 36; + if (reply->size % 36 != 0) + { + ++val; + } + if (val == 1) + { + val = DLMS_PLC_MAC_SUB_FRAMES_ONE; + } + else if (val == 2) + { + val = DLMS_PLC_MAC_SUB_FRAMES_TWO; + } + else if (val == 3) + { + val = DLMS_PLC_MAC_SUB_FRAMES_THREE; + } + else if (val == 4) + { + val = DLMS_PLC_MAC_SUB_FRAMES_FOUR; + } + else if (val == 5) + { + val = DLMS_PLC_MAC_SUB_FRAMES_FIVE; + } + else if (val == 6) + { + val = DLMS_PLC_MAC_SUB_FRAMES_SIX; + } + else if (val == 7) + { + val = DLMS_PLC_MAC_SUB_FRAMES_SEVEN; + } + else + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + ret = bb_setUInt16ByIndex(reply, 0, (uint16_t)val); + } + return ret; +} + +int dlms_getMacFrame( + dlmsSettings* settings, + unsigned char frame, + unsigned char creditFields, + gxByteBuffer* data, + gxByteBuffer* reply) +{ + if (settings->interfaceType == DLMS_INTERFACE_TYPE_PLC) + { + return dlms_getPlcFrame(settings, creditFields, data, reply); + } + return dlms_getMacHdlcFrame(settings, frame, creditFields, data, reply); +} + +#endif //DLMS_IGNORE_PLC + +int dlms_getDataFromFrame( + gxByteBuffer* reply, + gxReplyData* data, + unsigned char hdlc) +{ +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + uint32_t offset = data->data.size; + uint32_t cnt; +#else + uint16_t offset = data->data.size; + uint16_t cnt; +#endif + if (data->packetLength < reply->position) + { + cnt = 0; + } + else + { + cnt = data->packetLength - reply->position; + } + if (cnt != 0) + { + int ret; + if ((ret = bb_capacity(&data->data, offset + cnt)) != 0 || + (ret = bb_set2(&data->data, reply, reply->position, cnt)) != 0) + { + return ret; + } + if (hdlc) + { + reply->position += 3; + } + } + // Set position to begin of new data. + data->data.position = offset; + return 0; +} + +#ifndef DLMS_IGNORE_HDLC + +int dlms_getHdlcData( + unsigned char server, + dlmsSettings* settings, + gxByteBuffer* reply, + gxReplyData* data, + unsigned char* frame, + unsigned char preEstablished, + unsigned char first) +{ + int ret; + unsigned char ch; + uint16_t eopPos; +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + uint32_t pos, frameLen = 0; + uint32_t packetStartID = reply->position; +#else + uint16_t pos, frameLen = 0; + uint16_t packetStartID = (uint16_t)reply->position; +#endif + uint16_t crc, crcRead; + // If whole frame is not received yet. + if (reply->size - reply->position < 9) + { + data->complete = 0; + return 0; + } + data->complete = 1; + // Find start of HDLC frame. + for (pos = (uint16_t)reply->position; pos < reply->size; ++pos) + { + if ((ret = bb_getUInt8(reply, &ch)) != 0) + { + return ret; + } + if (ch == HDLC_FRAME_START_END) + { + packetStartID = pos; + break; + } + } + // Not a HDLC frame. + // Sometimes meters can send some strange data between DLMS frames. + if (reply->position == reply->size) + { + data->complete = 0; + // Not enough data to parse; + return 0; + } + if ((ret = bb_getUInt8(reply, frame)) != 0) + { + return ret; + } + if ((*frame & 0xF0) != 0xA0) + { + --reply->position; + // If same data. + return dlms_getHdlcData(server, settings, reply, data, frame, preEstablished, first); + } + // Check frame length. + if ((*frame & 0x7) != 0) + { + frameLen = ((*frame & 0x7) << 8); + } + if ((ret = bb_getUInt8(reply, &ch)) != 0) + { + return ret; + } + // If not enough data. + frameLen += ch; + if ((reply->size - reply->position + 1) < frameLen) + { + data->complete = 0; + reply->position = packetStartID; + // Not enough data to parse; + return 0; + } + eopPos = (uint16_t)(frameLen + packetStartID + 1); + if ((ret = bb_getUInt8ByIndex(reply, eopPos, &ch)) != 0) + { + return ret; + } + if (ch != HDLC_FRAME_START_END) + { + reply->position -= 2; + return dlms_getHdlcData(server, settings, reply, data, frame, preEstablished, first); + } + + // Check addresses. + ret = dlms_checkHdlcAddress(server, settings, reply, eopPos); + if (ret != 0) + { + //If pre-established client address has change. + if (ret == DLMS_ERROR_CODE_INVALID_CLIENT_ADDRESS) + { + return DLMS_ERROR_CODE_INVALID_CLIENT_ADDRESS; + } + else + { + if (ret == DLMS_ERROR_CODE_INVALID_SERVER_ADDRESS && + reply->position + 4 == reply->size) + { + data->packetLength = 0; + bb_clear(reply); + return ret; + } + if (ret == DLMS_ERROR_CODE_FALSE) + { + // If echo or reply to other meter. + return dlms_getHdlcData(server, settings, reply, data, frame, preEstablished, first); + } + reply->position = packetStartID + 1; + ret = dlms_getHdlcData(server, settings, reply, data, frame, preEstablished, first); + return ret; + } + } + // Is there more data available. + unsigned char moreData = (*frame & 0x8) != 0; + // Get frame type. + if ((ret = bb_getUInt8(reply, frame)) != 0) + { + return ret; + } + + // Is there more data available. + if (moreData) + { + data->moreData |= DLMS_DATA_REQUEST_TYPES_FRAME; + } + else + { + data->moreData = ((DLMS_DATA_REQUEST_TYPES)(data->moreData & ~DLMS_DATA_REQUEST_TYPES_FRAME)); + } + + if (!preEstablished +#ifndef DLMS_IGNORE_HDLC_CHECK + && !checkFrame(settings, *frame) +#endif //DLMS_IGNORE_HDLC_CHECK + ) + { + reply->position = eopPos + 1; + if (settings->server) + { + return DLMS_ERROR_CODE_INVALID_FRAME_NUMBER; + } + return dlms_getHdlcData(server, settings, reply, data, frame, preEstablished, first); + } + // Check that header CRC is correct. + crc = countCRC(reply, packetStartID + 1, + reply->position - packetStartID - 1); + + if ((ret = bb_getUInt16(reply, &crcRead)) != 0) + { + return ret; + } + + if (crc != crcRead) + { + if (reply->size - reply->position > 8) + { + return dlms_getHdlcData(server, settings, reply, data, frame, preEstablished, first); + } +#ifdef DLMS_DEBUG + svr_notifyTrace("Invalid CRC. ", -1); +#endif //DLMS_DEBUG + return DLMS_ERROR_CODE_WRONG_CRC; + } + // Check that packet CRC match only if there is a data part. + if (reply->position != packetStartID + frameLen + 1) + { + crc = countCRC(reply, packetStartID + 1, frameLen - 2); + if ((ret = bb_getUInt16ByIndex(reply, packetStartID + frameLen - 1, &crcRead)) != 0) + { + return ret; + } + if (crc != crcRead) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("Invalid CRC. ", -1); +#endif //DLMS_DEBUG + return DLMS_ERROR_CODE_WRONG_CRC; + } + // Remove CRC and EOP from packet length. + data->packetLength = eopPos - 2; + } + else + { + data->packetLength = eopPos - 2; + } + + + if (*frame != 0x13 && *frame != 0x3 && (*frame & HDLC_FRAME_TYPE_U_FRAME) == HDLC_FRAME_TYPE_U_FRAME) + { + // Get Eop if there is no data. + if (reply->position == packetStartID + frameLen + 1) + { + // Get EOP. + if ((ret = bb_getUInt8(reply, &ch)) != 0) + { + return ret; + } + } + data->command = (DLMS_COMMAND)*frame; + switch (data->command) + { + case DLMS_COMMAND_SNRM: + case DLMS_COMMAND_UA: + case DLMS_COMMAND_DISCONNECT_MODE: + case DLMS_COMMAND_REJECTED: + case DLMS_COMMAND_DISC: + break; + default: + //Unknown command. + return DLMS_ERROR_CODE_REJECTED; + } + } + else if (*frame != 0x13 && *frame != 0x3 && (*frame & HDLC_FRAME_TYPE_S_FRAME) == HDLC_FRAME_TYPE_S_FRAME) + { + // If S-frame + int tmp = (*frame >> 2) & 0x3; + // If frame is rejected. + if (tmp == HDLC_CONTROL_FRAME_REJECT) + { + return DLMS_ERROR_CODE_REJECTED; + } + else if (tmp == HDLC_CONTROL_FRAME_RECEIVE_NOT_READY) + { + return DLMS_ERROR_CODE_REJECTED; + } + else if (tmp == HDLC_CONTROL_FRAME_RECEIVE_READY) + { + } + // Get Eop if there is no data. + if (reply->position == packetStartID + frameLen + 1) + { + // Get EOP. + if ((ret = bb_getUInt8(reply, &ch)) != 0) + { + return ret; + } + } + } + else + { + // I-frame + // Get Eop if there is no data. + if (reply->position == packetStartID + frameLen + 1) + { + // Get EOP. + if ((ret = bb_getUInt8(reply, &ch)) != 0) + { + return ret; + } + if ((*frame & 0x1) == 0x1) + { + data->moreData = DLMS_DATA_REQUEST_TYPES_FRAME; + } + } + else + { + dlms_checkLLCBytes(settings, reply); + } + } + if (settings->server && (first || data->command == DLMS_COMMAND_SNRM)) + { +#ifndef DLMS_IGNORE_SERVER + // Check is data send to this server. + if (!svr_isTarget(settings, settings->serverAddress, settings->clientAddress)) + { + settings->serverAddress = 0; + settings->clientAddress = 0; + if (reply->size - reply->position > 8) + { +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + uint32_t pos = reply->position; +#else + uint16_t pos = reply->position; +#endif //!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + ret = dlms_getHdlcData(server, settings, reply, data, frame, preEstablished, first); + if (settings->serverAddress != 0 && settings->clientAddress != 0) + { + reply->position = pos; + } + return ret; + } + return DLMS_ERROR_CODE_INVALID_CLIENT_ADDRESS; + } +#endif //DLMS_IGNORE_SERVER + } + return DLMS_ERROR_CODE_OK; +} +#endif //DLMS_IGNORE_HDLC + +#ifndef DLMS_IGNORE_WRAPPER +int dlms_checkWrapperAddress(dlmsSettings* settings, + gxByteBuffer* buff, + gxReplyData* data, + gxReplyData* notify, + unsigned char* isNotify) +{ + int ret; + uint16_t value; + *isNotify = 0; + if (settings->server) + { + if ((ret = bb_getUInt16(buff, &value)) != 0) + { + return ret; + } + // Check that client addresses match. + if (settings->clientAddress != 0 && settings->clientAddress != value) + { + return DLMS_ERROR_CODE_INVALID_CLIENT_ADDRESS; + } + else + { + settings->clientAddress = value; + } + + if ((ret = bb_getUInt16(buff, &value)) != 0) + { + return ret; + } + // Check that server addresses match. + if (settings->serverAddress != 0 && settings->serverAddress != value) + { + return DLMS_ERROR_CODE_INVALID_SERVER_ADDRESS; + } + else + { + settings->serverAddress = value; + } + } + else + { + if ((ret = bb_getUInt16(buff, &value)) != 0) + { + return ret; + } + // Check that server addresses match. + if (settings->serverAddress != 0 && settings->serverAddress != value) + { + if (notify == NULL) + { + return DLMS_ERROR_CODE_INVALID_SERVER_ADDRESS; + } + notify->serverAddress = value; + *isNotify = 1; + } + else + { + settings->serverAddress = value; + } + + if ((ret = bb_getUInt16(buff, &value)) != 0) + { + return ret; + } + // Check that client addresses match. + if (settings->clientAddress != 0 && settings->clientAddress != value) + { + if (notify == NULL) + { + return DLMS_ERROR_CODE_INVALID_CLIENT_ADDRESS; + } + notify->clientAddress = value; + *isNotify = 1; + } + else + { + settings->clientAddress = value; + } + } + return DLMS_ERROR_CODE_OK; +} +#endif //DLMS_IGNORE_WRAPPER + +#ifndef DLMS_IGNORE_WRAPPER +int dlms_getTcpData( + dlmsSettings* settings, + gxByteBuffer* buff, + gxReplyData* data, + gxReplyData* notify, + unsigned char* isNotify) +{ + int ret, pos; + uint16_t value; + *isNotify = 0; + // If whole frame is not received yet. + if (buff->size - buff->position < 8) + { + data->complete = 0; + return DLMS_ERROR_CODE_OK; + } + pos = buff->position; + data->complete = 0; + if (notify != NULL) + { + notify->complete = 0; + } + while (buff->position != buff->size) + { + // Get version + if ((ret = bb_getUInt16(buff, &value)) != 0) + { + return ret; + } + if (value == 1) + { + // Check TCP/IP addresses. + if ((ret = dlms_checkWrapperAddress(settings, buff, data, notify, isNotify)) != 0) + { + return ret; + } + //If notify. + if (notify != NULL && *isNotify != 0) + { + data = notify; + } + // Get length. + if ((ret = bb_getUInt16(buff, &value)) != 0) + { + return ret; + } + data->complete = !((buff->size - buff->position) < value); + if (!data->complete) + { + buff->position = pos; + } + else + { + data->packetLength = buff->position + value; + } + break; + } + else + { + --buff->position; + } + } + return DLMS_ERROR_CODE_OK; +} +#endif //DLMS_IGNORE_WRAPPER + +#ifndef DLMS_IGNORE_WIRELESS_MBUS +int dlms_getMBusData( + dlmsSettings* settings, + gxByteBuffer* buff, + gxReplyData* data) +{ + int ret; + unsigned char len, ch; + //L-field. + if ((ret = bb_getUInt8(buff, &len)) != 0) + { + return ret; + } + //Some meters are counting length to frame size. + if (buff->size < (unsigned char)(len - 1)) + { + data->complete = 0; + buff->position = buff->position - 1; + } + else + { + //Some meters are counting length to frame size. + if (buff->size < len) + { + --len; + } + data->packetLength = len; + data->complete = 1; + //C-field. + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + // DLMS_MBUS_COMMAND cmd = (DLMS_MBUS_COMMAND)ch; + //M-Field. + uint16_t manufacturerID; + if ((ret = bb_getUInt16(buff, &manufacturerID)) != 0) + { + return ret; + } + //A-Field. + uint32_t id; + if ((ret = bb_getUInt32(buff, &id)) != 0) + { + return ret; + } + unsigned char meterVersion; + if ((ret = bb_getUInt8(buff, &meterVersion)) != 0 || + (ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + // DLMS_MBUS_METER_TYPE type = (DLMS_MBUS_METER_TYPE)ch; + // CI-Field + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + // DLMS_MBUS_CONTROL_INFO ci = (DLMS_MBUS_CONTROL_INFO)ch; + //Access number. + unsigned char frameId; + if ((ret = bb_getUInt8(buff, &frameId)) != 0) + { + return ret; + } + //State of the meter + unsigned char state; + if ((ret = bb_getUInt8(buff, &state)) != 0) + { + return ret; + } + //Configuration word. + uint16_t configurationWord; + if ((ret = bb_getUInt16(buff, &configurationWord)) != 0) + { + return ret; + } + //unsigned char encryptedBlocks = (unsigned char)(configurationWord >> 12); + // DLMS_MBUS_ENCRYPTION_MODE encryption = (DLMS_MBUS_ENCRYPTION_MODE)(configurationWord & 7); + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + settings->clientAddress = ch; + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + settings->serverAddress = ch; + } + return ret; +} + +#endif //DLMS_IGNORE_WIRELESS_MBUS + +#ifndef DLMS_IGNORE_PLC + +int dlms_getPlcData( + dlmsSettings* settings, + gxByteBuffer* buff, + gxReplyData* data) +{ + if (bb_available(buff) < 9) + { + data->complete = 0; + return 0; + } + unsigned char ch; + int ret; + unsigned short pos; + int packetStartID = buff->position; + // Find STX. + unsigned char stx; + for (pos = (unsigned short)buff->position; pos < buff->size; ++pos) + { + if ((ret = bb_getUInt8(buff, &stx)) != 0) + { + return ret; + } + if (stx == 2) + { + packetStartID = pos; + break; + } + } + // Not a PLC frame. + if (buff->position == buff->size) + { + // Not enough data to parse; + data->complete = 0; + buff->position = packetStartID; + return 0; + } + unsigned char len; + if ((ret = bb_getUInt8(buff, &len)) != 0) + { + return ret; + } + int index = buff->position; + if (bb_available(buff) < len) + { + data->complete = 0; + buff->position = buff->position - 2; + } + else + { + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + //Credit fields. IC, CC, DC + unsigned char credit; + if ((ret = bb_getUInt8(buff, &credit)) != 0) + { + return ret; + } + //MAC Addresses. + uint32_t mac; + if ((ret = bb_getUInt24(buff, &mac)) != 0) + { + return ret; + } + //SA. + short macSa = (short)(mac >> 12); + //DA. + short macDa = (short)(mac & 0xFFF); + //PAD length. + unsigned char padLen; + if ((ret = bb_getUInt8(buff, &padLen)) != 0) + { + return ret; + } + + if (buff->size < (unsigned short)(len + padLen + 2)) + { + data->complete = 0; + buff->position = buff->position - index - 6; + } + else + { + //DL.Data.request + if ((ret = bb_getUInt8(buff, &ch)) != 0) + { + return ret; + } + if (ch != DLMS_PLC_DATA_LINK_DATA_REQUEST) + { + //Parsing MAC LLC data failed. Invalid DataLink data request. + return DLMS_ERROR_CODE_INVALID_COMMAND; + } + unsigned char da, sa; + if ((ret = bb_getUInt8(buff, &da)) != 0 || + (ret = bb_getUInt8(buff, &sa)) != 0) + { + return ret; + } + if (settings->server) + { + data->complete = + (macDa == DLMS_PLC_DESTINATION_ADDRESS_ALL_PHYSICAL || macDa == settings->plcSettings.macSourceAddress) && + (macSa == DLMS_PLC_SOURCE_ADDRESS_INITIATOR || macSa == settings->plcSettings.macDestinationAddress); + data->serverAddress = macDa; + data->clientAddress = macSa; + } + else + { + data->complete = + macDa == DLMS_PLC_DESTINATION_ADDRESS_ALL_PHYSICAL || + macDa == DLMS_PLC_SOURCE_ADDRESS_INITIATOR || + macDa == settings->plcSettings.macDestinationAddress; + data->clientAddress = macDa; + data->serverAddress = macSa; + } + //Skip padding. + if (data->complete) + { + uint16_t crcCount, crc; + crcCount = countCRC(buff, 0, len + padLen); + if ((ret = bb_getUInt16ByIndex(buff, len + padLen, &crc)) != 0) + { + return ret; + } + //Check CRC. + if (crc != crcCount) + { + //Invalid data checksum. + return DLMS_ERROR_CODE_WRONG_CRC; + } + data->packetLength = len; + } + } + } + return ret; +} + +int dlms_getPlcHdlcData( + dlmsSettings* settings, + gxByteBuffer* buff, + gxReplyData* data, + unsigned char* frame) +{ + if (bb_available(buff) < 2) + { + data->complete = 0; + return 0; + } + int ret; + *frame = 0; + unsigned char frameLen; + //SN field. + uint16_t ns; + if ((ret = bb_getUInt16(buff, &ns)) != 0) + { + return ret; + } + switch (ns) + { + case DLMS_PLC_MAC_SUB_FRAMES_ONE: + frameLen = 36; + break; + case DLMS_PLC_MAC_SUB_FRAMES_TWO: + frameLen = 2 * 36; + break; + case DLMS_PLC_MAC_SUB_FRAMES_THREE: + frameLen = 3 * 36; + break; + case DLMS_PLC_MAC_SUB_FRAMES_FOUR: + frameLen = 4 * 36; + break; + case DLMS_PLC_MAC_SUB_FRAMES_FIVE: + frameLen = 5 * 36; + break; + case DLMS_PLC_MAC_SUB_FRAMES_SIX: + frameLen = 6 * 36; + break; + case DLMS_PLC_MAC_SUB_FRAMES_SEVEN: + frameLen = 7 * 36; + break; + default: + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if (bb_available(buff) < (unsigned char)(frameLen - 2)) + { + data->complete = 0; + } + else + { + unsigned long index = buff->position; + //Credit fields. IC, CC, DC + unsigned char credit; + if ((ret = bb_getUInt8(buff, &credit)) != 0) + { + return ret; + } + //MAC Addresses. + uint32_t mac; + if ((ret = bb_getUInt24(buff, &mac)) != 0) + { + return ret; + } + //SA. + unsigned short sa = (unsigned short)(mac >> 12); + //DA. + unsigned short da = (unsigned short)(mac & 0xFFF); + if (settings->server) + { + data->complete = (da == DLMS_PLC_DESTINATION_ADDRESS_ALL_PHYSICAL || da == settings->plcSettings.macSourceAddress) && + (sa == DLMS_PLC_HDLC_SOURCE_ADDRESS_INITIATOR || sa == settings->plcSettings.macDestinationAddress); + data->serverAddress = da; + data->clientAddress = sa; + } + else + { + data->complete = da == DLMS_PLC_HDLC_SOURCE_ADDRESS_INITIATOR || da == settings->plcSettings.macDestinationAddress; + data->serverAddress = da; + data->clientAddress = sa; + } + if (data->complete) + { + //PAD length. + unsigned char padLen; + if ((ret = bb_getUInt8(buff, &padLen)) != 0) + { + return ret; + } + if ((ret = dlms_getHdlcData(settings->server, settings, buff, data, frame, 0, 1)) != 0) + { + return ret; + } + dlms_getDataFromFrame(buff, data, dlms_useHdlc(settings->interfaceType)); + buff->position = buff->position + padLen; + uint32_t crcCount = dlms_countFCS24(buff->data, index, buff->position - index); + uint32_t crc; + if ((ret = bb_getUInt24ByIndex(buff, buff->position, &crc)) != 0) + { + return ret; + } + //Check CRC. + if (crc != crcCount) + { + //Invalid data checksum. + return DLMS_ERROR_CODE_WRONG_CRC; + } + data->packetLength = (uint16_t)(2 + buff->position - index); + } + else + { + buff->position = (uint16_t)(buff->position + frameLen - index - 4); + } + } + return ret; +} + +// Check is this PLC S-FSK message. +// buff: Received data. +// Returns True, if this is PLC message. +unsigned char dlms_isPlcSfskData(gxByteBuffer* buff) +{ + if (bb_available(buff) < 2) + { + return 0; + } + int ret; + uint16_t len; + if ((ret = bb_getUInt16ByIndex(buff, buff->position, &len)) != 0) + { + return (unsigned char)ret; + } + switch (len) + { + case DLMS_PLC_MAC_SUB_FRAMES_ONE: + case DLMS_PLC_MAC_SUB_FRAMES_TWO: + case DLMS_PLC_MAC_SUB_FRAMES_THREE: + case DLMS_PLC_MAC_SUB_FRAMES_FOUR: + case DLMS_PLC_MAC_SUB_FRAMES_FIVE: + case DLMS_PLC_MAC_SUB_FRAMES_SIX: + case DLMS_PLC_MAC_SUB_FRAMES_SEVEN: + return 1; + default: + return 0; + } +} +#endif //DLMS_IGNORE_PLC + +int dlms_getDataFromBlock(gxByteBuffer* data, uint16_t index) +{ +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + uint32_t pos, len = data->position - index; +#else + uint16_t pos, len = data->position - index; +#endif + if (data->size == data->position) + { + bb_clear(data); + return 0; + } + pos = data->position; + bb_move(data, data->position, data->position - len, data->size - data->position); + data->position = pos - len; + return 0; +} + +int dlms_receiverReady( + dlmsSettings* settings, + DLMS_DATA_REQUEST_TYPES type, + gxByteBuffer* reply) +{ + int ret; + DLMS_COMMAND cmd; + message tmp; + gxByteBuffer bb; + bb_clear(reply); + if (type == DLMS_DATA_REQUEST_TYPES_NONE) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } +#ifndef DLMS_IGNORE_HDLC + // Get next frame. + if ((type & DLMS_DATA_REQUEST_TYPES_FRAME) != 0) + { + unsigned char id = getReceiverReady(settings); + switch (settings->interfaceType) + { +#ifndef DLMS_IGNORE_PLC + case DLMS_INTERFACE_TYPE_PLC_HDLC: + ret = dlms_getMacHdlcFrame(settings, id, 0, NULL, reply); + break; +#endif //DLMS_IGNORE_PLC +#ifndef DLMS_IGNORE_HDLC + case DLMS_INTERFACE_TYPE_HDLC: + ret = dlms_getHdlcFrame(settings, id, NULL, reply); + break; +#endif //DLMS_IGNORE_HDLC + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; + } +#endif //DLMS_IGNORE_HDLC + // Get next block. + if (settings->useLogicalNameReferencing) + { + if (settings->server) + { + cmd = DLMS_COMMAND_GET_RESPONSE; + } + else + { + cmd = DLMS_COMMAND_GET_REQUEST; + } + } + else + { +#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + if (settings->server) + { + cmd = DLMS_COMMAND_READ_RESPONSE; + } + else + { + cmd = DLMS_COMMAND_READ_REQUEST; + } +#else + return DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif //#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + } +#ifdef DLMS_IGNORE_MALLOC + unsigned char buff[40]; + bb_attach(&bb, buff, 0, sizeof(buff)); +#else + BYTE_BUFFER_INIT(&bb); +#endif //DLMS_IGNORE_MALLOC + + if (settings->useLogicalNameReferencing) + { + bb_setUInt32(&bb, settings->blockIndex); + } + else + { + bb_setUInt16(&bb, (uint16_t)settings->blockIndex); + } + ++settings->blockIndex; +#ifdef DLMS_IGNORE_MALLOC + gxByteBuffer* p[] = { reply }; + mes_attach(&tmp, p, 1); +#else + mes_init(&tmp); +#endif //DLMS_IGNORE_MALLOC + if (settings->useLogicalNameReferencing) + { + gxLNParameters p; + params_initLN(&p, settings, 0, cmd, DLMS_GET_COMMAND_TYPE_NEXT_DATA_BLOCK, &bb, NULL, 0xFF, DLMS_COMMAND_NONE, 0, 0); +#ifdef DLMS_IGNORE_MALLOC + p.serializedPdu = &bb; +#endif //DLMS_IGNORE_MALLOC + ret = dlms_getLnMessages(&p, &tmp); + } + else + { +#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + gxSNParameters p; + params_initSN(&p, settings, cmd, 1, DLMS_VARIABLE_ACCESS_SPECIFICATION_BLOCK_NUMBER_ACCESS, &bb, NULL, DLMS_COMMAND_NONE); + ret = dlms_getSnMessages(&p, &tmp); +#else + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif //!defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + } +#ifndef DLMS_IGNORE_MALLOC + if (ret == 0) + { + ret = bb_set2(reply, (gxByteBuffer*)tmp.data[0], 0, tmp.data[0]->size); + } + bb_clear(&bb); + mes_clear(&tmp); +#endif //DLMS_IGNORE_MALLOC + return ret; +} + +#ifndef DLMS_IGNORE_WRAPPER +int dlms_getWrapperFrame( + dlmsSettings* settings, + DLMS_COMMAND command, + gxByteBuffer* data, + gxByteBuffer* reply) +{ + int ret; + if ((ret = bb_clear(reply)) == 0 && + (ret = bb_capacity(reply, 8 + data->size - data->position)) == 0 && + // Add version. + (ret = bb_setUInt16(reply, 1)) == 0) + { + if (settings->server) + { + if ((ret = bb_setUInt16(reply, (unsigned short)settings->serverAddress)) == 0) + { + if (((dlmsServerSettings*)settings)->pushClientAddress != 0 && (command == DLMS_COMMAND_DATA_NOTIFICATION || command == DLMS_COMMAND_EVENT_NOTIFICATION)) + { + ret = bb_setUInt16(reply, ((dlmsServerSettings*)settings)->pushClientAddress); + } + else + { + ret = bb_setUInt16(reply, settings->clientAddress); + } + } + } + else + { + if ((ret = bb_setUInt16(reply, settings->clientAddress)) == 0) + { + ret = bb_setUInt16(reply, (unsigned short)settings->serverAddress); + } + } + // Data length. + if (ret == 0 && (ret = bb_setUInt16(reply, (uint16_t)data->size)) == 0) + { + // Data + ret = bb_set2(reply, data, data->position, data->size - data->position); + } + // Remove sent data in server side. + if (ret == 0 && settings->server) + { + if (data->size == data->position) + { + ret = bb_clear(data); + } + else + { + ret = bb_move(data, data->position, 0, data->size - data->position); + data->position = 0; + } + } + } + return ret; +} +#endif //DLMS_IGNORE_WRAPPER + +int dlms_verifyInvokeId(dlmsSettings* settings, gxReplyData* reply) +{ + if (settings->autoIncreaseInvokeID && reply->invokeId != dlms_getInvokeIDPriority(settings, 0)) + { + //Invalid invoke ID. + return DLMS_ERROR_CODE_INVALID_INVOKE_ID; + } + return 0; +} + +int dlms_handleGetResponse( + dlmsSettings* settings, + gxReplyData* reply, + uint16_t index) +{ + int ret; + uint16_t count; + unsigned char ch; + uint32_t number; + short type; + // Get type. + if ((ret = bb_getUInt8(&reply->data, &ch)) != 0) + { + return ret; + } + type = ch; + // Get invoke ID and priority. + if ((ret = bb_getUInt8(&reply->data, &reply->invokeId)) != 0) + { + return ret; + } + if ((ret = dlms_verifyInvokeId(settings, reply)) != 0) + { + return ret; + } + // Response normal + if (type == 1) + { + // Result + if ((ret = bb_getUInt8(&reply->data, &ch)) != 0) + { + return ret; + } + if (ch != 0) + { + if ((ret = bb_getUInt8(&reply->data, &ch)) != 0) + { + return ret; + } + return ch; + } + ret = dlms_getDataFromBlock(&reply->data, 0); + } + else if (type == 2) + { + // GetResponsewithDataBlock + // Is Last block. + if ((ret = bb_getUInt8(&reply->data, &ch)) != 0) + { + return ret; + } + if (ch == 0) + { + reply->moreData = (DLMS_DATA_REQUEST_TYPES)(reply->moreData | DLMS_DATA_REQUEST_TYPES_BLOCK); + } + else + { + reply->moreData = + (DLMS_DATA_REQUEST_TYPES)(reply->moreData & ~DLMS_DATA_REQUEST_TYPES_BLOCK); + } + // Get Block number. + if ((ret = bb_getUInt32(&reply->data, &number)) != 0) + { + return ret; + } + // If meter's block index is zero based or Actaris is read. + // Actaris SL7000 might return wrong block index sometimes. + // It's not reseted to 1. + if (number != 1 && settings->blockIndex == 1) + { + settings->blockIndex = number; + } + else if (number != settings->blockIndex) + { + return DLMS_ERROR_CODE_DATA_BLOCK_NUMBER_INVALID; + } + // Get status. + if ((ret = bb_getUInt8(&reply->data, &ch)) != 0) + { + return ret; + } + if (ch != 0) + { + if ((ret = bb_getUInt8(&reply->data, &ch)) != 0) + { + return ret; + } + return ch; + } + else + { + // Get data size. + if ((ret = hlp_getObjectCount2(&reply->data, &count)) != 0) + { + return ret; + } + // if whole block is read. + if ((reply->moreData & DLMS_DATA_REQUEST_TYPES_FRAME) == 0) + { + // Check Block length. + if (count > (uint16_t)(bb_available(&reply->data))) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + reply->command = DLMS_COMMAND_NONE; + } + if (count == 0) + { + // If meter sends empty data block. + reply->data.size = index; + } + else + { + if ((ret = dlms_getDataFromBlock(&reply->data, index)) != 0) + { + return ret; + } + } + // If last packet and data is not try to peek. + if (reply->moreData == DLMS_DATA_REQUEST_TYPES_NONE) + { + if (!reply->peek) + { + reply->data.position = 0; + resetBlockIndex(settings); + } + } + } + } + else if (type == 3) + { + return DLMS_ERROR_CODE_FALSE; + } + else + { + //Invalid Get response. + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} + +int handleWriteResponse(gxReplyData* data) +{ + unsigned char ch; + int ret; + uint16_t count, pos; + if (hlp_getObjectCount2(&data->data, &count) != 0) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + for (pos = 0; pos != count; ++pos) + { + if ((ret = bb_getUInt8(&data->data, &ch)) != 0) + { + return ret; + } + if (ch != 0) + { + if ((ret = bb_getUInt8(&data->data, &ch)) != 0) + { + return ret; + } + return ch; + } + } + return DLMS_ERROR_CODE_OK; +} + +int dlms_handleWriteResponse( + gxReplyData* data) +{ + unsigned char ch; + int ret; + uint16_t pos, count; + if (hlp_getObjectCount2(&data->data, &count) != 0) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + for (pos = 0; pos != count; ++pos) + { + if ((ret = bb_getUInt8(&data->data, &ch)) != 0) + { + return ret; + } + if (ch != 0) + { + if ((ret = bb_getUInt8(&data->data, &ch)) != 0) + { + return ret; + } + return ch; + } + } + return DLMS_ERROR_CODE_OK; +} + +int dlms_getValueFromData(dlmsSettings* settings, + gxReplyData* reply) +{ + uint16_t index; + int ret; +#if !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + int pos; + dlmsVARIANT_PTR tmp; +#endif //!defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + dlmsVARIANT value; + gxDataInfo info; + di_init(&info); + var_init(&value); + if (reply->dataValue.vt == DLMS_DATA_TYPE_ARRAY) + { + info.type = DLMS_DATA_TYPE_ARRAY; + info.count = (uint16_t)reply->totalCount; + info.index = (uint16_t)reply->data.size; + } + index = (uint16_t)(reply->data.position); + reply->data.position = reply->readPosition; + if ((ret = dlms_getData(&reply->data, &info, &value)) != 0) + { + var_clear(&value); + return ret; + } + // If new data. + if (value.vt != DLMS_DATA_TYPE_NONE) + { + if (value.vt != DLMS_DATA_TYPE_ARRAY && value.vt != DLMS_DATA_TYPE_STRUCTURE) + { + reply->dataType = info.type; + reply->dataValue = value; + reply->totalCount = 0; + if (reply->command == DLMS_COMMAND_DATA_NOTIFICATION) + { + reply->readPosition = reply->data.position; + } + } + else + { + if (reply->dataValue.vt == DLMS_DATA_TYPE_NONE) + { + reply->dataValue = value; + } + else + { +#if !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + for (pos = 0; pos != value.Arr->size; ++pos) + { + if ((ret = va_getByIndex(value.Arr, pos, &tmp)) != 0) + { + return ret; + } + va_push(reply->dataValue.Arr, tmp); + } +#endif //!defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + } + } + reply->readPosition = reply->data.position; + // Element count. + reply->totalCount = info.count; + } + else if (info.complete + && reply->command == DLMS_COMMAND_DATA_NOTIFICATION) + { + // If last item is null. This is a special case. + reply->readPosition = reply->data.position; + } + reply->data.position = index; + + // If last data frame of the data block is read. + if (reply->command != DLMS_COMMAND_DATA_NOTIFICATION + && info.complete && reply->moreData == DLMS_DATA_REQUEST_TYPES_NONE) + { + // If all blocks are read. + resetBlockIndex(settings); + reply->data.position = 0; + } + return 0; +} + +int dlms_readResponseDataBlockResult( + dlmsSettings* settings, + gxReplyData* reply, + uint16_t index) +{ + int ret; + uint16_t number; + uint16_t blockLength; + unsigned char lastBlock; + if ((ret = bb_getUInt8(&reply->data, &lastBlock)) != 0) + { + return ret; + } + // Get Block number. + if ((ret = bb_getUInt16(&reply->data, &number)) != 0) + { + return ret; + } + if (hlp_getObjectCount2(&reply->data, &blockLength) != 0) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + // Is Last block. + if (!lastBlock) + { + reply->moreData |= DLMS_DATA_REQUEST_TYPES_BLOCK; + } + else + { + reply->moreData &= ~DLMS_DATA_REQUEST_TYPES_BLOCK; + } + // If meter's block index is zero based. + if (number != 1 && settings->blockIndex == 1) + { + settings->blockIndex = number; + } + if (number != settings->blockIndex) + { + //Invalid Block number + return DLMS_ERROR_CODE_DATA_BLOCK_NUMBER_INVALID; + } + // If whole block is not read. + if ((reply->moreData & DLMS_DATA_REQUEST_TYPES_FRAME) != 0) + { + dlms_getDataFromBlock(&reply->data, index); + return DLMS_ERROR_CODE_FALSE; + } + if (blockLength != bb_available(&reply->data)) + { + //Invalid block length. + return DLMS_ERROR_CODE_DATA_BLOCK_UNAVAILABLE; + } + reply->command = DLMS_COMMAND_NONE; + + dlms_getDataFromBlock(&reply->data, index); + reply->totalCount = 0; + // If last packet and data is not try to peek. + if (reply->moreData == DLMS_DATA_REQUEST_TYPES_NONE) + { + resetBlockIndex(settings); + } + return ret; +} +int dlms_handleReadResponse( + dlmsSettings* settings, + gxReplyData* reply, + uint16_t index) +{ + int ret; + unsigned char ch; + uint16_t number; + uint16_t pos, cnt = reply->totalCount; + DLMS_SINGLE_READ_RESPONSE type; + variantArray values; + + // If we are reading value first time or block is handed. + unsigned char first = reply->totalCount == 0 || reply->commandType == DLMS_SINGLE_READ_RESPONSE_DATA_BLOCK_RESULT; + if (first) + { + if (hlp_getObjectCount2(&reply->data, &cnt) != 0) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + reply->totalCount = cnt; + } + if (cnt != 1) + { + //Parse data after all data is received when readlist is used. + if (reply->moreData != DLMS_DATA_REQUEST_TYPES_NONE) + { + if ((ret = dlms_getDataFromBlock(&reply->data, 0)) == 0) + { + ret = DLMS_ERROR_CODE_FALSE; + } + return ret; + } + if (!first) + { + reply->data.position = 0; + first = 1; + } + } + va_init(&values); + for (pos = 0; pos != cnt; ++pos) + { + // Get status code. Status code is begin of each PDU. + if (first) + { + if ((ret = bb_getUInt8(&reply->data, &ch)) != 0) + { + return ret; + } + reply->commandType = ch; + type = (DLMS_SINGLE_READ_RESPONSE)ch; + } + else + { + type = (DLMS_SINGLE_READ_RESPONSE)reply->commandType; + } + switch (type) + { + case DLMS_SINGLE_READ_RESPONSE_DATA: + if (cnt == 1) + { + ret = dlms_getDataFromBlock(&reply->data, 0); + } + else + { + // If read multiple items. + reply->readPosition = reply->data.position; + dlms_getValueFromData(settings, reply); + reply->data.position = reply->readPosition; + va_push(&values, &reply->dataValue); + var_clear(&reply->dataValue); + } + break; + case DLMS_SINGLE_READ_RESPONSE_DATA_ACCESS_ERROR: + // Get error code. + if ((ret = bb_getUInt8(&reply->data, &ch)) != 0) + { + return ret; + } + return ch; + case DLMS_SINGLE_READ_RESPONSE_DATA_BLOCK_RESULT: + if ((ret = dlms_readResponseDataBlockResult(settings, reply, index)) != 0) + { + return ret; + } + break; + case DLMS_SINGLE_READ_RESPONSE_BLOCK_NUMBER: + // Get Block number. + if ((ret = bb_getUInt16(&reply->data, &number)) != 0) + { + return ret; + } + if (number != settings->blockIndex) + { + //Invalid Block number + return DLMS_ERROR_CODE_DATA_BLOCK_NUMBER_INVALID; + } + ++settings->blockIndex; + reply->moreData |= DLMS_DATA_REQUEST_TYPES_BLOCK; + break; + default: + //HandleReadResponse failed. Invalid tag. + return DLMS_ERROR_CODE_INVALID_TAG; + } + } + if (values.size != 0) + { +#ifndef DLMS_IGNORE_MALLOC + reply->dataValue.vt = DLMS_DATA_TYPE_ARRAY; + reply->dataValue.Arr = gxmalloc(sizeof(variantArray)); + va_init(reply->dataValue.Arr); + reply->dataValue.Arr->capacity = values.capacity; + va_copyArray(reply->dataValue.Arr, &values); + gxfree(values.data); +#endif //DLMS_IGNORE_MALLOC + } + if (cnt != 1) + { + return DLMS_ERROR_CODE_FALSE; + } + return 0; +} + +int dlms_handleMethodResponse( + dlmsSettings* settings, + gxReplyData* data) +{ + int ret; + unsigned char ch, type; + // Get type. + if ((ret = bb_getUInt8(&data->data, &type)) != 0) + { + return ret; + } + // Get invoke ID and priority. + if ((ret = bb_getUInt8(&data->data, &data->invokeId)) != 0) + { + return ret; + } + if ((ret = dlms_verifyInvokeId(settings, data)) != 0) + { + return ret; + } + //Action-Response-Normal + if (type == 1) + { + //Get Action-Result + if ((ret = bb_getUInt8(&data->data, &ch)) != 0) + { + return ret; + } + if (ch != 0) + { + return ch; + } + resetBlockIndex(settings); + // Get data if exists. Some meters do not return here anything. + if (data->data.position < data->data.size) + { + //Get-Data-Result. + if ((ret = bb_getUInt8(&data->data, &ch)) != 0) + { + return ret; + } + //If data. + if (ch == 0) + { + return dlms_getDataFromBlock(&data->data, 0); + } + else if (ch == 1) //Data-Access-Result + { + //Get Data-Access-Result + if ((ret = bb_getUInt8(&data->data, &ch)) != 0) + { + return ret; + } + if (ch != 0) + { + if (ch == 9) + { + //Handle Texas Instrument missing byte here. + if ((ret = bb_getUInt8ByIndex(&data->data, data->data.position, &ch)) != 0) + { + return ret; + } + if (ch == 16) + { + --data->data.position; + return dlms_getDataFromBlock(&data->data, 0); + } + } + if ((ret = bb_getUInt8(&data->data, &ch)) != 0) + { + return ret; + } + return ch; + } + return dlms_getDataFromBlock(&data->data, 0); + } + else + { + return DLMS_ERROR_CODE_INVALID_TAG; + } + } + } + //Action-Response-With-Pblock + else if (type == 2) + { + return DLMS_ERROR_CODE_INVALID_COMMAND; + } + // Action-Response-With-List. + else if (type == 3) + { + return DLMS_ERROR_CODE_INVALID_COMMAND; + } + //Action-Response-Next-Pblock + else if (type == 4) + { + return DLMS_ERROR_CODE_INVALID_COMMAND; + } + else + { + return DLMS_ERROR_CODE_INVALID_COMMAND; + } + return DLMS_ERROR_CODE_OK; +} + +int dlms_handlePush(gxReplyData* reply) +{ + unsigned char ch; + uint32_t ul; + int ret; + uint16_t index = (uint16_t)(reply->data.position - 1); + // Is last block + if ((ret = bb_getUInt8(&reply->data, &ch)) != 0) + { + return ret; + } + + if ((ch & 0x80) == 0) + { + reply->moreData = (DLMS_DATA_REQUEST_TYPES)(reply->moreData | DLMS_DATA_REQUEST_TYPES_BLOCK); + } + else + { + reply->moreData = (DLMS_DATA_REQUEST_TYPES)(reply->moreData & ~DLMS_DATA_REQUEST_TYPES_BLOCK); + } + // Get block number sent. + if ((ret = bb_getUInt8(&reply->data, &ch)) != 0) + { + return ret; + } + // Get block number acknowledged + if ((ret = bb_getUInt8(&reply->data, &ch)) != 0) + { + return ret; + } + // Get APU tag. + if ((ret = bb_getUInt8(&reply->data, &ch)) != 0) + { + return ret; + } + // Addl fields + if ((ret = bb_getUInt8(&reply->data, &ch)) != 0) + { + return ret; + } + // Data-Notification + if ((ret = bb_getUInt8(&reply->data, &ch)) != 0) + { + return ret; + } + if ((ch & 0x0F) == 0) + { + //Invalid data. + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + // Long-Invoke-Id-And-Priority + if ((ret = bb_getUInt32(&reply->data, &ul)) != 0) + { + return ret; + } + // Get date time and skip it if used. + if ((ret = bb_getUInt8(&reply->data, &ch)) != 0) + { + return ret; + } + if (ch != 0) + { + reply->data.position = reply->data.position + ch; + } + return dlms_getDataFromBlock(&reply->data, index); +} + +int dlms_handleSetResponse( + dlmsSettings* settings, + gxReplyData* data) +{ + unsigned char ch, type; + int ret; + if ((ret = bb_getUInt8(&data->data, &type)) != 0) + { + return ret; + } + + //Invoke ID and priority. + if ((ret = bb_getUInt8(&data->data, &data->invokeId)) != 0) + { + return ret; + } + if ((ret = dlms_verifyInvokeId(settings, data)) != 0) + { + return ret; + } + // SetResponseNormal + if (type == DLMS_SET_RESPONSE_TYPE_NORMAL) + { + ret = bb_getUInt8(&data->data, &ch); + if (ret == 0 && ch != 0) + { + return ch; + } + } + else if (type == DLMS_SET_RESPONSE_TYPE_DATA_BLOCK || type == DLMS_SET_RESPONSE_TYPE_LAST_DATA_BLOCK) + { + uint32_t tmp; + ret = bb_getUInt32(&data->data, &tmp); + } + else if (type == DLMS_SET_RESPONSE_TYPE_WITH_LIST) + { + uint16_t pos, cnt; + if (hlp_getObjectCount2(&data->data, &cnt) != 0) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + for (pos = 0; pos != cnt; ++pos) + { + if ((ret = bb_getUInt8(&data->data, &ch)) != 0) + { + break; + } + if (ch != 0) + { + ret = ch; + } + } + } + else + { + //Invalid data type. + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} + + +int dlms_changeType2( + dlmsVARIANT* value, + DLMS_DATA_TYPE type, + dlmsVARIANT* newValue) +{ + gxByteBuffer bb; + if (value->byteArr != NULL) + { + bb_attach(&bb, value->byteArr->data, value->byteArr->size, value->byteArr->size); + bb.position = value->byteArr->position; + } + return dlms_changeType(&bb, type, newValue); + +} + +int dlms_changeType( + gxByteBuffer* value, + DLMS_DATA_TYPE type, + dlmsVARIANT* newValue) +{ + int ret; + gxDataInfo info; + di_init(&info); +#ifndef DLMS_IGNORE_MALLOC + var_clear(newValue); +#endif //DLMS_IGNORE_MALLOC + if (value->size == 0) + { + if (type == DLMS_DATA_TYPE_STRING || type == DLMS_DATA_TYPE_STRING_UTF8) + { + newValue->vt = type; + } + return DLMS_ERROR_CODE_OK; + } + if (type == DLMS_DATA_TYPE_NONE) + { +#if !defined(GX_DLMS_MICROCONTROLLER) && !defined(DLMS_IGNORE_MALLOC) + char* tmp = bb_toHexString(value); + newValue->strVal = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + BYTE_BUFFER_INIT(newValue->strVal); + bb_addString(newValue->strVal, tmp); + gxfree(tmp); + newValue->vt = DLMS_DATA_TYPE_STRING; + return DLMS_ERROR_CODE_OK; +#else + return DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif //!defined(GX_DLMS_MICROCONTROLLER) && !defined(DLMS_IGNORE_MALLOC) + } + info.type = type; + if ((ret = dlms_getData(value, &info, newValue)) != 0) + { + return ret; + } + value->position = 0; + if (!info.complete) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + if (type == DLMS_DATA_TYPE_OCTET_STRING && newValue->vt == DLMS_DATA_TYPE_OCTET_STRING) + { +#if !defined(GX_DLMS_MICROCONTROLLER) && !defined(DLMS_IGNORE_MALLOC) + char* tmp = bb_toHexString(value); + newValue->strVal = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + BYTE_BUFFER_INIT(newValue->strVal); + bb_addString(newValue->strVal, tmp); + gxfree(tmp); + newValue->vt = DLMS_DATA_TYPE_STRING; +#else + return DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif //!defined(GX_DLMS_MICROCONTROLLER) && !defined(DLMS_IGNORE_MALLOC) + } + return 0; +} + +/** +* Handle data notification get data from block and/or update error status. +* +* @param reply +* Received data from the client. +*/ +int dlms_handleDataNotification( + dlmsSettings* settings, + gxReplyData* reply) +{ + uint32_t id; + int ret; + unsigned char len; + gxByteBuffer tmp; + dlmsVARIANT t; + uint16_t start = (uint16_t)(reply->data.position - 1); + // Get invoke id. + if ((ret = bb_getUInt32(&reply->data, &id)) != 0) + { + return ret; + } + // Get date time. +#ifdef DLMS_USE_EPOCH_TIME + reply->time = 0; +#else + memset(&reply->time, 0, sizeof(struct tm)); +#endif //DLMS_USE_EPOCH_TIME + if ((ret = bb_getUInt8(&reply->data, &len)) != 0) + { + return ret; + } + if (len != 0) + { +#ifndef DLMS_IGNORE_MALLOC + var_init(&t); +#else + gxtime tm; + GX_DATETIME(t) = &tm; +#endif //DLMS_IGNORE_MALLOC + unsigned char buff[12]; + bb_attach(&tmp, buff, 0, sizeof(buff)); + if ((ret = bb_set2(&tmp, &reply->data, reply->data.position, len)) != 0 || + (ret = dlms_changeType(&tmp, DLMS_DATA_TYPE_DATETIME, &t)) != 0) + { + return ret; + } +#ifdef DLMS_USE_EPOCH_TIME +#ifndef DLMS_IGNORE_MALLOC + reply->time = t.dateTime->value; +#else + reply->time = tm.value; +#endif //DLMS_IGNORE_MALLOC +#else +#ifndef DLMS_IGNORE_MALLOC + reply->time = t.dateTime->value; +#else + reply->time = ((gxtime*)t.pVal)->value; +#endif //DLMS_IGNORE_MALLOC +#endif // DLMS_USE_EPOCH_TIME + } + if ((ret = dlms_getDataFromBlock(&reply->data, start)) != 0) + { + return ret; + } +#ifndef DLMS_IGNORE_MALLOC + return dlms_getValueFromData(settings, reply); +#else + //Client app must do the data parsing if malloc is not used. + return 0; +#endif //DLMS_IGNORE_MALLOC +} + +/** +* Handle General block transfer message. +* +* @param settings +* DLMS settings. +* @param data +* received data. +*/ +int dlms_handleGbt( + dlmsSettings* settings, + gxReplyData* data) +{ + int ret; + unsigned char bc; + uint16_t bn, bna; + uint16_t index = (uint16_t)(data->data.position - 1); + if ((ret = bb_getUInt8(&data->data, &bc)) != 0) + { + return ret; + } + // Is streaming active. + data->streaming = (bc & 0x40) != 0; + data->windowSize = (bc & 0x3F); + // Block number. + if ((ret = bb_getUInt16(&data->data, &bn)) != 0) + { + return ret; + } + // Block number acknowledged. + if ((ret = bb_getUInt16(&data->data, &bna)) != 0) + { + return ret; + } + // Remove existing data when first block is received. + if (bn == 1) + { + index = 0; + } + else if (bna != settings->blockIndex - 1) + { + // If this block is already received. + data->data.size = index; + data->command = DLMS_COMMAND_NONE; + return 0; + } + + data->blockNumber = bn; + // Block number acknowledged. + data->blockNumberAck = bna; + data->command = DLMS_COMMAND_NONE; + uint16_t len; + if (hlp_getObjectCount2(&data->data, &len) != 0) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + if (len != (data->data.size - data->data.position)) + { + data->complete = 0; + return 0; + } + if ((ret = dlms_getDataFromBlock(&data->data, index)) != 0) + { + return ret; + } + + // Is Last block. + if ((bc & 0x80) == 0) { + data->moreData |= DLMS_DATA_REQUEST_TYPES_GBT; + } + else + { + data->moreData &= ~DLMS_DATA_REQUEST_TYPES_GBT; + if (data->data.size != 0) + { + data->data.position = 0; + if ((ret = dlms_getPdu(settings, data, 0)) != 0) + { + return ret; + } + // Get data if all data is read or we want to peek data. + if (data->data.position != data->data.size + && ( +#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + data->command == DLMS_COMMAND_READ_RESPONSE || +#endif //!defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + data->command == DLMS_COMMAND_GET_RESPONSE) + && (data->moreData == DLMS_DATA_REQUEST_TYPES_NONE || data->peek)) + { + data->data.position = 0; + ret = dlms_getValueFromData(settings, data); + } + } + } + return ret; +} + +#if !defined(DLMS_IGNORE_SERVER) +int dlms_handleGloDedRequest(dlmsSettings* settings, + gxReplyData* data) +{ + int ret = 0; +#ifdef DLMS_IGNORE_HIGH_GMAC + ret = DLMS_ERROR_CODE_NOT_IMPLEMENTED; +#else + DLMS_SECURITY_SUITE suite; + uint64_t invocationCounter; + // If all frames are read. + if ((data->moreData & DLMS_DATA_REQUEST_TYPES_FRAME) == 0) + { + unsigned char ch; + DLMS_SECURITY security; + --data->data.position; + unsigned char emptySourceSystemTile; + emptySourceSystemTile = memcmp(settings->sourceSystemTitle, EMPTY_SYSTEM_TITLE, 8) == 0; + if (dlms_useDedicatedKey(settings) && (settings->connected & DLMS_CONNECTION_STATE_DLMS) != 0) + { + if ((ret = cip_decrypt(&settings->cipher, + settings->sourceSystemTitle, + settings->cipher.dedicatedKey, + &data->data, + &security, + &suite, + &invocationCounter)) != 0) + { + return ret; + } + } + //If pre-set connection is made. + else if (dlms_usePreEstablishedConnection(settings) && emptySourceSystemTile) + { +#ifndef DLMS_IGNORE_SERVER + if (settings->server && settings->connected == DLMS_CONNECTION_STATE_NONE && !data->preEstablished) + { + // Check is data send to this server. + if (!svr_isTarget(settings, settings->serverAddress, settings->clientAddress)) + { + if ((settings->connected & DLMS_CONNECTION_STATE_DLMS) == 0) + { + settings->serverAddress = settings->clientAddress = 0; + } + return DLMS_ERROR_CODE_INVALID_CLIENT_ADDRESS; + } + if ((ret = svr_connected((dlmsServerSettings*)settings)) != 0) + { + return ret; + } + } +#endif //DLMS_IGNORE_SERVER + if ((ret = cip_decrypt(&settings->cipher, +#ifndef DLMS_IGNORE_MALLOC + settings->preEstablishedSystemTitle->data, + &settings->cipher.blockCipherKey, +#else + settings->preEstablishedSystemTitle, + settings->cipher.blockCipherKey, +#endif //DLMS_IGNORE_MALLOC + & data->data, + &security, + &suite, + &invocationCounter)) != 0) + { + return ret; + } + if (data->preEstablished == 0) + { + data->preEstablished = 1; + } + } + else + { + if ((ret = cip_decrypt(&settings->cipher, +#ifndef DLMS_IGNORE_MALLOC + settings->sourceSystemTitle, + &settings->cipher.blockCipherKey, +#else + settings->sourceSystemTitle, + settings->cipher.blockCipherKey, +#endif //DLMS_IGNORE_MALLOC + & data->data, + &security, + &suite, + &invocationCounter)) != 0) + { + return ret; + } + } + //If IC value is wrong. + if (settings->expectedInvocationCounter != NULL) + { + if (invocationCounter < *settings->expectedInvocationCounter) + { + return DLMS_ERROR_CODE_INVOCATION_COUNTER_TOO_SMALL; + } + //Update IC. +#ifdef DLMS_COSEM_INVOCATION_COUNTER_SIZE64 + * settings->expectedInvocationCounter = (1 + invocationCounter); +#else + * settings->expectedInvocationCounter = (uint32_t)(1 + invocationCounter); +#endif //DLMS_COSEM_INVOCATION_COUNTER_SIZE64 + } + // Get command. + if ((ret = bb_getUInt8(&data->data, &ch)) != 0) + { + return ret; + } + data->encryptedCommand = data->command; + data->command = (DLMS_COMMAND)ch; + } + else + { + data->data.position -= 1; + } +#endif //DLMS_IGNORE_HIGH_GMAC + return ret; +} +#endif // !defined(DLMS_IGNORE_SERVER) + +#if !defined(DLMS_IGNORE_CLIENT) +int dlms_handleGloDedResponse(dlmsSettings* settings, + gxReplyData* data, uint32_t index) +{ +#ifdef DLMS_IGNORE_HIGH_GMAC + return DLMS_ERROR_CODE_NOT_IMPLEMENTED; +#else + int ret = 0; + DLMS_SECURITY_SUITE suite; + uint64_t invocationCounter; + if ((data->moreData & DLMS_DATA_REQUEST_TYPES_FRAME) == 0) + { + DLMS_SECURITY security; + --data->data.position; + data->data.position = index; + gxByteBuffer bb; + bb_attach(&bb, data->data.data + index, bb_available(&data->data), bb_getCapacity(&data->data)); + if ((settings->connected & DLMS_CONNECTION_STATE_DLMS) != 0 && dlms_useDedicatedKey(settings)) + { + if ((ret = cip_decrypt(&settings->cipher, + settings->sourceSystemTitle, + settings->cipher.dedicatedKey, + &bb, + &security, + &suite, + &invocationCounter)) != 0) + { + return ret; + } + } + else + { + if ((ret = cip_decrypt(&settings->cipher, + settings->sourceSystemTitle, +#ifndef DLMS_IGNORE_MALLOC + & settings->cipher.blockCipherKey, +#else + settings->cipher.blockCipherKey, +#endif //DLMS_IGNORE_MALLOC + & bb, + &security, + &suite, + &invocationCounter)) != 0) + { + return ret; + } + } + data->data.size = bb.size + index; + //If target is sending data ciphered using different security policy. + if (settings->cipher.security != security) + { + return DLMS_ERROR_CODE_INVALID_DECIPHERING_ERROR; + } + if (settings->expectedInvocationCounter != NULL) + { + //If data is ciphered using invalid invocation counter value. + if (invocationCounter != *settings->expectedInvocationCounter) + { + return DLMS_ERROR_CODE_INVOCATION_COUNTER_TOO_SMALL; + } +#ifdef DLMS_COSEM_INVOCATION_COUNTER_SIZE64 + * settings->expectedInvocationCounter = (1 + invocationCounter); +#else + * settings->expectedInvocationCounter = (uint32_t)(1 + invocationCounter); +#endif //DLMS_COSEM_INVOCATION_COUNTER_SIZE64 + } + data->command = DLMS_COMMAND_NONE; + ret = dlms_getPdu(settings, data, 0); + data->cipherIndex = (uint16_t)data->data.size; + } + return ret; +#endif //DLMS_IGNORE_HIGH_GMAC +} +#endif //!defined(DLMS_IGNORE_CLIENT) + +#if !defined(DLMS_IGNORE_GENERAL_CIPHERING) && !defined(DLMS_IGNORE_HIGH_GMAC) +int dlms_handleGeneralCiphering( + dlmsSettings* settings, + gxReplyData* data) +{ +#ifdef DLMS_IGNORE_HIGH_GMAC + return DLMS_ERROR_CODE_NOT_IMPLEMENTED; +#else + unsigned char ch; + int ret; + // If all frames are read. + if ((data->moreData & DLMS_DATA_REQUEST_TYPES_FRAME) == 0) + { + --data->data.position; + DLMS_SECURITY security; + DLMS_SECURITY_SUITE suite; + uint64_t invocationCounter; + if ((ret = cip_decrypt(&settings->cipher, + settings->sourceSystemTitle, +#ifndef DLMS_IGNORE_MALLOC + & settings->cipher.blockCipherKey, +#else + settings->cipher.blockCipherKey, +#endif //DLMS_IGNORE_MALLOC + & data->data, + &security, + &suite, + &invocationCounter)) != 0) + { + return ret; + } + // Get command + if ((ret = bb_getUInt8(&data->data, &ch)) != 0) + { + return ret; + } + data->command = DLMS_COMMAND_NONE; + if (security != DLMS_SECURITY_NONE) + { + if ((ret = dlms_getPdu(settings, data, 0)) != 0) + { + return ret; + } + } + } + return 0; +#endif //DLMS_IGNORE_HIGH_GMAC +} +#endif //!defined(DLMS_IGNORE_GENERAL_CIPHERING) && !defined(DLMS_IGNORE_HIGH_GMAC) + +#if !defined(DLMS_IGNORE_SERVER) +int32_t dlms_handleConfirmedServiceError(gxByteBuffer* data) +{ + int32_t ret; + unsigned char ch; + if ((ret = bb_getUInt8(data, &ch)) != 0) + { + return ret; + } + DLMS_CONFIRMED_SERVICE_ERROR service = (DLMS_CONFIRMED_SERVICE_ERROR)ch; + if ((ret = bb_getUInt8(data, &ch)) != 0) + { + return ret; + } + DLMS_SERVICE_ERROR type = (DLMS_SERVICE_ERROR)ch; + if ((ret = bb_getUInt8(data, &ch)) != 0) + { + return ret; + } + ret = service; + ret <<= 16; + ret |= DLMS_ERROR_TYPE_CONFIRMED_SERVICE_ERROR; + ret |= type << 8; + ret |= ch; + return ret; +} + +int dlms_handleExceptionResponse(gxByteBuffer* data) +{ + int ret; + unsigned char ch; + // DLMS_EXCEPTION_STATE_ERROR state; + DLMS_EXCEPTION_SERVICE_ERROR error; + if ((ret = bb_getUInt8(data, &ch)) != 0) + { + return ret; + } + // state = (DLMS_EXCEPTION_STATE_ERROR)ch; + if ((ret = bb_getUInt8(data, &ch)) != 0) + { + return ret; + } + error = (DLMS_EXCEPTION_SERVICE_ERROR)ch; + uint32_t value = 0; + if (error == DLMS_EXCEPTION_SERVICE_ERROR_INVOCATION_COUNTER_ERROR && bb_available(data) > 3) + { + bb_getUInt32(data, &value); + } + return DLMS_ERROR_TYPE_EXCEPTION_RESPONSE | value << 8 | error; +} +#endif //!defined(DLMS_IGNORE_SERVER) + + +int dlms_getPdu( + dlmsSettings* settings, + gxReplyData* data, + unsigned char first) +{ + int ret = DLMS_ERROR_CODE_OK; +#if !defined(DLMS_IGNORE_CLIENT) + uint32_t index; +#endif //!defined(DLMS_IGNORE_CLIENT) + unsigned char ch; + DLMS_COMMAND cmd = data->command; + // If header is not read yet or GBT message. + if (cmd == DLMS_COMMAND_NONE) + { + // If PDU is missing. + if (bb_available(&data->data) == 0) + { + // Invalid PDU. + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } +#if !defined(DLMS_IGNORE_CLIENT) + index = data->data.position; +#endif //!defined(DLMS_IGNORE_CLIENT) + // Get command. + if ((ret = bb_getUInt8(&data->data, &ch)) != 0) + { + return ret; + } + cmd = (DLMS_COMMAND)ch; + data->command = cmd; + switch (cmd) + { +#if !defined(DLMS_IGNORE_CLIENT) +#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + case DLMS_COMMAND_READ_RESPONSE: + if ((ret = dlms_handleReadResponse(settings, data, (uint16_t)index)) != 0) + { + if (ret == DLMS_ERROR_CODE_FALSE) + { + return DLMS_ERROR_CODE_OK; + } + return ret; + } + break; +#endif //!defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + case DLMS_COMMAND_GET_RESPONSE: + if ((ret = dlms_handleGetResponse(settings, data, (uint16_t)index)) != 0) + { + if (ret == DLMS_ERROR_CODE_FALSE) + { + return DLMS_ERROR_CODE_OK; + } + return ret; + } + break; + case DLMS_COMMAND_SET_RESPONSE: + ret = dlms_handleSetResponse(settings, data); + break; +#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + case DLMS_COMMAND_WRITE_RESPONSE: + ret = dlms_handleWriteResponse(data); + break; +#endif //!defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + case DLMS_COMMAND_METHOD_RESPONSE: + ret = dlms_handleMethodResponse(settings, data); + break; + case DLMS_COMMAND_GENERAL_BLOCK_TRANSFER: + ret = dlms_handleGbt(settings, data); + break; +#endif //!defined(DLMS_IGNORE_CLIENT) + case DLMS_COMMAND_AARQ: + case DLMS_COMMAND_AARE: + // This is parsed later. + data->data.position -= 1; + break; + case DLMS_COMMAND_RELEASE_RESPONSE: + break; +#if !defined(DLMS_IGNORE_SERVER) + case DLMS_COMMAND_CONFIRMED_SERVICE_ERROR: + ret = dlms_handleConfirmedServiceError(&data->data); + break; + case DLMS_COMMAND_EXCEPTION_RESPONSE: + ret = dlms_handleExceptionResponse(&data->data); + break; + case DLMS_COMMAND_GET_REQUEST: +#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + case DLMS_COMMAND_READ_REQUEST: + case DLMS_COMMAND_WRITE_REQUEST: +#endif //!defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + case DLMS_COMMAND_SET_REQUEST: + case DLMS_COMMAND_METHOD_REQUEST: + case DLMS_COMMAND_RELEASE_REQUEST: + // Server handles this. + if ((data->moreData & DLMS_DATA_REQUEST_TYPES_FRAME) != 0) + { + break; + } + break; +#endif //!defined(DLMS_IGNORE_SERVER) +#ifndef DLMS_IGNORE_HIGH_GMAC +#if !defined(DLMS_IGNORE_SERVER) + case DLMS_COMMAND_GLO_READ_REQUEST: + case DLMS_COMMAND_GLO_WRITE_REQUEST: + case DLMS_COMMAND_GLO_GET_REQUEST: + case DLMS_COMMAND_GLO_SET_REQUEST: + case DLMS_COMMAND_GLO_METHOD_REQUEST: + case DLMS_COMMAND_DED_GET_REQUEST: + case DLMS_COMMAND_DED_SET_REQUEST: + case DLMS_COMMAND_DED_METHOD_REQUEST: + ret = dlms_handleGloDedRequest(settings, data); + // Server handles this. + break; +#endif //!defined(DLMS_IGNORE_SERVER) +#if !defined(DLMS_IGNORE_CLIENT) + case DLMS_COMMAND_GLO_READ_RESPONSE: + case DLMS_COMMAND_GLO_WRITE_RESPONSE: + case DLMS_COMMAND_GLO_GET_RESPONSE: + case DLMS_COMMAND_GLO_SET_RESPONSE: + case DLMS_COMMAND_GLO_METHOD_RESPONSE: + case DLMS_COMMAND_DED_GET_RESPONSE: + case DLMS_COMMAND_DED_SET_RESPONSE: + case DLMS_COMMAND_DED_EVENT_NOTIFICATION: + case DLMS_COMMAND_DED_METHOD_RESPONSE: + // If all frames are read. + ret = dlms_handleGloDedResponse(settings, data, index); + break; +#endif // !defined(DLMS_IGNORE_CLIENT) + case DLMS_COMMAND_GENERAL_GLO_CIPHERING: + case DLMS_COMMAND_GENERAL_DED_CIPHERING: +#if !defined(DLMS_IGNORE_SERVER) + if (settings->server) + { + if ((settings->connected & DLMS_CONNECTION_STATE_DLMS) == 0) + { + return DLMS_ERROR_CODE_INVALID_DECIPHERING_ERROR; + } + ret = dlms_handleGloDedRequest(settings, data); + } +#endif// !defined(DLMS_IGNORE_CLIENT) +#if !defined(DLMS_IGNORE_CLIENT) +#if !defined(DLMS_IGNORE_SERVER) + else +#endif // !defined(DLMS_IGNORE_SERVER) + { + ret = dlms_handleGloDedResponse(settings, data, index); + } +#endif //!defined(DLMS_IGNORE_CLIENT) + break; +#if !defined(DLMS_IGNORE_GENERAL_CIPHERING) && !defined(DLMS_IGNORE_HIGH_GMAC) + case DLMS_COMMAND_GENERAL_CIPHERING: + ret = dlms_handleGeneralCiphering(settings, data); + break; +#endif //!defined(DLMS_IGNORE_GENERAL_CIPHERING) && !defined(DLMS_IGNORE_HIGH_GMAC) +#endif //DLMS_IGNORE_HIGH_GMAC + case DLMS_COMMAND_DATA_NOTIFICATION: + ret = dlms_handleDataNotification(settings, data); + // Client handles this. + break; + case DLMS_COMMAND_EVENT_NOTIFICATION: + // Client handles this. + break; + case DLMS_COMMAND_INFORMATION_REPORT: + // Client handles this. + break; + default: + // Invalid command. + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + } + else if ((data->moreData & DLMS_DATA_REQUEST_TYPES_FRAME) == 0) + { + // Is whole block is read and if last packet and data is not try to + // peek. + if (!data->peek && data->moreData == DLMS_DATA_REQUEST_TYPES_NONE) + { + if (!settings->server || data->command == DLMS_COMMAND_AARE || data->command == DLMS_COMMAND_AARQ) + { + data->data.position = 0; + } + else + { + data->data.position = 1; + } + } + if (cmd == DLMS_COMMAND_GENERAL_BLOCK_TRANSFER) + { + data->data.position = data->cipherIndex + 1; + ret = dlms_handleGbt(settings, data); + data->cipherIndex = (uint16_t)data->data.size; + data->command = DLMS_COMMAND_NONE; + } + // Get command if operating as a server. +#ifndef DLMS_IGNORE_SERVER + if (settings->server) + { +#ifndef DLMS_IGNORE_HIGH_GMAC + // Ciphered messages are handled after whole PDU is received. + switch (cmd) + { + case DLMS_COMMAND_GLO_READ_REQUEST: + case DLMS_COMMAND_GLO_WRITE_REQUEST: + case DLMS_COMMAND_GLO_GET_REQUEST: + case DLMS_COMMAND_GLO_SET_REQUEST: + case DLMS_COMMAND_GLO_METHOD_REQUEST: + data->command = DLMS_COMMAND_NONE; + data->data.position = (data->cipherIndex); + ret = dlms_getPdu(settings, data, 0); + break; + default: + break; + } +#endif //DLMS_IGNORE_HIGH_GMAC + } + else +#endif //DLMS_IGNORE_SERVER + { + // Client do not need a command any more. + data->command = DLMS_COMMAND_NONE; +#ifndef DLMS_IGNORE_HIGH_GMAC + // Ciphered messages are handled after whole PDU is received. + switch (cmd) + { + case DLMS_COMMAND_GLO_READ_RESPONSE: + case DLMS_COMMAND_GLO_WRITE_RESPONSE: + case DLMS_COMMAND_GLO_GET_RESPONSE: + case DLMS_COMMAND_GLO_SET_RESPONSE: + case DLMS_COMMAND_GLO_METHOD_RESPONSE: + case DLMS_COMMAND_DED_GET_RESPONSE: + case DLMS_COMMAND_DED_SET_RESPONSE: + case DLMS_COMMAND_DED_METHOD_RESPONSE: + case DLMS_COMMAND_GENERAL_GLO_CIPHERING: + case DLMS_COMMAND_GENERAL_DED_CIPHERING: + data->data.position = data->cipherIndex; + ret = dlms_getPdu(settings, data, 0); + break; + default: + break; + } +#endif //DLMS_IGNORE_HIGH_GMAC + } + } + +#if !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) +#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) + // Get data only blocks if SN is used. This is faster. + if (ret == 0 && cmd == DLMS_COMMAND_READ_RESPONSE + && data->commandType == DLMS_SINGLE_READ_RESPONSE_DATA_BLOCK_RESULT + && (data->moreData & DLMS_DATA_REQUEST_TYPES_FRAME) != 0) + { + return 0; + } +#endif //!defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) + // Get data if all data is read or we want to peek data. + if (ret == 0 && !data->ignoreValue && data->data.position != data->data.size + && ( +#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) + cmd == DLMS_COMMAND_READ_RESPONSE || +#endif //!defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) + cmd == DLMS_COMMAND_GET_RESPONSE) + && (data->moreData == DLMS_DATA_REQUEST_TYPES_NONE + || data->peek)) + { + ret = dlms_getValueFromData(settings, data); + } +#else + data->dataValue.byteArr = &data->data; + data->dataValue.vt = DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_OCTET_STRING; +#endif //!defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + return ret; +} + +#ifndef DLMS_IGNORE_HDLC +/** +* Add LLC bytes to generated message. +* +* @param settings +* DLMS settings. +* @param data +* Data where bytes are added. +*/ +int dlms_addLLCBytes( + dlmsSettings* settings, + gxByteBuffer* data) +{ + int ret; + if (settings->server) + { + ret = bb_insert(LLC_REPLY_BYTES, 3, data, 0); + } + else + { + ret = bb_insert(LLC_SEND_BYTES, 3, data, 0); + } + return ret; +} +#endif //DLMS_IGNORE_HDLC + + +#ifdef DLMS_USE_EPOCH_TIME +int dlms_updateSendTime(uint32_t value, gxByteBuffer* reply) +#else +int dlms_updateSendTime(struct tm* value, gxByteBuffer* reply) +#endif // DLMS_USE_EPOCH_TIME +{ +#ifdef DLMS_USE_EPOCH_TIME + if (value == 0) +#else + if (value == NULL) +#endif // DLMS_USE_EPOCH_TIME + { + return bb_setUInt8(reply, (unsigned char)DLMS_DATA_TYPE_NONE); + } + // Data is send in octet string. Remove data type. + int ret; + uint16_t pos = (uint16_t)reply->size; + dlmsVARIANT tmp; + gxtime t; +#ifndef DLMS_IGNORE_MALLOC + tmp.dateTime = &t; + tmp.vt = DLMS_DATA_TYPE_DATETIME; +#else + GX_DATETIME(tmp) = &t; +#endif // DLMS_IGNORE_MALLOC +#ifdef DLMS_USE_EPOCH_TIME + time_initUnix(&t, value); +#else + time_initUnix(&t, 0); + t.value = *value; +#endif //DLMS_USE_EPOCH_TIME + if ((ret = dlms_setData(reply, DLMS_DATA_TYPE_OCTET_STRING, &tmp)) != 0) + { + return ret; + } + //Remove data type. + return bb_move(reply, pos + 1, pos, reply->size - pos - 1); +} + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME +int dlms_appendMultipleSNBlocks( + gxSNParameters* p, + gxByteBuffer* reply) +{ + uint32_t maxSize; +#ifndef DLMS_IGNORE_HIGH_GMAC + unsigned char ciphering = p->settings->cipher.security != DLMS_SECURITY_NONE; +#else + unsigned char ciphering = 0; +#endif //DLMS_IGNORE_HIGH_GMAC + uint32_t hSize = reply->size + 3; + // Add LLC bytes. + if (p->command == DLMS_COMMAND_WRITE_REQUEST + || p->command == DLMS_COMMAND_READ_REQUEST) + { + hSize += 1 + hlp_getObjectCountSizeInBytes(p->count); + } + maxSize = p->settings->maxPduSize - hSize; + if (ciphering) + { + maxSize -= CIPHERING_HEADER_SIZE; +#ifndef DLMS_IGNORE_HDLC + if (dlms_useHdlc(p->settings->interfaceType)) + { + maxSize -= 3; + } +#endif //DLMS_IGNORE_HDLC + } + maxSize -= hlp_getObjectCountSizeInBytes(maxSize); + if ((uint16_t)(p->data->size - p->data->position) > maxSize) + { + // More blocks. + bb_setUInt8(reply, 0); + } + else + { + // Last block. + bb_setUInt8(reply, p->lastBlock); + maxSize = p->data->size - p->data->position; + } + // Add block index. + bb_setUInt16(reply, p->blockIndex); + if (p->command == DLMS_COMMAND_WRITE_REQUEST) + { + ++p->blockIndex; + hlp_setObjectCount(p->count, reply); + bb_setUInt8(reply, DLMS_DATA_TYPE_OCTET_STRING); + } + else if (p->command == DLMS_COMMAND_READ_REQUEST) + { + ++p->blockIndex; + } + + hlp_setObjectCount(maxSize, reply); + return maxSize; +} + +int dlms_getSNPdu( + gxSNParameters* p, + gxByteBuffer* reply) +{ + int ret = 0, cnt = 0; + unsigned char cipherSize = 0; +#ifndef DLMS_IGNORE_HIGH_GMAC + unsigned char ciphering = p->command != DLMS_COMMAND_AARQ && p->command != DLMS_COMMAND_AARE && p->settings->cipher.security != DLMS_SECURITY_NONE; +#else + unsigned char ciphering = 0; +#endif //DLMS_IGNORE_HIGH_GMAC + gxByteBuffer* h; + if (p->settings->server) + { + gxByteBuffer header; + bb_attach(&header, pduAttributes, 0, sizeof(pduAttributes)); + h = &header; + } + else + { + h = reply; + } + if (ciphering) + { + cipherSize = CIPHERING_HEADER_SIZE; + } + if (p->data != NULL) + { + cnt = p->data->size - p->data->position; + } + // Add command. + if (p->command == DLMS_COMMAND_INFORMATION_REPORT) + { + bb_setUInt8(h, (unsigned char)p->command); + // Add date time. + if ((ret = dlms_updateSendTime(p->time, reply)) != 0) + { + return ret; + } + hlp_setObjectCount(p->count, reply); + bb_set2(reply, p->attributeDescriptor, 0, p->attributeDescriptor->size); + } + else if (p->command != DLMS_COMMAND_AARQ && p->command != DLMS_COMMAND_AARE) + { + bb_setUInt8(h, (unsigned char)p->command); + if (p->count != 0xFF) + { + hlp_setObjectCount(p->count, h); + } + if (!p->multipleBlocks) + { + if (p->requestType != 0xFF) + { + bb_setUInt8(h, p->requestType); + } + if (p->attributeDescriptor != NULL) + { + bb_set2(h, p->attributeDescriptor, 0, p->attributeDescriptor->size); + } + p->multipleBlocks = h->size + cipherSize + cnt > p->settings->maxPduSize; + // If reply data is not fit to one PDU. + if (p->multipleBlocks) + { + reply->size = 0; + if (p->command == DLMS_COMMAND_WRITE_REQUEST) + { + p->requestType = DLMS_VARIABLE_ACCESS_SPECIFICATION_WRITE_DATA_BLOCK_ACCESS; + } + else if (p->command == DLMS_COMMAND_READ_REQUEST) + { + p->requestType = DLMS_VARIABLE_ACCESS_SPECIFICATION_READ_DATA_BLOCK_ACCESS; + } + else if (p->command == DLMS_COMMAND_READ_RESPONSE) + { + p->requestType = DLMS_SINGLE_READ_RESPONSE_DATA_BLOCK_RESULT; + } + else + { + //Invalid command. + return DLMS_ERROR_CODE_INVALID_COMMAND; + } + bb_setUInt8(reply, (unsigned char)p->command); + // Set object count. + bb_setUInt8(reply, 1); + if (p->requestType != 0xFF) + { + bb_setUInt8(reply, p->requestType); + } + cnt = dlms_appendMultipleSNBlocks(p, h); + } + } + else + { + if (p->command == DLMS_COMMAND_WRITE_REQUEST) + { + p->requestType = DLMS_VARIABLE_ACCESS_SPECIFICATION_WRITE_DATA_BLOCK_ACCESS; + } + else if (p->command == DLMS_COMMAND_READ_REQUEST) + { + p->requestType = DLMS_VARIABLE_ACCESS_SPECIFICATION_READ_DATA_BLOCK_ACCESS; + } + else if (p->command == DLMS_COMMAND_READ_RESPONSE) + { + p->requestType = DLMS_SINGLE_READ_RESPONSE_DATA_BLOCK_RESULT; + } + else + { + //Invalid command. + return DLMS_ERROR_CODE_INVALID_COMMAND; + } + if (p->requestType != 0xFF) + { + bb_setUInt8(h, p->requestType); + } + if (p->attributeDescriptor != NULL) + { + bb_set2(h, p->attributeDescriptor, 0, p->attributeDescriptor->size); + } + cnt = dlms_appendMultipleSNBlocks(p, h); + } + } + // Add data. + if (p->settings->server) + { + bb_insert(h->data, h->size, reply, 0); + } + else if (p->data != NULL) + { + bb_set2(reply, p->data, p->data->position, cnt); + } +#ifndef DLMS_IGNORE_HIGH_GMAC + // If Ciphering is used. + if (ciphering && p->command != DLMS_COMMAND_AARQ + && p->command != DLMS_COMMAND_AARE) + { + ret = cip_encrypt( + &p->settings->cipher, + p->settings->cipher.security, + DLMS_COUNT_TYPE_PACKET, + p->settings->cipher.invocationCounter, + dlms_getGloMessage(p->settings, p->command, p->encryptedCommand), +#ifndef DLMS_IGNORE_MALLOC + p->settings->cipher.systemTitle.data, + &p->settings->cipher.blockCipherKey, +#else + p->settings->cipher.systemTitle, + p->settings->cipher.blockCipherKey, +#endif //DLMS_IGNORE_MALLOC + reply); + if (ret != 0) + { + return ret; + } + reply->position = reply->size = 0; + } +#endif //DLMS_IGNORE_HIGH_GMAC +#ifndef DLMS_IGNORE_HDLC + if (ret == 0 && dlms_useHdlc(p->settings->interfaceType)) + { + ret = dlms_addLLCBytes(p->settings, reply); + } +#endif //DLMS_IGNORE_HDLC + return 0; +} +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + + +/** +* Check is all data fit to one data block. +* +* @param p +* LN parameters. +* @param reply +* Generated reply. +*/ +void dlms_multipleBlocks( + gxLNParameters* p, + gxByteBuffer* reply, + unsigned char ciphering) +{ + // Check is all data fit to one message if data is given. + int len = bb_available(p->data); + if (p->attributeDescriptor != NULL) + { + len += p->attributeDescriptor->size; + } + if (ciphering) + { + len += CIPHERING_HEADER_SIZE; + } + if (!p->multipleBlocks) + { + // Add command type and invoke and priority. + p->multipleBlocks = 2 + reply->size + len > p->settings->maxPduSize; + } + if (p->lastBlock) + { + // Add command type and invoke and priority. + p->lastBlock = !(8 + reply->size + len > p->settings->maxPduSize); + } +} + +int dlms_getLNPdu( + gxLNParameters* p, + gxByteBuffer* reply) +{ + int ret = 0; +#ifndef DLMS_IGNORE_HIGH_GMAC + unsigned char ciphering = (p->command != DLMS_COMMAND_AARQ && p->command != DLMS_COMMAND_AARE && + p->settings->cipher.security != DLMS_SECURITY_NONE) || p->encryptedCommand != DLMS_COMMAND_NONE; +#else + unsigned char ciphering = 0; +#endif //DLMS_IGNORE_HIGH_GMAC +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + uint32_t len = 0; +#else + uint16_t len = 0; +#endif + if (p->command == DLMS_COMMAND_AARQ) + { + //Data is already added to reply when malloc is not used. +#ifndef DLMS_IGNORE_MALLOC + if ((ret = bb_set2(reply, p->attributeDescriptor, 0, p->attributeDescriptor->size)) != 0) + { + return ret; + } +#endif //DLMS_IGNORE_MALLOC + } + else + { + gxByteBuffer header; + gxByteBuffer* h; + if (p->settings->server) + { + bb_attach(&header, pduAttributes, 0, sizeof(pduAttributes)); + h = &header; + } + else + { +#ifdef DLMS_IGNORE_MALLOC + bb_attach(&header, pduAttributes, 0, sizeof(pduAttributes)); + h = &header; +#else + h = reply; +#endif //DLMS_IGNORE_MALLOC + } + // Add command. + if (p->command != DLMS_COMMAND_GENERAL_BLOCK_TRANSFER) + { + ret = bb_setUInt8(h, (unsigned char)p->command); + } + if (p->command == DLMS_COMMAND_EVENT_NOTIFICATION || + p->command == DLMS_COMMAND_DATA_NOTIFICATION || + p->command == DLMS_COMMAND_ACCESS_REQUEST || + p->command == DLMS_COMMAND_ACCESS_RESPONSE) + { + // Add Long-Invoke-Id-And-Priority + if (p->command != DLMS_COMMAND_EVENT_NOTIFICATION) + { + if (p->invokeId != 0) + { + ret = bb_setUInt32(h, p->invokeId); + } + else + { + ret = bb_setUInt32(h, dlms_getLongInvokeIDPriority(p->settings)); + } + } + // Add date time. + ret = dlms_updateSendTime(p->time, h); + } + else if (p->command != DLMS_COMMAND_RELEASE_REQUEST) + { + // Get request size can be bigger than PDU size. + if (p->command != DLMS_COMMAND_GET_REQUEST && p->data != NULL + && p->data->size != 0) + { + dlms_multipleBlocks(p, h, ciphering); + } + // Change Request type if Set request and multiple blocks is + // needed. + if (p->command == DLMS_COMMAND_SET_REQUEST) + { + if (p->multipleBlocks) + { + if (p->requestType == 1) + { + p->requestType = 2; + } + else if (p->requestType == 2) + { + p->requestType = 3; + } + } + } + // Change request type If get response and multiple blocks is + // needed. + if (p->command == DLMS_COMMAND_GET_RESPONSE) + { + if (p->multipleBlocks) + { + if (p->requestType == 1) + { + p->requestType = 2; + } + } + } + ret = bb_setUInt8(h, p->requestType); + // Add Invoke Id And Priority. + if (p->invokeId != 0) + { + ret = bb_setUInt8(h, p->invokeId); + } + else + { + ret = bb_setUInt8(h, dlms_getInvokeIDPriority(p->settings, p->settings->autoIncreaseInvokeID)); + } + } +#ifndef DLMS_IGNORE_MALLOC + // Add attribute descriptor. + if (ret == 0 && p->attributeDescriptor != NULL) + { + ret = bb_set(reply, p->attributeDescriptor->data, p->attributeDescriptor->size); + } +#endif //DLMS_IGNORE_MALLOC + if (ret == 0 && + p->command != DLMS_COMMAND_EVENT_NOTIFICATION && + p->command != DLMS_COMMAND_DATA_NOTIFICATION && + (p->settings->negotiatedConformance & DLMS_CONFORMANCE_GENERAL_BLOCK_TRANSFER) == 0) + { + int totalLength; + // If multiple blocks. + if (p->multipleBlocks) + { + // Is last block. + if (p->lastBlock) + { + ret = bb_setUInt8(h, 1); + } + else + { + ret = bb_setUInt8(h, 0); + } + // Block index. + ret = bb_setUInt32(h, p->blockIndex); + p->blockIndex = p->blockIndex + 1; + // Add status if reply. + if (p->status != 0xFF) + { + if (p->status != 0 && p->command == DLMS_COMMAND_GET_RESPONSE) + { + ret = bb_setUInt8(h, 1); + } + ret = bb_setUInt8(h, p->status); + } + // Block size. + if (p->data != NULL) + { + len = (uint16_t)(p->data->size - p->data->position); + } + else + { + len = 0; + } + totalLength = len + h->size; +#ifndef DLMS_IGNORE_HIGH_GMAC + if (ciphering) + { + totalLength += CIPHERING_HEADER_SIZE; + } +#endif //DLMS_IGNORE_HIGH_GMAC + if (totalLength > p->settings->maxPduSize) + { + len = (uint16_t)(p->settings->maxPduSize - h->size); +#ifndef DLMS_IGNORE_HIGH_GMAC + if (ciphering) + { + len -= CIPHERING_HEADER_SIZE; + } +#endif //DLMS_IGNORE_HIGH_GMAC + len -= hlp_getObjectCountSizeInBytes(len); + } + ret = hlp_setObjectCount(len, h); + if (ret == 0) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = bb_insert(h->data, h->size, reply, 0)) != 0) + { + //If this fails PDU buffer size must be bigger. + return ret; + } +#else + if (p->settings->server) + { + if ((ret = bb_insert(h->data, h->size, reply, 0)) != 0) + { + //If this fails PDU buffer size must be bigger. + return ret; + } + } + else if (p->data != NULL) + { + ret = bb_set2(reply, p->data, p->data->position, len); + } +#endif //DLMS_IGNORE_MALLOC + } + } + } + // Add data that fits to one block. + if (ret == 0 && len == 0) + { + // Add status if reply. + if (p->status != 0xFF) + { + if (p->status != 0 + && (p->command == DLMS_COMMAND_GET_RESPONSE)) + { + ret = bb_setUInt8(h, 1); + } + ret = bb_setUInt8(h, p->status); + } + if (ret == 0 && p->data != NULL && p->data->size != 0) + { + len = bb_available(p->data); + if (len + reply->size > p->settings->maxPduSize) + { + len = (uint16_t)(p->settings->maxPduSize - h->size - p->data->size - p->data->position); + } +#ifdef DLMS_IGNORE_MALLOC + ret = bb_insert(h->data, h->size, reply, 0); + if (!p->settings->server) + { + p->data->position += len; + } +#else + if (p->settings->server) + { + ret = bb_insert(h->data, h->size, reply, 0); + } + else + { + ret = bb_set2(reply, p->data, p->data->position, len); + } +#endif //DLMS_IGNORE_MALLOC + } + else + { +#ifdef DLMS_IGNORE_MALLOC + ret = bb_insert(h->data, h->size, reply, 0); +#else + if (p->settings->server) + { + ret = bb_insert(h->data, h->size, reply, 0); + } +#endif //DLMS_IGNORE_MALLOC + } + } +#ifndef DLMS_IGNORE_HIGH_GMAC + if (ret == 0 && ciphering && reply->size != 0 && p->command != DLMS_COMMAND_RELEASE_REQUEST) + { +#ifndef DLMS_IGNORE_MALLOC + gxByteBuffer* key; +#else + unsigned char* key; +#endif //DLMS_IGNORE_MALLOC + if (p->settings->cipher.broacast) + { +#ifndef DLMS_IGNORE_MALLOC + key = &p->settings->cipher.broadcastBlockCipherKey; +#else + key = p->settings->cipher.broadcastBlockCipherKey; +#endif //DLMS_IGNORE_MALLOC + } + else if (dlms_useDedicatedKey(p->settings) && (p->settings->connected & DLMS_CONNECTION_STATE_DLMS) != 0) + { + key = p->settings->cipher.dedicatedKey; + } + else + { +#ifndef DLMS_IGNORE_MALLOC + key = &p->settings->cipher.blockCipherKey; +#else + key = p->settings->cipher.blockCipherKey; +#endif //DLMS_IGNORE_MALLOC + } + ret = cip_encrypt( + &p->settings->cipher, + p->settings->cipher.security, + DLMS_COUNT_TYPE_PACKET, + p->settings->cipher.invocationCounter, + dlms_getGloMessage(p->settings, p->command, p->encryptedCommand), +#ifndef DLMS_IGNORE_MALLOC + p->settings->cipher.systemTitle.data, +#else + p->settings->cipher.systemTitle, +#endif //DLMS_IGNORE_MALLOC + key, + reply); + } +#endif //DLMS_IGNORE_HIGH_GMAC1 + + if (p->command == DLMS_COMMAND_GENERAL_BLOCK_TRANSFER || + (p->multipleBlocks && (p->settings->negotiatedConformance & DLMS_CONFORMANCE_GENERAL_BLOCK_TRANSFER) != 0)) + { + bb_setUInt8(h, DLMS_COMMAND_GENERAL_BLOCK_TRANSFER); + dlms_multipleBlocks(p, h, ciphering); + // Is last block + if (!p->lastBlock) + { + bb_setUInt8(h, 0); + } + else + { + bb_setUInt8(h, 0x80); + } + // Set block number sent. + bb_setUInt8(h, 0); + // Set block number acknowledged + bb_setUInt8(h, (unsigned char)p->blockIndex); + p->blockIndex = p->blockIndex + 1; + // Add APU tag. + bb_setUInt8(h, 0); + // Add Addl fields + bb_setUInt8(h, 0); + } + } +#ifndef DLMS_IGNORE_HDLC + if (ret == 0 && dlms_useHdlc(p->settings->interfaceType)) + { + ret = dlms_addLLCBytes(p->settings, reply); + } +#endif //DLMS_IGNORE_HDLC + return ret; +} + +int dlms_getLnMessages( + gxLNParameters* p, + message* messages) +{ + int ret; + gxByteBuffer* pdu; + gxByteBuffer* it; +#ifndef DLMS_IGNORE_HDLC + unsigned char frame = 0; + if (p->command == DLMS_COMMAND_DATA_NOTIFICATION || + p->command == DLMS_COMMAND_EVENT_NOTIFICATION) + { + frame = 0x13; + } +#endif //DLMS_IGNORE_HDLC +#ifdef DLMS_IGNORE_MALLOC + pdu = p->serializedPdu; +#else + gxByteBuffer reply; + if (p->serializedPdu == NULL) + { + BYTE_BUFFER_INIT(&reply); + pdu = &reply; + } + else + { + pdu = p->serializedPdu; + } +#endif //DLMS_IGNORE_MALLOC + do + { + if ((ret = dlms_getLNPdu(p, pdu)) == 0) + { + p->lastBlock = 1; + if (p->attributeDescriptor == NULL) + { + ++p->settings->blockIndex; + } + } + while (ret == 0 && pdu->position != pdu->size) + { +#ifdef DLMS_IGNORE_MALLOC + if (!(messages->size < messages->capacity)) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + it = messages->data[messages->size]; + ++messages->size; + bb_clear(it); +#else + if (messages->attached) + { + if (messages->size < messages->capacity) + { + it = messages->data[messages->size]; + ++messages->size; + bb_clear(it); + } + else + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + } + else + { + it = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + if (it == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + BYTE_BUFFER_INIT(it); + mes_push(messages, it); + } +#endif //DLMS_IGNORE_MALLOC + switch (p->settings->interfaceType) + { +#ifndef DLMS_IGNORE_WRAPPER + case DLMS_INTERFACE_TYPE_WRAPPER: + ret = dlms_getWrapperFrame(p->settings, p->command, pdu, it); + break; +#endif //DLMS_IGNORE_WRAPPER +#ifndef DLMS_IGNORE_HDLC + case DLMS_INTERFACE_TYPE_HDLC: + case DLMS_INTERFACE_TYPE_HDLC_WITH_MODE_E: + ret = dlms_getHdlcFrame(p->settings, frame, pdu, it); + if (ret == 0 && pdu->position != pdu->size) + { + frame = getNextSend(p->settings, 0); + } + break; +#endif //DLMS_IGNORE_HDLC + case DLMS_INTERFACE_TYPE_PDU: + ret = bb_set2(it, pdu, 0, pdu->size); + break; +#ifndef DLMS_IGNORE_PLC + case DLMS_INTERFACE_TYPE_PLC: + ret = dlms_getPlcFrame(p->settings, 0x90, pdu, it); + break; + case DLMS_INTERFACE_TYPE_PLC_HDLC: + ret = dlms_getMacHdlcFrame(p->settings, frame, 0, pdu, it); + break; +#endif //DLMS_IGNORE_PLC + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if (ret != 0) + { + break; + } + } + bb_clear(pdu); +#ifndef DLMS_IGNORE_HDLC + frame = 0; +#endif //DLMS_IGNORE_HDLC + } while (ret == 0 && p->data != NULL && p->data->position != p->data->size); + return ret; +} + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME +int dlms_getSnMessages( + gxSNParameters* p, + message* messages) +{ + int ret; + gxByteBuffer data; + gxByteBuffer* it; + unsigned char frame = 0x0; + if (p->command == DLMS_COMMAND_INFORMATION_REPORT) + { + if ((p->settings->connected & DLMS_CONNECTION_STATE_DLMS) != 0) + { + //If connection is established. + frame = 0x13; + } + else + { + frame = 0x3; + } + } + else if (p->command == DLMS_COMMAND_NONE) + { + frame = getNextSend(p->settings, 1); + } + BYTE_BUFFER_INIT(&data); + mes_clear(messages); + do + { + ret = dlms_getSNPdu(p, &data); + // Command is not add to next PDUs. + while (ret == 0 && data.position != data.size) + { +#ifndef DLMS_IGNORE_MALLOC + it = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); +#else + if (!(messages->size < messages->capacity)) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + it = messages->data[messages->size]; + ++messages->size; +#endif //DLMS_IGNORE_MALLOC + BYTE_BUFFER_INIT(it); + if (p->settings->interfaceType == DLMS_INTERFACE_TYPE_WRAPPER) + { +#ifndef DLMS_IGNORE_WRAPPER + ret = dlms_getWrapperFrame(p->settings, p->command, &data, it); +#else + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif //DLMS_IGNORE_WRAPPER + } + else + { +#ifndef DLMS_IGNORE_HDLC + ret = dlms_getHdlcFrame(p->settings, frame, &data, it); + if (data.position != data.size) + { + frame = getNextSend(p->settings, 0); + } +#else + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif //DLMS_IGNORE_HDLC + } + if (ret != 0) + { + break; + } +#ifndef DLMS_IGNORE_MALLOC + mes_push(messages, it); +#endif //DLMS_IGNORE_MALLOC + } + bb_clear(&data); + frame = 0; + } while (ret == 0 && p->data != NULL && p->data->position != p->data->size); + return 0; +} +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + +int dlms_getData2( + dlmsSettings* settings, + gxByteBuffer* reply, + gxReplyData* data, + unsigned char first) +{ + unsigned char isNotify; + return dlms_getData3(settings, reply, data, NULL, first, &isNotify); +} + +int dlms_getData3( + dlmsSettings* settings, + gxByteBuffer* reply, + gxReplyData* data, + gxReplyData* notify, + unsigned char first, + unsigned char* isNotify) +{ + int ret; + unsigned char frame = 0; + if (isNotify != NULL) + { + *isNotify = 0; + } + switch (settings->interfaceType) + { +#ifndef DLMS_IGNORE_HDLC + case DLMS_INTERFACE_TYPE_HDLC: + case DLMS_INTERFACE_TYPE_HDLC_WITH_MODE_E: + ret = dlms_getHdlcData(settings->server, settings, reply, data, &frame, data->preEstablished, first); + break; +#endif //DLMS_IGNORE_HDLC +#ifndef DLMS_IGNORE_WRAPPER + case DLMS_INTERFACE_TYPE_WRAPPER: + ret = dlms_getTcpData(settings, reply, data, notify, isNotify); + break; +#endif //DLMS_IGNORE_WRAPPER +#ifndef DLMS_IGNORE_WIRELESS_MBUS + case DLMS_INTERFACE_TYPE_WIRELESS_MBUS: + ret = dlms_getMBusData(settings, reply, data); + break; +#endif //DLMS_IGNORE_WIRELESS_MBUS + case DLMS_INTERFACE_TYPE_PDU: + data->packetLength = reply->size; + data->complete = reply->size != 0; + ret = 0; + break; +#ifndef DLMS_IGNORE_PLC + case DLMS_INTERFACE_TYPE_PLC: + ret = dlms_getPlcData(settings, reply, data); + break; + case DLMS_INTERFACE_TYPE_PLC_HDLC: + ret = dlms_getPlcHdlcData(settings, reply, data, &frame); +#endif //DLMS_IGNORE_PLC + break; + default: + // Invalid Interface type. + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + if (ret != 0) + { + return ret; + } + if (*isNotify && notify != NULL) + { + if (!notify->complete) + { + // If all data is not read yet. + return 0; + } + data = notify; + } + else if (!data->complete) + { + // If all data is not read yet. + return 0; + } + if (settings->interfaceType != DLMS_INTERFACE_TYPE_PLC_HDLC) + { + if ((ret = dlms_getDataFromFrame(reply, data, dlms_useHdlc(settings->interfaceType))) != 0) + { + return ret; + } + } + // If keepalive or get next frame request. + if (((frame != 0x13 && frame != 0x3) || data->moreData != DLMS_DATA_REQUEST_TYPES_NONE) && (frame & 0x1) != 0) + { + if (dlms_useHdlc(settings->interfaceType) && data->data.size != 0) + { + if (reply->position != reply->size) + { + reply->position += 3; + } + } + if (data->command == DLMS_COMMAND_REJECTED) + { + return DLMS_ERROR_CODE_REJECTED; + } + return DLMS_ERROR_CODE_OK; + } + ret = dlms_getPdu(settings, data, first); + if (ret == 0 && notify != NULL && !isNotify) + { + //Check command to make sure it's not notify message. + switch (data->command) + { + case DLMS_COMMAND_DATA_NOTIFICATION: + case DLMS_COMMAND_GLO_EVENT_NOTIFICATION_REQUEST: + case DLMS_COMMAND_INFORMATION_REPORT: + case DLMS_COMMAND_EVENT_NOTIFICATION: + case DLMS_COMMAND_DED_EVENT_NOTIFICATION: + *isNotify = 1; + notify->complete = data->complete; + notify->moreData = data->moreData; + notify->command = data->command; + data->command = DLMS_COMMAND_NONE; + notify->time = data->time; +#ifdef DLMS_USE_EPOCH_TIME + data->time = 0; +#else + memset(&data->time, 0, sizeof(data->time)); +#endif // DLMS_USE_EPOCH_TIME + bb_set2(¬ify->data, &data->data, data->data.position, bb_available(&data->data)); + bb_clear(&data->data); + notify->dataValue = data->dataValue; + data->dataValue.vt = DLMS_DATA_TYPE_NONE; + break; + default: + break; + } + } + return ret; +} + +int dlms_generateChallenge( + gxByteBuffer* challenge) +{ + // Random challenge is 8 to 64 bytes. + // Texas Instruments accepts only 16 byte int32_t challenge. + // For this reason challenge size is 16 bytes at the moment. + int ret = 0, pos, len = 16;//hlp_rand() % 58 + 8; + bb_clear(challenge); + for (pos = 0; pos != len; ++pos) + { + if ((ret = bb_setUInt8(challenge, hlp_rand())) != 0) + { + break; + } + } + return ret; +} + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME +int dlms_getActionInfo( + DLMS_OBJECT_TYPE objectType, + unsigned char* value, + unsigned char* count) +{ + switch (objectType) + { + case DLMS_OBJECT_TYPE_DATA: + case DLMS_OBJECT_TYPE_ACTION_SCHEDULE: + case DLMS_OBJECT_TYPE_AUTO_ANSWER: + case DLMS_OBJECT_TYPE_AUTO_CONNECT: + case DLMS_OBJECT_TYPE_MAC_ADDRESS_SETUP: + case DLMS_OBJECT_TYPE_GPRS_SETUP: + case DLMS_OBJECT_TYPE_IEC_HDLC_SETUP: + case DLMS_OBJECT_TYPE_IEC_LOCAL_PORT_SETUP: + case DLMS_OBJECT_TYPE_IEC_TWISTED_PAIR_SETUP: + case DLMS_OBJECT_TYPE_MODEM_CONFIGURATION: + case DLMS_OBJECT_TYPE_PPP_SETUP: + case DLMS_OBJECT_TYPE_REGISTER_MONITOR: + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_STARTUP: + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_JOIN: + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_APS_FRAGMENTATION: + case DLMS_OBJECT_TYPE_ZIG_BEE_NETWORK_CONTROL: + case DLMS_OBJECT_TYPE_SCHEDULE: + case DLMS_OBJECT_TYPE_SMTP_SETUP: + case DLMS_OBJECT_TYPE_STATUS_MAPPING: + case DLMS_OBJECT_TYPE_TCP_UDP_SETUP: + case DLMS_OBJECT_TYPE_UTILITY_TABLES: + *value = 0; + *count = 0; + break; + case DLMS_OBJECT_TYPE_MBUS_DIAGNOSTIC: + *value = 48; + *count = 1; + break; + case DLMS_OBJECT_TYPE_IMAGE_TRANSFER: + *value = 0x40; + *count = 4; + break; + case DLMS_OBJECT_TYPE_ACTIVITY_CALENDAR: + *value = 0x50; + *count = 1; + break; + case DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME: + *value = 0x60; + *count = 4; + break; + case DLMS_OBJECT_TYPE_ASSOCIATION_SHORT_NAME: + *value = 0x20; + *count = 8; + break; + case DLMS_OBJECT_TYPE_CLOCK: + *value = 0x60; + *count = 6; + break; + case DLMS_OBJECT_TYPE_DEMAND_REGISTER: + *value = 0x48; + *count = 2; + break; + case DLMS_OBJECT_TYPE_EXTENDED_REGISTER: + *value = 0x38; + *count = 1; + break; + case DLMS_OBJECT_TYPE_IP4_SETUP: + *value = 0x60; + *count = 3; + break; + case DLMS_OBJECT_TYPE_MBUS_SLAVE_PORT_SETUP: + *value = 0x60; + *count = 8; + break; + case DLMS_OBJECT_TYPE_PROFILE_GENERIC: + *value = 0x58; + *count = 4; + break; + case DLMS_OBJECT_TYPE_REGISTER: + *value = 0x28; + *count = 1; + break; + case DLMS_OBJECT_TYPE_REGISTER_ACTIVATION: + *value = 0x30; + *count = 3; + break; + case DLMS_OBJECT_TYPE_REGISTER_TABLE: + *value = 0x28; + *count = 2; + break; + case DLMS_OBJECT_TYPE_SAP_ASSIGNMENT: + case DLMS_OBJECT_TYPE_SCRIPT_TABLE: + *value = 0x20; + *count = 1; + break; + case DLMS_OBJECT_TYPE_SPECIAL_DAYS_TABLE: + *value = 0x10; + *count = 2; + break; + case DLMS_OBJECT_TYPE_DISCONNECT_CONTROL: + *value = 0x20; + *count = 2; + break; + case DLMS_OBJECT_TYPE_PUSH_SETUP: + *value = 0x38; + *count = 1; + break; + default: + *count = *value = 0; + break; + } + return DLMS_ERROR_CODE_OK; +} +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + +int dlms_secure( + dlmsSettings* settings, + int32_t ic, + gxByteBuffer* data, + gxByteBuffer* secret, + gxByteBuffer* reply) +{ + int ret = 0; + gxByteBuffer challenge; + bb_clear(reply); +#ifdef DLMS_IGNORE_MALLOC + bb_attach(&challenge, pduAttributes, 0, sizeof(pduAttributes)); +#else + BYTE_BUFFER_INIT(&challenge); +#endif //DLMS_IGNORE_MALLOC + if (settings->authentication == DLMS_AUTHENTICATION_HIGH) + { +#ifndef DLMS_IGNORE_AES + unsigned char tmp[16]; + gxByteBuffer s; + uint16_t len = (uint16_t)data->size; + bb_attach(&s, tmp, 0, sizeof(tmp)); + if (len % 16 != 0) + { + len += (16 - (data->size % 16)); + } + if (secret->size > data->size) + { + len = (uint16_t)secret->size; + if (len % 16 != 0) + { + len += (16 - (secret->size % 16)); + } + } + if ((ret = bb_set(&s, secret->data, secret->size)) == 0 && + (ret = bb_zero(&s, s.size, len - s.size)) == 0 && + (ret = bb_set(&challenge, data->data, data->size)) == 0 && + (ret = bb_zero(&challenge, challenge.size, len - challenge.size)) == 0 && + (ret = bb_capacity(reply, challenge.size)) == 0) + { + gxaes_ecb_encrypt(challenge.data, s.data, reply->data, s.size); + } + reply->size = s.size; +#ifndef DLMS_IGNORE_MALLOC + bb_clear(&s); + bb_clear(&challenge); +#endif //DLMS_IGNORE_MALLOC + return ret; +#else + return DLMS_ERROR_CODE_NOT_IMPLEMENTED; +#endif //DLMS_IGNORE_AES + } + // Get server Challenge. + // Get shared secret +#ifndef DLMS_IGNORE_HIGH_GMAC + if (settings->authentication != DLMS_AUTHENTICATION_HIGH_GMAC) +#endif //DLMS_IGNORE_HIGH_GMAC + { + if (settings->authentication == DLMS_AUTHENTICATION_HIGH_SHA256) + { + //If SHA256 is not used. +#ifdef DLMS_IGNORE_HIGH_SHA256 + return DLMS_ERROR_CODE_NOT_IMPLEMENTED; +#else +#ifndef DLMS_IGNORE_HIGH_GMAC +#ifdef DLMS_IGNORE_MALLOC + if ((ret = bb_set(&challenge, secret->data, secret->size)) != 0 || + (ret = bb_set(&challenge, settings->cipher.systemTitle, 8)) != 0 || + (ret = bb_set(&challenge, settings->sourceSystemTitle, 8)) != 0) + { + return ret; + } +#else + if ((ret = bb_set(&challenge, secret->data, secret->size)) != 0 || + (ret = bb_set(&challenge, settings->cipher.systemTitle.data, settings->cipher.systemTitle.size)) != 0 || + (ret = bb_set(&challenge, settings->sourceSystemTitle, 8)) != 0) + { + return ret; + } +#endif //DLMS_IGNORE_MALLOC + if (settings->server) + { + if ((ret = bb_set(&challenge, settings->ctoSChallenge.data, settings->ctoSChallenge.size)) != 0 || + (ret = bb_set(&challenge, settings->stoCChallenge.data, settings->stoCChallenge.size)) != 0) + { + return ret; + } + } + else + { + if ((ret = bb_set(&challenge, settings->stoCChallenge.data, settings->stoCChallenge.size)) != 0 || + (ret = bb_set(&challenge, settings->ctoSChallenge.data, settings->ctoSChallenge.size)) != 0) + { + return ret; + } + } +#endif //DLMS_IGNORE_HIGH_GMAC +#endif //DLMS_IGNORE_HIGH_SHA256 + } + else + { + if ((ret = bb_set(&challenge, data->data, data->size)) != 0 || + (ret = bb_set(&challenge, secret->data, secret->size)) != 0) + { + return ret; + } + } + } + if (settings->authentication == DLMS_AUTHENTICATION_HIGH_MD5) + { + //If MD5 is not used. +#ifdef DLMS_IGNORE_HIGH_MD5 + return DLMS_ERROR_CODE_NOT_IMPLEMENTED; +#else + ret = gxmd5_encrypt(&challenge, reply); + bb_clear(&challenge); + return ret; +#endif //DLMS_IGNORE_HIGH_MD5 + } + else if (settings->authentication == DLMS_AUTHENTICATION_HIGH_SHA1) + { + //If SHA1 is not used. +#ifdef DLMS_IGNORE_HIGH_SHA1 + return DLMS_ERROR_CODE_NOT_IMPLEMENTED; +#else + ret = gxsha1_encrypt(&challenge, reply); + bb_clear(&challenge); + return ret; +#endif //DLMS_IGNORE_HIGH_SHA1 + } + else if (settings->authentication == DLMS_AUTHENTICATION_HIGH_SHA256) + { + //If SHA256 is not used. +#ifdef DLMS_IGNORE_HIGH_SHA256 + return DLMS_ERROR_CODE_NOT_IMPLEMENTED; +#else + ret = gxsha256_encrypt(&challenge, reply); + bb_clear(&challenge); + return ret; +#endif //DLMS_IGNORE_HIGH_SHA256 + } +#ifndef DLMS_IGNORE_HIGH_GMAC + else if (settings->authentication == DLMS_AUTHENTICATION_HIGH_GMAC) + { + //If GMAC is not used. +#ifdef DLMS_IGNORE_HIGH_GMAC + bb_clear(&challenge); + return DLMS_ERROR_CODE_NOT_IMPLEMENTED; +#else + ret = cip_encrypt( + &settings->cipher, + DLMS_SECURITY_AUTHENTICATION, + DLMS_COUNT_TYPE_TAG, + ic, + 0, + secret->data, +#ifdef DLMS_IGNORE_MALLOC + settings->cipher.blockCipherKey, +#else + & settings->cipher.blockCipherKey, +#endif //DLMS_IGNORE_MALLOC + data); + if (ret == 0) + { + if ((ret = bb_setUInt8(reply, DLMS_SECURITY_AUTHENTICATION | settings->cipher.suite)) != 0 || + (ret = bb_setUInt32(reply, ic)) != 0 || + (ret = bb_set2(reply, data, data->size - 12, 12)) != 0) + { + + } + } + bb_clear(&challenge); +#endif //DLMS_IGNORE_HIGH_GMAC + } +#endif //DLMS_IGNORE_HIGH_GMAC + return ret; +} + +int dlms_parseSnrmUaResponse( + dlmsSettings* settings, + gxByteBuffer* data) +{ + uint32_t value; + unsigned char ch, id, len; + uint16_t tmp; + int ret; + //If default settings are used. + if (data->size - data->position == 0) + { + return 0; + } + // Skip FromatID + if ((ret = bb_getUInt8(data, &ch)) != 0) + { + return ret; + } + // Skip Group ID. + if ((ret = bb_getUInt8(data, &ch)) != 0) + { + return ret; + } + // Skip Group len + if ((ret = bb_getUInt8(data, &ch)) != 0) + { + return ret; + } + while (data->position < data->size) + { + if ((ret = bb_getUInt8(data, &id)) != 0 || + (ret = bb_getUInt8(data, &len)) != 0) + { + return ret; + } + switch (len) + { + case 1: + ret = bb_getUInt8(data, &ch); + value = ch; + break; + case 2: + ret = bb_getUInt16(data, &tmp); + value = tmp; + break; + case 4: + ret = bb_getUInt32(data, &value); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + // RX / TX are delivered from the partner's point of view => + // reversed to ours + switch (id) + { + case HDLC_INFO_MAX_INFO_TX: + if (value < settings->maxInfoRX) + { + settings->maxInfoRX = (uint16_t)value; + } + break; + case HDLC_INFO_MAX_INFO_RX: + if (value < settings->maxInfoTX) + { + settings->maxInfoTX = (uint16_t)value; + } + break; + case HDLC_INFO_WINDOW_SIZE_TX: + if (value < settings->windowSizeRX) + { + settings->windowSizeRX = (unsigned char)value; + } + break; + case HDLC_INFO_WINDOW_SIZE_RX: + if (value < settings->windowSizeTX) + { + settings->windowSizeTX = (unsigned char)value; + } + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + } + return ret; +} + +int dlms_appendHdlcParameter(gxByteBuffer* data, uint16_t value) +{ + if (value < 0x100) + { + bb_setUInt8(data, 1); + bb_setUInt8(data, (unsigned char)value); + } + else + { + bb_setUInt8(data, 2); + bb_setUInt16(data, value); + } + return 0; +} + +int dlms_isPduFull(dlmsSettings* settings, gxByteBuffer* data, uint16_t* size) +{ + unsigned char ret; + if (bb_isAttached(data)) + { + uint16_t len = 0; + if (size != NULL) + { + if (*size == 0) + { + *size = (uint16_t)data->size; + } + len = *size; + } +#ifndef DLMS_IGNORE_HIGH_GMAC + if (settings->cipher.security != DLMS_SECURITY_NONE) + { + len += 20 + CIPHERING_HEADER_SIZE + (uint16_t)data->size; + } + else +#endif //DLMS_IGNORE_HIGH_GMAC + { + len += 20 + (uint16_t)data->size; + } + ret = settings->maxPduSize < len; + } + else + { + ret = 0; + } + return ret; +} diff --git a/components/xt211/dlms.h b/components/xt211/dlms.h new file mode 100644 index 0000000..d5b9b22 --- /dev/null +++ b/components/xt211/dlms.h @@ -0,0 +1,314 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef DLMS_H +#define DLMS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "errorcodes.h" +#include "bytebuffer.h" +#include "message.h" +#include "helpers.h" +#include "dlmssettings.h" +#include "apdu.h" +#include "variant.h" +#include "objectarray.h" +#include "replydata.h" +#include "datainfo.h" +#include "parameters.h" + + //Makes sure that the basic settings are set. + int dlms_checkInit( + dlmsSettings* settings); + +#ifndef DLMS_IGNORE_HDLC + //Is HDLC framing used. + unsigned char dlms_useHdlc(DLMS_INTERFACE_TYPE type); + + /** + * Get PDU as HDLC frame. + */ + int dlms_getHdlcFrame( + dlmsSettings* settings, + int frame, + gxByteBuffer* data, + gxByteBuffer* reply); + +#endif //DLMS_IGNORE_HDLC + +#ifndef DLMS_IGNORE_PLC + int dlms_getMacHdlcFrame( + dlmsSettings* settings, + unsigned char frame, + unsigned char creditFields, + gxByteBuffer* data, + gxByteBuffer* reply); +#endif //DLMS_IGNORE_HDLC + +#ifndef DLMS_IGNORE_WRAPPER + /** + * Split DLMS PDU to wrapper frames. + * + * @param settings + * DLMS settings. + * @param data + * Wrapped data. + * @return Wrapper frames. + */ + int dlms_getWrapperFrame( + dlmsSettings* settings, + DLMS_COMMAND command, + gxByteBuffer* data, + gxByteBuffer* reply); +#endif //DLMS_IGNORE_WRAPPER + +#ifndef DLMS_IGNORE_HIGH_GMAC + unsigned char dlms_useDedicatedKey(dlmsSettings* settings); +#endif //DLMS_IGNORE_HIGH_GMAC + + //Set data from DLMS Varuant to DLMS byte stream. + int dlms_setData( + gxByteBuffer* data, + DLMS_DATA_TYPE type, + dlmsVARIANT *value); + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + //Set data from DLMS Varuant to DLMS byte stream. + int dlms_setData2( + unsigned char *buff, + uint32_t length, + DLMS_DATA_TYPE type, + dlmsVARIANT *value); +#else + //Set data from DLMS Varuant to DLMS byte stream. + int dlms_setData2( + unsigned char *buff, + uint16_t length, + DLMS_DATA_TYPE type, + dlmsVARIANT *value); +#endif + + int dlms_receiverReady( + dlmsSettings* settings, + DLMS_DATA_REQUEST_TYPES type, + gxByteBuffer* reply); + + /** + * Get next logical name PDU. + * + * @param p + * LN parameters. + * @param reply + * Generated message. + */ + int dlms_getLNPdu( + gxLNParameters* p, + gxByteBuffer* reply); + + //Get value from DLMS byte stream. + int dlms_getData( + gxByteBuffer* data, + gxDataInfo* info, + dlmsVARIANT *value); + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + /** + * Get next short name PDU. + * @param p SN parameters. + * @param reply Generated message. + */ + int dlms_getSNPdu( + gxSNParameters* p, + gxByteBuffer* reply); + +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + +#ifndef DLMS_IGNORE_HDLC + //Return DLMS_ERROR_CODE_FALSE if LLC bytes are not included. + int dlms_checkLLCBytes( + dlmsSettings* settings, + gxByteBuffer* data); + + int dlms_getHdlcData( + unsigned char server, + dlmsSettings* settings, + gxByteBuffer* reply, + gxReplyData* data, + unsigned char* frame, + unsigned char preEstablished, + unsigned char first); +#endif //DLMS_IGNORE_HDLC + +#ifndef DLMS_IGNORE_WRAPPER + int dlms_getTcpData( + dlmsSettings* settings, + gxByteBuffer* buff, + gxReplyData* data, + gxReplyData* notify, + unsigned char* isNotify); +#endif //DLMS_IGNORE_WRAPPER + + int dlms_changeType2( + dlmsVARIANT *value, + DLMS_DATA_TYPE type, + dlmsVARIANT *newValue); + + int dlms_changeType( + gxByteBuffer* value, + DLMS_DATA_TYPE type, + dlmsVARIANT *newValue); + + + int dlms_getPdu( + dlmsSettings* settings, + gxReplyData* data, + unsigned char first); + + int dlms_getData2( + dlmsSettings* settings, + gxByteBuffer* reply, + gxReplyData* data, + unsigned char first); + + int dlms_getData3( + dlmsSettings* settings, + gxByteBuffer* reply, + gxReplyData* data, + gxReplyData* notify, + unsigned char first, + unsigned char* isNotify); + + /** + * Get all Logical name messages. Client uses this to generate messages. + * + * @param p + * LN settings. + * @param reply + * Generated messages. + * @return Status code. + */ + int dlms_getLnMessages( + gxLNParameters *p, + message* reply); + +#ifndef DLMS_IGNORE_HDLC + /** + * Add LLC bytes to generated message. + * + * @param settings + * DLMS settings. + * @param data + * Data where bytes are added. + */ + int dlms_addLLCBytes( + dlmsSettings* settings, + gxByteBuffer* data); +#endif //DLMS_IGNORE_HDLC + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + + /** + * Get all Short Name messages. Client uses this to generate messages. + * + * @param p + * DLMS SN parameters. + * @param reply + * Generated messages. + * @return Status code. + */ + int dlms_getSnMessages( + gxSNParameters *p, + message* reply); + + int dlms_getActionInfo( + DLMS_OBJECT_TYPE objectType, + unsigned char *value, + unsigned char *count); +#endif // DLMS_IGNORE_ASSOCIATION_SHORT_NAME + + int dlms_generateChallenge( + gxByteBuffer* challenge); + + /** + * Chipher text. + * + * @param auth + * Authentication level. + * @param data + * Text to chipher. + * @param secret + * Secret. + * @return Chiphered text. + */ + int dlms_secure( + dlmsSettings* settings, + int32_t ic, + gxByteBuffer* data, + gxByteBuffer* secret, + gxByteBuffer* reply); + + int dlms_parseSnrmUaResponse( + dlmsSettings* settings, + gxByteBuffer* data); + + // Add HDLC parameter. + int dlms_appendHdlcParameter( + gxByteBuffer* data, + uint16_t value); + + //Is it possible to add more data to the PDU before it's full. + int dlms_isPduFull( + dlmsSettings* settings, + gxByteBuffer* data, + uint16_t* size); + + int dlms_getMacFrame( + dlmsSettings* settings, + unsigned char frame, + unsigned char creditFields, + gxByteBuffer* data, + gxByteBuffer* reply); + + /** + * This function returns true, if pre-established connection is used. + */ + unsigned char dlms_usePreEstablishedConnection(dlmsSettings* settings); + + +#ifdef __cplusplus +} +#endif + +#endif //DLMS_H diff --git a/components/xt211/dlmsSettings.c b/components/xt211/dlmsSettings.c new file mode 100644 index 0000000..00eb678 --- /dev/null +++ b/components/xt211/dlmsSettings.c @@ -0,0 +1,478 @@ +// +// -------------------------------------------------------------------------- +// 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" +#include "dlmssettings.h" +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) +#include +#include +#endif + +// Server sender frame sequence starting number. +static const unsigned char SERVER_START_SENDER_FRAME_SEQUENCE = 0x1E; +// Server receiver frame sequence starting number. +static const unsigned char SERVER_START_RECEIVER_FRAME_SEQUENCE = 0xFE; +// Client sender frame sequence starting number. +static const unsigned char CLIENT_START_SENDER_FRAME_SEQUENCE = 0xFE; +// Client receiver frame sequence starting number. +static const unsigned char CLIENT_START_RCEIVER_FRAME_SEQUENCE = 0xE; + +//Initialize server. +void svr_init( + dlmsServerSettings* settings, + unsigned char useLogicalNameReferencing, + DLMS_INTERFACE_TYPE interfaceType, + uint16_t frameSize, + uint16_t pduSize, + unsigned char* frameBuffer, + uint16_t frameBufferSize, + unsigned char* pduBuffer, + uint16_t pduBufferSize) +{ + cl_init(&settings->base, useLogicalNameReferencing, 0, 0, DLMS_AUTHENTICATION_NONE, NULL, interfaceType); + settings->base.proposedConformance |= DLMS_CONFORMANCE_GENERAL_PROTECTION; + bb_attach(&settings->receivedData, frameBuffer, 0, frameBufferSize); + reply_init(&settings->info); + bb_attach(&settings->info.data, pduBuffer, 0, pduBufferSize); + settings->base.maxInfoRX = settings->base.maxInfoTX = frameSize; + settings->base.maxServerPDUSize = pduSize; + settings->base.server = 1; + settings->initialized = 0; + trans_init(&settings->transaction); +#ifndef DLMS_IGNORE_TCP_UDP_SETUP + settings->wrapper = NULL; +#endif // DLMS_IGNORE_TCP_UDP_SETUP +#ifndef DLMS_IGNORE_IEC_HDLC_SETUP + settings->hdlc = NULL; +#endif //DLMS_IGNORE_IEC_HDLC_SETUP +#ifndef DLMS_IGNORE_IEC_LOCAL_PORT_SETUP + settings->localPortSetup = NULL; +#endif //DLMS_IGNORE_IEC_LOCAL_PORT_SETUP +#ifndef DLMS_IGNORE_CLOCK + settings->defaultClock = NULL; +#endif //DLMS_IGNORE_CLOCK + settings->dataReceived = 0; + settings->frameReceived = 0; + resetFrameSequence(&settings->base); + settings->pushClientAddress = 0; +} + +//Initialize client. +void cl_init( + dlmsSettings* settings, + unsigned char useLogicalNameReferencing, + uint16_t clientAddress, + uint32_t serverAddress, + DLMS_AUTHENTICATION authentication, + const char* password, + DLMS_INTERFACE_TYPE interfaceType) +{ + settings->autoIncreaseInvokeID = 0; + settings->qualityOfService = 0; + settings->protocolVersion = 0; +#ifndef DLMS_IGNORE_MALLOC + settings->preEstablishedSystemTitle = NULL; +#else + memset(settings->preEstablishedSystemTitle, 0, 8); +#endif //DLMS_IGNORE_MALLOC + settings->blockIndex = 1; + settings->clientAddress = clientAddress; + settings->serverAddress = serverAddress; + settings->dlmsVersionNumber = 6; + settings->useLogicalNameReferencing = useLogicalNameReferencing; + settings->interfaceType = interfaceType; + settings->authentication = authentication; + BYTE_BUFFER_INIT(&settings->password); + bb_addString(&settings->password, password); + memset(settings->sourceSystemTitle, 0, sizeof(settings->sourceSystemTitle)); +#ifdef DLMS_IGNORE_MALLOC + memset(settings->kek, 0, sizeof(settings->kek)); +#else + BYTE_BUFFER_INIT(&settings->kek); +#endif //DLMS_IGNORE_MALLOC + settings->maxServerPDUSize = 1024; + settings->maxPduSize = 0xFFFF; + settings->server = 0; + if (useLogicalNameReferencing) + { + settings->proposedConformance = (DLMS_CONFORMANCE) + (DLMS_CONFORMANCE_BLOCK_TRANSFER_WITH_ACTION | + DLMS_CONFORMANCE_BLOCK_TRANSFER_WITH_SET_OR_WRITE | + DLMS_CONFORMANCE_BLOCK_TRANSFER_WITH_GET_OR_READ | + DLMS_CONFORMANCE_SET | + DLMS_CONFORMANCE_SELECTIVE_ACCESS | + DLMS_CONFORMANCE_ACTION | + DLMS_CONFORMANCE_MULTIPLE_REFERENCES | + DLMS_CONFORMANCE_GET | + DLMS_CONFORMANCE_GENERAL_PROTECTION); + } + else + { + settings->proposedConformance = (DLMS_CONFORMANCE)(DLMS_CONFORMANCE_INFORMATION_REPORT | + DLMS_CONFORMANCE_READ | DLMS_CONFORMANCE_UN_CONFIRMED_WRITE | + DLMS_CONFORMANCE_WRITE | DLMS_CONFORMANCE_PARAMETERIZED_ACCESS | + DLMS_CONFORMANCE_MULTIPLE_REFERENCES); + } + settings->longInvokeID = 0; + settings->maxInfoTX = settings->maxInfoRX = 0x80; + settings->windowSizeTX = settings->windowSizeRX = 1; + settings->connected = DLMS_CONNECTION_STATE_NONE; + oa_init(&settings->objects); + settings->connected = DLMS_CONNECTION_STATE_NONE; + settings->customChallenges = 0; + settings->invokeID = 1; + BYTE_BUFFER_INIT(&settings->ctoSChallenge); + BYTE_BUFFER_INIT(&settings->stoCChallenge); + settings->priority = DLMS_PRIORITY_HIGH; + settings->serviceClass = DLMS_SERVICE_CLASS_CONFIRMED; +#ifndef DLMS_IGNORE_HIGH_GMAC + cip_init(&settings->cipher); +#endif //DLMS_IGNORE_HIGH_GMAC + settings->userId = -1; + resetFrameSequence(settings); + settings->serializedPdu = NULL; + oa_init(&settings->releasedObjects); + settings->expectedSecurityPolicy = 0xFF; + settings->expectedSecuritySuite = 0xFF; + settings->expectedInvocationCounter = NULL; + settings->expectedClientSystemTitle = NULL; +#ifndef DLMS_IGNORE_PLC + plc_reset(settings); +#endif //DLMS_IGNORE_PLC + oa_init(&settings->internalObjects); +} + +void cl_clear( + dlmsSettings* settings) +{ + settings->protocolVersion = 0; +#ifndef DLMS_IGNORE_MALLOC + if (settings->preEstablishedSystemTitle != NULL) + { + bb_clear(settings->preEstablishedSystemTitle); + gxfree(settings->preEstablishedSystemTitle); + settings->preEstablishedSystemTitle = NULL; + } +#else + memset(settings->preEstablishedSystemTitle, 0, 8); +#endif //DLMS_IGNORE_MALLOC + memset(settings->sourceSystemTitle, 0, sizeof(settings->sourceSystemTitle)); + bb_clear(&settings->password); +#ifdef DLMS_IGNORE_MALLOC + memset(settings->kek, 0, sizeof(settings->kek)); +#else + bb_clear(&settings->kek); +#endif //DLMS_IGNORE_MALLOC + oa_clear(&settings->objects, !settings->server); + settings->connected = DLMS_CONNECTION_STATE_NONE; + settings->customChallenges = 0; + settings->invokeID = 1; + bb_clear(&settings->ctoSChallenge); + bb_clear(&settings->stoCChallenge); + settings->priority = DLMS_PRIORITY_HIGH; + settings->serviceClass = DLMS_SERVICE_CLASS_CONFIRMED; +#ifndef DLMS_IGNORE_HIGH_GMAC + cip_clear(&settings->cipher); +#endif //DLMS_IGNORE_HIGH_GMAC + settings->maxPduSize = 0xFFFF; + settings->userId = -1; + oa_clear(&settings->releasedObjects, 1); + oa_clear(&settings->internalObjects, 0); + resetFrameSequence(settings); + settings->expectedInvocationCounter = NULL; +} + +void svr_clear( + dlmsServerSettings* settings) +{ + cl_clear(&settings->base); +} + +#ifndef DLMS_IGNORE_PLC +void plc_reset( + dlmsSettings* settings) +{ + settings->plcSettings.initialCredit = 7; + settings->plcSettings.currentCredit = 7; + settings->plcSettings.deltaCredit = 0; + //New device addresses are used. + if (settings->interfaceType == DLMS_INTERFACE_TYPE_PLC) + { + if (settings->server) + { + settings->plcSettings.macSourceAddress = DLMS_PLC_SOURCE_ADDRESS_NEW; + settings->plcSettings.macDestinationAddress = DLMS_PLC_SOURCE_ADDRESS_INITIATOR; + } + else + { + settings->plcSettings.macSourceAddress = DLMS_PLC_SOURCE_ADDRESS_INITIATOR; + settings->plcSettings.macDestinationAddress = DLMS_PLC_DESTINATION_ADDRESS_ALL_PHYSICAL; + } + settings->plcSettings.allowedTimeSlots = 10; + } + else + { + if (settings->server) + { + settings->plcSettings.macSourceAddress = DLMS_PLC_SOURCE_ADDRESS_NEW; + settings->plcSettings.macDestinationAddress = DLMS_PLC_HDLC_SOURCE_ADDRESS_INITIATOR; + } + else + { + settings->plcSettings.macSourceAddress = DLMS_PLC_HDLC_SOURCE_ADDRESS_INITIATOR; + settings->plcSettings.macDestinationAddress = DLMS_PLC_DESTINATION_ADDRESS_ALL_PHYSICAL; + } + settings->plcSettings.allowedTimeSlots = 0x14; + } + settings->plcSettings.responseProbability = 100; +} +#endif //DLMS_IGNORE_PLC + +void resetBlockIndex( + dlmsSettings* settings) +{ + settings->blockIndex = 1; +} + +void resetFrameSequence( + dlmsSettings* settings) +{ + if (settings->server) + { + settings->senderFrame = SERVER_START_SENDER_FRAME_SEQUENCE; + settings->receiverFrame = SERVER_START_RECEIVER_FRAME_SEQUENCE; + } + else + { + settings->senderFrame = CLIENT_START_SENDER_FRAME_SEQUENCE; + settings->receiverFrame = CLIENT_START_RCEIVER_FRAME_SEQUENCE; + } +} + +unsigned char increaseReceiverSequence( + unsigned char value) +{ + return ((value + 0x20) | 0x10 | (value & 0xE)); +} + +// Increase sender sequence. +// +// @param value +// Frame value. +// Increased sender frame sequence. +unsigned char increaseSendSequence( + unsigned char value) +{ + return (unsigned char)((value & 0xF0) | ((value + 0x2) & 0xE)); +} + +#ifndef DLMS_IGNORE_HDLC_CHECK +unsigned char checkFrame( + dlmsSettings* settings, + unsigned char frame) +{ + //If notify + if (frame == 0x13) + { + return 1; + } + // If U frame. + if ((frame & 0x3) == 3) + { + if (frame == 0x93) + { + unsigned char isEcho = !settings->server && frame == 0x93 && + (settings->senderFrame == 0x10 || settings->senderFrame == 0xfe) && + settings->receiverFrame == 0xE; + resetFrameSequence(settings); + return !isEcho; + } + if (frame == 0x73 && !settings->server) + { + return settings->senderFrame == 0xFE && settings->receiverFrame == 0xE; + } + return 1; + } + // If S -frame + if ((frame & 0x1) == 1) + { + //If echo. + if (frame == (settings->senderFrame & 0xF1)) + { + return 0; + } + settings->receiverFrame = increaseReceiverSequence(settings->receiverFrame); + return 1; + } + //Handle I-frame. + unsigned char expected; + if ((settings->senderFrame & 0x1) == 0) + { + expected = increaseReceiverSequence(increaseSendSequence(settings->receiverFrame)); + if (frame == expected) + { + settings->receiverFrame = frame; + return 1; + } + //If the final bit is not set. + if (frame == (expected & ~0x10) && settings->windowSizeRX != 1) + { + settings->receiverFrame = frame; + return 1; + } + //If Final bit is not set for the previous message. + if ((settings->receiverFrame & 0x10) == 0 && settings->windowSizeRX != 1) + { + expected = (unsigned char)(0x10 | increaseSendSequence(settings->receiverFrame)); + if (frame == expected) + { + settings->receiverFrame = frame; + return 1; + } + //If the final bit is not set. + if (frame == (expected & ~0x10)) + { + settings->receiverFrame = frame; + return 1; + } + } + } + //If answer for RR. + else + { + expected = increaseSendSequence(settings->receiverFrame); + if (frame == expected) + { + settings->receiverFrame = frame; + return 1; + } + if (frame == (expected & ~0x10)) + { + settings->receiverFrame = frame; + return 1; + } + if (settings->windowSizeRX != 1) + { + //If HDLC window size is bigger than one. + if (frame == (expected | 0x10)) + { + settings->receiverFrame = frame; + return 1; + } + } + } + //Pre-established connections needs this. + if ((!settings->server && settings->receiverFrame == SERVER_START_RECEIVER_FRAME_SEQUENCE) || + (settings->server && settings->receiverFrame == CLIENT_START_RCEIVER_FRAME_SEQUENCE)) + { + settings->receiverFrame = frame; + return 1; + } +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__)//If Windows or Linux + printf("Invalid frame %X. Expected %X.\r\n", frame, expected); +#endif + return 0; +} +#endif //DLMS_IGNORE_HDLC_CHECK + +unsigned char getNextSend( + dlmsSettings* settings, unsigned char first) +{ + if (first) + { + settings->senderFrame = increaseReceiverSequence(increaseSendSequence((unsigned char)settings->senderFrame)); + } + else + { + settings->senderFrame = increaseSendSequence((unsigned char)settings->senderFrame); + } + return (unsigned char)settings->senderFrame; +} + +unsigned char getReceiverReady( + dlmsSettings* settings) +{ + settings->senderFrame = increaseReceiverSequence((unsigned char)(settings->senderFrame | 1)); + return (unsigned char)(settings->senderFrame & 0xF1); +} + +unsigned char getKeepAlive( + dlmsSettings* settings) +{ + settings->senderFrame = (unsigned char)(settings->senderFrame | 1); + return (unsigned char)(settings->senderFrame & 0xF1); +} + +#ifndef DLMS_IGNORE_HIGH_GMAC +unsigned char isCiphered( + ciphering* cipher) +{ + return cipher->security != DLMS_SECURITY_NONE; +} +#endif //DLMS_IGNORE_HIGH_GMAC + +void trans_init(gxLongTransaction* trans) +{ + trans->command = DLMS_COMMAND_NONE; +#ifndef DLMS_IGNORE_MALLOC + BYTE_BUFFER_INIT(&trans->data); +#endif //DLMS_IGNORE_MALLOC + vec_init(&trans->targets); +} + +void trans_clear(gxLongTransaction* trans) +{ + trans->command = DLMS_COMMAND_NONE; +#ifndef DLMS_IGNORE_MALLOC + bb_clear(&trans->data); +#endif //DLMS_IGNORE_MALLOC + vec_clear(&trans->targets); +} + +void updateInvokeId( + dlmsServerSettings* settings, + unsigned char value) +{ + if ((value & 0x80) != 0) { + settings->base.priority = DLMS_PRIORITY_HIGH; + } + else { + settings->base.priority = DLMS_PRIORITY_NORMAL; + } + if ((value & 0x40) != 0) { + settings->base.serviceClass = DLMS_SERVICE_CLASS_CONFIRMED; + } + else { + settings->base.serviceClass = DLMS_SERVICE_CLASS_UN_CONFIRMED; + } + settings->base.invokeID = (unsigned char)(value & 0xF); +} diff --git a/components/xt211/dlmssettings.h b/components/xt211/dlmssettings.h new file mode 100644 index 0000000..04370ec --- /dev/null +++ b/components/xt211/dlmssettings.h @@ -0,0 +1,424 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef DLMS_SETTINGS_H +#define DLMS_SETTINGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "enums.h" +#include "variant.h" +#include "objectarray.h" +#include "message.h" +#include "gxvalueeventargs.h" +#include "replydata.h" +#include "ciphering.h" + +#ifndef DLMS_IGNORE_PLC + + typedef struct + { + unsigned char responseProbability; + uint16_t allowedTimeSlots; + unsigned char discoverReportInitialCredit; + unsigned char icEqualCredit; + }gxPlcRegister; + + // PLC communication settings. + typedef struct + { + gxByteBuffer systemTitle; + + /** + * Initial credit (IC) tells how many times the frame must be repeated. + * Maximum value is 7. + */ + unsigned char initialCredit; + /** + * The current credit (CC) initial value equal to IC and automatically + * decremented by the MAC layer after each repetition. Maximum value is 7. + */ + unsigned char currentCredit; + + /** + * Delta credit (DC) is used by the system management application entity + * (SMAE) of the Client for credit management, while it has no meaning for a + * Server or a REPEATER. It represents the difference(IC-CC) of the last + * communication originated by the system identified by the DA address to + * the system identified by the SA address. Maximum value is 3. + */ + unsigned char deltaCredit; + /** + * Source MAC address. + */ + uint16_t macSourceAddress; + /** + * Destination MAC address. + */ + uint16_t macDestinationAddress; + /** + * Response probability. + */ + unsigned char responseProbability; + /** + * Allowed time slots. + */ + uint16_t allowedTimeSlots; + /** + * Server saves client system title. + */ + gxByteBuffer clientSystemTitle; + }gxPlcSettings; +#endif //DLMS_IGNORE_PLC + + typedef struct + { + // Is custom challenges used. If custom challenge is used new challenge is + // not generated if it is Set. This is for debugging purposes. + unsigned char customChallenges; + + // Client to server challenge. + gxByteBuffer ctoSChallenge; + + // Server to Client challenge. + gxByteBuffer stoCChallenge; + + unsigned char sourceSystemTitle[8]; + + // Invoke ID. + unsigned char invokeID; + + //Long Invoke ID. + int longInvokeID; + + // Priority. + DLMS_PRIORITY priority; + + // Service class. + DLMS_SERVICE_CLASS serviceClass; + + // Client address. + uint16_t clientAddress; + //Server address. + uint32_t serverAddress; + + unsigned char useLogicalNameReferencing; + DLMS_INTERFACE_TYPE interfaceType; + DLMS_AUTHENTICATION authentication; + gxByteBuffer password; +#ifndef DLMS_IGNORE_MALLOC + gxByteBuffer kek; +#else + unsigned char kek[16]; +#endif //DLMS_IGNORE_MALLOC + /** + * DLMS version number. + */ + unsigned char dlmsVersionNumber; + + /** + * Max PDU size used in communicating. + */ + uint16_t maxPduSize; + + /** + * Max PDU size that server uses. Client can ask anything, but server will decide. + */ + uint16_t maxServerPDUSize; + + /** + * HDLC sender frame sequence number. + */ + unsigned char senderFrame; + + /** + * HDLC receiver block sequence number. + */ + unsigned char receiverFrame; + /** + * Server functionality is not supported at the moment in ANSI C version. + */ + unsigned char server; + unsigned char isAuthenticationRequired; + + //When connection is made client tells what kind of services it want's to use. + DLMS_CONFORMANCE proposedConformance; + + // Functionality what server can offer. + DLMS_CONFORMANCE negotiatedConformance; + + //Used max info TX. + uint16_t maxInfoTX; + //Used max info RX. + uint16_t maxInfoRX; + //Used max window size in TX. + unsigned char windowSizeTX; + //Used max window size in RX. + unsigned char windowSizeRX; + + // Initialize PDU size that is restored after the connection is closed. + uint16_t initializePduSize; + //Initialized max info TX. + uint16_t initializeMaxInfoTX; + //Initialized max info RX. + uint16_t initializeMaxInfoRX; + //Initialized max window size in TX. + unsigned char initializeWindowSizeTX; + //Initialized max window size in RX. + unsigned char initializeWindowSizeRX; +#ifndef DLMS_IGNORE_PLC + //PLC settings. + gxPlcSettings plcSettings; +#endif //DLMS_IGNORE_PLC + + //List of internal COSEM objects. + //Objects in this list are not added to assocaition view. + //Objects can be used to save internal data. + objectArray internalObjects; + + //List of COSEM objects. + objectArray objects; + + // Block packet index. + uint32_t blockIndex; + //Is connected to the meter. + DLMS_CONNECTION_STATE connected; + +#ifndef DLMS_IGNORE_HIGH_GMAC + ciphering cipher; +#endif //DLMS_IGNORE_HIGH_GMAC + + int16_t userId; + + /** + * Protocol version. + */ + unsigned char protocolVersion; + + unsigned char qualityOfService; + //Pre-established Application Associations system title. + +#ifndef DLMS_IGNORE_MALLOC + gxByteBuffer* preEstablishedSystemTitle; +#else + unsigned char preEstablishedSystemTitle[8]; +#endif //DLMS_IGNORE_MALLOC + + //Client serializes data to this PDU when malloc is not used or heap size is limited. + gxByteBuffer* serializedPdu; + //Auto increase Invoke ID. + unsigned char autoIncreaseInvokeID; + //Client adds objects that are not found from the association view here so they are released when client is clear. + objectArray releasedObjects; + + ///////////////////////////////////////////////////////////////////////// + // Expected security suite. + // If Expected security suite is set client can't connect with other security suite. + unsigned char expectedSecuritySuite; + ///////////////////////////////////////////////////////////////////////// + // Expected security policy. + // If Expected security policy is set client can't connect with other security policies. + unsigned char expectedSecurityPolicy; + ///////////////////////////////////////////////////////////////////////// + // Expected Invocation(Frame) counter value. + // Expected Invocation counter is not check if value is zero. +#ifdef DLMS_COSEM_INVOCATION_COUNTER_SIZE64 + uint64_t* expectedInvocationCounter; +#else + uint32_t* expectedInvocationCounter; +#endif //DLMS_COSEM_INVOCATION_COUNTER_SIZE64 + ///////////////////////////////////////////////////////////////////////// + // Expected client system title. + unsigned char* expectedClientSystemTitle; + } dlmsSettings; + + typedef struct + { + /** + * Executed command. + */ + DLMS_COMMAND command; + + /** + * Targets. + */ + gxValueEventCollection targets; + +#ifndef DLMS_IGNORE_MALLOC + /** + * Extra data from PDU. + */ + gxByteBuffer data; +#endif //DLMS_IGNORE_MALLOC + } gxLongTransaction; + + typedef struct + { + dlmsSettings base; + + gxReplyData info; + /** + * Received data frame. + */ + gxByteBuffer receivedData; + + /** + * Long get or read transaction information. + */ + gxLongTransaction transaction; + + /** + * Is server initialized. + */ + unsigned char initialized; +#ifndef DLMS_IGNORE_IEC_HDLC_SETUP + gxIecHdlcSetup* hdlc; +#endif //DLMS_IGNORE_IEC_HDLC_SETUP +#ifndef DLMS_IGNORE_IEC_LOCAL_PORT_SETUP + gxLocalPortSetup* localPortSetup; +#endif //DLMS_IGNORE_IEC_LOCAL_PORT_SETUP + +#ifndef DLMS_IGNORE_TCP_UDP_SETUP + gxTcpUdpSetup* wrapper; +#endif //DLMS_IGNORE_TCP_UDP_SETUP +#ifndef DLMS_IGNORE_CLOCK + gxClock* defaultClock; +#endif //DLMS_IGNORE_CLOCK + + //Time when last frame was received. HDLC framing is using this. + uint32_t dataReceived; + //Time when last byte was received. HDLC framing is using this. + uint32_t frameReceived; + //Server is using push client address when sending push messages. Client address is used if PushAddress is zero. + uint16_t pushClientAddress; +#ifndef DLMS_IGNORE_IEC + /*Flag ID is used when server is operating using optical probe.*/ + unsigned char flagId[3]; +#endif //DLMS_IGNORE_IEC + } dlmsServerSettings; + + //Initialize server. + void svr_init( + dlmsServerSettings* settings, + unsigned char useLogicalNameReferencing, + DLMS_INTERFACE_TYPE interfaceType, + //Max frame size. + uint16_t frameSize, + //Max PDU size. + uint16_t pduSize, + //Buffer where received frames are saved. + unsigned char* frameBuffer, + //Size of frame buffer. + uint16_t frameBufferSize, + //PDU Buffer. + unsigned char* pduBuffer, + //Size of PDU buffer. + uint16_t pduBufferSize); + + //Initialize client. + void cl_init( + dlmsSettings* settings, + unsigned char useLogicalNameReferencing, + uint16_t clientAddress, + uint32_t serverAddress, + DLMS_AUTHENTICATION authentication, + const char* password, + DLMS_INTERFACE_TYPE interfaceType); + + //Clear DLMS settings. + void cl_clear( + dlmsSettings* settings); + + void svr_clear( + dlmsServerSettings* settings); + +#ifndef DLMS_IGNORE_PLC + // Set default values for PLC. + void plc_reset( + dlmsSettings* settings); +#endif //DLMS_IGNORE_PLC + + //Reset block index. + void resetBlockIndex( + dlmsSettings* settings); + + void resetFrameSequence( + dlmsSettings* settings); + +#ifndef DLMS_IGNORE_HDLC_CHECK + unsigned char checkFrame( + dlmsSettings* settings, + unsigned char frame); +#endif //DLMS_IGNORE_HDLC_CHECK + + void updateInvokeId( + dlmsServerSettings* settings, unsigned char value); + + // Increase receiver sequence. + // + // value: Frame value. + // Increased receiver frame sequence. + unsigned char increaseReceiverSequence( + unsigned char value); + + // Increase sender sequence. + // + // value : Frame value. + // Increased sender frame sequence. + unsigned char increaseSendSequence( + unsigned char value); + + unsigned char getNextSend( + dlmsSettings* settings, unsigned char first); + + unsigned char getReceiverReady( + dlmsSettings* settings); + + unsigned char getKeepAlive( + dlmsSettings* settings); + +#ifndef DLMS_IGNORE_HIGH_GMAC + unsigned char isCiphered( + ciphering* cipher); +#endif //DLMS_IGNORE_HIGH_GMAC + + void trans_init(gxLongTransaction* trans); + + void trans_clear(gxLongTransaction* trans); + +#ifdef __cplusplus +} +#endif + +#endif //DLMS_SETTINGS_H diff --git a/components/xt211/enums.h b/components/xt211/enums.h new file mode 100644 index 0000000..9574203 --- /dev/null +++ b/components/xt211/enums.h @@ -0,0 +1,3419 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef ENUMS_H +#define ENUMS_H + +#include "gxignore.h" + +#ifdef __cplusplus +extern "C" { +#endif + // Server sender frame sequence starting number. + // This buffer is also used for save challenge. +#define PDU_MAX_HEADER_SIZE 70 + +#define CIPHERING_HEADER_SIZE 22 //7 + 12 + 3 + + typedef enum + { + DLMS_ASSOCIATION_RESULT_ACCEPTED = 0, + DLMS_ASSOCIATION_RESULT_PERMANENT_REJECTED = 1, + DLMS_ASSOCIATION_RESULT_TRANSIENT_REJECTED = 2 + } DLMS_ASSOCIATION_RESULT; + + typedef enum + { + //Connection succeeded. + DLMS_SOURCE_DIAGNOSTIC_NONE = 0, + //Connection failed. No reason is given. + DLMS_SOURCE_DIAGNOSTIC_NO_REASON_GIVEN = 1, + //Connection failed. Application context name is not supported. + DLMS_SOURCE_DIAGNOSTIC_APPLICATION_CONTEXT_NAME_NOT_SUPPORTED = 2, + //Client system title is missing. + DLMS_SOURCE_DIAGNOSTIC_CALLING_AP_TITLE_NOT_RECOGNIZED = 3, + //Connection failed. No reason is given. + DLMS_SOURCE_DIAGNOSTIC_CALLING_AP_INVOCATION_IDENTIFIER_NOT_RECOGNIZED = 4, + //Connection failed. Calling AE qualifier not recognized. + DLMS_SOURCE_DIAGNOSTIC_CALLING_AE_QUALIFIER_NOT_RECOGNIZED = 5, + //Connection failed. Calling AE invocation identifier not recognized. + DLMS_SOURCE_DIAGNOSTIC_CALLING_AE_INVOCATION_IDENTIFIER_NOT_RECOGNIZED = 6, + //Connection failed. Called AP title not recognized. + DLMS_SOURCE_DIAGNOSTIC_CALLED_AP_TITLE_NOT_RECOGNIZED = 7, + //Connection failed. Called AP invocation identifier not recognized + DLMS_SOURCE_DIAGNOSTIC_CALLED_AP_INVOCATION_IDENTIFIER_NOT_RECOGNIZED = 8, + //Connection failed. Called AE qualifier not recognized. + DLMS_SOURCE_DIAGNOSTIC_CALLED_AE_QUALIFIER_NOT_RECOGNIZED = 9, + //Connection failed. Called AE invocation identifier not recognized. + DLMS_SOURCE_DIAGNOSTIC_CALLED_AE_INVOCATION_IDENTIFIER_NOT_RECOGNIZED = 10, + //Connection failed. Authentication mechanism name not recognised. + DLMS_SOURCE_DIAGNOSTIC_AUTHENTICATION_MECHANISM_NAME_NOT_RECOGNISED = 11, + //Connection failed. Authentication mechanism name required. + DLMS_SOURCE_DIAGNOSTIC_AUTHENTICATION_MECHANISM_NAME_REQUIRED = 12, + //Connection failed. Authentication failure. + DLMS_SOURCE_DIAGNOSTIC_AUTHENTICATION_FAILURE = 13, + //Connection failed. Authentication required. + DLMS_SOURCE_DIAGNOSTIC_AUTHENTICATION_REQUIRED = 14 + } DLMS_SOURCE_DIAGNOSTIC; + + typedef enum + { + DLMS_ACSE_SERVICE_PROVIDER_NULL = 0, + DLMS_ACSE_SERVICE_PROVIDER_NO_REASON_GIVEN = 1, + DLMS_ACSE_SERVICE_PROVIDER_NO_COMMON_ACSE_VERSION = 2 + }DLMS_ACSE_SERVICE_PROVIDER; + + // Defines whether or not the device has been assigned an address + // since last power up of the device. + typedef enum + { + // Not assigned an address yet. + DLMS_ADDRESS_STATE_NONE, + // Assigned an address either by manual setting, or by automated method. + DLMS_ADDRESS_STATE_ASSIGNED + } DLMS_ADDRESS_STATE; + + // Security policy Enforces authentication and/or encryption algorithm provided with security_suite. + typedef enum + { + /* + * Security is not used. + */ + DLMS_SECURITY_POLICY_NOTHING = 0, + /* + All messages to be authenticated. This enumeration values are used in Security Setup version 0. + */ + DLMS_SECURITY_POLICY_AUTHENTICATED = 1, + /* + All messages to be encrypted. This enumeration values are used in Security Setup version 0. + */ + DLMS_SECURITY_POLICY_ENCRYPTED = 2, + /* + All messages to be authenticated and encrypted. This enumeration values are used in Security Setup version 0. + */ + DLMS_SECURITY_POLICY_AUTHENTICATED_ENCRYPTED = 3, + /* + * Request is authenticated. This enumeration values are used in Security Setup version 1. + */ + DLMS_SECURITY_POLICY_AUTHENTICATED_REQUEST = 0x4, + /* + * Request is encrypted. This enumeration values are used in Security Setup version 1. + */ + DLMS_SECURITY_POLICY_ENCRYPTED_REQUEST = 0x8, + /* + * Request is digitally signed. This enumeration values are used in Security Setup version 1. + */ + DLMS_SECURITY_POLICY_DIGITALLY_SIGNED_REQUEST = 0x10, + /* + * Response is authenticated. This enumeration values are used in Security Setup version 1. + */ + DLMS_SECURITY_POLICY_AUTHENTICATED_RESPONSE = 0x20, + /* + * Response is encrypted. This enumeration values are used in Security Setup version 1. + */ + DLMS_SECURITY_POLICY_ENCRYPTED_RESPONSE = 0x40, + /* + * Response is digitally signed. This enumeration values are used in Security Setup version 1. + */ + DLMS_SECURITY_POLICY_DIGITALLY_SIGNED_RESPONSE = 0x80 + } DLMS_SECURITY_POLICY; + + //Security suite Specifies authentication, encryption and key wrapping algorithm. + typedef enum + { + /* + AES-GCM-128 for authenticated encryption and AES-128 for key wrapping. + */ + DLMS_SECURITY_SUITE_V0 = 0, + /* + AES-GCM-128 authenticated encryption, ECDSA P-256 digital signature, ECDH P-256 key agreement, SHA-256 hash, V.44 compression and AES-128 key wrap. + */ + DLMS_SECURITY_SUITE_V1 = 1, + /* + AES-GCM-256 authenticated encryption, ECDSA P-384 digital signature, ECDH P-384 key agreement, SHA-384 hash, V.44 compression and AES-256 key wrap + */ + DLMS_SECURITY_SUITE_V2 = 2 + } DLMS_SECURITY_SUITE; + + typedef enum + { + DLMS_SERVICE_TYPE_TCP = 0, + DLMS_SERVICE_TYPE_UDP = 1, + DLMS_SERVICE_TYPE_FTP = 2, + DLMS_SERVICE_TYPE_SMTP = 3, + DLMS_SERVICE_TYPE_SMS = 4, + DLMS_SERVICE_TYPE_HDLC = 5, + DLMS_SERVICE_TYPE_M_BUS = 6, + DLMS_SERVICE_TYPE_ZIG_BEE = 7 + } DLMS_SERVICE_TYPE; + + typedef enum + { + DLMS_MESSAGE_TYPE_COSEM_APDU = 0, + DLMS_MESSAGE_TYPE_COSEM_APDU_XML = 1, + DLMS_MESSAGE_TYPE_MANUFACTURER_SPESIFIC = 128 + } DLMS_MESSAGE_TYPE; + + typedef enum + { + DLMS_CLOCK_STATUS_OK = 0x0, + DLMS_CLOCK_STATUS_INVALID_VALUE = 0x1, + DLMS_CLOCK_STATUS_DOUBTFUL_VALUE = 0x2, + DLMS_CLOCK_STATUS_DIFFERENT_CLOCK_BASE = 0x4, + DLMS_CLOCK_STATUS_RESERVED1 = 0x8, + DLMS_CLOCK_STATUS_RESERVED2 = 0x10, + DLMS_CLOCK_STATUS_RESERVED3 = 0x20, + DLMS_CLOCK_STATUS_RESERVED4 = 0x40, + DLMS_CLOCK_STATUS_DAYLIGHT_SAVE_ACTIVE = 0x80, + //Skip clock status on write. + DLMS_CLOCK_STATUS_SKIP = 0xFF + } DLMS_CLOCK_STATUS; + + // DataType extra info. + typedef enum + { + // No extra info. + DLMS_DATE_TIME_EXTRA_INFO_NONE = 0x0, + // Daylight savings begin. + DLMS_DATE_TIME_EXTRA_INFO_DST_BEGIN = 0x1, + // Daylight savings end. + DLMS_DATE_TIME_EXTRA_INFO_DST_END = 0x2, + // Last day of month. + DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY = 0x4, + // 2nd last day of month + DLMS_DATE_TIME_EXTRA_INFO_LAST_DAY2 = 0x8, + }DLMS_DATE_TIME_EXTRA_INFO; + + /* + * Used priority. + */ + typedef enum + { + // Normal priority. + DLMS_PRIORITY_NORMAL = 0, + + // High priority. + DLMS_PRIORITY_HIGH = 1 + } DLMS_PRIORITY; + + typedef enum + { + DLMS_SERVICE_CLASS_UN_CONFIRMED = 0, + DLMS_SERVICE_CLASS_CONFIRMED = 1 + } DLMS_SERVICE_CLASS; + + typedef enum tagDLMS_OBJECT_TYPE + { + DLMS_OBJECT_TYPE_NONE = 0, + DLMS_OBJECT_TYPE_DATA = 1, + DLMS_OBJECT_TYPE_REGISTER = 3, + DLMS_OBJECT_TYPE_EXTENDED_REGISTER = 4, + DLMS_OBJECT_TYPE_DEMAND_REGISTER = 5, + DLMS_OBJECT_TYPE_REGISTER_ACTIVATION = 6, + DLMS_OBJECT_TYPE_PROFILE_GENERIC = 7, + DLMS_OBJECT_TYPE_CLOCK = 8, +#ifndef DLMS_IGNORE_SCRIPT_TABLE + DLMS_OBJECT_TYPE_SCRIPT_TABLE = 9, +#endif //DLMS_IGNORE_SCRIPT_TABLE +#ifndef DLMS_IGNORE_SCHEDULE + DLMS_OBJECT_TYPE_SCHEDULE = 10, +#endif //DLMS_IGNORE_SCHEDULE + DLMS_OBJECT_TYPE_SPECIAL_DAYS_TABLE = 11, + DLMS_OBJECT_TYPE_ASSOCIATION_SHORT_NAME = 12, + DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME = 15, + DLMS_OBJECT_TYPE_SAP_ASSIGNMENT = 17, + DLMS_OBJECT_TYPE_IMAGE_TRANSFER = 18, + DLMS_OBJECT_TYPE_IEC_LOCAL_PORT_SETUP = 19, + DLMS_OBJECT_TYPE_ACTIVITY_CALENDAR = 20, + DLMS_OBJECT_TYPE_REGISTER_MONITOR = 21, + DLMS_OBJECT_TYPE_ACTION_SCHEDULE = 22, + DLMS_OBJECT_TYPE_IEC_HDLC_SETUP = 23, + DLMS_OBJECT_TYPE_IEC_TWISTED_PAIR_SETUP = 24, + DLMS_OBJECT_TYPE_MBUS_SLAVE_PORT_SETUP = 25, + DLMS_OBJECT_TYPE_UTILITY_TABLES = 26, + DLMS_OBJECT_TYPE_MODEM_CONFIGURATION = 27, +#ifndef DLMS_IGNORE_SCRIPT_AUTO_ANSWER + DLMS_OBJECT_TYPE_AUTO_ANSWER = 28, +#endif //DLMS_IGNORE_SCRIPT_AUTO_ANSWER +#ifndef DLMS_IGNORE_SCRIPT_AUTO_CONNECT + DLMS_OBJECT_TYPE_AUTO_CONNECT = 29, +#endif //DLMS_IGNORE_SCRIPT_AUTO_CONNECT + DLMS_OBJECT_TYPE_TCP_UDP_SETUP = 41, + DLMS_OBJECT_TYPE_IP4_SETUP = 42, + DLMS_OBJECT_TYPE_MAC_ADDRESS_SETUP = 43, + DLMS_OBJECT_TYPE_PPP_SETUP = 44, + DLMS_OBJECT_TYPE_GPRS_SETUP = 45, + DLMS_OBJECT_TYPE_SMTP_SETUP = 46, + DLMS_OBJECT_TYPE_GSM_DIAGNOSTIC = 47, + DLMS_OBJECT_TYPE_IP6_SETUP = 48, + DLMS_OBJECT_TYPE_REGISTER_TABLE = 61, + DLMS_OBJECT_TYPE_COMPACT_DATA = 62, + DLMS_OBJECT_TYPE_STATUS_MAPPING = 63, + DLMS_OBJECT_TYPE_SECURITY_SETUP = 64, + DLMS_OBJECT_TYPE_DISCONNECT_CONTROL = 70, + DLMS_OBJECT_TYPE_LIMITER = 71, + DLMS_OBJECT_TYPE_MBUS_CLIENT = 72, + + DLMS_OBJECT_TYPE_PUSH_SETUP = 40, + /** + * S-FSK Phy MAC Setup + */ + DLMS_OBJECT_TYPE_SFSK_PHY_MAC_SETUP = 50, + + /* + * S-FSK Active initiator. + */ + DLMS_OBJECT_TYPE_SFSK_ACTIVE_INITIATOR = 51, + /* + * S-FSK MAC synchronization timeouts + */ + DLMS_OBJECT_TYPE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS = 52, + + /* + * S-FSK MAC Counters. + */ + DLMS_OBJECT_TYPE_SFSK_MAC_COUNTERS = 53, + + /* + * IEC 61334-4-32 LLC setup. + */ + DLMS_OBJECT_TYPE_IEC_61334_4_32_LLC_SETUP = 55, + + /* + * S-FSK Reporting system list. + */ + DLMS_OBJECT_TYPE_SFSK_REPORTING_SYSTEM_LIST = 56, + + /* + * ISO/IEC 8802-2 LLC Type 1 setup. + */ + DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE1_SETUP = 57, + + /* + * ISO/IEC 8802-2 LLC Type 2 setup. + */ + DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE2_SETUP = 58, + /* + * ISO/IEC 8802-2 LLC Type 3 setup. + */ + DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE3_SETUP = 59, + + DLMS_OBJECT_TYPE_WIRELESS_MODE_Q_CHANNEL = 73, + DLMS_OBJECT_TYPE_MBUS_MASTER_PORT_SETUP = 74, + DLMS_OBJECT_TYPE_MBUS_PORT_SETUP = 76, + DLMS_OBJECT_TYPE_MBUS_DIAGNOSTIC = 77, + DLMS_OBJECT_TYPE_PARAMETER_MONITOR = 65, + /* + * Arbitrator + */ + DLMS_OBJECT_TYPE_ARBITRATOR = 68, + /* + * Addresses that are provided by the base node during the opening of the + * convergence layer. + */ + DLMS_OBJECT_TYPE_LLC_SSCS_SETUP = 80, + + /* + * Counters related to the physical layers exchanges. + */ + DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS = 81, + + /* + * A necessary parameters to set up and manage the PRIME NB OFDM PLC MAC + * layer. + */ + DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_SETUP = 82, + + /* + * Functional behaviour of MAC. + */ + DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS = 83, + + /* + * Statistical information on the operation of the MAC layer for management + * purposes. + */ + DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_COUNTERS = 84, + + /* + * Parameters related to the management of the devices connected to the + * network. + */ + DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA = 85, + + /* + * Identification information related to administration and maintenance of + * PRIME NB OFDM PLC devices. + */ + DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION = 86, + + /* + * G3-PLC MAC layer counters + */ + DLMS_OBJECT_TYPE_G3_PLC_MAC_LAYER_COUNTERS = 90, + + /* + * G3-PLC MAC setup. + */ + DLMS_OBJECT_TYPE_G3_PLC_MAC_SETUP = 91, + + /* + * G3-PLC 6LoWPAN. + */ + DLMS_OBJECT_TYPE_G3_PLC_6LO_WPAN = 92, + + /* + * Function control. + */ + DLMS_OBJECT_TYPE_FUNCTION_CONTROL = 122, + + /* + * Configure a ZigBee PRO device with information necessary to create or + * join the network. + */ + DLMS_OBJECT_TYPE_ZIG_BEE_SAS_STARTUP = 101, + /* + * Configure the behavior of a ZigBee PRO device on joining or loss of + * connection to the network. + */ + DLMS_OBJECT_TYPE_ZIG_BEE_SAS_JOIN = 102, + /* + * Configure the fragmentation feature of ZigBee PRO transport layer. + */ + DLMS_OBJECT_TYPE_ZIG_BEE_SAS_APS_FRAGMENTATION = 103, + + DLMS_OBJECT_TYPE_ZIG_BEE_NETWORK_CONTROL = 104, + + DLMS_OBJECT_TYPE_DATA_PROTECTION = 30, + DLMS_OBJECT_TYPE_ACCOUNT = 111, + DLMS_OBJECT_TYPE_CREDIT = 112, + DLMS_OBJECT_TYPE_CHARGE = 113, + DLMS_OBJECT_TYPE_TOKEN_GATEWAY = 115, + DLMS_OBJECT_TYPE_ARRAY_MANAGER = 123, + // Tariff Plan (Piano Tariffario) is used in Italian standard UNI/TS 11291-11. + DLMS_OBJECT_TYPE_TARIFF_PLAN = 8192, + } DLMS_OBJECT_TYPE; + + typedef enum + { + HDLC_INFO_MAX_INFO_TX = 0x5, + HDLC_INFO_MAX_INFO_RX = 0x6, + HDLC_INFO_WINDOW_SIZE_TX = 0x7, + HDLC_INFO_WINDOW_SIZE_RX = 0x8 + } HDLC_INFO; + + typedef enum + { + DEFAULT_MAX_INFO_TX = 128, + DEFAULT_MAX_INFO_RX = 128, + DEFAULT_MAX_WINDOW_SIZE_TX = 1, + DEFAULT_MAX_WINDOW_SIZE_RX = 1 + } DEFAULT_MAX; + + typedef enum + { + DLMS_DATA_TYPE_NONE = 0, + DLMS_DATA_TYPE_BOOLEAN = 3, + DLMS_DATA_TYPE_BIT_STRING = 4, + DLMS_DATA_TYPE_INT32 = 5, + DLMS_DATA_TYPE_UINT32 = 6, + DLMS_DATA_TYPE_OCTET_STRING = 9, + DLMS_DATA_TYPE_STRING = 10, + DLMS_DATA_TYPE_BINARY_CODED_DESIMAL = 13, + DLMS_DATA_TYPE_STRING_UTF8 = 12, + DLMS_DATA_TYPE_INT8 = 15, + DLMS_DATA_TYPE_INT16 = 16, + DLMS_DATA_TYPE_UINT8 = 17, + DLMS_DATA_TYPE_UINT16 = 18, + DLMS_DATA_TYPE_INT64 = 20, + DLMS_DATA_TYPE_UINT64 = 21, + DLMS_DATA_TYPE_ENUM = 22, + DLMS_DATA_TYPE_FLOAT32 = 23, + DLMS_DATA_TYPE_FLOAT64 = 24, + DLMS_DATA_TYPE_DATETIME = 25, + DLMS_DATA_TYPE_DATE = 26, + DLMS_DATA_TYPE_TIME = 27, + DLMS_DATA_TYPE_ARRAY = 1, + DLMS_DATA_TYPE_STRUCTURE = 2, + DLMS_DATA_TYPE_COMPACT_ARRAY = 19, + DLMS_DATA_TYPE_BYREF = 0x80 + } DLMS_DATA_TYPE; + + typedef enum + { + // + // No access. + // + DLMS_ACCESS_MODE_NONE = 0, + // + // The client is allowed only reading from the server. + // + DLMS_ACCESS_MODE_READ = 1, + // + // The client is allowed only writing to the server. + // + DLMS_ACCESS_MODE_WRITE = 2, + // + // The client is allowed both reading from the server and writing to it. + // + DLMS_ACCESS_MODE_READ_WRITE = 3, + DLMS_ACCESS_MODE_AUTHENTICATED_READ = 4, + DLMS_ACCESS_MODE_AUTHENTICATED_WRITE = 5, + DLMS_ACCESS_MODE_AUTHENTICATED_READ_WRITE = 6 + } DLMS_ACCESS_MODE; + + /*The DLMS_METHOD_ACCESS_MODE enumerates the method access modes.*/ + typedef enum + { + // No access. + DLMS_METHOD_ACCESS_MODE_NONE = 0x0, + // Access. + DLMS_METHOD_ACCESS_MODE_ACCESS = 0x1, + // Authenticated Access. + DLMS_METHOD_ACCESS_MODE_AUTHENTICATED_ACCESS = 0x2, + // Authenticated request is allowed. + DLMS_METHOD_ACCESS_MODE_AUTHENTICATED_REQUEST = 0x4, + // Encrypted request is allowed. + DLMS_METHOD_ACCESS_MODE_ENCRYPTED_REQUEST = 0x8, + // Digitally signed request is allowed. + DLMS_METHOD_ACCESS_MODE_DIGITALLY_SIGNED_REQUEST = 0x10, + // Authenticated response is allowed. + DLMS_METHOD_ACCESS_MODE_AUTHENTICATED_RESPONSE = 0x20, + // Encrypted response is allowed. + DLMS_METHOD_ACCESS_MODE_ENCRYPTED_RESPONSE = 0x40, + // Digitally signed response is allowed. + DLMS_METHOD_ACCESS_MODE_DIGITALLY_SIGNED_RESPONSE = 0x80 + } DLMS_METHOD_ACCESS_MODE; + + typedef enum + { + DLMS_ASSOCIATION_STATUS_NON_ASSOCIATED = 0, + DLMS_ASSOCIATION_STATUS_ASSOCIATION_PENDING = 1, + DLMS_ASSOCIATION_STATUS_ASSOCIATED = 2 + } DLMS_ASSOCIATION_STATUS; + + + /* + * Enumerates Action request types. + */ + typedef enum + { + /* + * Normal action. + */ + DLMS_ACTION_COMMAND_TYPE_NORMAL = 1, + /* + * Next block. + */ + DLMS_ACTION_COMMAND_TYPE_NEXT_BLOCK = 2, + /* + * Action with list. + */ + DLMS_ACTION_COMMAND_TYPE_WITH_LIST = 3, + /* + * Action with first block. + */ + DLMS_ACTION_COMMAND_TYPE_WITH_FIRST_BLOCK = 4, + /* + * Action with list and first block. + */ + DLMS_ACTION_COMMAND_TYPE_WITH_LIST_AND_FIRST_BLOCK = 5, + /* + * Action with block. + */ + DLMS_ACTION_COMMAND_TYPE_WITH_BLOCK = 6 + } DLMS_ACTION_COMMAND_TYPE; + + typedef enum + { + /* + If this option is present, the device shall be allowed to send security, + compartmentation, handling restrictions and TCC (closed user group) + parameters within its IP Datagrams. The value of the IP-Option- + Length Field must be 11, and the IP-Option-Data shall contain the + value of the Security, Compartments, Handling Restrictions and + Transmission Control Code values, as specified in STD0005 / RFC791. + */ + DLMS_IP_OPTION_TYPE_SECURITY = 0x82, + /* + If this option is present, the device shall supply routing information to be + used by the gateways in forwarding the datagram to the destination, and to + record the route information. + The IP-Option-length and IP-Option-Data values are specified in STD0005 / RFC 791. + */ + DLMS_IP_OPTION_TYPE_LOOSE_SOURCE_AND_RECORD_ROUTE = 0x83, + /* + If this option is present, the device shall supply routing information to be + used by the gateways in forwarding the datagram to the destination, and to + record the route information. + The IP-Option-length and IP-Option-Data values are specified in STD0005 / RFC 791. + */ + DLMS_IP_OPTION_TYPE_STRICT_SOURCE_AND_RECORD_ROUTE = 0x89, + /* + If this option is present, the device shall as well: + send originated IP Datagrams with that option, providing means + to record the route of these Datagrams; + as a router, send routed IP Datagrams with the route option + adjusted according to this option. + The IP-Option-length and IP-Option-Data values are specified in + STD0005 / RFC 791. + */ + DLMS_IP_OPTION_TYPE_RECORD_ROUTE = 0x07, + /* + If this option is present, the device shall as well: + send originated IP Datagrams with that option, providing means + to time-stamp the datagram in the route to its destination; + as a router, send routed IP Datagrams with the time-stamp option + adjusted according to this option. + The IP-Option-length and IP-Option-Data values are specified in STD0005 / RFC 791. + */ + DLMS_IP_OPTION_TYPE_INTERNET_TIMESTAMP = 0x44 + } DLMS_IP_OPTION_TYPE; + + typedef enum + { + /* + Size of execution_time = 1. Wildcard in date allowed. + */ + DLMS_SINGLE_ACTION_SCHEDULE_TYPE1 = 1, + /* + Size of execution_time = n. + All time values are the same, wildcards in date not allowed. + */ + DLMS_SINGLE_ACTION_SCHEDULE_TYPE2 = 2, + /* + Size of execution_time = n. + All time values are the same, wildcards in date are allowed, + */ + DLMS_SINGLE_ACTION_SCHEDULE_TYPE3 = 3, + /* + Size of execution_time = n. + Time values may be different, wildcards in date not allowed, + */ + DLMS_SINGLE_ACTION_SCHEDULE_TYPE4 = 4, + /* + Size of execution_time = n. + Time values may be different, wildcards in date are allowed + */ + DLMS_SINGLE_ACTION_SCHEDULE_TYPE5 = 5 + } DLMS_SINGLE_ACTION_SCHEDULE_TYPE; + + typedef enum + { + DLMS_IMAGE_TRANSFER_STATUS_NOT_INITIATED, + DLMS_IMAGE_TRANSFER_STATUS_INITIATED, + DLMS_IMAGE_TRANSFER_STATUS_VERIFICATION_INITIATED, + DLMS_IMAGE_TRANSFER_STATUS_VERIFICATION_SUCCESSFUL, + DLMS_IMAGE_TRANSFER_STATUS_VERIFICATION_FAILED, + DLMS_IMAGE_TRANSFER_STATUS_ACTIVATION_INITIATED, + DLMS_IMAGE_TRANSFER_STATUS_ACTIVATION_SUCCESSFUL, + DLMS_IMAGE_TRANSFER_STATUS_ACTIVATION_FAILED + } DLMS_IMAGE_TRANSFER_STATUS; + + typedef enum + { + /* + * Transport security is not used. + */ + DLMS_SECURITY_NONE = 0, + + /* + * Authentication security is used. + */ + DLMS_SECURITY_AUTHENTICATION = 0x10, + + /* + * Encryption security is used. + */ + DLMS_SECURITY_ENCRYPTION = 0x20, + + /* + * Authentication and Encryption security are used. + */ + DLMS_SECURITY_AUTHENTICATION_ENCRYPTION = 0x30, + } DLMS_SECURITY; + + typedef enum + { + DLMS_COUNT_TYPE_TAG = 0x1, + DLMS_COUNT_TYPE_DATA = 2, + DLMS_COUNT_TYPE_PACKET = 3 + } DLMS_COUNT_TYPE; + + /* + * HDLC frame types. + */ + typedef enum + { + /* + * I-Frame. Information frames are used to transport user data. + */ + HDLC_FRAME_TYPE_I_FRAME = 0x0, + /* + * S-frame. Supervisory Frames are used for flow and error control. + * Rejected, RNR and RR. + */ + HDLC_FRAME_TYPE_S_FRAME = 0x1, + /* + * U-frame. Unnumbered frames are used for link management. Example SNRM and + * UA. + */ + HDLC_FRAME_TYPE_U_FRAME = 0x3 + } HDLC_FRAME_TYPE; + + /* + *BER encoding enumeration values. + */ + typedef enum + { + /* + * End of Content. + */ + BER_TYPE_EOC = 0x00, + /* + * Boolean. + */ + BER_TYPE_BOOLEAN = 0x1, + /* + * Integer. + */ + BER_TYPE_INTEGER = 0x2, + /* + * Bit String. + */ + BER_TYPE_BIT_STRING = 0x3, + /* + * Octet string. + */ + BER_TYPE_OCTET_STRING = 0x4, + /* + * Null value. + */ + BER_TYPE_NULL = 0x5, + /* + * Object identifier. + */ + BER_TYPE_OBJECT_IDENTIFIER = 0x6, + /* + * Object Descriptor. + */ + BER_TYPE_OBJECT_DESCRIPTOR = 7, + /* + * External + */ + BER_TYPE_EXTERNAL = 8, + /* + * Real (float). + */ + BER_TYPE_REAL = 9, + /* + * Enumerated. + */ + BER_TYPE_ENUMERATED = 10, + /* + * Utf8 String. + */ + BER_TYPE_UTF8_STRING = 12, + /* + * Numeric string. + */ + BER_TYPE_NUMERIC_STRING = 18, + /* + * Printable string. + */ + BER_TYPE_PRINTABLE_STRING = 19, + /* + * Teletex string. + */ + BER_TYPE_TELETEX_STRING = 20, + /* + * Videotex string. + */ + BER_TYPE_VIDEOTEX_STRING = 21, + /* + * Ia5 string + */ + BER_TYPE_IA5_STRING = 22, + /* + * Utc time. + */ + BER_TYPE_UTC_TIME = 23, + /* + * Generalized time. + */ + BER_TYPE_GENERALIZED_TIME = 24, + /* + * Graphic string. + */ + BER_TYPE_GRAPHIC_STRING = 25, + /* + * Visible string. + */ + BER_TYPE_VISIBLE_STRING = 26, + /* + * General string. + */ + BER_TYPE_GENERAL_STRING = 27, + /* + * Universal string. + */ + BER_TYPE_UNIVERSAL_STRING = 28, + /* + * Bmp string. + */ + BER_TYPE_BMP_STRING = 30, + /* + * Application class. + */ + BER_TYPE_APPLICATION = 0x40, + /* + * Context class. + */ + BER_TYPE_CONTEXT = 0x80, + /* + * Private class. + */ + BER_TYPE_PRIVATE = 0xc0, + /* + * Constructed. + */ + BER_TYPE_CONSTRUCTED = 0x20 + } BER_TYPE; + + /* + * APDU types. + */ + typedef enum + { + /* + * IMPLICIT BIT STRING {version1 = 0} DEFAULT {version1} + */ + PDU_TYPE_PROTOCOL_VERSION = 0, + + /* + * Application-context-name + */ + PDU_TYPE_APPLICATION_CONTEXT_NAME = 1, + + /* + * AP-title OPTIONAL + */ + PDU_TYPE_CALLED_AP_TITLE = 2, + + /* + * AE-qualifier OPTIONAL. + */ + PDU_TYPE_CALLED_AE_QUALIFIER = 3, + + /* + * AP-invocation-identifier OPTIONAL. + */ + PDU_TYPE_CALLED_AP_INVOCATION_ID = 4, + + /* + * AE-invocation-identifier OPTIONAL + */ + PDU_TYPE_CALLED_AE_INVOCATION_ID = 5, + + /* + * AP-title OPTIONAL + */ + PDU_TYPE_CALLING_AP_TITLE = 6, + + /* + * AE-qualifier OPTIONAL + */ + PDU_TYPE_CALLING_AE_QUALIFIER = 7, + + /* + * AP-invocation-identifier OPTIONAL + */ + PDU_TYPE_CALLING_AP_INVOCATION_ID = 8, + + /* + * AE-invocation-identifier OPTIONAL + */ + PDU_TYPE_CALLING_AE_INVOCATION_ID = 9, + + /* + * The following field shall not be present if only the kernel is used. + */ + PDU_TYPE_SENDER_ACSE_REQUIREMENTS = 10, + + /* + * The following field shall only be present if the authentication + * functional unit is selected. + */ + PDU_TYPE_MECHANISM_NAME = 11, + + /* + * The following field shall only be present if the authentication + * functional unit is selected. + */ + PDU_TYPE_CALLING_AUTHENTICATION_VALUE = 12, + + /* + * Implementation-data. + */ + PDU_TYPE_IMPLEMENTATION_INFORMATION = 29, + + /* + * Association-information OPTIONAL + */ + PDU_TYPE_USER_INFORMATION = 30 + } PDU_TYPE; + + /* + * HDLC control frame types. + */ + typedef enum + { + /* + * Receive is ready. + */ + HDLC_CONTROL_FRAME_RECEIVE_READY = 0, + /* + * Receive is not ready. + */ + HDLC_CONTROL_FRAME_RECEIVE_NOT_READY = 0x1, + /* + * Frame is rejected. + */ + HDLC_CONTROL_FRAME_REJECT = 2, + /* + * Frame is selective rejected. Not all meters support this. + */ + HDLC_CONTROL_FRAME_SELECTIVE_REJECT = 3 + } HDLC_CONTROL_FRAME; + + /* + * Authentication enumerates the authentication levels. + */ + typedef enum + { + /* + * No authentication is used. + */ + DLMS_AUTHENTICATION_NONE = 0, + + /* + * Low authentication is used. + */ + DLMS_AUTHENTICATION_LOW = 1, +#ifndef DLMS_IGNORE_AES + /* + * High authentication is used. Because DLMS/COSEM specification does not + * specify details of the HLS mechanism we have implemented Indian standard. + * Texas Instruments also uses this. + */ + DLMS_AUTHENTICATION_HIGH = 2, +#endif //DLMS_IGNORE_AES + /* + * High authentication is used. Password is hashed with MD5. + */ + DLMS_AUTHENTICATION_HIGH_MD5 = 3, + + /* + * High authentication is used. Password is hashed with SHA1. + */ + DLMS_AUTHENTICATION_HIGH_SHA1 = 4, + +#ifndef DLMS_IGNORE_HIGH_GMAC + /* + * High authentication is used. Password is hashed with GMAC. + */ + DLMS_AUTHENTICATION_HIGH_GMAC = 5, +#endif //DLMS_IGNORE_HIGH_GMAC + + /* + * High authentication is used. Password is hashed with SHA-256. + */ + DLMS_AUTHENTICATION_HIGH_SHA256 = 6, + /* + * High authentication is used. Password is hashed with ECDSA. + */ + DLMS_AUTHENTICATION_HIGH_ECDSA = 7 + } DLMS_AUTHENTICATION; + + //Interface type that is used. + typedef enum + { + //General + DLMS_INTERFACE_TYPE_HDLC = 0, + // IEC 62056-47 COSEM transport layers for IPv4 networks + DLMS_INTERFACE_TYPE_WRAPPER = 0x1, + /** + * Plain PDU is returned. + */ + DLMS_INTERFACE_TYPE_PDU, + /** + * Wireless M-Bus frame. + */ + DLMS_INTERFACE_TYPE_WIRELESS_MBUS, + /** + * IEC 62056-21 E-Mode is used to initialize communication before moving to + * HDLC protocol. + */ + DLMS_INTERFACE_TYPE_HDLC_WITH_MODE_E, + /** + * PLC Logical link control (LLC) profile is used with IEC 61334-4-32 + * connectionless LLC sublayer. + * + * Blue Book: 10.4.4.3.3 The connectionless LLC sublayer. + */ + DLMS_INTERFACE_TYPE_PLC, + /** + * PLC Logical link control (LLC) profile is used with HDLC. + * + * Blue Book: 10.4.4.3.4 The HDLC based LLC sublayer. + */ + DLMS_INTERFACE_TYPE_PLC_HDLC, + /** + * LowPower Wide Area Networks (LPWAN) profile is used. + */ + DLMS_INTERFACE_TYPE_LPWAN, + /** + * Wi-SUN FAN mesh network is used. + */ + DLMS_INTERFACE_TYPE_WI_SUN, + /** + * OFDM PLC PRIME is defined in IEC 62056-8-4. + */ + DLMS_INTERFACE_TYPE_PLC_PRIME + } DLMS_INTERFACE_TYPE; + + typedef enum + { + DLMS_DATA_REQUEST_TYPES_NONE = 0x0, + DLMS_DATA_REQUEST_TYPES_FRAME = 0x1, + DLMS_DATA_REQUEST_TYPES_BLOCK = 0x2, + DLMS_DATA_REQUEST_TYPES_GBT = 0x4 + } DLMS_DATA_REQUEST_TYPES; + + /* + * DLMS commands. + */ + typedef enum + { + /* + * No command to execute. + */ + DLMS_COMMAND_NONE = 0, + + /* + * Initiate request. + */ + DLMS_COMMAND_INITIATE_REQUEST = 0x1, + + /* + * Initiate response. + */ + DLMS_COMMAND_INITIATE_RESPONSE = 0x8, + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + /* + * Read request. + */ + DLMS_COMMAND_READ_REQUEST = 0x5, + /* + * Read response. + */ + DLMS_COMMAND_READ_RESPONSE = 0xC, + /* + * Write request. + */ + DLMS_COMMAND_WRITE_REQUEST = 0x6, + + /* + * Write response. + */ + DLMS_COMMAND_WRITE_RESPONSE = 0xD, +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + + /* + * Get request. + */ + DLMS_COMMAND_GET_REQUEST = 0xC0, + + /* + * Get response. + */ + DLMS_COMMAND_GET_RESPONSE = 0xC4, + + /* + * Set request. + */ + DLMS_COMMAND_SET_REQUEST = 0xC1, + + /* + * Set response. + */ + DLMS_COMMAND_SET_RESPONSE = 0xC5, + + /* + * Action request. + */ + DLMS_COMMAND_METHOD_REQUEST = 0xC3, + + /* + * Action response. + */ + DLMS_COMMAND_METHOD_RESPONSE = 0xC7, + + /* + HDLC Disconnect Mode. + Responder for Disconnect Mode request. + */ + DLMS_COMMAND_DISCONNECT_MODE = 0x1f, + + /* + * HDLC Unacceptable Frame. + */ + DLMS_COMMAND_REJECTED = 0x97, + + /* + * SNRM request. + */ + DLMS_COMMAND_SNRM = 0x93, + + /* + * UA request. + */ + DLMS_COMMAND_UA = 0x73, + + /* + * AARQ request. + */ + DLMS_COMMAND_AARQ = 0x60, + + /* + * AARE request. + */ + DLMS_COMMAND_AARE = 0x61, + + /* + * Disconnect request for HDLC framing. + */ + DLMS_COMMAND_DISC = 0x53, + + /* + * Disconnect request. + */ + DLMS_COMMAND_RELEASE_REQUEST = 0x62, + + /* + * Disconnect response. + */ + DLMS_COMMAND_RELEASE_RESPONSE = 0x63, + + /* + * Confirmed Service Error. + */ + DLMS_COMMAND_CONFIRMED_SERVICE_ERROR = 0x0E, + + /* + * Exception Response. + */ + DLMS_COMMAND_EXCEPTION_RESPONSE = 0xD8, + + /* + * General Block Transfer. + */ + DLMS_COMMAND_GENERAL_BLOCK_TRANSFER = 0xE0, + + /* + * Access Request. + */ + DLMS_COMMAND_ACCESS_REQUEST = 0xD9, + /* + * Access Response. + */ + DLMS_COMMAND_ACCESS_RESPONSE = 0xDA, + /* + * Data Notification request. + */ + DLMS_COMMAND_DATA_NOTIFICATION = 0x0F, + + /* + * Event Notification request. + */ + DLMS_COMMAND_EVENT_NOTIFICATION = 0xC2, + + /* + * Information Report request. + */ + DLMS_COMMAND_INFORMATION_REPORT = 0x18, + +#ifndef DLMS_IGNORE_HIGH_GMAC + /* + * Glo get request. + */ + DLMS_COMMAND_GLO_GET_REQUEST = 0xC8, + + /* + * Glo get response. + */ + DLMS_COMMAND_GLO_GET_RESPONSE = 0xCC, + + /* + * Glo set request. + */ + DLMS_COMMAND_GLO_SET_REQUEST = 0xC9, + + /* + * Glo set response. + */ + DLMS_COMMAND_GLO_SET_RESPONSE = 0xCD, + + /* + * Glo event notification request. + */ + DLMS_COMMAND_GLO_EVENT_NOTIFICATION_REQUEST = 0xCA, + + /* + * Glo method request. + */ + DLMS_COMMAND_GLO_METHOD_REQUEST = 0xCB, + + /* + * Glo method response. + */ + DLMS_COMMAND_GLO_METHOD_RESPONSE = 0xCF, + + /* + * Glo Initiate request. + */ + DLMS_COMMAND_GLO_INITIATE_REQUEST = 0x21, + /* + * Glo read request. + */ + DLMS_COMMAND_GLO_READ_REQUEST = 37, + + /* + * Glo write request. + */ + DLMS_COMMAND_GLO_WRITE_REQUEST = 38, + /* + * Glo Initiate response. + */ + DLMS_COMMAND_GLO_INITIATE_RESPONSE = 40, + /* + * Glo read response. + */ + DLMS_COMMAND_GLO_READ_RESPONSE = 44, + /* + * Glo write response. + */ + DLMS_COMMAND_GLO_WRITE_RESPONSE = 45, + + /* + * Glo Confirmed Service Error.. + */ + DLMS_COMMAND_GLO_CONFIRMED_SERVICE_ERROR = 46, + + /* + * General GLO ciphering. + */ + DLMS_COMMAND_GENERAL_GLO_CIPHERING = 0xDB, + /* + * General DED ciphering. + */ + DLMS_COMMAND_GENERAL_DED_CIPHERING = 0xDC, + /* + * General ciphering. + */ + DLMS_COMMAND_GENERAL_CIPHERING = 0xDD, + + /* + * Ded get request. + */ + DLMS_COMMAND_DED_GET_REQUEST = 0xD0, + + /* + * Ded get response. + */ + DLMS_COMMAND_DED_GET_RESPONSE = 0xD4, + + /* + * Ded set request. + */ + DLMS_COMMAND_DED_SET_REQUEST = 0xD1, + + /* + * Ded set response. + */ + DLMS_COMMAND_DED_SET_RESPONSE = 0xD5, + + /* + * Ded event notification request. + */ + DLMS_COMMAND_DED_EVENT_NOTIFICATION = 0xD2, + + /* + * Ded method request. + */ + DLMS_COMMAND_DED_METHOD_REQUEST = 0xD3, + + /* + * Ded method response. + */ + DLMS_COMMAND_DED_METHOD_RESPONSE = 0xD7, + + /* + * Ded read request. + */ + DLMS_COMMAND_DED_READ_REQUEST = 69, + + /* + * Ded write request. + */ + DLMS_COMMAND_DED_WRITE_REQUEST = 70, + + /* + * Ded read response. + */ + DLMS_COMMAND_DED_READ_RESPONSE = 76, + /* + * Ded write response. + */ + DLMS_COMMAND_DED_WRITE_RESPONSE = 77, + /* + * Glo Confirmed Service Error.. + */ + DLMS_COMMAND_DED_CONFIRMED_SERVICE_ERROR = 78, + + /*Ded initiate request.*/ + DLMS_COMMAND_DED_INITIATE_REQUEST = 65, + /*Ded initiate response.*/ + DLMS_COMMAND_DED_INITIATE_RESPONSE = 72, + + /*Unnumbered information UI frame*/ + DLMS_COMMAND_UNNUMBERED_INFORMATION_UI = 0x3, + /*Final unnumbered information UI*/ + DLMS_COMMAND_UNNUMBERED_INFORMATION_UI_FINAL = 0x13, + +#endif //DLMS_IGNORE_HIGH_GMAC + /* + * Request message from client to gateway. + */ + DLMS_COMMAND_GATEWAY_REQUEST = 0xE6, + + /* + * Response message from gateway to client. + */ + DLMS_COMMAND_GATEWAY_RESPONSE = 0xE7, + + // PLC discover request. + DLMS_COMMAND_DISCOVER_REQUEST = 0x1D, + // PLC discover report. + DLMS_COMMAND_DISCOVER_REPORT = 0x1E, + // PLC register request. + DLMS_COMMAND_REGISTER_REQUEST = 0x1C, + // PLC ping request. + DLMS_COMMAND_PING_REQUEST = 0x19, + // PLC ping response. + DLMS_COMMAND_PING_RESPONSE = 0x1A, + // PLC repeat call request. + DLMS_COMMAND_REPEAT_CALL_REQUEST = 0x1F + } DLMS_COMMAND; + + /* + * Confirmed service error tells when error has occurred. + */ + typedef enum + { + /* + * Error has occurred on initialize. + */ + DLMS_CONFIRMED_SERVICE_ERROR_INITIATE_ERROR = 1, + /* + * Error has occurred on read. + */ + DLMS_CONFIRMED_SERVICE_ERROR_READ = 5, + /* + * Error has occurred on write. + */ + DLMS_CONFIRMED_SERVICE_ERROR_WRITE = 6 + } DLMS_CONFIRMED_SERVICE_ERROR; + + /* + * Access describes access errors. + */ + typedef enum + { + /* + * Other error. + */ + DLMS_ACCESS_OTHER = 0, + /* + * Scope of access violated. + */ + DLMS_ACCESS_SCOPE_OF_ACCESS_VIOLATED = 1, + /* + * Object access is invalid. + */ + DLMS_ACCESS_OBJECT_ACCESS_INVALID = 2, + /* + * Hardware fault. + */ + DLMS_ACCESS_HARDWARE_FAULT = 3, + /* + * Object is unavailable. + */ + DLMS_ACCESS_OBJECT_UNAVAILABLE = 4 + } DLMS_ACCESS; + + /* + * Application reference describes application errors. + */ + typedef enum + { + /* + * Other error is occurred. + */ + DLMS_APPLICATION_REFERENCE_OTHER = 0, + /* + * Time elapsed. + */ + DLMS_APPLICATION_REFERENCE_TIME_ELAPSED = 1, + /* + * Application unreachable. + */ + DLMS_APPLICATION_REFERENCE_APPLICATION_UNREACHABLE = 2, + /* + * Application reference is invalid. + */ + DLMS_APPLICATION_REFERENCE_APPLICATION_REFERENCE_INVALID = 3, + /* + * Application context unsupported. + */ + DLMS_APPLICATION_REFERENCE_APPLICATION_CONTEXT_UNSUPPORTED = 4, + /* + * Provider communication error. + */ + DLMS_APPLICATION_REFERENCE_PROVIDER_COMMUNICATION_ERROR = 5, + /* + * Deciphering error. + */ + DLMS_APPLICATION_REFERENCE_DECIPHERING_ERROR = 6 + } DLMS_APPLICATION_REFERENCE; + + + /* + * Definition describes definition errors. + */ + typedef enum + { + /* + * Other error. + */ + DLMS_DEFINITION_OTHER = 0, + /* + * Object is Undefined. + */ + DLMS_DEFINITION_OBJECT_UNDEFINED = 1, + /* + * Object class inconsistent. + */ + DLMS_DEFINITION_OBJECT_CLASS_INCONSISTENT = 2, + /* + * Object attribute inconsistent. + */ + DLMS_DEFINITION_OBJECT_ATTRIBUTE_INCONSISTENT = 3 + } DLMS_DEFINITION; + + /* + * DLMS service errors. + * + * @author Gurux Ltd. + */ + typedef enum + { + /* + * Operation is not possible + */ + DLMS_EXCEPTION_SERVICE_ERROR_OPERATION_NOT_POSSIBLE = 1, + /* + * Service is not supported. + */ + DLMS_EXCEPTION_SERVICE_ERROR_SERVICE_NOT_SUPPORTED = 2, + /* + * Other reason. + */ + DLMS_EXCEPTION_SERVICE_ERROR_OTHER_REASON = 3, + /* + * PDU is too long. + */ + DLMS_EXCEPTION_SERVICE_ERROR_PDU_TOO_LONG = 4, + /* + * Ciphering failed. + */ + DLMS_EXCEPTION_SERVICE_ERROR_DECIPHERING_ERROR = 5, + /* + * Invocation counter is invalid. + */ + DLMS_EXCEPTION_SERVICE_ERROR_INVOCATION_COUNTER_ERROR = 6 + } DLMS_EXCEPTION_SERVICE_ERROR; + + /* + * Hardware resource describes hardware errors. + */ + typedef enum + { + /* + * Other hardware resource error. + */ + DLMS_HARDWARE_RESOURCE_OTHER = 0, + /* + * Memory is unavailable. + */ + DLMS_HARDWARE_RESOURCE_MEMORY_UNAVAILABLE = 1, + /* + * Processor resource is unavailable. + */ + DLMS_HARDWARE_RESOURCE_PROCESSOR_RESOURCE_UNAVAILABLE = 2, + /* + * Mass storage is unavailable. + */ + DLMS_HARDWARE_RESOURCE_MASS_STORAGE_UNAVAILABLE = 3, + /* + * Other resource is unavailable. + */ + DLMS_HARDWARE_RESOURCE_OTHER_RESOURCE_UNAVAILABLE = 4 + } DLMS_HARDWARE_RESOURCE; + + + /* + * Initiate describes onitiate errors. + */ + typedef enum + { + /* + * Other error. + */ + DLMS_INITIATE_OTHER = 0, + /* + * Dlms version is too low. + */ + DLMS_INITIATE_DLMS_VERSION_TOO_LOW = 1, + /* + * Incompatible conformance. + */ + DLMS_INITIATE_INCOMPATIBLE_CONFORMANCE = 2, + /* + * Pdu size is too short. + */ + DLMS_INITIATE_PDU_SIZE_TOOSHORT = 3, + /* + * Refused by the VDE handler. + */ + DLMS_INITIATE_REFUSED_BY_THE_VDE_HANDLER = 4 + } DLMS_INITIATE; + + /* + * LoadDataSet describes load dataset errors. + */ + typedef enum + { + /* + * Other error. + */ + DLMS_LOAD_DATASET_OTHER = 0, + /* + * Primitive out of sequence. + */ + DLMS_LOAD_DATASET_PRIMITIVE_OUT_OF_SEQUENCE = 1, + /* + * Not loadable. + */ + DLMS_LOAD_DATASET_NOT_LOADABLE = 2, + /* + * Dataset size is too large. + */ + DLMS_LOAD_DATASET_SIZE_TOO_LARGE = 3, + /* + * Not awaited segment. + */ + DLMS_LOAD_DATASET_NOT_AWAITED_SEGMENT = 4, + /* + * Interpretation failure. + */ + DLMS_LOAD_DATASET_INTERPRETATION_FAILURE = 5, + /* + * Storage failure. + */ + DLMS_LOAD_DATASET_STORAGE_FAILURE = 6, + /* + * Dataset not ready. + */ + DLMS_LOAD_DATASET_NOT_READY = 7 + } DLMS_LOAD_DATASET; + + /* + * Task describes load task errors. + */ + typedef enum + { + /* + * Other error. + */ + DLMS_TASK_OTHER = 0, + /* + * No remote control. + */ + DLMS_TASK_NO_REMOTE_CONTROL = 1, + /* + * Ti is stopped. + */ + DLMS_TASK_TI_STOPPED = 2, + /* + * TI is running. + */ + DLMS_TASK_TI_RUNNIN = 3, + /* + * TI is unusable. + */ + DLMS_TASK_TI_UNUSABLE = 4 + } DLMS_TASK; + + + /* + * VdeState error describes Vde state errors. + */ + typedef enum + { + /* + * Other error. + */ + DLMS_VDE_STATE_ERROR_OTHER = 0, + /* + * No DLMS context. + */ + DLMS_VDE_STATE_ERROR_NO_DLMS_CONTEXT = 1, + /* + * Loading dataset error. + */ + DLMS_VDE_STATE_ERROR_LOADING_DATASET = 2, + /* + * Status No change. + */ + DLMS_VDE_STATE_ERROR_STATUS_NO_CHANGE = 3, + /* + * Status Inoperable. + */ + DLMS_VDE_STATE_ERROR_STATUS_INOPERABLE = 4 + } DLMS_VDE_STATE_ERROR; + + /* + * Enumerates Get request and response types. + */ + typedef enum + { + /* + * Normal Get. + */ + DLMS_GET_COMMAND_TYPE_NORMAL = 1, + /* + * Next data block. + */ + DLMS_GET_COMMAND_TYPE_NEXT_DATA_BLOCK = 2, + /* + * Get request with list. + */ + DLMS_GET_COMMAND_TYPE_WITH_LIST = 3 + } DLMS_GET_COMMAND_TYPE; + + /* + * Service describes service errors. + */ + typedef enum + { + /* + * Other error. + */ + DLMS_SERVICE_OTHER = 0, + /* + * PDU size is wrong. + */ + DLMS_SERVICE_PDU_SIZE = 1, + /* + * Service is unsupported. + */ + DLMS_SERVICE_UNSUPPORTED = 2 + } DLMS_SERVICE; + + /* + * ServiceError enumerates service errors. + */ + typedef enum + { + /* + * Application error. + */ + DLMS_SERVICE_ERROR_APPLICATION_REFERENCE = 0, + /* + * Hardware error. + */ + DLMS_SERVICE_ERROR_HARDWARE_RESOURCE = 1, + /* + * Vde state error. + */ + DLMS_SERVICE_ERROR_VDE_STATE_ERROR = 2, + /* + * Service error. + */ + DLMS_SERVICE_ERROR_SERVICE = 3, + /* + * Definition error. + */ + DLMS_SERVICE_ERROR_DEFINITION = 4, + /* + * Access error. + */ + DLMS_SERVICE_ERROR_ACCESS = 5, + /* + * Initiate error. + */ + DLMS_SERVICE_ERROR_INITIATE = 6, + /* + * LoadDataSet error. + */ + DLMS_SERVICE_ERROR_LOAD_DATASET = 7, + /* + * Task error. + */ + DLMS_SERVICE_ERROR_TAS = 8, + /* + * Other error describes manufacturer specific error code. + */ + DLMS_SERVICE_ERROR_OTHER_ERROR = 9 + } DLMS_SERVICE_ERROR; + + /* + * Enumerates Set request types. + */ + typedef enum + { + /* + * Normal Set. + */ + DLMS_SET_COMMAND_TYPE_NORMAL = 1, + /* + * Set with first data block. + */ + DLMS_SET_COMMAND_TYPE_FIRST_DATABLOCK = 2, + /* + * Set with data block. + */ + DLMS_SET_COMMAND_TYPE_WITH_DATABLOCK = 3, + /* + * Set with list . + */ + DLMS_SET_COMMAND_TYPE_WITH_LIST = 4, + /* + * Set with list and first data block. + */ + DLMS_SET_COMMAND_TYPE_WITH_LIST_AND_WITH_FIRST_DATA_BLOCK = 5 + } DLMS_SET_COMMAND_TYPE; + + /* + * Enumerates single read response types. + */ + typedef enum + { + /* + * Normal data. + */ + DLMS_SINGLE_READ_RESPONSE_DATA = 0, + /* + * Error has occurred on read. + */ + DLMS_SINGLE_READ_RESPONSE_DATA_ACCESS_ERROR = 1, + /* + * Return data as blocks. + */ + DLMS_SINGLE_READ_RESPONSE_DATA_BLOCK_RESULT = 2, + /* + * Return block number. + */ + DLMS_SINGLE_READ_RESPONSE_BLOCK_NUMBER = 3 + } DLMS_SINGLE_READ_RESPONSE; + + /* + * Enumerates single write response types. + */ + typedef enum + { + /* + * Write succeeded. + */ + DLMS_SINGLE_WRITE_RESPONSE_SUCCESS = 0, + /* + * Write error has occurred. + */ + DLMS_SINGLE_WRITE_RESPONSE_DATA_ACCESS_ERROR = 1, + /* + * Get next block. + */ + DLMS_SINGLE_WRITE_RESPONSE_BLOCK_NUMBER = 2 + } DLMS_SINGLE_WRITE_RESPONSE; + + /* + * Enumerates how data is access on read or write. + */ + typedef enum + { + /* + * Read data using SN. + */ + DLMS_VARIABLE_ACCESS_SPECIFICATION_VARIABLE_NAME = 2, + /* + * Get data using parameterized access. + */ + DLMS_VARIABLE_ACCESS_SPECIFICATION_PARAMETERISED_ACCESS = 4, + /* + * Get next block. + */ + DLMS_VARIABLE_ACCESS_SPECIFICATION_BLOCK_NUMBER_ACCESS = 5, + /* + * Read data as blocks. + */ + DLMS_VARIABLE_ACCESS_SPECIFICATION_READ_DATA_BLOCK_ACCESS = 6, + /* + * Write data as blocks. + */ + DLMS_VARIABLE_ACCESS_SPECIFICATION_WRITE_DATA_BLOCK_ACCESS = 7 + } DLMS_VARIABLE_ACCESS_SPECIFICATION; + + /* +* Enumerates all conformance bits. +* https://www.gurux.fi/Gurux.DLMS.Conformance +*/ + typedef enum + { + /* + * Reserved zero conformance bit. + */ + DLMS_CONFORMANCE_NONE = 0, + /* + * Reserved zero conformance bit. + */ + DLMS_CONFORMANCE_RESERVED_ZERO = 0x1, + + /* + * General protection conformance bit. + */ + DLMS_CONFORMANCE_GENERAL_PROTECTION = 0x2, + + /* + * General block transfer conformance bit. + */ + DLMS_CONFORMANCE_GENERAL_BLOCK_TRANSFER = 0x4, + /* + * Read conformance bit. + */ + DLMS_CONFORMANCE_READ = 0x8, + /* + * Write conformance bit. + */ + DLMS_CONFORMANCE_WRITE = 0x10, + /* + * Un confirmed write conformance bit. + */ + DLMS_CONFORMANCE_UN_CONFIRMED_WRITE = 0x20, + /* + Delta value encoding. + */ + DLMS_CONFORMANCE_DELTA_VALUE_ENCODING = 0x40, + /* + * Reserved seven conformance bit. + */ + DLMS_CONFORMANCE_RESERVED_SEVEN = 0x80, + /* + * Attribute 0 supported with set conformance bit. + */ + DLMS_CONFORMANCE_ATTRIBUTE_0_SUPPORTED_WITH_SET = 0x100, + /* + * Priority mgmt supported conformance bit. + */ + DLMS_CONFORMANCE_PRIORITY_MGMT_SUPPORTED = 0x200, + /* + * Attribute 0 supported with get conformance bit. + */ + DLMS_CONFORMANCE_ATTRIBUTE_0_SUPPORTED_WITH_GET = 0x400, + /* + * Block transfer with get or read conformance bit. + */ + DLMS_CONFORMANCE_BLOCK_TRANSFER_WITH_GET_OR_READ = 0x800, + /* + * Block transfer with set or write conformance bit. + */ + DLMS_CONFORMANCE_BLOCK_TRANSFER_WITH_SET_OR_WRITE = 0x1000, + /* + * Block transfer with action conformance bit. + */ + DLMS_CONFORMANCE_BLOCK_TRANSFER_WITH_ACTION = 0x2000, + /* + * multiple references conformance bit. + */ + DLMS_CONFORMANCE_MULTIPLE_REFERENCES = 0x4000, + /* + * Information report conformance bit. + */ + DLMS_CONFORMANCE_INFORMATION_REPORT = 0x8000, + /* + * Data notification conformance bit. + */ + DLMS_CONFORMANCE_DATA_NOTIFICATION = 0x10000, + /* + * Access conformance bit. + */ + DLMS_CONFORMANCE_ACCESS = 0x20000, + /* + * Parameterized access conformance bit. + */ + DLMS_CONFORMANCE_PARAMETERIZED_ACCESS = 0x40000, + /* + * Get conformance bit. + */ + DLMS_CONFORMANCE_GET = 0x80000, + /* + * Set conformance bit. + */ + DLMS_CONFORMANCE_SET = 0x100000, + /* + * Selective access conformance bit. + */ + DLMS_CONFORMANCE_SELECTIVE_ACCESS = 0x200000, + /* + * Event notification conformance bit. + */ + DLMS_CONFORMANCE_EVENT_NOTIFICATION = 0x400000, + /* + * Action conformance bit. + */ + DLMS_CONFORMANCE_ACTION = 0x800000 + }DLMS_CONFORMANCE; + + typedef enum + { + /* + If this option is present, the device shall be allowed to send security, + compartmentation, handling restrictions and TCC (closed user group) + parameters within its IP Datagrams. The value of the IP-Option- + Length Field must be 11, and the IP-Option-Data shall contain the + value of the Security, Compartments, Handling Restrictions and + Transmission Control Code values, as specified in STD0005 / RFC791. + */ + IP_OPTION_TYPE_DLMS_SECURITY = 0x82, + /* + If this option is present, the device shall supply routing information to be + used by the gateways in forwarding the datagram to the destination, and to + record the route information. + The IP-Option-length and IP-Option-Data values are specified in STD0005 / RFC 791. + */ + IP_OPTION_TYPE_LOOSE_SOURCE_AND_RECORD_ROUTE = 0x83, + /* + If this option is present, the device shall supply routing information to be + used by the gateways in forwarding the datagram to the destination, and to + record the route information. + The IP-Option-length and IP-Option-Data values are specified in STD0005 / RFC 791. + */ + IP_OPTION_TYPE_STRICT_SOURCE_AND_RECORD_ROUTE = 0x89, + /* + If this option is present, the device shall as well: + send originated IP Datagrams with that option, providing means + to record the route of these Datagrams; + as a router, send routed IP Datagrams with the route option + adjusted according to this option. + The IP-Option-length and IP-Option-Data values are specified in + STD0005 / RFC 791. + */ + IP_OPTION_TYPE_RECORD_ROUTE = 0x07, + /* + If this option is present, the device shall as well: + send originated IP Datagrams with that option, providing means + to time-stamp the datagram in the route to its destination; + as a router, send routed IP Datagrams with the time-stamp option + adjusted according to this option. + The IP-Option-length and IP-Option-Data values are specified in STD0005 / RFC 791. + */ + IP_OPTION_TYPE_INTERNET_TIMESTAMP = 0x44 + }IP_OPTION_TYPE; + + // Enumerates Set response types. + typedef enum + { + /* + * Normal set response. + */ + DLMS_SET_RESPONSE_TYPE_NORMAL = 1, + /* + * Set response in data blocks. + */ + DLMS_SET_RESPONSE_TYPE_DATA_BLOCK = 2, + /* + * Set response in last data block. + */ + DLMS_SET_RESPONSE_TYPE_LAST_DATA_BLOCK = 3, + /* + * Set response in last data block with list. + */ + DLMS_SET_RESPONSE_TYPE_LAST_DATA_BLOCK_WITH_LIST = 4, + /* + * Set with list response. + */ + DLMS_SET_RESPONSE_TYPE_WITH_LIST = 5 + }DLMS_SET_RESPONSE_TYPE; + + /* + * Enumerates all Unit constants. + */ + typedef enum + { + /* + * No Unit. + */ + DLMS_UNIT_NONE = 0, + /* + * Year. + */ + DLMS_UNIT_YEAR = 1, + + /* + * Month. + */ + DLMS_UNIT_MONTH = 2, + + /* + * Week. + */ + DLMS_UNIT_WEEK = 3, + + /* + * Day. + */ + DLMS_UNIT_DAY = 4, + + /* + * Hour. + */ + DLMS_UNIT_HOUR = 5, + + /* + * Minute. + */ + DLMS_UNIT_MINUTE = 6, + + /* + * Second. + */ + DLMS_UNIT_SECOND = 7, + + /* + * Phase angle degree. + */ + DLMS_UNIT_PHASE_ANGLE_DEGREE = 8, + /* + * Temperature T degree centigrade, rad*180/p. + */ + DLMS_UNIT_TEMPERATURE = 9, + /* + * Local currency. + */ + DLMS_UNIT_LOCAL_CURRENCY = 10, + /* + * Length l meter m. + */ + DLMS_UNIT_LENGTH = 11, + /* + * Speed v m/s. + */ + DLMS_UNIT_SPEED = 12, + /* + * Volume V m3. + */ + DLMS_UNIT_VOLUME_CUBIC_METER = 13, + /* + * Corrected volume m3. + */ + DLMS_UNIT_CORRECTED_VOLUME = 14, + /* + * Volume flux m3/60*60s. + */ + DLMS_UNIT_VOLUME_FLUX_HOUR = 15, + /* + * Corrected volume flux m3/60*60s. + */ + DLMS_UNIT_CORRECTED_VOLUME_FLUX_HOUR = 16, + /* + * Volume flux m3/24*60*60s. + */ + DLMS_UNIT_VOLUME_FLUX_DAY = 17, + /* + * Corrected volume flux m3/24*60*60s. + */ + DLMS_UNIT_CORRECTED_VOLUME_FLUX_DAY = 18, + /* + * Volume 10-3 m3. + */ + DLMS_UNIT_VOLUME_LITER = 19, + /* + * Mass m kilogram kg. + */ + DLMS_UNIT_MASS_KG = 20, + /* + * return "Force F newton N. + */ + DLMS_UNIT_FORCE = 21, + /* + * Energy newtonmeter J = Nm = Ws. + */ + DLMS_UNIT_ENERGY = 22, + /* + * Pressure p pascal N/m2. + */ + DLMS_UNIT_PRESSURE_PASCAL = 23, + /* + * Pressure p bar 10-5 N/m2. + */ + DLMS_UNIT_PRESSURE_BAR = 24, + /* + * Energy joule J = Nm = Ws. + */ + DLMS_UNIT_ENERGY_JOULE = 25, + /* + * Thermal power J/60*60s. + */ + DLMS_UNIT_THERMAL_POWER = 26, + /* + * Active power P watt W = J/s. + */ + DLMS_UNIT_ACTIVE_POWER = 27, + /* + * Apparent power S. + */ + DLMS_UNIT_APPARENT_POWER = 28, + /* + * Reactive power Q. + */ + DLMS_UNIT_REACTIVE_POWER = 29, + /* + * Active energy W*60*60s. + */ + DLMS_UNIT_ACTIVE_ENERGY = 30, + /* + * Apparent energy VA*60*60s. + */ + DLMS_UNIT_APPARENT_ENERGY = 31, + /* + * Reactive energy var*60*60s. + */ + DLMS_UNIT_REACTIVE_ENERGY = 32, + /* + * Current I ampere A. + */ + DLMS_UNIT_CURRENT = 33, + /* + * Electrical charge Q coulomb C = As. + */ + DLMS_UNIT_ELECTRICAL_CHARGE = 34, + /* + * Voltage. + */ + DLMS_UNIT_VOLTAGE = 35, + /* + * Electrical field strength E V/m. + */ + DLMS_UNIT_ELECTRICAL_FIELD_STRENGTH = 36, + /* + * Capacity C farad C/V = As/V. + */ + DLMS_UNIT_CAPACITY = 37, + /* + * Resistance R ohm = V/A. + */ + DLMS_UNIT_RESISTANCE = 38, + /* + * Resistivity. + */ + DLMS_UNIT_RESISTIVITY = 39, + /* + * Magnetic flux F weber Wb = Vs. + */ + DLMS_UNIT_MAGNETIC_FLUX = 40, + /* + * Induction T tesla Wb/m2. + */ + DLMS_UNIT_INDUCTION = 41, + /* + * Magnetic field strength H A/m. + */ + DLMS_UNIT_MAGNETIC = 42, + /* + * Inductivity L henry H = Wb/A. + */ + DLMS_UNIT_INDUCTIVITY = 43, + /* + * Frequency f. + */ + DLMS_UNIT_FREQUENCY = 44, + /* + * Active energy meter constant 1/Wh. + */ + DLMS_UNIT_ACTIVE = 45, + /* + * Reactive energy meter constant. + */ + DLMS_UNIT_REACTIVE = 46, + /* + * Apparent energy meter constant. + */ + DLMS_UNIT_APPARENT = 47, + /* + * V260*60s. + */ + DLMS_UNIT_V260 = 48, + /* + * A260*60s. + */ + DLMS_UNIT_A260 = 49, + /* + * Mass flux kg/s. + */ + DLMS_UNIT_MASS_KG_PER_SECOND = 50, + /* + * Unit is Conductance siemens 1/ohm. + */ + DLMS_UNIT_CONDUCTANCE = 51, + /* + * Temperature in Kelvin. + */ + DLMS_UNIT_KELVIN = 52, + /* + * 1/(V2h) RU2h , volt-squared hour meter constant or pulse value. + */ + DLMS_UNIT_RU2H = 53, + /* + * 1/(A2h) RI2h , ampere-squared hour meter constant or pulse value. + */ + DLMS_UNIT_RI2H = 54, + /* + * 1/m3 RV , meter constant or pulse value = volume). + */ + DLMS_UNIT_CUBIC_METER_RV = 55, + /* + * Percentage. + */ + DLMS_UNIT_PERCENTAGE = 56, + /* + * Ah ampere hours. + */ + DLMS_UNIT_AMPERE_HOURS = 57, + /* + * Wh/m3 energy per volume 3,6*103 J/m3. + */ + DLMS_UNIT_ENERGY_PER_VOLUME = 60, + /* + * J/m3 calorific value, wobbe. + */ + DLMS_UNIT_WOBBE = 61, + /* + * Mol % molar fraction of gas composition mole percent = Basic gas + * composition unit). + */ + DLMS_UNIT_MOLE_PERCENT = 62, + /* + * g/m3 mass density, quantity of material. + */ + DLMS_UNIT_MASS_DENSITY = 63, + /* + * Dynamic viscosity pascal second = Characteristic of gas stream). + */ + DLMS_UNIT_PASCAL_SECOND = 64, + /* + * J/kg Specific energy NOTE The amount of energy per unit of mass of a + * substance Joule / kilogram m2 . kg . s -2 / kg = m2. + */ + DLMS_UNIT_JOULE_KILOGRAM = 65, + /* + * Pressure, gram per square centimeter. + */ + DLMS_UNIT_PRESSURE_GRAM_PER_SQUARE_CENTIMETER = 66, + /* + * Pressure, atmosphere. + */ + DLMS_UNIT_PRESSURE_ATMOSPHERE = 67, + /* + * Signal strength, dB milliwatt (e.g. of GSM radio systems) + */ + DLMS_UNIT_SIGNAL_STRENGTH_MILLI_WATT = 70, + /* + * Signal strength, dB microvolt. + */ + DLMS_UNIT_SIGNAL_STRENGTH_MICRO_VOLT = 71, + /* + * Logarithmic unit that expresses the ratio between two values of a physical quantity + */ + DLMS_UNIT_DB = 72, + /* + * Length in inches. + */ + DLMS_UNIT_INCH = 128, + /* + * Foot (Length). + */ + DLMS_UNIT_FOOT = 129, + /* + * Pound (mass). + */ + DLMS_UNIT_POUND = 130, + /* + * Fahrenheit. + */ + DLMS_UNIT_FAHRENHEIT = 131, + /* + * Rankine. + */ + DLMS_UNIT_RANKINE = 132, + /* + * Square inch. + */ + DLMS_UNIT_SQUARE_INCH = 133, + /* + * Square foot. + */ + DLMS_UNIT_SQUARE_FOOT = 134, + /* + * Acre. + */ + DLMS_UNIT_ACRE = 135, + /* + * Cubic inch. + */ + DLMS_UNIT_CUBIC_INCH = 136, + /* + * Cubic foot. + */ + DLMS_UNIT_CUBIC_FOOT = 137, + /* + * Acre foot. + */ + DLMS_UNIT_ACRE_FOOT = 138, + /* + * Gallon (imperial). + */ + DLMS_UNIT_GALLON_IMPERIAL = 139, + /* + * Gallon (US). + */ + DLMS_UNIT_GALLON_US = 140, + /* + * Pound force. + */ + DLMS_UNIT_POUND_FORCE = 141, + /* + * Pound force per square inch. + */ + DLMS_UNIT_POUND_FORCE_PER_SQUARE_INCH = 142, + /* + * Pound per cubic foot. + */ + DLMS_UNIT_POUND_PER_CUBIC_FOOT = 143, + /* + * Pound per (foot second). + */ + DLMS_UNIT_POUND_PER_FOOT_SECOND = 144, + /* + * Square foot per second. + */ + DLMS_UNIT_SQUARE_FOOT_PER_SECOND = 145, + /* + * British thermal unit. + */ + DLMS_UNIT_BRITISH_THERMAL_UNIT = 146, + /* + * Therm EU. + */ + DLMS_UNIT_THERM_EU = 147, + /* + * Therm US. + */ + DLMS_UNIT_THERM_US = 148, + /* + * British thermal unit per pound. + */ + DLMS_UNIT_BRITISH_THERMAL_UNIT_PER_POUND = 149, + /* + * British thermal unit per cubic foot. + */ + DLMS_UNIT_BRITISH_THERMAL_UNIT_PER_CUBIC_FOOT = 150, + /* + * Cubic feet. + */ + DLMS_UNIT_CUBIC_FEET = 151, + /* + * Foot per second. + */ + DLMS_UNIT_FOOT_PER_SECOND = 152, + /* + * Cubic foot per second. + */ + DLMS_UNIT_CUBIC_FOOT_PER_SECOND = 153, + /* + * Cubic foot per min. + */ + DLMS_UNIT_CUBIC_FOOT_PER_MIN = 154, + /* + * Cubic foot per hour. + */ + DLMS_UNIT_CUBIC_FOOT_PER_HOUR = 155, + /* + * Cubic foot per day + */ + DLMS_UNIT_CUBIC_FOOT_PER_DAY = 156, + /* + * Acre foot per second. + */ + DLMS_UNIT_ACRE_FOOT_PER_SECOND = 157, + /* + * Acre foot per min. + */ + DLMS_UNIT_ACRE_FOOT_PER_MIN = 158, + /* + * Acre foot per hour. + */ + DLMS_UNIT_ACRE_FOOT_PER_HOUR = 159, + /* + * Acre foot per day. + */ + DLMS_UNIT_ACRE_FOOT_PER_DAY = 160, + /* + * Imperial gallon. + */ + DLMS_UNIT_IMPERIAL_GALLON = 161, + /* + * Imperial gallon per second. + */ + DLMS_UNIT_IMPERIAL_GALLON_PER_SECOND = 162, + /* + * Imperial gallon per min. + */ + DLMS_UNIT_IMPERIAL_GALLON_PER_MIN = 163, + /* + * Imperial gallon per hour. + */ + DLMS_UNIT_IMPERIAL_GALLON_PER_HOUR = 164, + /* + * Imperial gallon per day. + */ + DLMS_UNIT_IMPERIAL_GALLON_PER_DAY = 165, + /* + * US gallon. + */ + DLMS_UNIT_US_GALLON = 166, + /* + * US gallon per second. + */ + DLMS_UNIT_US_GALLON_PER_SECOND = 167, + /* + * US gallon per min. + */ + DLMS_UNIT_US_GALLON_PER_MIN = 168, + /* + * US gallon per hour. + */ + DLMS_UNIT_US_GALLON_PER_HOUR = 169, + /* + * US gallon per day. + */ + DLMS_UNIT_US_GALLON_PER_DAY = 170, + /* + * British thermal unit per second. + */ + DLMS_UNIT_BRITISH_THERMAL_UNIT_PER_SECOND = 171, + /* + * British thermal unit per minute. + */ + DLMS_UNIT_BRITISH_THERMAL_UNIT_PER_MIN = 172, + /* + * British thermal unit per hour. + */ + DLMS_UNIT_BRITISH_THERMAL_UNIT_PER_HOUR = 173, + /* + * British thermal unit per day. + */ + DLMS_UNIT_BRITISH_THERMAL_UNIT_PER_DAY = 174, + /* + * Other Unit. + */ + DLMS_UNIT_OTHER = 254, + /* + * No Unit. + */ + DLMS_UNIT_NO_UNIT = 255 + }DLMS_UNIT; + + + /* + * Specifies trace levels. + * + */ + typedef enum { + /* + * Output no tracing and debugging messages. + */ + GX_TRACE_LEVEL_OFF, + + /* + * Output error-handling messages. + */ + GX_TRACE_LEVEL_ERROR, + + /* + * Output warnings and error-handling messages. + */ + GX_TRACE_LEVEL_WARNING, + + /* + * Output informational messages, warnings, and error-handling messages. + */ + GX_TRACE_LEVEL_INFO, + + /* + * Output all debugging and tracing messages. + */ + GX_TRACE_LEVEL_VERBOSE + }GX_TRACE_LEVEL; + + + /* + * Defines the GSM status. + */ + typedef enum { + /* + * Not registered. + */ + DLMS_GSM_STATUS_NONE, + /* + * Registered, home network. + */ + DLMS_GSM_STATUS_HOME_NETWORK, + /* + * Not registered, but MT is currently searching a new operator to register + * to. + */ + DLMS_GSM_STATUS_SEARCHING, + /* + * Registration denied. + */ + DLMS_GSM_STATUS_DENIED, + /* + * Unknown. + */ + DLMS_GSM_STATUS_UNKNOWN, + /* + * Registered, roaming. + */ + DLMS_GSM_STATUS_ROAMING + }DLMS_GSM_STATUS; + + + /* + * GSM circuit switced status. + */ + typedef enum { + /* + * Inactive. + */ + DLMS_GSM_CIRCUIT_SWITCH_STATUS_INACTIVE, + /* + * Incoming call. + */ + DLMS_GSM_CIRCUIT_SWITCH_STATUS_INCOMING_CALL, + /* + * Active. + */ + DLMS_GSM_CIRCUIT_SWITCH_STATUS_ACTIVE + }DLMS_GSM_CIRCUIT_SWITCH_STATUS; + + + /* + * Packet switched status of the modem. + */ + typedef enum { + /* + * Inactive + */ + DLMS_GSM_PACKET_SWITCH_STATUS_INACTIVE, + /* + * GPRS + */ + DLMS_GSM_PACKET_SWITCH_STATUS_GPRS, + /* + * EDGE + */ + DLMS_GSM_PACKET_SWITCH_STATUS_EDGE, + /* + * UMTS + */ + DLMS_GSM_PACKET_SWITCH_STATUS_UMTS, + /* + * HSDPA + */ + DLMS_GSM_PACKET_SWITCH_STATUS_HSDPA, + /* + * LTE + */ + DLMS_GSM_PACKET_SWITCH_STATUS_LTE, + /* + * CDMA + */ + DLMS_GSM_PACKET_SWITCH_STATUS_CDMA + }DLMS_GSM_PACKET_SWITCH_STATUS; + + /* + * Enumerates payment Modes.
+ * Online help:
+ * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + typedef enum + { + /* + * Credit mode. + */ + DLMS_ACCOUNT_PAYMENT_MODE_CREDIT = 1, + /* + * Prepayment mode. + */ + DLMS_ACCOUNT_PAYMENT_MODE_PREPAYMENT = 2 + }DLMS_ACCOUNT_PAYMENT_MODE; + + /* + * Enumerates account status modes.
+ * Online help:
+ * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + typedef enum + { + /* + * New (inactive) account. + */ + DLMS_ACCOUNT_STATUS_NEW_INACTIVE_ACCOUNT = 1, + /* + * Account active. + */ + DLMS_ACCOUNT_STATUS_ACTIVE = 2, + /* + * Account closed. + */ + DLMS_ACCOUNT_STATUS_CLOSED = 3 + }DLMS_ACCOUNT_STATUS; + + /* +* Enumerates account credit status modes.
+* Online help:
+* http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount +*/ + typedef enum { + /* + * In credit. + */ + DLMS_ACCOUNT_CREDIT_STATUS_NONE = 0x0, + /* + * In credit. + */ + DLMS_ACCOUNT_CREDIT_STATUS_IN_CREDIT = 0x1, + + /* + * Low credit. + */ + DLMS_ACCOUNT_CREDIT_STATUS_LOW_CREDIT = 0x2, + + /* + * Next credit enabled. + */ + DLMS_ACCOUNT_CREDIT_STATUS_NEXT_CREDIT_ENABLED = 0x4, + + /* + * Next credit selectable. + */ + DLMS_ACCOUNT_CREDIT_STATUS_NEXT_CREDIT_SELECTABLE = 0x8, + + /* + * Credit reference list. + */ + DLMS_ACCOUNT_CREDIT_STATUS_CREDIT_REFERENCE_LIST = 0x10, + + /* + * Selectable credit in use. + */ + DLMS_ACCOUNT_CREDIT_STATUS_SELECTABLE_CREDIT_IN_USE = 0x20, + + /* + * Out of credit. + */ + DLMS_ACCOUNT_CREDIT_STATUS_OUT_OF_CREDIT = 0x40, + + /* + * Reserved. + */ + DLMS_ACCOUNT_CREDIT_STATUS_RESERVED = 0x80 + }DLMS_ACCOUNT_CREDIT_STATUS; + + /* + * Enumerates payment Modes.
+ * Online help:
+ * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + typedef enum { + /* + * Time. + */ + DLMS_CURRENCY_TIME, + /* + * Consumption. + */ + DLMS_CURRENCY_CONSUMPTION, + /* + * Monetary. + */ + DLMS_CURRENCY_MONETARY + }DLMS_CURRENCY; + + typedef enum + { + DLMS_REQUIRED_PROTECTION_NONE = 0, + //Authenticated request. + DLMS_REQUIRED_PROTECTION_AUTHENTICATED_REQUEST = 0x4, + //Encrypted request. + DLMS_REQUIRED_PROTECTION_ENCRYPTED_REQUEST = 0x8, + //Digitally signed request + DLMS_REQUIRED_PROTECTION_DIGITALLY_SIGNED_REQUEST = 0x10, + //Authenticated response. + DLMS_REQUIRED_PROTECTION_AUTHENTICATED_RESPONSE = 0x20, + //Encrypted response. + DLMS_REQUIRED_PROTECTION_ENCRYPTED_RESPONSE = 0x40, + //Digitally signed response + DLMS_REQUIRED_PROTECTION_DIGITALLY_SIGNED_RESPONSE = 0x80, + }DLMS_REQUIRED_PROTECTION; + + typedef enum + { + /* + * None. + */ + DLMS_CREDIT_COLLECTION_CONFIGURATION_NONE = 0, + /* + * Collect when supply disconnected. + */ + DLMS_CREDIT_COLLECTION_CONFIGURATION_DISCONNECTED = 0x1, + /* + * Collect in load limiting periods. + */ + DLMS_CREDIT_COLLECTION_CONFIGURATION_LOAD_LIMITING = 0x2, + /* + * Collect in friendly credit periods. + */ + DLMS_CREDIT_COLLECTION_CONFIGURATION_FRIENDLY_CREDIT = 0x4 + }DLMS_CREDIT_COLLECTION_CONFIGURATION; + + // Enumerates payment Modes. + typedef enum + { + // Credit mode. + DLMS_PAYMENT_MODE_CREDIT = 1, + + // Prepayment mode. + DLMS_PAYMENT_MODE_PREPAYMENT = 2 + }DLMS_PAYMENT_MODE; + + + // Enumerates token status codes. + // Online help:
+ // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSTokenGateway + typedef enum + { + // Token format result OK. + FORMAT_OK, + + // Authentication result OK. + AUTHENTICATION_OK, + + // Validation result OK. + VALIDATION_OK, + + // Token execution result OK. + TOKEN_EXECUTION_OK, + + // Token format failure. + DLMS_TOKEN_STATUS_CODE_TOKEN_FORMAT_FAILURE, + + // Authentication failure. + DLMS_TOKEN_STATUS_CODE_AUTHENTICATION_FAILURE, + + // Validation result failure. + DLMS_TOKEN_STATUS_CODE_VALIDATION_RESULT_FAILURE, + + // Token execution result failure. + DLMS_TOKEN_STATUS_CODE_TOKEN_EXECUTION_RESULT_FAILURE, + + // Token received and not yet processed. + DLMS_TOKEN_STATUS_CODE_TOKEN_RECEIVED + }DLMS_TOKEN_STATUS_CODE; + + // Enumerates token delivery methods. + // Online help:
+ // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSTokenGateway + typedef enum + { + // Via remote communications. + DLMS_TOKEN_DELIVERY_REMOTE, + + // Via local communications. + DLMS_TOKEN_DELIVERY_LOCAL, + + // Via manual entry. + DLMS_TOKEN_DELIVERY_MANUAL + }DLMS_TOKEN_DELIVERY; + + /* + * Enumerates application context name. + */ + typedef enum { + /* + * Logical name. + */ + DLMS_APPLICATION_CONTEXT_NAME_LOGICAL_NAME = 1, + /* + * Short name. + */ + DLMS_APPLICATION_CONTEXT_NAME_SHORT_NAME = 2, + /* + * Logical name with ciphering. + */ + DLMS_APPLICATION_CONTEXT_NAME_LOGICAL_NAME_WITH_CIPHERING = 3, + /* + * Short name with ciphering. + */ + DLMS_APPLICATION_CONTEXT_NAME_SHORT_NAME_WITH_CIPHERING = 4 + }DLMS_APPLICATION_CONTEXT_NAME; + + // Certificate entity. + typedef enum { + // Certificate entity is server. + DLMS_CERTIFICATE_ENTITY_Server = 0, + // Certificate entity is client. + DLMS_CERTIFICATE_ENTITY_Client, + // Certificate entity is certification authority. + DLMS_CERTIFICATE_ENTITY_Certification_Authority, + // Certificate entity is other. + DLMS_CERTIFICATE_ENTITY_Other + }DLMS_CERTIFICATE_ENTITY; + + // Certificate type. + typedef enum { + // Certificate type is digital signature. + DLMS_CERTIFICATE_TYPE_DIGITAL_SIGNATURE = 0, + // Certificate type is key agreement. + DLMS_CERTIFICATE_TYPE_KEY_AGREEMENT = 1, + // Certificate type is TLS. + DLMS_CERTIFICATE_TYPE_TLS = 2, + // Certificate type is other. + DLMS_CERTIFICATE_TYPE_OTHER = 3 + } DLMS_CERTIFICATE_TYPE; + + // Connection types. + typedef enum { + //Connection is not made for the meter. + DLMS_CONNECTION_STATE_NONE = 0, + //Connection is made for HDLC level. + DLMS_CONNECTION_STATE_HDLC = 1, + //Connection is made for DLMS level. + DLMS_CONNECTION_STATE_DLMS = 2, + //Connection is made for optical IEC 62056-21 level. + DLMS_CONNECTION_STATE_IEC = 4 + }DLMS_CONNECTION_STATE; + + typedef enum { + //Data is captured with Capture-method. + DLMS_CAPTURE_METHOD_INVOKE, + //Data is captured upon reading. + DLMS_CAPTURE_METHOD_IMPLICIT + }DLMS_CAPTURE_METHOD; + + /** + * Present functional state of the node. + */ + typedef enum + { + /** + * Disconnected. + */ + DLMS_MAC_STATE_DISCONNECTED, + /** + * Terminal. + */ + DLMS_MAC_STATE_TERMINAL, + /** + * Switch. + */ + DLMS_MAC_STATE_SWITCH, + /** + * Base. + */ + DLMS_MAC_STATE_BASE + }DLMS_MAC_STATE; + + /** + * Present functional state of the node. + */ + typedef enum + { + DLMS_MAC_CAPABILITIES_NONE = 0, + /** + * Switch capable. + */ + DLMS_MAC_CAPABILITIES_SWITCH_CAPABLE = 1, + /** + * Packet aggregation. + */ + DLMS_MAC_CAPABILITIES_PACKET_AGGREGATION = 2, + /** + * Contention free period. + */ + DLMS_MAC_CAPABILITIES_CONTENTION_FREE_PERIOD = 4, + /** + * Direct connection. + */ + DLMS_MAC_CAPABILITIES_DIRECT_CONNECTION = 8, + /** + * Multicast. + */ + DLMS_MAC_CAPABILITIES_MULTICAST = 0x10, + /** + * PHY Robustness Management. + */ + DLMS_MAC_CAPABILITIES_PHY_ROBUSTNESS_MANAGEMENT = 0x20, + /** + * ARQ. + */ + DLMS_MAC_CAPABILITIES_ARQ = 0x40, + /** + * Reserved for future use. + */ + DLMS_MAC_CAPABILITIES_RESERVED_FOR_FUTURE_USE = 0x80, + /** + * Direct Connection Switching. + */ + DLMS_MAC_CAPABILITIES_DIRECT_CONNECTION_SWITCHING = 0x100, + /** + * Multicast Switching Capability. + */ + DLMS_MAC_CAPABILITIES_MULTICAST_SWITCHING_CAPABILITY = 0x200, + /** + * PHY Robustness Management Switching Capability. + */ + DLMS_MAC_CAPABILITIES_PHY_ROBUSTNESS_MANAGEMENT_SWITCHING_CAPABILITY = 0x400, + /** + * ARQ Buffering Switching Capability. + */ + DLMS_MAC_CAPABILITIES_ARQ_BUFFERING_SWITCHING_CAPABILITY = 0x800 + } + DLMS_MAC_CAPABILITIES; + + /* + * Enumerates credit types. + * Online help: + * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSCredit + */ + typedef enum + { + /* + * Token credit. + */ + DLMS_CREDIT_TYPE_TOKEN = 0, + /* + * Reserved credit. + */ + DLMS_CREDIT_TYPE_RESERVED, + /* + * Emergency credit. + */ + DLMS_CREDIT_TYPE_EMERGENCY, + /* + * TimeBased credit. + */ + DLMS_CREDIT_TYPE_TIME_BASED, + /* + * Consumption based credit. + */ + DLMS_CREDIT_TYPE_CONSUMPTION_BASED + }DLMS_CREDIT_TYPE; + + /* + * Enumerates credit status values. + * Online help: + * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSCredit + */ + typedef enum + { + /* + * Enabled state. + */ + DLMS_CREDIT_STATUS_ENABLED, + /* + * Selectable state. + */ + DLMS_CREDIT_STATUS_SELECTABLE, + /* + * Selected/Invoked state. + */ + DLMS_CREDIT_STATUS_INVOKED, + /* + * In use state. + */ + DLMS_CREDIT_STATUS_IN_USE, + /* + * Consumed state. + */ + DLMS_CREDIT_STATUS_CONSUMED + }DLMS_CREDIT_STATUS; + + /* + * Enumerated Credit configuration values. + * Online help: + * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + typedef enum + { + /* + * None. + */ + DLMS_CREDIT_CONFIGURATION_NONE = 0x0, + /* + * Requires visual indication + */ + DLMS_CREDIT_CONFIGURATION_VISUAL = 0x1, + /* + * Requires confirmation before it can be selected/invoked + */ + DLMS_CREDIT_CONFIGURATION_CONFIRMATION = 0x2, + /* + * Requires the credit amount to be paid back. + */ + DLMS_CREDIT_CONFIGURATION_PAID_BACK = 0x4, + /* + * Resettable. + */ + DLMS_CREDIT_CONFIGURATION_RESETTABLE = 0x8, + /* + * Able to receive credit amounts from tokens. + */ + DLMS_CREDIT_CONFIGURATION_TOKENS = 0x10 + }DLMS_CREDIT_CONFIGURATION; + + /* + * Enumerates account credit status modes. + * Online help: + * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSCharge + */ + typedef enum + { + /* + * Consumption based collection. + */ + DLMS_CHARGE_TYPE_CONSUMPTION_BASED_COLLECTION = 0, + /* + * Time based collection. + */ + DLMS_CHARGE_TYPE_TIME_BASED_COLLECTION, + /* + * Payment based collection. + */ + DLMS_CHARGE_TYPE_PAYMENT_EVENT_BASED_COLLECTION + }DLMS_CHARGE_TYPE; + + // Defines the weekdays. + typedef enum + { + /// No day of week is selected. + DLMS_WEEKDAYS_NONE = 0, + // Indicates Monday. + DLMS_WEEKDAYS_MONDAY = 0x1, + // Indicates Tuesday. + DLMS_WEEKDAYS_TUESDAY = 0x2, + // Indicates Wednesday. + DLMS_WEEKDAYS_WEDNESDAY = 0x4, + // Indicates Thursday. + DLMS_WEEKDAYS_THURSDAY = 0x8, + // Indicates Friday. + DLMS_WEEKDAYS_FRIDAY = 0x10, + // Indicates Saturday. + DLMS_WEEKDAYS_SATURDAY = 0x20, + // Indicates Sunday. + DLMS_WEEKDAYS_SUNDAY = 0x40 + }DLMS_WEEKDAYS; + + // Charge configuration enumeration types. + typedef enum + { + //NONE + DLMS_CHARGE_CONFIGURATION_NONE = 0, + // Percentage based collection. + DLMS_CHARGE_CONFIGURATION_PERCENTAGE_BASED_COLLECTION = 0x1, + // Continuous collection. + DLMS_CHARGE_CONFIGURATION_CONTINUOUS_COLLECTION = 0x2 + }DLMS_CHARGE_CONFIGURATION; + + // DLMS state errors. + typedef enum + { + //Invalid value. + DLMS_EXCEPTION_STATE_ERROR_SERVICE_INVALID = 0, + //Service is not allowed. + DLMS_EXCEPTION_STATE_ERROR_SERVICE_NOT_ALLOWED = 1, + //Unknown service. + DLMS_EXCEPTION_STATE_ERROR_SERVICE_UNKNOWN = 2 + }DLMS_EXCEPTION_STATE_ERROR; + + + //MIB variable initiator electrical phase. + typedef enum + { + /** + * Not defined. + */ + DLMS_INITIATOR_ELECTRICAL_PHASE_NOT_DEFINED, + /** + * Phase 1. + */ + DLMS_INITIATOR_ELECTRICAL_PHASE_1, + /** + * Phase 2. + */ + DLMS_INITIATOR_ELECTRICAL_PHASE_2, + /** + * Phase 3. + */ + DLMS_INITIATOR_ELECTRICAL_PHASE_3 + }DLMS_INITIATOR_ELECTRICAL_PHASE; + + /** + * MIB variable initiator electrical phase. + */ + typedef enum + { + /** + * Not defined. + */ + DLMS_DELTA_ELECTRICAL_PHASE_NOT_DEFINED, + /** + * The server system is connected to the same phase as the client system. + */ + DLMS_DELTA_ELECTRICAL_PHASE_SAME, + + DLMS_DELTA_ELECTRICAL_PHASE_DEGREES_60, + + DLMS_DELTA_ELECTRICAL_PHASE_DEGREES_120, + + DLMS_DELTA_ELECTRICAL_PHASE_DEGREES_180, + + DLMS_DELTA_ELECTRICAL_PHASE_DEGREES_MINUS_120, + + DLMS_DELTA_ELECTRICAL_PHASE_DEGREES_MINUS_60 + }DLMS_DELTA_ELECTRICAL_PHASE; + + + /** + * Repeater enumerator values. + */ + typedef enum + { + /** + * Newer repeater. + */ + DLMS_REPEATER_NEVER, + /** + * Always repeater. + */ + DLMS_REPEATER_ALWAYS, + /** + * Dynamic repeater. + */ + DLMS_REPEATER_DYNAMIC + }DLMS_REPEATER; + + + /** + * IEC Twisted pair setup working mode. + */ + typedef enum + { + /** + * The interface ignores all received frames. + */ + DLMS_IEC_TWISTED_PAIR_SETUP_MODE_INACTIVE, + + /** + * Always active. + */ + DLMS_IEC_TWISTED_PAIR_SETUP_MODE_ACTIVE + }DLMS_IEC_TWISTED_PAIR_SETUP_MODE; + + /** + * PLC Source address enumerations. + */ + typedef enum + { + DLMS_PLC_SOURCE_ADDRESS_INITIATOR = 0xC00, + DLMS_PLC_SOURCE_ADDRESS_NEW = 0xFFE + }DLMS_PLC_SOURCE_ADDRESS; + + // PLC Destination address enumerations. + typedef enum + { + DLMS_PLC_DESTINATION_ADDRESS_ALL_PHYSICAL = 0xFFF + }DLMS_PLC_DESTINATION_ADDRESS; + + /** + * PLC HDLC Source address enumerations. + */ + typedef enum + { + // Initiator. + DLMS_PLC_HDLC_SOURCE_ADDRESS_INITIATOR = 0xC01, + }DLMS_PLC_HDLC_SOURCE_ADDRESS; + + /** + * PLC data link data commands. + * */ + typedef enum + { + DLMS_PLC_DATA_LINK_DATA_REQUEST = 0x90 + }DLMS_PLC_DATA_LINK_DATA; + + // Sequence number of MAC sub frame. + typedef enum + { + DLMS_PLC_MAC_SUB_FRAMES_ONE = 0x6C6C, + DLMS_PLC_MAC_SUB_FRAMES_TWO = 0x3A3A, + DLMS_PLC_MAC_SUB_FRAMES_THREE = 0x5656, + DLMS_PLC_MAC_SUB_FRAMES_FOUR = 0x7171, + DLMS_PLC_MAC_SUB_FRAMES_FIVE = 0x1D1D, + DLMS_PLC_MAC_SUB_FRAMES_SIX = 0x4B4B, + DLMS_PLC_MAC_SUB_FRAMES_SEVEN = 0x2727, + }DLMS_PLC_MAC_SUB_FRAMES; + + // M-Bus command. + typedef enum + { + DLMS_MBUS_COMMAND_SND_NR = 0x44, + DLMS_MBUS_COMMAND_SND_UD2 = 0x43, + DLMS_MBUS_COMMAND_RSP_UD = 0x08 + } DLMS_MBUS_COMMAND; + + // M-Bus meter type. + typedef enum + { + // Other meter. + DLMS_MBUS_METER_TYPE_OTHER = 0, + // Oil meter. + DLMS_MBUS_METER_TYPE_OIL = 1, + // Energy meter. + DLMS_MBUS_METER_TYPE_ENERGY = 2, + // Gas meter. + DLMS_MBUS_METER_TYPE_GAS = 3, + // Heat meter. + DLMS_MBUS_METER_TYPE_HEAT = 4, + // Steam meter. + DLMS_MBUS_METER_TYPE_STEAM = 5, + // Hot water meter. + DLMS_MBUS_METER_TYPE_HOT_WATER = 6, + // Water meter. + DLMS_MBUS_METER_TYPE_WATER = 7, + // Heat cost allocator meter. + DLMS_MBUS_METER_TYPE_HEAT_COST_ALLOCATOR = 8, + // Gas mode 2 meter. + DLMS_MBUS_METER_TYPE_GAS_MODE2 = 10, + // Heat mode 2 meter. + DLMS_MBUS_METER_TYPE_HEAT_MODE2 = 11, + /// Hot water mode 2 meter. + DLMS_MBUS_METER_TYPE_HOT_WATER_MODE2 = 12, + /// Water mode 2 meter. + DLMS_MBUS_METER_TYPE_WATER_MODE2 = 13, + // Heat cost allocator mode 2 meter. + DLMS_MBUS_METER_TYPE_HEAT_COST_ALLOCATOR_MODE2 = 14, + // Unknown meter type. + DLMS_MBUS_METER_TYPE_UNKNOWN = 0x0F + }DLMS_MBUS_METER_TYPE; + + // Defines the M-Bus port communication status. + typedef enum + { + // No access. + DLMS_MBUS_PORT_COMMUNICATION_STATE_NO_ACCESS = 0, + // Temporary no access + DLMS_MBUS_PORT_COMMUNICATION_STATE_TEMPORARY_NO_ACCESS, + // Limited access + DLMS_MBUS_PORT_COMMUNICATION_STATE_LIMITED_ACCESS, + // Unlimited access. + DLMS_MBUS_PORT_COMMUNICATION_STATE_UNLIMITED_ACCESS, + // wM-Bus. + DLMS_MBUS_PORT_COMMUNICATION_STATE_WMBUS, + }DLMS_MBUS_PORT_COMMUNICATION_STATE; + + // Defines the M-Bus data header types. + typedef enum + { + // M-Bus data header is not used. + DLMS_MBUS_DATA_HEADER_TYPE_NONE = 0, + // Short data header is used. + DLMS_MBUS_DATA_HEADER_TYPE_SHORT, + // Long data header is used. + DLMS_MBUS_DATA_HEADER_TYPE_LONG + }DLMS_MBUS_DATA_HEADER_TYPE; + + // M-Bus control info. + typedef enum + { + // Long M-Bus data header present, direction master to slave + DLMS_MBUS_CONTROL_INFO_LONG_HEADER_MASTER = 0x60, + // Short M-Bus data header present, direction master to slave + DLMS_MBUS_CONTROL_INFO_SHORT_HEADER_MASTER = 0x61, + // Long M-Bus data header present, direction slave to master + DLMS_MBUS_CONTROL_INFO_LONG_HEADER_SLAVE = 0x7C, + // Short M-Bus data header present, direction slave to master + DLMS_MBUS_CONTROL_INFO_SHORT_HEADER_SLAVE = 0x7D, + // M-Bus short Header. + DLMS_MBUS_CONTROL_INFO_SHORT_HEADER = 0x7A, + // M-Bus long Header. + DLMS_MBUS_CONTROL_INFO_LONG_HEADER = 0x72 + }DLMS_MBUS_CONTROL_INFO; + + /*M-Bus link status.*/ + typedef enum + { + /*Data never received.*/ + DLMS_MBUS_LINK_STATUS_NONE, + /* Normal operation.*/ + DLMS_MBUS_LINK_STATUS_NORMAL, + /* Link temporarily interrupted.*/ + DLMS_MBUS_LINK_STATUS_TEMPORARILY_INTERRUPTED, + /*Link permanently interrupted.*/ + DLMS_MBUS_LINK_STATUS_PERMANENTLY_INTERRUPTED, + }DLMS_MBUS_LINK_STATUS; + + // Encryption modes. + typedef enum + { + // Encryption is not used. + DLMS_MBUS_ENCRYPTION_MODE_NONE, + // AES with Counter Mode (CTR) noPadding and IV. + DLMS_MBUS_ENCRYPTION_MODE_AES_128, + // DES with Cipher Block Chaining Mode (CBC). + DLMS_MBUS_ENCRYPTION_MODE_DES_CBC, + // DES with Cipher Block Chaining Mode (CBC) and Initial Vector. + DLMS_MBUS_ENCRYPTION_MODE_DES_CBC_IV, + // AES with Cipher Block Chaining Mode (CBC) and Initial Vector. + DLMS_MBUS_ENCRYPTION_MODE_AES_CBC_IV = 5, + // AES 128 with Cipher Block Chaining Mode (CBC) and dynamic key and Initial Vector with 0. + DLMS_MBUS_ENCRYPTION_MODE_AES_CBC_IV_0 = 7, + // TLS + DLMS_MBUS_ENCRYPTION_MODE_TLS = 13 + }DLMS_MBUS_ENCRYPTION_MODE; + + // Enumerates modulation types. + typedef enum + { + // Robust Mode. + DLMS_G3_PLC_MODULATION_ROBUST_MODE, + // DBPSK. + DLMS_G3_PLC_MODULATION_DBPSK, + // DQPSK. + DLMS_G3_PLC_MODULATION_DQPSK, + // D8PSK. + DLMS_G3_PLC_MODULATION_D8PSK, + // 16-QAM. + DLMS_G3_PLC_MODULATION_QAM16 + } DLMS_G3_PLC_MODULATION; + + // Enumerates gain resolution steps. + typedef enum + { + // Step is 6 dB. + DLMS_G3_PLC_GAIN_RESOLUTION_DB6, + // Step is 3 dB. + DLMS_G3_PLC_GAIN_RESOLUTION_DB3 + }DLMS_G3_PLC_GAIN_RESOLUTION; + + // Enumerates the type of the device connected to the modem. + typedef enum + { + // PAN device. + DLMS_PAN_DEVICE_TYPE_DEVICE, + // PAN coordinator. + DLMS_PAN_DEVICE_TYPE_COORDINATOR, + // Not Defined. + DLMS_PAN_DEVICE_TYPE_NOT_DEFINED + }DLMS_PAN_DEVICE_TYPE; + + + // Defines the ZigBee status enumeration values. + typedef enum + { + /// + /// Authorised on PAN. + /// + DLMS_ZIG_BEE_STATUS_AUTHORISED = 0x1, + /// + /// Actively reporting on PAN. + /// + DLMS_ZIG_BEE_STATUS_REPORTING = 0x2, + /// + /// Unauthorised on PAN but has reported + /// + DLMS_ZIG_BEE_STATUS_UNAUTHORISED = 0x4, + /// + /// Authorised after swap-out. + /// + DLMS_ZIG_BEE_STATUS_AUTHORISED_SWAP_OUT = 0x8, + /// + /// SEP Transmitting. + /// + DLMS_ZIG_BEE_STATUS_SEP_TRANSMITTING = 0x10 + }DLMS_ZIG_BEE_STATUS; +#ifdef __cplusplus +} +#endif + +#endif //ENUMS_H diff --git a/components/xt211/errorcodes.h b/components/xt211/errorcodes.h new file mode 100644 index 0000000..047e98d --- /dev/null +++ b/components/xt211/errorcodes.h @@ -0,0 +1,167 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef DLMS_ERROR_CODE_H +#define DLMS_ERROR_CODE_H + +#ifdef __cplusplus +extern "C" { +#endif + + typedef enum + { + DLMS_ERROR_TYPE_EXCEPTION_RESPONSE = 0x80000000, + DLMS_ERROR_TYPE_CONFIRMED_SERVICE_ERROR = 0x40000000, + DLMS_ERROR_TYPE_COMMUNICATION_ERROR = 0x20000000 + }DLMS_ERROR_TYPE; + + ///////////////////////////////////////////////////////////////////////////// +// Enumerates all DLMS error codes. +// https://www.gurux.fi/Gurux.DLMS.ErrorCodes +///////////////////////////////////////////////////////////////////////////// + typedef enum + { + //Meter is not accept frame. + DLMS_ERROR_CODE_UNACCEPTABLE_FRAME = -3, + //Meter rejects send packet. + DLMS_ERROR_CODE_REJECTED = -2, + DLMS_ERROR_CODE_FALSE = -1, + ////////////////////////////////////////// + //DLMS Standard error codes start here. + DLMS_ERROR_CODE_OK = 0, + //Access Error : Device reports a hardware fault + DLMS_ERROR_CODE_HARDWARE_FAULT = 1, + //Access Error : Device reports a temporary failure + DLMS_ERROR_CODE_TEMPORARY_FAILURE = 2, + // Access Error : Device reports Read-Write denied + DLMS_ERROR_CODE_READ_WRITE_DENIED = 3, + // Access Error : Device reports a undefined object + DLMS_ERROR_CODE_UNDEFINED_OBJECT = 4, + // Access Error : Device reports a inconsistent Class or Object + DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT = 9, + // Access Error : Device reports a unavailable object + DLMS_ERROR_CODE_UNAVAILABLE_OBJECT = 11, + // Access Error : Device reports a unmatched type + DLMS_ERROR_CODE_UNMATCH_TYPE = 12, + // Access Error : Device reports scope of access violated + DLMS_ERROR_CODE_ACCESS_VIOLATED = 13, + // Access Error : Data Block Unavailable. + DLMS_ERROR_CODE_DATA_BLOCK_UNAVAILABLE = 14, + // Access Error : Long Get Or Read Aborted. + DLMS_ERROR_CODE_LONG_GET_OR_READ_ABORTED = 15, + // Access Error : No Long Get Or Read In Progress. + DLMS_ERROR_CODE_NO_LONG_GET_OR_READ_IN_PROGRESS = 16, + // Access Error : Long Set Or Write Aborted. + DLMS_ERROR_CODE_LONG_SET_OR_WRITE_ABORTED = 17, + // Access Error : No Long Set Or Write In Progress. + DLMS_ERROR_CODE_NO_LONG_SET_OR_WRITE_IN_PROGRESS = 18, + // Access Error : Data Block Number Invalid. + DLMS_ERROR_CODE_DATA_BLOCK_NUMBER_INVALID = 19, + // Access Error : Other Reason. + DLMS_ERROR_CODE_OTHER_REASON = 250, + //DLMS Standard error codes end here. + ////////////////////////////////////////// + + //Unknown error. + DLMS_ERROR_CODE_UNKNOWN, + //Data send failed. + DLMS_ERROR_CODE_SEND_FAILED, + //Data receive failed. + DLMS_ERROR_CODE_RECEIVE_FAILED, + DLMS_ERROR_CODE_NOT_IMPLEMENTED, + //Secure connection is not supported. + DLMS_ERROR_CODE_DLMS_SECURITY_NOT_IMPLEMENTED, + //Invalid DLMS command. + DLMS_ERROR_CODE_INVALID_COMMAND, + //Invalid Block number. + DLMS_ERROR_CODE_INVALID_BLOCK_NUMBER, + //Invalid parameter. + DLMS_ERROR_CODE_INVALID_PARAMETER, + //Server is not initialized. + DLMS_ERROR_CODE_NOT_INITIALIZED, + //Not enough memory available. + DLMS_ERROR_CODE_OUTOFMEMORY, + //Packet is not a reply for a send packet. + DLMS_ERROR_CODE_NOT_REPLY, + //Invalid Logical Name + DLMS_ERROR_CODE_INVALID_LOGICAL_NAME, + //Client HDLC Address is not set. + DLMS_ERROR_CODE_INVALID_CLIENT_ADDRESS, + //Server HDLC Address is not set. + DLMS_ERROR_CODE_INVALID_SERVER_ADDRESS, + //Not a HDLC frame. + DLMS_ERROR_CODE_INVALID_DATA_FORMAT, + //Invalid DLMS version number. + DLMS_ERROR_CODE_INVALID_VERSION_NUMBER, + //Client addresses do not match + DLMS_ERROR_CODE_CLIENT_ADDRESS_NO_NOT_MATCH, + //Server addresses do not match + DLMS_ERROR_CODE_SERVER_ADDRESS_NO_NOT_MATCH, + //CRC do not match. + DLMS_ERROR_CODE_WRONG_CRC, + //Invalid response + DLMS_ERROR_CODE_INVALID_RESPONSE, + //Invalid Tag. + DLMS_ERROR_CODE_INVALID_TAG, + //Encoding failed. Not enough data. + DLMS_ERROR_CODE_ENCODING_FAILED, + DLMS_ERROR_CODE_REJECTED_PERMAMENT, + DLMS_ERROR_CODE_REJECTED_TRANSIENT, + DLMS_ERROR_CODE_NO_REASON_GIVEN, + DLMS_ERROR_CODE_APPLICATION_CONTEXT_NAME_NOT_SUPPORTED, + DLMS_ERROR_CODE_AUTHENTICATION_MECHANISM_NAME_NOT_RECOGNISED, + DLMS_ERROR_CODE_AUTHENTICATION_MECHANISM_NAME_REQUIRED, + DLMS_ERROR_CODE_AUTHENTICATION_FAILURE, + DLMS_ERROR_CODE_AUTHENTICATION_REQUIRED, + //Invalid frame number. + DLMS_ERROR_CODE_INVALID_FRAME_NUMBER, + DLMS_ERROR_CODE_INVALID_DATE_TIME, + DLMS_ERROR_CODE_INVALID_INVOKE_ID, + //Invocation counter value is too small. + DLMS_ERROR_CODE_INVOCATION_COUNTER_TOO_SMALL, + //Client try to connect with wrong security. + DLMS_ERROR_CODE_INVALID_DECIPHERING_ERROR, + //Client try to connect with wrong security suite. + DLMS_ERROR_CODE_INVALID_SECURITY_SUITE, + //Serialization load failed. + DLMS_ERROR_CODE_SERIALIZATION_LOAD_FAILURE, + //Serialization save failed. + DLMS_ERROR_CODE_SERIALIZATION_SAVE_FAILURE, + //Serialization count failed. + DLMS_ERROR_CODE_SERIALIZATION_COUNT_FAILURE + }DLMS_ERROR_CODE; + +#ifdef __cplusplus +} +#endif + +#endif //DLMS_ERROR_CODE_H diff --git a/components/xt211/gxaes.c b/components/xt211/gxaes.c new file mode 100644 index 0000000..053744c --- /dev/null +++ b/components/xt211/gxaes.c @@ -0,0 +1,603 @@ +// +// -------------------------------------------------------------------------- +// 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" +#ifndef DLMS_IGNORE_AES +#include // CBC mode, for memset +#include +#include "gxaes.h" + +#if defined(USE_AVR) || defined(ARDUINO_ARCH_AVR) +//If AVR is used. +#include +#endif //#if defined(USE_AVR) || defined(ARDUINO_ARCH_AVR) + +#define Nb 4 +#define BLOCKLEN 16 //Block length in bytes AES is 128b block only + +#if defined(AES256) && (AES256 == 1) +#define Nk 8 +#define KEYLEN 32 +#define Nr 14 +#define keyExpSize 240 +#elif defined(AES192) && (AES192 == 1) +#define Nk 6 +#define KEYLEN 24 +#define Nr 12 +#define keyExpSize 208 +#else +#define Nk 4 // The number of 32 bit words in a key. +#define KEYLEN 16 // Key length in bytes +#define Nr 10 // The number of rounds in AES Cipher. +#define keyExpSize 176 +#endif + +#ifndef MULTIPLY_AS_A_FUNCTION +#define MULTIPLY_AS_A_FUNCTION 0 +#endif + +// state - array holding the intermediate results during decryption. +typedef unsigned char state_t[4][4]; +static state_t* state; + +// The array that stores the round keys. +static unsigned char RoundKey[keyExpSize]; + +// The Key input to the AES Program +static const unsigned char* Key; + +#if defined(CBC) && CBC +// Initial Vector used only for CBC mode +static unsigned char* Iv; +#endif + +#ifndef USE_PROGMEM + static const unsigned char __SBOX[256] = { +#else + static const unsigned char __SBOX[256] PROGMEM = { +#endif //#if defined(_WIN32) || defined(_WIN64) + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; + +#ifndef USE_PROGMEM + static const unsigned char __RS_BOX[256] = { + #else + static const unsigned char __RS_BOX[256] PROGMEM = { +#endif //#if defined(_WIN32) || defined(_WIN64) + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }; + +// The round constant word array, Rcon[i], contains the values given by +// x to th e power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8) +#ifndef USE_PROGMEM + static const unsigned char __R_CON[11] = { +#else +static const unsigned char __R_CON[11] PROGMEM = { +#endif //#if defined(_WIN32) || defined(_WIN64) + 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 }; + +#if 0 +#ifndef USE_PROGMEM +static const unsigned char __R_CON[256] = { +#else +static const unsigned char __R_CON[256] PROGMEM = { +#endif //#if defined(_WIN32) || defined(_WIN64) + 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, + 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, + 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, + 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, + 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, + 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, + 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, + 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, + 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, + 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, + 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, + 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, + 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, + 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, + 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, + 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d }; +#endif + +static unsigned char getSBoxValue(unsigned char offset) +{ +#ifdef ARDUINO_ARCH_AVR + //If Arduino is used data is read from flash like this. + return pgm_read_byte_near(__SBOX + offset); +#else + return __SBOX[offset]; +#endif //ARDUINO_ARCH_AVR +} + +static unsigned char getSBoxInvert(unsigned char offset) +{ +#ifdef ARDUINO_ARCH_AVR + //If Arduino is used data is read from flash like this. + return pgm_read_byte_near(__RS_BOX + offset); +#else + return __RS_BOX[offset]; +#endif //ARDUINO_ARCH_AVR +} + +static unsigned char getRCon(unsigned char offset) +{ +#ifdef ARDUINO_ARCH_AVR + //If Arduino is used data is read from flash like this. + return pgm_read_byte_near(__R_CON + offset); +#else + return __R_CON[offset]; +#endif //ARDUINO_ARCH_AVR +} + +// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states. +static void KeyExpansion(void) +{ + unsigned char k; + uint32_t i; + // Used for the column/row operations + unsigned char tempa[4]; + + // The first round key is the key itself. + for (i = 0; i < Nk; ++i) + { + RoundKey[(i * 4) + 0] = Key[(i * 4) + 0]; + RoundKey[(i * 4) + 1] = Key[(i * 4) + 1]; + RoundKey[(i * 4) + 2] = Key[(i * 4) + 2]; + RoundKey[(i * 4) + 3] = Key[(i * 4) + 3]; + } + + // All other round keys are found from the previous round keys. + //i == Nk + for (; i < Nb * (Nr + 1); ++i) + { + { + tempa[0] = RoundKey[(i - 1) * 4 + 0]; + tempa[1] = RoundKey[(i - 1) * 4 + 1]; + tempa[2] = RoundKey[(i - 1) * 4 + 2]; + tempa[3] = RoundKey[(i - 1) * 4 + 3]; + } + + if (i % Nk == 0) + { + // This function shifts the 4 bytes in a word to the left once. + // [a0,a1,a2,a3] becomes [a1,a2,a3,a0] + + // Function RotWord() + { + k = tempa[0]; + tempa[0] = tempa[1]; + tempa[1] = tempa[2]; + tempa[2] = tempa[3]; + tempa[3] = k; + } + + // SubWord() is a function that takes a four-byte input word and + // applies the S-box to each of the four bytes to produce an output word. + + // Function Subword() + { + tempa[0] = getSBoxValue(tempa[0]); + tempa[1] = getSBoxValue(tempa[1]); + tempa[2] = getSBoxValue(tempa[2]); + tempa[3] = getSBoxValue(tempa[3]); + } + + tempa[0] = (unsigned char)(tempa[0] ^ getRCon((unsigned char)(i / Nk))); + } +#if defined(AES256) && (AES256 == 1) + if (i % Nk == 4) + { + // Function Subword() + { + tempa[0] = getSBoxValue(tempa[0]); + tempa[1] = getSBoxValue(tempa[1]); + tempa[2] = getSBoxValue(tempa[2]); + tempa[3] = getSBoxValue(tempa[3]); + } + } +#endif + RoundKey[i * 4 + 0] = RoundKey[(i - Nk) * 4 + 0] ^ tempa[0]; + RoundKey[i * 4 + 1] = RoundKey[(i - Nk) * 4 + 1] ^ tempa[1]; + RoundKey[i * 4 + 2] = RoundKey[(i - Nk) * 4 + 2] ^ tempa[2]; + RoundKey[i * 4 + 3] = RoundKey[(i - Nk) * 4 + 3] ^ tempa[3]; + } +} + +// This function adds the round key to state. +// The round key is added to the state by an XOR function. +static void AddRoundKey(unsigned char round) +{ + unsigned char i, j; + for (i = 0; i < 4; ++i) + { + for (j = 0; j < 4; ++j) + { + (*state)[i][j] ^= RoundKey[round * Nb * 4 + i * Nb + j]; + } + } +} + +// The SubBytes Function Substitutes the values in the +// state matrix with values in an S-box. +static void SubBytes(void) +{ + unsigned char i, j; + for (i = 0; i < 4; ++i) + { + for (j = 0; j < 4; ++j) + { + (*state)[j][i] = getSBoxValue((*state)[j][i]); + } + } +} + +// The ShiftRows() function shifts the rows in the state to the left. +// Each row is shifted with different offset. +// Offset = Row number. So the first row is not shifted. +static void ShiftRows(void) +{ + unsigned char temp; + + // Rotate first row 1 columns to left + temp = (*state)[0][1]; + (*state)[0][1] = (*state)[1][1]; + (*state)[1][1] = (*state)[2][1]; + (*state)[2][1] = (*state)[3][1]; + (*state)[3][1] = temp; + + // Rotate second row 2 columns to left + temp = (*state)[0][2]; + (*state)[0][2] = (*state)[2][2]; + (*state)[2][2] = temp; + + temp = (*state)[1][2]; + (*state)[1][2] = (*state)[3][2]; + (*state)[3][2] = temp; + + // Rotate third row 3 columns to left + temp = (*state)[0][3]; + (*state)[0][3] = (*state)[3][3]; + (*state)[3][3] = (*state)[2][3]; + (*state)[2][3] = (*state)[1][3]; + (*state)[1][3] = temp; +} + +static unsigned char xtime(unsigned char x) +{ + return (unsigned char)((x << 1) ^ (((x >> 7) & 1) * 0x1b)); +} + +// MixColumns function mixes the columns of the state matrix +static void MixColumns(void) +{ + unsigned char i; + unsigned char Tmp, Tm, t; + for (i = 0; i < 4; ++i) + { + t = (*state)[i][0]; + Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3]; + Tm = (*state)[i][0] ^ (*state)[i][1]; Tm = xtime(Tm); (*state)[i][0] ^= Tm ^ Tmp; + Tm = (*state)[i][1] ^ (*state)[i][2]; Tm = xtime(Tm); (*state)[i][1] ^= Tm ^ Tmp; + Tm = (*state)[i][2] ^ (*state)[i][3]; Tm = xtime(Tm); (*state)[i][2] ^= Tm ^ Tmp; + Tm = (*state)[i][3] ^ t; Tm = xtime(Tm); (*state)[i][3] ^= Tm ^ Tmp; + } +} + +// Multiply is used to multiply numbers in the field GF(2^8) +#if MULTIPLY_AS_A_FUNCTION +static unsigned char Multiply(unsigned char x, unsigned char y) +{ + return (((y & 1) * x) ^ + ((y >> 1 & 1) * xtime(x)) ^ + ((y >> 2 & 1) * xtime(xtime(x))) ^ + ((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^ + ((y >> 4 & 1) * xtime(xtime(xtime(xtime(x)))))); +} +#else +#define Multiply(x, y) \ + ( ((y & 1) * x) ^ \ + ((y>>1 & 1) * xtime(x)) ^ \ + ((y>>2 & 1) * xtime(xtime(x))) ^ \ + ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \ + ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \ + +#endif + +// MixColumns function mixes the columns of the state matrix. +// The method used to multiply may be difficult to understand for the inexperienced. +// Please use the references to gain more information. +static void InvMixColumns(void) +{ + int i; + unsigned char a, b, c, d; + for (i = 0; i < 4; ++i) + { + a = (*state)[i][0]; + b = (*state)[i][1]; + c = (*state)[i][2]; + d = (*state)[i][3]; + + (*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09); + (*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d); + (*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b); + (*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e); + } +} + + +// The SubBytes Function Substitutes the values in the +// state matrix with values in an S-box. +static void InvSubBytes(void) +{ + unsigned char i, j; + for (i = 0; i < 4; ++i) + { + for (j = 0; j < 4; ++j) + { + (*state)[j][i] = getSBoxInvert((*state)[j][i]); + } + } +} + +static void InvShiftRows(void) +{ + unsigned char temp; + + // Rotate first row 1 columns to right + temp = (*state)[3][1]; + (*state)[3][1] = (*state)[2][1]; + (*state)[2][1] = (*state)[1][1]; + (*state)[1][1] = (*state)[0][1]; + (*state)[0][1] = temp; + + // Rotate second row 2 columns to right + temp = (*state)[0][2]; + (*state)[0][2] = (*state)[2][2]; + (*state)[2][2] = temp; + + temp = (*state)[1][2]; + (*state)[1][2] = (*state)[3][2]; + (*state)[3][2] = temp; + + // Rotate third row 3 columns to right + temp = (*state)[0][3]; + (*state)[0][3] = (*state)[1][3]; + (*state)[1][3] = (*state)[2][3]; + (*state)[2][3] = (*state)[3][3]; + (*state)[3][3] = temp; +} + + +// Cipher is the main function that encrypts the PlainText. +static void Cipher(void) +{ + unsigned char round = 0; + + // Add the First round key to the state before starting the rounds. + AddRoundKey(0); + + // There will be Nr rounds. + // The first Nr-1 rounds are identical. + // These Nr-1 rounds are executed in the loop below. + for (round = 1; round < Nr; ++round) + { + SubBytes(); + ShiftRows(); + MixColumns(); + AddRoundKey(round); + } + + // The last round is given below. + // The MixColumns function is not here in the last round. + SubBytes(); + ShiftRows(); + AddRoundKey(Nr); +} + +static void InvCipher(void) +{ + unsigned char round = 0; + + // Add the First round key to the state before starting the rounds. + AddRoundKey(Nr); + + // There will be Nr rounds. + // The first Nr-1 rounds are identical. + // These Nr-1 rounds are executed in the loop below. + for (round = (Nr - 1); round > 0; --round) + { + InvShiftRows(); + InvSubBytes(); + AddRoundKey(round); + InvMixColumns(); + } + + // The last round is given below. + // The MixColumns function is not here in the last round. + InvShiftRows(); + InvSubBytes(); + AddRoundKey(0); +} + + +/*****************************************************************************/ +/* Public functions: */ +/*****************************************************************************/ +#if defined(ECB) && (ECB == 1) + +void gxaes_ecb_encrypt(const unsigned char* input, const unsigned char* key, unsigned char* output, const size_t length) +{ + // Copy input to output, and work in-memory on output + memcpy(output, input, length); + state = (state_t*)output; + + Key = key; + KeyExpansion(); + + // The next function call encrypts the PlainText with the Key using AES algorithm. + Cipher(); +} + +void gxaes_ecb_decrypt(const unsigned char* input, const unsigned char* key, unsigned char *output, const size_t length) +{ + // Copy input to output, and work in-memory on output + memcpy(output, input, length); + state = (state_t*)output; + + // The KeyExpansion routine must be called before encryption. + Key = key; + KeyExpansion(); + + InvCipher(); +} + + +#endif // #if defined(ECB) && (ECB == 1) + +#if defined(CBC) && (CBC == 1) + +static void XorWithIv(unsigned char* buf) +{ + unsigned char i; + for (i = 0; i < BLOCKLEN; ++i) //WAS for(i = 0; i < KEYLEN; ++i) but the block in AES is always 128bit so 16 bytes! + { + buf[i] ^= Iv[i]; + } +} + +void gxaes_cbc_encrypt(unsigned char* output, unsigned char* input, uint32_t length, const unsigned char* key, const unsigned char* iv) +{ + uintptr_t i; + unsigned char extra = length % BLOCKLEN; /* Remaining bytes in the last non-full block */ + + // Skip the key expansion if key is passed as 0 + if (0 != key) + { + Key = key; + KeyExpansion(); + } + + if (iv != 0) + { + Iv = (unsigned char*)iv; + } + + for (i = 0; i < length; i += BLOCKLEN) + { + XorWithIv(input); + memcpy(output, input, BLOCKLEN); + state = (state_t*)output; + Cipher(); + Iv = output; + input += BLOCKLEN; + output += BLOCKLEN; + //printf("Step %d - %d", i/16, i); + } + + if (extra) + { + memcpy(output, input, extra); + state = (state_t*)output; + Cipher(); + } +} + +void gxaes_cbc_decrypt(unsigned char* output, unsigned char* input, uint32_t length, const unsigned char* key, const unsigned char* iv) +{ + uintptr_t i; + unsigned char extra = length % BLOCKLEN; /* Remaining bytes in the last non-full block */ + + // Skip the key expansion if key is passed as 0 + if (0 != key) + { + Key = key; + KeyExpansion(); + } + + // If iv is passed as 0, we continue to encrypt without re-setting the Iv + if (iv != 0) + { + Iv = (unsigned char*)iv; + } + + for (i = 0; i < length; i += BLOCKLEN) + { + memcpy(output, input, BLOCKLEN); + state = (state_t*)output; + InvCipher(); + XorWithIv(output); + Iv = input; + input += BLOCKLEN; + output += BLOCKLEN; + } + + if (extra) + { + memcpy(output, input, extra); + state = (state_t*)output; + InvCipher(); + } +} + +#endif // #if defined(CBC) && (CBC == 1) + +#endif //DLMS_IGNORE_AES diff --git a/components/xt211/gxaes.h b/components/xt211/gxaes.h new file mode 100644 index 0000000..3a78e5a --- /dev/null +++ b/components/xt211/gxaes.h @@ -0,0 +1,73 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef GXAES1 +#define GXAES1 + +#include "gxignore.h" +#ifndef DLMS_IGNORE_AES + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifndef CBC +#define CBC 1 +#endif + +#ifndef ECB +#define ECB 1 +#endif + +#define AES128 1 + //#define AES192 1 + //#define AES256 1 + +#if defined(ECB) && (ECB == 1) + + void gxaes_ecb_encrypt(const unsigned char* input, const unsigned char* key, unsigned char *output, const size_t length); + void gxaes_ecb_decrypt(const unsigned char* input, const unsigned char* key, unsigned char *output, const size_t length); + +#endif // #if defined(ECB) && (ECB == !) + +#if defined(CBC) && (CBC == 1) + void gxaes_cbc_encrypt(unsigned char* output, unsigned char* input, uint32_t length, const unsigned char* key, const unsigned char* iv); + void gxaes_cbc_decrypt(unsigned char* output, unsigned char* input, uint32_t length, const unsigned char* key, const unsigned char* iv); + +#endif // #if defined(CBC) && (CBC == 1) + +#ifdef __cplusplus +} +#endif +#endif //DLMS_IGNORE_AES +#endif //GXAES1 diff --git a/components/xt211/gxarray.c b/components/xt211/gxarray.c new file mode 100644 index 0000000..2ccca6f --- /dev/null +++ b/components/xt211/gxarray.c @@ -0,0 +1,460 @@ +// +// -------------------------------------------------------------------------- +// 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 _MSC_VER > 1400 +#include +#endif +#include +#include "errorcodes.h" +#include "gxarray.h" +#include "bytebuffer.h" +#include "gxkey.h" + +//Initialize gxArray. +void arr_init(gxArray* arr) +{ + arr->capacity = 0; + arr->data = NULL; + arr->size = 0; +#ifndef DLMS_IGNORE_MALLOC + arr->position = 0; +#endif //DLMS_IGNORE_MALLOC +} + +char arr_isAttached(gxArray* arr) +{ + return (arr->capacity & 0x8000) == 0x8000; +} + +uint16_t arr_getCapacity(gxArray* arr) +{ + return arr->capacity & 0x7FFF; +} + +void arr_attach( + gxArray* arr, + void* value, + uint16_t count, + uint16_t capacity) +{ + arr->data = value; + arr->capacity = (uint16_t)(0x8000 | capacity); + arr->size = count; +#ifndef DLMS_IGNORE_MALLOC + arr->position = 0; +#endif //DLMS_IGNORE_MALLOC +} + + +//Allocate new size for the array in bytes. +int arr_capacity(gxArray* arr, int capacity) +{ +#ifndef DLMS_IGNORE_MALLOC + if (!arr_isAttached(arr)) + { + if (capacity == 0) + { + if (arr->data != NULL) + { + gxfree(arr->data); + arr->data = NULL; + } + } + else + { + if (arr->data == NULL) + { + arr->data = (void**)gxmalloc(capacity * sizeof(void*)); + if (arr->data == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + } + else + { +#ifdef gxrealloc + void* tmp = (void**)gxrealloc(arr->data, capacity * sizeof(void*)); + //If not enought memory available. + 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(void*)); + //If not enought memory available. + if (arr->data == NULL) + { + arr->data = old; + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + memcpy(arr->data, old, sizeof(void*) * arr->size); + gxfree(old); + #endif // gxrealloc + } + } + arr->capacity = (uint16_t)capacity; + } +#endif //DLMS_IGNORE_MALLOC + if (arr_getCapacity(arr) < capacity) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + return 0; +} + + +#ifndef DLMS_IGNORE_MALLOC +int arr_push(gxArray* arr, void* item) +{ + if (arr->size >= arr->capacity) + { + int ret = arr_capacity(arr, arr->capacity + GXARRAY_CAPACITY); + if (ret != 0) + { + return ret; + } + } + arr->data[arr->size] = item; + ++arr->size; + return 0; +} +#endif //DLMS_IGNORE_MALLOC + +void arr_clear( + gxArray* arr) +{ +#ifndef DLMS_IGNORE_MALLOC + int pos; + if (arr->size != 0) + { + for (pos = 0; pos != arr->size; ++pos) + { + gxfree(arr->data[pos]); + } + } + if (!arr_isAttached(arr) && arr->capacity != 0) + { + gxfree(arr->data); + arr->data = NULL; + arr->capacity = 0; + } + if (!arr_isAttached(arr)) + { + arr->size = 0; + } +#else + arr->size = 0; +#endif //DLMS_IGNORE_MALLOC + +#ifndef DLMS_IGNORE_MALLOC + arr->position = 0; +#endif //DLMS_IGNORE_MALLOC +} + +void arr_empty( + gxArray* arr) +{ +#ifndef DLMS_IGNORE_MALLOC + if (arr->size != 0) + { + gxfree(arr->data); + arr->data = NULL; + } + arr->capacity = 0; + if (!arr_isAttached(arr)) + { + arr->size = 0; + } +#else + arr->size = 0; +#endif //DLMS_IGNORE_MALLOC +#ifndef DLMS_IGNORE_MALLOC + arr->position = 0; +#endif //DLMS_IGNORE_MALLOC +} + +#ifndef DLMS_IGNORE_MALLOC +int arr_get(gxArray* arr, void** value) +{ + if (arr->position >= arr->size) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + *value = arr->data[arr->position]; + ++arr->position; + return 0; +} +#endif //DLMS_IGNORE_MALLOC + + + +#ifndef DLMS_IGNORE_MALLOC +int arr_getByIndex(gxArray* arr, uint16_t index, void** value) +{ + if (arr == NULL || value == NULL) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if (index >= arr->size) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + *value = arr->data[index]; + return 0; +} + +int arr_getByIndex3(gxArray* arr, uint16_t index, void** value, unsigned char checkSize) +{ + if (arr == NULL || value == NULL) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if (index >= arr->size) + { + if (checkSize || index >= arr->capacity) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + } + *value = arr->data[index]; + return 0; +} +#else +int arr_getByIndex(gxArray* arr, uint16_t index, void** value, uint16_t itemSize) +{ + if (arr == NULL || value == NULL) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if (index >= arr->size) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + *value = (void*)((unsigned char*)arr->data + (index * itemSize)); + return 0; +} +int arr_getByIndex3(gxArray* arr, uint16_t index, void** value, uint16_t itemSize, unsigned char checkSize) +{ + if (arr == NULL || value == NULL) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if (index >= arr->size) + { + if (checkSize || index >= arr->capacity) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + } + *value = (void*)((unsigned char*)arr->data + (index * itemSize)); + return 0; +} +#endif //DLMS_IGNORE_MALLOC + + +int arr_getByIndex2(gxArray* arr, uint16_t index, void** value, uint16_t itemSize) +{ +#ifndef DLMS_IGNORE_MALLOC + return arr_getByIndex(arr, index, value); +#else + return arr_getByIndex(arr, index, value, itemSize); +#endif //DLMS_IGNORE_MALLOC +} + +int arr_getByIndex4(gxArray* arr, uint16_t index, void** value, uint16_t itemSize, unsigned char checkSize) +{ +#ifndef DLMS_IGNORE_MALLOC + return arr_getByIndex3(arr, index, value, checkSize); +#else + return arr_getByIndex3(arr, index, value, itemSize, checkSize); +#endif //DLMS_IGNORE_MALLOC +} + +int arr_getByIndexRef(gxArray* arr, uint16_t index, void** value) +{ + if (arr == NULL || value == NULL) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if (index >= arr->size) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + *value = (void*)((gxArray**)arr->data)[index]; + return 0; +} + +int arr_setByIndexRef(gxArray* arr, void* value) +{ + if (!(arr->size < arr_getCapacity(arr))) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + ((gxArray**)arr->data)[arr->size] = value; + ++arr->size; + return 0; +} + + +void arr_clearKeyValuePair(gxArray* arr) +{ +#ifndef DLMS_IGNORE_MALLOC + gxKey* k; + int pos; + if (arr->capacity != 0) + { + for (pos = 0; pos != arr->size; ++pos) + { + k = (gxKey*)arr->data[pos]; + gxfree(k->key); + gxfree(k->value); + gxfree(k); + } + gxfree(arr->data); + arr->data = NULL; + arr->capacity = 0; + arr->size = 0; + arr->position = 0; + } +#else + arr_clear(arr); +#endif //DLMS_IGNORE_MALLOC +} + +void arr_clearStrings(gxArray* arr) +{ +#ifndef DLMS_IGNORE_MALLOC + gxByteBuffer* it; + int pos; + if (arr->capacity != 0) + { + for (pos = 0; pos != arr->size; ++pos) + { + it = (gxByteBuffer*)arr->data[pos]; + gxfree(it->data); + gxfree(it); + } + gxfree(arr->data); + arr->data = NULL; + arr->capacity = 0; + arr->size = 0; + arr->position = 0; + } +#else + arr_clear(arr); +#endif //DLMS_IGNORE_MALLOC +} + +#ifndef DLMS_IGNORE_MALLOC +int arr_removeByIndex(gxArray* arr, uint16_t index, void** value) +{ + int pos; + if (index >= arr->size) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + if (value != NULL) + { + *value = arr->data[index]; + } + for (pos = index; pos != arr->size; ++pos) + { + arr->data[pos] = arr->data[pos + 1]; + } + --arr->size; + return 0; +} +#else +int arr_removeByIndex( + gxArray* arr, + uint16_t index, + uint16_t itemSize) +{ + int ret; + uint16_t pos; + void* prev = NULL; + void* item = NULL; + if ((ret = arr_getByIndex(arr, index, &prev, itemSize)) == 0) + { + for (pos = index + 1; pos < arr->size; ++pos) + { + if ((ret = arr_getByIndex(arr, pos, &item, itemSize)) == 0) + { + memcpy(prev, item, itemSize); + prev = item; + } + } + --arr->size; + } + return 0; +} + +#endif //DLMS_IGNORE_MALLOC + +#ifndef DLMS_IGNORE_MALLOC +int arr_swap(gxArray* arr, uint16_t index1, uint16_t index2) +{ + void* tmp; + if (!(index1 < arr->size || index2 < arr->size)) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + tmp = arr->data[index1]; + arr->data[index1] = arr->data[index2]; + arr->data[index2] = tmp; + return 0; +} +#else +int arr_swap( + gxArray* arr, + uint16_t index1, + uint16_t index2, + uint16_t itemSize, + void* tmp) +{ + int ret; + void* prev = NULL; + void* item = NULL; + if ((ret = arr_getByIndex(arr, index1, &prev, itemSize)) == 0 && + (ret = arr_getByIndex(arr, index2, &item, itemSize)) == 0) + { + memcpy(tmp, prev, itemSize); + memcpy(prev, item, itemSize); + memcpy(item, tmp, itemSize); + } + return 0; +} +#endif //DLMS_IGNORE_MALLOC diff --git a/components/xt211/gxarray.h b/components/xt211/gxarray.h new file mode 100644 index 0000000..b54ef92 --- /dev/null +++ b/components/xt211/gxarray.h @@ -0,0 +1,165 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef GXARRAY_H +#define GXARRAY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include /* memset */ +#include "gxint.h" + +#define GXARRAY_CAPACITY 10 + + typedef struct + { +#ifndef DLMS_IGNORE_MALLOC + void** data; +#else + void* data; +#endif //DLMS_IGNORE_MALLOC + + uint16_t capacity; + uint16_t size; +#ifndef DLMS_IGNORE_MALLOC + int position; +#endif //DLMS_IGNORE_MALLOC + } gxArray; + + //Initialize gxArray. + void arr_init(gxArray* arr); + + void arr_attach( + gxArray* arr, + void* value, + uint16_t count, + uint16_t capacity); + /* + * Is static buffer used. + */ + char arr_isAttached( + gxArray* arr); + + /*Get maximum buffer size.*/ + uint16_t arr_getCapacity( + gxArray* arr); + + //Allocate new size for the array in bytes. + int arr_capacity(gxArray* arr, int capacity); + + +#ifndef DLMS_IGNORE_MALLOC + //Push new data to the gxArray. + int arr_push(gxArray* arr, void* item); +#endif //DLMS_IGNORE_MALLOC + + //Clear array. All items are automatically free. + void arr_clear(gxArray* arr); + + //Empty array but is not free items. + void arr_empty( + gxArray* arr); + + //Clear key value pair array. All items are automatically free. + void arr_clearKeyValuePair(gxArray* arr); + + //Clear string array. + void arr_clearStrings(gxArray* arr); + +#ifndef DLMS_IGNORE_MALLOC + int arr_get(gxArray* arr, void** value); + + int arr_getByIndex( + gxArray* arr, + uint16_t index, + void** value); + + int arr_getByIndex3( + gxArray* arr, + uint16_t index, + void** value, + unsigned char checkSize); + + int arr_removeByIndex( + gxArray* arr, + uint16_t index, + void** value); + + //Swap two array items. + int arr_swap(gxArray* arr, uint16_t index1, uint16_t index2); +#else + int arr_getByIndex( + gxArray* arr, + uint16_t index, + void** value, + uint16_t itemSize); + + int arr_getByIndex3( + gxArray* arr, + uint16_t index, + void** value, + uint16_t itemSize, + unsigned char checkSize); + + int arr_removeByIndex( + gxArray* arr, + uint16_t index, + uint16_t itemSize); + + //Swap two array items. + int arr_swap( + gxArray* arr, + uint16_t index1, + uint16_t index2, + uint16_t itemSize, + void* tmp); + + //This method is used to access array where items are saved with pointer. + //Example: registerAssignment. + int arr_getByIndexRef(gxArray* arr, uint16_t index, void** value); + + int arr_setByIndexRef(gxArray* arr, void* value); + +#endif //DLMS_IGNORE_MALLOC + + int arr_getByIndex2(gxArray* arr, uint16_t index, void** value, uint16_t itemSize); + int arr_getByIndex4(gxArray* arr, uint16_t index, void** value, uint16_t itemSize, unsigned char checkSize); + +#define ARR_ATTACH(X, V, S) arr_attach(&X, V, S, sizeof(V)/sizeof(V[0])) + +#ifdef __cplusplus +} +#endif + +#endif //GXARRAY_H diff --git a/components/xt211/gxdefine.h b/components/xt211/gxdefine.h new file mode 100644 index 0000000..e9a0731 --- /dev/null +++ b/components/xt211/gxdefine.h @@ -0,0 +1,148 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- +#ifndef GXDEFINE_H +#define GXDEFINE_H + +#ifdef __cplusplus +extern "C" { +#endif + +//Define max user name length. +#define MAX_USER_NAME_LENGTH 20 + +//Define max destination length. +#define MAX_DESTINATION_LENGTH 20 + +//Define max SAP logical device name length. +#define MAX_SAP_LOGICAL_DEVICE_NAME_LENGTH 20 + +//Define max season profile name length. +#define MAX_SEASON_PROFILE_NAME_LENGTH 20 + +//Define max season profile name length. +#define MAX_SEASON_PROFILE_NAME_LENGTH 20 + +//Define max season profile week name length. +#define MAX_SEASON_PROFILE_WEEK_NAME_LENGTH 20 + +//Define max week profile name length. +#define MAX_SEASON_WEEK_PROFILE_NAME_LENGTH 20 + +//Define max IP4 setup IP option data length. +#define MAX_IP4_SETUP_IP_OPTION_DATA_LENGTH 20 + +//Define max SAP item name length. +#define MAX_SAP_ITEM_NAME_LENGTH 20 + +//Define max modem initialization string length. +#define MAX_MODEM_INITIALIZATION_STRING_LENGTH 20 + +//Define max modem profile string length. +#define MAX_MODEM_PROFILE_STRING_LENGTH 20 + +//Define max certificate serial number length. +#define MAX_CERTIFICATE_SERIAL_NUMBER_LENGTH 20 + +//Define max certificate issuer length. +#define MAX_CERTIFICATE_ISSUER_LENGTH 40 + +//Define max certificate subject length. +#define MAX_CERTIFICATE_SUBJECT_LENGTH 20 + +//Define max function name length. +#define MAX_FUNCTION_NAME_LENGTH 10 + +//Define max function target length. +#define MAX_FUNCTION_TARGET_LENGTH 10 + +//Define max certificate subject alt length. +#define MAX_CERTIFICATE_SUBJECT_ALT_LENGTH 40 + +//Define max certificate subject alt length. +#define MAX_CAPTURE_DEFINITION_ELEMENT_LENGTH 100 + +//Define max certificate subject alt length. +#define MAX_CHARGE_TABLE_INDEX_LENGTH 100 + +//Define max certificate subject alt length. +#define MAX_TOKEN_GATEWAY_DESCRIPTION_LENGTH 20 + +//Define max image identification length. +#define MAX_IMAGE_IDENTIFICATION_LENGTH 20 + +//Define image signature length. +#define MAX_IMAGE_SIGNATURE_LENGTH 20 + +//Define max push setup target length. +#define MAX_PUSH_SETUP_TARGET_LENGTH 20 + +//Define max currency name length. +#define MAX_CURRENCY_NAME_LENGTH 20 + +//Define max client PDU size. +#define MAX_CLIENT_PDU_SIZE 200 + +//Define max capture object buffer size. +#define MAX_CAPTURE_OBJECT_BUFFER_SIZE 100 + +//Define max challenge size. +#define MAX_CHALLENGE_SIZE 64 + +//Define max register activation mask name length. +#define MAX_REGISTER_ACTIVATION_MASK_NAME_LENGTH 10 + +//Define max reporting system item name length. +#define MAX_REPORTING_SYSTEM_ITEM_LENGTH 20 + +//Define max SAP item count. This is used when data is serialized. +#define MAX_SAP_ITEM_SERIALIZE_COUNT 5 + +//Define key size for G3 MAC key table. +#define MAX_G3_MAC_KEY_TABLE_KEY_SIZE 16 + +//Define neighbour table gain item size for G3 MAC Setup object. +#define MAX_G3_MAC_NEIGHBOUR_TABLE_GAIN_ITEM_SIZE 6 + +//Define neighbour table gain size for G3 MAC Setup object. +#define MAX_G3_MAC_NEIGHBOUR_TABLE_GAIN_SIZE 5 + +//Define neighbour table tone map item size in bytes for G3 MAC Setup object. +#define MAX_G3_MAC_NEIGHBOUR_TABLE_TONE_MAP_ITEM_SIZE 3 + +//Define neighbour table tone map size for G3 MAC Setup object. +#define MAX_G3_MAC_NEIGHBOUR_TABLE_TONE_MAP_SIZE 5 + +#ifdef __cplusplus +} +#endif + +#endif //GXDEFINE_H diff --git a/components/xt211/gxget.c b/components/xt211/gxget.c new file mode 100644 index 0000000..09b8f3a --- /dev/null +++ b/components/xt211/gxget.c @@ -0,0 +1,6947 @@ +// +// -------------------------------------------------------------------------- +// 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 "gxignore.h" +#include "gxmem.h" +#if _MSC_VER > 1400 +#include +#endif +#include +#include + +#include "gxget.h" +#include "gxarray.h" +#include "bitarray.h" +#include "cosem.h" +#include "dlms.h" +#include "gxkey.h" +#include "helpers.h" +#include "serverevents.h" + +#ifdef DLMS_IGNORE_OBJECT_POINTERS +#define OBJECT_TYPE it->objectType +#define SCRIPT_LOGICAL_NAME action->scriptLogicalName +#else +#define OBJECT_TYPE it->target->objectType +#define SCRIPT_LOGICAL_NAME action->script == NULL ? EMPTY_LN : action->script->logicalName +#endif //DLMS_IGNORE_OBJECT_POINTERS + +int cosem_getByteBuffer(gxValueEventArg* e) +{ + if (e->value.vt != DLMS_DATA_TYPE_OCTET_STRING) + { + e->value.vt = DLMS_DATA_TYPE_OCTET_STRING; +#ifndef DLMS_IGNORE_MALLOC + if (e->value.byteArr == NULL) + { + e->value.byteArr = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + if (e->value.byteArr == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + BYTE_BUFFER_INIT(e->value.byteArr); + } +#endif //DLMS_IGNORE_MALLOC + } + e->byteArray = 1; + return 0; +} + +#ifndef DLMS_IGNORE_DATA +int cosem_getData(gxValueEventArg* e) +{ + int ret; + if (e->index == 2) + { + //Return plain value if request is coming from action. + if (e->action) + { + ret = var_copy(&e->value, &((gxData*)e->target)->value); + } + else + { + ret = cosem_setVariant(e->value.byteArr, &((gxData*)e->target)->value); + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_DATA +#ifndef DLMS_IGNORE_REGISTER +int cosem_getRegister( + gxValueEventArg* e) +{ + int ret; + gxByteBuffer* data = e->value.byteArr; + if (e->index == 2) + { + //Return plain value if request is coming from action. + if (e->action) + { + ret = var_copy(&e->value, &((gxRegister*)e->target)->value); + } + else + { + ret = cosem_setVariant(e->value.byteArr, &((gxRegister*)e->target)->value); + } + } + else if (e->index == 3) + { + if ((ret = cosem_setStructure(data, 2)) != 0 || + (ret = cosem_setInt8(data, ((gxRegister*)e->target)->scaler)) != 0 || + (ret = cosem_setEnum(data, ((gxRegister*)e->target)->unit)) != 0) + { + //Error code is returned at the end of the function. + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_REGISTER +#ifndef DLMS_IGNORE_REGISTER_TABLE +int cosem_getRegisterTable( + gxValueEventArg* e) +{ + int ret; + if (e->index == 2) + { + //TODO: ret = cosem_setVariant(e->value.byteArr, &((gxRegisterTable*)e->target)->value); + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + else if (e->index == 4) + { + gxByteBuffer* data = e->value.byteArr; + if ((ret = cosem_setStructure(data, 2)) != 0 || + (ret = cosem_setInt8(data, ((gxRegisterTable*)e->target)->scaler)) != 0 || + (ret = cosem_setEnum(data, ((gxRegisterTable*)e->target)->unit)) != 0) + { + //Error code is returned at the end of the function. + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_REGISTER_TABLE +#ifndef DLMS_IGNORE_CLOCK +int cosem_getClock( + gxValueEventArg* e) +{ + int ret; + if (e->index == 2) + { + ret = cosem_setDateTimeAsOctetString(e->value.byteArr, &((gxClock*)e->target)->time); + } + else if (e->index == 3) + { + ret = cosem_setInt16(e->value.byteArr, ((gxClock*)e->target)->timeZone); + } + else if (e->index == 4) + { + ret = cosem_setUInt8(e->value.byteArr, ((gxClock*)e->target)->status); + } + else if (e->index == 5) + { + ret = cosem_setDateTimeAsOctetString(e->value.byteArr, &((gxClock*)e->target)->begin); + } + else if (e->index == 6) + { + ret = cosem_setDateTimeAsOctetString(e->value.byteArr, &((gxClock*)e->target)->end); + } + else if (e->index == 7) + { + ret = cosem_setInt8(e->value.byteArr, ((gxClock*)e->target)->deviation); + } + else if (e->index == 8) + { + ret = cosem_setBoolean(e->value.byteArr, ((gxClock*)e->target)->enabled); + } + else if (e->index == 9) + { + ret = cosem_setEnum(e->value.byteArr, ((gxClock*)e->target)->clockBase); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_CLOCK +#ifndef DLMS_IGNORE_ACTION_SCHEDULE +int cosem_getActionSchedule( + gxValueEventArg* e) +{ + int ret = DLMS_ERROR_CODE_OK; + uint16_t pos; + gxtime* tm; + gxActionSchedule* object = (gxActionSchedule*)e->target; + gxByteBuffer* data = e->value.byteArr; + if (e->index == 2) + { + if ((ret = cosem_setStructure(data, 2)) != 0 || + //Add LN. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = hlp_setObjectCount(6, data)) != 0 || +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = bb_set(data, obj_getLogicalName((gxObject*)object->executedScript), 6)) != 0 || +#else + (ret = bb_set(data, object->executedScriptLogicalName, 6)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + //Add executed script selector. + (ret = cosem_setUInt16(data, object->executedScriptSelector)) != 0) + { + //Error code is returned at the end of the function. + } + } + else if (e->index == 3) + { + ret = cosem_setEnum(e->value.byteArr, object->type); + } + else if (e->index == 4) + { + if ((ret = cosem_setArray(data, object->executionTime.size)) == 0) + { + for (pos = 0; pos != object->executionTime.size; ++pos) + { + if ((ret = cosem_setStructure(data, 2)) != 0) + { + break; + } +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->executionTime, pos, (void**)&tm)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->executionTime, pos, (void**)&tm, sizeof(gxtime))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = cosem_setTimeAsOctetString(data, tm)) != 0 || + (ret = cosem_setDateAsOctetString(data, tm)) != 0) + { + break; + } + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_ACTION_SCHEDULE +#ifndef DLMS_IGNORE_ACTIVITY_CALENDAR +int getActivityCalendarDayProfileTable(gxArray* list, gxByteBuffer* ba) +{ + gxDayProfile* dp; + gxDayProfileAction* action; + int ret; + uint16_t pos, pos2; + if ((ret = cosem_setArray(ba, list->size)) != 0) + { + return ret; + } + for (pos = 0; pos != list->size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(list, pos, (void**)&dp)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(list, pos, (void**)&dp, sizeof(gxDayProfile))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = cosem_setStructure(ba, 2)) != 0 || + (ret = cosem_setUInt8(ba, dp->dayId)) != 0 || + //Add count + (ret = cosem_setArray(ba, dp->daySchedules.size)) != 0) + { + break; + } + for (pos2 = 0; pos2 != dp->daySchedules.size; ++pos2) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&dp->daySchedules, pos2, (void**)&action)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&dp->daySchedules, pos2, (void**)&action, sizeof(gxDayProfileAction))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = cosem_setStructure(ba, 3)) != 0 || + (ret = cosem_setTimeAsOctetString(ba, &action->startTime)) != 0 || + (ret = cosem_setOctetString2(ba, SCRIPT_LOGICAL_NAME, 6)) != 0 || + (ret = cosem_setUInt16(ba, action->scriptSelector)) != 0) + { + break; + } + } + } + return ret; +} + +int getActivityCalendarWeekProfileTable(gxArray* list, gxByteBuffer* ba) +{ + int ret = 0; + uint16_t pos; + gxWeekProfile* wp; + //Add count + if ((ret = cosem_setArray(ba, list->size)) != 0) + { + return ret; + } + for (pos = 0; pos != list->size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = cosem_setStructure(ba, 8)) != 0 || + (ret = arr_getByIndex(list, pos, (void**)&wp, sizeof(gxWeekProfile))) != 0 || + (ret = cosem_setOctetString2(ba, wp->name.value, wp->name.size)) != 0 || + (ret = cosem_setUInt8(ba, wp->monday)) != 0 || + (ret = cosem_setUInt8(ba, wp->tuesday)) != 0 || + (ret = cosem_setUInt8(ba, wp->wednesday)) != 0 || + (ret = cosem_setUInt8(ba, wp->thursday)) != 0 || + (ret = cosem_setUInt8(ba, wp->friday)) != 0 || + (ret = cosem_setUInt8(ba, wp->saturday)) != 0 || + (ret = cosem_setUInt8(ba, wp->sunday)) != 0) + { + break; + } +#else + if ((ret = cosem_setStructure(ba, 8)) != 0 || + (ret = arr_getByIndex(list, pos, (void**)&wp)) != 0 || + (ret = cosem_setOctetString(ba, &wp->name)) != 0 || + (ret = cosem_setUInt8(ba, wp->monday)) != 0 || + (ret = cosem_setUInt8(ba, wp->tuesday)) != 0 || + (ret = cosem_setUInt8(ba, wp->wednesday)) != 0 || + (ret = cosem_setUInt8(ba, wp->thursday)) != 0 || + (ret = cosem_setUInt8(ba, wp->friday)) != 0 || + (ret = cosem_setUInt8(ba, wp->saturday)) != 0 || + (ret = cosem_setUInt8(ba, wp->sunday)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +int getActivityCalendarSeasonProfile(gxArray* list, gxByteBuffer* ba) +{ + int ret = 0; + uint16_t pos; + gxSeasonProfile* sp; + //Add count + if ((ret = cosem_setArray(ba, list->size)) != 0) + { + return ret; + } + for (pos = 0; pos != list->size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(list, pos, (void**)&sp, sizeof(gxSeasonProfile))) != 0) + { + break; + } + if ((ret = cosem_setStructure(ba, 3)) != 0 || + //Add name. + (ret = cosem_setOctetString2(ba, sp->name.value, sp->name.size)) != 0 || + //Add start time. + (ret = cosem_setDateTimeAsOctetString(ba, &sp->start)) != 0 || + //Add week day. + (ret = cosem_setOctetString2(ba, sp->weekName.value, sp->weekName.size)) != 0) + { + break; + } +#else + if ((ret = cosem_setStructure(ba, 3)) != 0 || + (ret = arr_getByIndex(list, pos, (void**)&sp)) != 0 || + //Add name. + (ret = cosem_setOctetString(ba, &sp->name)) != 0 || + //Add start time. + (ret = cosem_setDateTimeAsOctetString(ba, &sp->start)) != 0 || + //Add week day. + (ret = cosem_setOctetString(ba, &sp->weekName)) != 0) + { + break; + } + +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +int getActivityCalendarName( + gxByteBuffer* name, + gxByteBuffer* ba) +{ + return cosem_setOctetString(ba, name); +} + +int cosem_getActivityCalendar( + gxValueEventArg* e) +{ + int ret; + gxByteBuffer* data = e->value.byteArr; + gxActivityCalendar* object = (gxActivityCalendar*)e->target; + if (e->index == 2) + { + ret = getActivityCalendarName(&object->calendarNameActive, data); + } + else if (e->index == 3) + { + ret = getActivityCalendarSeasonProfile(&object->seasonProfileActive, data); + } + else if (e->index == 4) + { + ret = getActivityCalendarWeekProfileTable(&object->weekProfileTableActive, data); + } + else if (e->index == 5) + { + ret = getActivityCalendarDayProfileTable(&object->dayProfileTableActive, data); + } + else if (e->index == 6) + { + ret = getActivityCalendarName(&object->calendarNamePassive, data); + } + else if (e->index == 7) + { + ret = getActivityCalendarSeasonProfile(&object->seasonProfilePassive, data); + } + else if (e->index == 8) + { + ret = getActivityCalendarWeekProfileTable(&object->weekProfileTablePassive, data); + } + else if (e->index == 9) + { + ret = getActivityCalendarDayProfileTable(&object->dayProfileTablePassive, data); + } + else if (e->index == 10) + { + ret = cosem_setDateTimeAsOctetString(data, &object->time); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_ACTIVITY_CALENDAR +#ifndef DLMS_IGNORE_SERVER +int getLNAccessRights( + dlmsSettings* settings, + gxObject* object, + gxByteBuffer* data) +{ + unsigned char pos, cnt; + int ret; + unsigned char ch; + cnt = obj_attributeCount(object); + if ((ret = cosem_setStructure(data, 2)) != 0 || + (ret = cosem_setArray(data, cnt)) != 0) + { + return ret; + } + for (pos = 1; pos != cnt + 1; ++pos) + { + ch = (unsigned char)svr_getAttributeAccess(settings, object, pos); + //attribute_access_item + if ((ret = cosem_setStructure(data, 3)) != 0 || + //Add index. + (ret = cosem_setInt8(data, pos)) != 0 || + //Add value. + (ret = cosem_setEnum(data, ch)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_NONE)) != 0) + { + return ret; + } + } +#ifdef INDIAN_STANDARD + if ((ret = cosem_setArray(data, 0)) != 0) + { + return ret; + } +#else + cnt = obj_methodCount(object); + if ((ret = cosem_setArray(data, cnt)) != 0) + { + return ret; + } + for (pos = 1; pos != cnt + 1; ++pos) + { + ch = (unsigned char)svr_getMethodAccess(settings, object, pos); + //attribute_access_item + if ((ret = cosem_setStructure(data, 2)) != 0 || + //Add index. + (ret = cosem_setInt8(data, pos)) != 0 || + //Add value. + (ret = cosem_setEnum(data, ch)) != 0) + { + return ret; + } + } +#endif //INDIAN_STANDARD + return 0; +} +#endif //DLMS_IGNORE_SERVER + +#ifndef DLMS_IGNORE_SERVER + +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME +// Returns LN Association View. +int getLNObjects( + dlmsSettings* settings, + gxValueEventArg* e, + gxByteBuffer* data) +{ + uint16_t pduSize = 0; + gxAssociationLogicalName* object = (gxAssociationLogicalName*)e->target; + int ret; + uint16_t pos; + unsigned char found = 0; + gxObject* it, * it2; + static const unsigned char ln[] = { 0, 0, 40, 0, 0, 255 }; + if ((ret = bb_capacity(data, settings->maxPduSize)) != 0) + { + return ret; + } + //Add count only for first time. + if (!e->transaction) + { + uint16_t count = object->objectList.size; + //Find current association and if nout found add it. + for (pos = 0; pos != object->objectList.size; ++pos) + { + if ((ret = oa_getByIndex(&object->objectList, pos, &it)) != 0) + { + return ret; + } + if (e->target != it && it->objectType == DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME) + { + if (memcmp(ln, it->logicalName, 6) == 0) + { + found = 1; + } + else + { + //Remove extra association view. + --count; + } + } + } + //Remove objects that are only internal use. + for (pos = 0; pos != settings->internalObjects.size; ++pos) + { + if ((ret = oa_getByIndex(&settings->internalObjects, pos, &it)) != 0) + { + return ret; + } + oa_findByLN(&object->objectList, it->objectType, it->logicalName, &it2); + if (it2 != NULL) + { + --count; + } + } + if (!found) + { + ++count; + } + e->transactionEndIndex = count; + if ((ret = cosem_setArray(data, count)) != 0) + { + return ret; + } + if (!found) + { + //Count + if ((ret = cosem_setStructure(data, 4)) != 0 || + //ClassID + (ret = cosem_setUInt16(data, DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME)) != 0 || + //Version + (ret = cosem_setUInt8(data, object->base.version)) != 0 || + //LN. + (ret = cosem_setOctetString2(data, ln, 6)) != 0) + { + return ret; + } + //Access rights. + ret = getLNAccessRights(settings, &object->base, data); + if (ret != 0) + { + return ret; + } + } + } + uint16_t pos2 = 0; + for (pos = 0; pos != object->objectList.size; ++pos) + { + ret = oa_getByIndex(&object->objectList, pos, &it); + if (ret != 0) + { + return ret; + } + //Remove objects that are only for internal use. + if ((ret = oa_findByLN(&settings->internalObjects, it->objectType, it->logicalName, &it2)) != 0) + { + break; + } + //If this is not ignored. + if (it2 == NULL) + { + if (it->objectType == DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME) + { + if (!(it == e->target || memcmp(ln, it->logicalName, 6) == 0)) + { + continue; + } + } + if (!(pos2 < (uint16_t)e->transactionStartIndex)) + { + pduSize = (uint16_t)data->size; + //Count + if ((ret = cosem_setStructure(data, 4)) != 0 || + //ClassID + (ret = cosem_setUInt16(data, it->objectType)) != 0 || + //Version + (ret = cosem_setUInt8(data, (unsigned char)it->version)) != 0 || + //LN. + (ret = cosem_setOctetString2(data, it->logicalName, 6)) != 0) + { + break; + } + //Access rights. + ret = getLNAccessRights(settings, it, data); + if (ret != 0) + { + break; + } + if (settings->server) + { + //If PDU is full. + if (!e->skipMaxPduSize && dlms_isPduFull(settings, data, NULL)) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + } + ++e->transactionStartIndex; + } + ++pos2; + } + } + if (ret == DLMS_ERROR_CODE_OUTOFMEMORY) + { + data->size = pduSize; + ret = 0; + } + else if (pos == object->objectList.size) + { + //If all objects fit to one PDU. + e->transactionEndIndex = e->transactionStartIndex = 0; + } + return ret; +} +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME +#endif //DLMS_IGNORE_SERVER + +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME +/* +* Returns User list. +*/ +int getUserList( + dlmsSettings* settings, + gxValueEventArg* e, + gxByteBuffer* data) +{ + unsigned char len; + uint16_t pos = 0; + int ret; +#ifndef DLMS_IGNORE_MALLOC + gxKey2* it; +#else + gxUser* it; +#endif //DLMS_IGNORE_MALLOC + unsigned id; + char* name; + gxAssociationLogicalName* target = (gxAssociationLogicalName*)e->target; + // Add count only for first time. + if (e->transactionStartIndex == 0) + { + e->transactionEndIndex = target->userList.size; + if ((ret = cosem_setArray(data, target->userList.size)) != 0) + { + return ret; + } + } + for (pos = (uint16_t)e->transactionStartIndex; pos < target->userList.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&target->userList, pos, (void**)&it)) != 0) + { + break; + } + id = it->key; + name = it->value; + len = (unsigned char)strlen(name); +#else + if ((ret = arr_getByIndex(&target->userList, pos, (void**)&it, sizeof(gxUser))) != 0) + { + break; + } + id = it->id; + name = it->name; + len = (unsigned char)strlen(it->name); +#endif //DLMS_IGNORE_MALLOC + // Count + if ((ret = cosem_setStructure(data, 2)) != 0 || + // Id + (ret = cosem_setUInt8(data, (unsigned char)id)) != 0 || + // Name + (ret = cosem_setOctetString2(data, (unsigned char*)name, len)) != 0) + { + return ret; + } + ++e->transactionStartIndex; + } + return 0; +} + +int cosem_getAssociationLogicalName( + dlmsSettings* settings, + gxValueEventArg* e) +{ + int ret = 0; + gxAssociationLogicalName* object = ((gxAssociationLogicalName*)e->target); + gxByteBuffer* data = e->value.byteArr; + if (e->index == 2) + { +#ifndef DLMS_IGNORE_SERVER + ret = getLNObjects(settings, e, data); +#endif //DLMS_IGNORE_SERVER + } + else if (e->index == 3) + { + //Add count + if ((ret = cosem_setStructure(data, 2)) != 0 || + (ret = cosem_setInt8(data, object->clientSAP)) != 0 || + (ret = cosem_setUInt16(data, object->serverSAP)) != 0) + { + } + } + else if (e->index == 4) + { + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + //Add count + (ret = bb_setUInt8(data, 0x7)) != 0 || + (ret = bb_setUInt8(data, 0x60)) != 0 || + (ret = bb_setUInt8(data, 0x85)) != 0 || + (ret = bb_setUInt8(data, 0x74)) != 0 || + //Add data. + (ret = bb_setUInt8(data, object->applicationContextName.identifiedOrganization)) != 0 || + (ret = bb_setUInt8(data, object->applicationContextName.dlmsUA)) != 0 || + (ret = bb_setUInt8(data, object->applicationContextName.applicationContext)) != 0 || + (ret = bb_setUInt8(data, object->applicationContextName.contextId)) != 0) + { + } + } + else if (e->index == 5) + { + unsigned char buff[4]; + gxByteBuffer tmp; + bb_attach(&tmp, buff, 0, sizeof(buff)); + //Add count + if ((ret = cosem_setStructure(data, 6)) != 0 || + //Add data. + (ret = cosem_setBitString(data, object->xDLMSContextInfo.conformance, 24)) != 0 || + (ret = cosem_setUInt16(data, object->xDLMSContextInfo.maxReceivePduSize)) != 0 || + (ret = cosem_setUInt16(data, object->xDLMSContextInfo.maxSendPduSize)) != 0 || + (ret = cosem_setUInt8(data, object->xDLMSContextInfo.dlmsVersionNumber)) != 0 || + (ret = cosem_setInt8(data, object->xDLMSContextInfo.qualityOfService)) != 0 || + (ret = cosem_setOctetString(data, &object->xDLMSContextInfo.cypheringInfo)) != 0) + { + } + } + else if (e->index == 6) + { + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + //Add count + (ret = bb_setUInt8(data, 0x7)) != 0 || + //Add data. + (ret = bb_setUInt8(data, 0x60)) != 0 || + (ret = bb_setUInt8(data, 0x85)) != 0 || + (ret = bb_setUInt8(data, 0x74)) != 0 || + (ret = bb_setUInt8(data, object->authenticationMechanismName.identifiedOrganization)) != 0 || + (ret = bb_setUInt8(data, object->authenticationMechanismName.dlmsUA)) != 0 || + (ret = bb_setUInt8(data, object->authenticationMechanismName.authenticationMechanismName)) != 0 || + (ret = bb_setUInt8(data, (unsigned char)object->authenticationMechanismName.mechanismId)) != 0) + { + return ret; + } + } + else if (e->index == 7) + { + ret = cosem_setOctetString(e->value.byteArr, &object->secret); + } + else if (e->index == 8) + { + ret = cosem_setEnum(e->value.byteArr, object->associationStatus); + } + else if (e->index == 9) + { +#if !(defined(DLMS_IGNORE_OBJECT_POINTERS) || defined(DLMS_IGNORE_SECURITY_SETUP)) + ret = cosem_setOctetString2(e->value.byteArr, obj_getLogicalName((gxObject*)object->securitySetup), 6); +#else + ret = cosem_setOctetString2(e->value.byteArr, object->securitySetupReference, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + else if (e->index == 10) + { + ret = getUserList(settings, e, e->value.byteArr); + } + else if (e->index == 11) + { + // Add structure size. + if ((ret = cosem_setStructure(data, 2)) != 0) + { + return ret; + } +#ifdef DLMS_IGNORE_MALLOC + char* str = (char*)object->currentUser.name; + unsigned char len = (unsigned char)strlen(str); + if ((ret = cosem_setUInt8(data, object->currentUser.id)) != 0 || + (ret = cosem_setOctetString2(data, (unsigned char*)str, len)) != 0) + { + return ret; + } +#else + if (object->currentUser.value == NULL) + { + if ((ret = cosem_setUInt8(data, 0)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRING)) != 0 || + (ret = bb_setUInt8(data, 0)) != 0) + { + return ret; + } + } + else + { + char* str = (char*)object->currentUser.value; + unsigned char len = (unsigned char)strlen(str); + if ((ret = cosem_setUInt8(data, object->currentUser.key)) != 0 || + (ret = cosem_setOctetString2(data, (unsigned char*)str, len)) != 0) + { + return ret; + } + } +#endif //DLMS_IGNORE_MALLOC + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME +// Returns SN Association View. +int getSNObjects( + dlmsSettings* settings, + gxValueEventArg* e, + gxByteBuffer* ba) +{ + uint16_t pduSize = 0; + objectArray* list = &((gxAssociationShortName*)e->target)->objectList; + uint16_t pos; + int ret = DLMS_ERROR_CODE_OK; + gxObject* it; + if ((ret = bb_capacity(ba, settings->maxPduSize)) != 0) + { + return ret; + } + //Add count only for first time. + if (!e->transaction) + { + e->transactionEndIndex = list->size; + //Add count + if ((ret = cosem_setArray(ba, list->size)) != 0) + { + return ret; + } + } + for (pos = (uint16_t)e->transactionStartIndex; pos != list->size; ++pos) + { + pduSize = (uint16_t)ba->size; + if ((ret = oa_getByIndex(list, pos, &it)) != 0 || + //Count + (ret = cosem_setStructure(ba, 4)) != 0 || + //Base address. + (ret = cosem_setInt16(ba, it->shortName)) != 0 || + //ClassID. + (ret = cosem_setUInt16(ba, it->objectType)) != 0 || + //Version. + (ret = cosem_setUInt8(ba, (unsigned char)it->version)) != 0 || + //LN. + (ret = cosem_setOctetString2(ba, it->logicalName, 6)) != 0) + { + break; + } + if (settings->server) + { + //If PDU is full. + if (dlms_isPduFull(settings, ba, NULL)) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + } + ++e->transactionStartIndex; + } + if (ret == DLMS_ERROR_CODE_OUTOFMEMORY) + { + ba->size = pduSize; + ret = 0; + } + return ret; +} + +#ifndef DLMS_IGNORE_SERVER +int getSNAccessRights( + dlmsSettings* settings, + gxObject* object, + gxByteBuffer* ba) +{ + int ret; + unsigned char ch, pos, cnt; + cnt = obj_attributeCount(object); + if ((ret = cosem_setStructure(ba, 3)) != 0 || + //Add SN. + (ret = cosem_setUInt16(ba, object->shortName)) != 0 || + //Add attribute access modes. + (ret = cosem_setArray(ba, cnt)) != 0) + { + return ret; + } + for (pos = 1; pos != cnt + 1; ++pos) + { + ch = (unsigned char)svr_getAttributeAccess(settings, object, pos); + if ((ret = cosem_setStructure(ba, 3)) != 0 || + //Add index. + (ret = cosem_setInt8(ba, pos)) != 0 || + //Add access. + (ret = cosem_setEnum(ba, ch)) != 0 || + //Add None. + (ret = bb_setUInt8(ba, DLMS_DATA_TYPE_NONE)) != 0) + { + return ret; + } + } + //Add mthod access modes. + cnt = obj_methodCount(object); + if ((ret = cosem_setArray(ba, cnt)) == 0) + { + for (pos = 1; pos != cnt + 1; ++pos) + { + ch = (unsigned char)svr_getMethodAccess(settings, object, pos); + if ((ret = cosem_setStructure(ba, 3)) != 0 || + //Add index. + (ret = cosem_setInt8(ba, pos)) != 0 || + //Add access. + (ret = cosem_setEnum(ba, ch)) != 0) + { + return ret; + } + } + } + return ret; +} + +int cosem_getAssociationShortName( + dlmsSettings* settings, + gxValueEventArg* e) +{ + int ret = DLMS_ERROR_CODE_OK; + uint16_t pos; + gxObject* it; + gxAssociationShortName* object = (gxAssociationShortName*)e->target; + gxByteBuffer* data = e->value.byteArr; + if (e->index == 2) + { + ret = getSNObjects(settings, e, data); + } + else if (e->index == 3) + { + if ((ret = cosem_setArray(data, object->objectList.size)) == 0) + { + for (pos = 0; pos != object->objectList.size; ++pos) + { + if ((ret = oa_getByIndex(&object->objectList, pos, &it)) != 0 || + (ret = getSNAccessRights(settings, it, data)) != 0) + { + break; + } + } + } + } + else if (e->index == 4) + { +#if !(defined(DLMS_IGNORE_OBJECT_POINTERS) || defined(DLMS_IGNORE_SECURITY_SETUP)) + ret = cosem_setOctetString2(e->value.byteArr, obj_getLogicalName((gxObject*)object->securitySetup), 6); +#else + ret = cosem_setOctetString2(e->value.byteArr, object->securitySetupReference, 6); +#endif //!(defined(DLMS_IGNORE_OBJECT_POINTERS) || defined(DLMS_IGNORE_SECURITY_SETUP)) + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SERVER +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + +#ifndef DLMS_IGNORE_AUTO_ANSWER +int cosem_getAutoAnswer( + gxValueEventArg* e) +{ + int ret = 0; + uint16_t pos; + gxAutoAnswer* object = (gxAutoAnswer*)e->target; + gxByteBuffer* data = e->value.byteArr; + if (e->index == 2) + { + ret = cosem_setEnum(data, object->mode); + } + else if (e->index == 3) + { +#ifndef DLMS_IGNORE_MALLOC + gxKey* kv; +#else + gxTimePair* kv; +#endif //DLMS_IGNORE_MALLOC + if ((ret = cosem_setArray(data, object->listeningWindow.size)) == 0) + { + for (pos = 0; pos != object->listeningWindow.size; ++pos) + { + if ((ret = cosem_setStructure(data, 2)) != 0) + { + break; + } +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->listeningWindow, pos, (void**)&kv)) != 0 || + (ret = cosem_setDateTimeAsOctetString(data, (gxtime*)kv->key)) != 0 || + (ret = cosem_setDateTimeAsOctetString(data, (gxtime*)kv->value)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->listeningWindow, pos, (void**)&kv, sizeof(gxTimePair))) != 0 || + //start_time + (ret = cosem_setDateTimeAsOctetString(data, &kv->first)) != 0 || + //end_time + (ret = cosem_setDateTimeAsOctetString(data, &kv->second)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + } + else if (e->index == 4) + { + ret = cosem_setEnum(data, object->status); + } + else if (e->index == 5) + { + ret = cosem_setUInt8(data, object->numberOfCalls); + } + else if (e->index == 6) + { + if ((ret = cosem_setStructure(data, 2)) != 0 || + (ret = cosem_setUInt8(data, object->numberOfRingsInListeningWindow)) != 0 || + (ret = cosem_setUInt8(data, object->numberOfRingsOutListeningWindow)) != 0) + { + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_AUTO_ANSWER +#ifndef DLMS_IGNORE_AUTO_CONNECT +int cosem_getAutoConnect( + gxValueEventArg* e) +{ + int ret = DLMS_ERROR_CODE_OK; + uint16_t pos; +#ifndef DLMS_IGNORE_MALLOC + gxKey* k; + gxByteBuffer* it; +#else + gxTimePair* k; + gxDestination* it; +#endif //DLMS_IGNORE_MALLOC + gxAutoConnect* object = (gxAutoConnect*)e->target; + gxByteBuffer* data = e->value.byteArr; + if (e->index == 2) + { + ret = cosem_setEnum(data, object->mode); + } + else if (e->index == 3) + { + ret = cosem_setUInt8(data, object->repetitions); + } + else if (e->index == 4) + { + ret = cosem_setUInt16(data, object->repetitionDelay); + } + else if (e->index == 5) + { + //Add count + if ((ret = cosem_setArray(data, object->callingWindow.size)) != 0) + { + return ret; + } + for (pos = 0; pos != object->callingWindow.size; ++pos) + { + if ((ret = cosem_setStructure(data, 2)) != 0) + { + break; + } +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->callingWindow, pos, (void**)&k)) != 0 || + (ret = cosem_setDateTimeAsOctetString(data, (gxtime*)k->key)) != 0 || + (ret = cosem_setDateTimeAsOctetString(data, (gxtime*)k->value)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->callingWindow, pos, (void**)&k, sizeof(gxTimePair))) != 0) + { + break; + } + if ((ret = cosem_setDateTimeAsOctetString(data, &k->first)) != 0 || + (ret = cosem_setDateTimeAsOctetString(data, &k->second)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + else if (e->index == 6) + { + //Add count + if ((ret = cosem_setArray(data, object->destinations.size)) != 0) + { + return ret; + } + for (pos = 0; pos != object->destinations.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->destinations, pos, (void**)&it)) != 0 || + (ret = cosem_setOctetString(data, it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->destinations, pos, (void**)&it, sizeof(gxDestination))) != 0 || + (ret = cosem_setOctetString2(data, it->value, it->size)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_AUTO_CONNECT +#ifndef DLMS_IGNORE_DEMAND_REGISTER +int cosem_getDemandRegister( + gxValueEventArg* e) +{ + int ret; + gxByteBuffer* data = e->value.byteArr; + gxDemandRegister* object = (gxDemandRegister*)e->target; + switch (e->index) + { + case 2: + //Return plain value if request is coming from action. + if (e->action) + { + ret = var_copy(&e->value, &object->currentAverageValue); + } + else + { + ret = cosem_setVariant(data, &object->currentAverageValue); + } + break; + case 3: + //Return plain value if request is coming from action. + if (e->action) + { + ret = var_copy(&e->value, &object->lastAverageValue); + } + else + { + ret = cosem_setVariant(data, &object->lastAverageValue); + } + break; + case 4: + if ((ret = cosem_setStructure(data, 2)) != 0 || + (ret = cosem_setInt8(data, object->scaler)) != 0 || + (ret = cosem_setEnum(data, object->unit)) != 0) + { + } + break; + case 5: + //Return plain value if request is coming from action. + if (e->action) + { + ret = var_copy(&e->value, &object->status); + } + else + { + ret = cosem_setVariant(data, &object->status); + } + break; + case 6: + ret = cosem_setDateTimeAsOctetString(data, &object->captureTime); + break; + case 7: + ret = cosem_setDateTimeAsOctetString(data, &object->startTimeCurrent); + break; + case 8: + ret = cosem_setUInt32(data, object->period); + break; + case 9: + ret = cosem_setUInt16(data, object->numberOfPeriods); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_DEMAND_REGISTER +#ifndef DLMS_IGNORE_MAC_ADDRESS_SETUP +int cosem_getMacAddressSetup( + gxValueEventArg* e) +{ + int ret = 0; + if (e->index == 2) + { + gxMacAddressSetup* object = (gxMacAddressSetup*)e->target; + ret = cosem_setOctetString(e->value.byteArr, &object->macAddress); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_MAC_ADDRESS_SETUP +#ifndef DLMS_IGNORE_EXTENDED_REGISTER +int cosem_getExtendedRegister( + gxValueEventArg* e) +{ + int ret = DLMS_ERROR_CODE_OK; + gxExtendedRegister* object = (gxExtendedRegister*)e->target; + gxByteBuffer* data = e->value.byteArr; + if (e->index == 2) + { + //Return plain value if request is coming from action. + if (e->action) + { + ret = var_copy(&e->value, &object->value); + } + else + { + ret = cosem_setVariant(data, &object->value); + } + } + else if (e->index == 3) + { + if ((ret = cosem_setStructure(data, 2)) != 0 || + (ret = cosem_setInt8(data, object->scaler)) != 0 || + (ret = cosem_setUInt8(data, object->unit)) != 0) + { + return ret; + } + } + else if (e->index == 4) + { + //Return plain value if request is coming from action. + if (e->action) + { + ret = var_copy(&e->value, &object->status); + } + else + { + ret = cosem_setVariant(data, &object->status); + } + } + else if (e->index == 5) + { + ret = cosem_setDateTimeAsOctetString(data, &object->captureTime); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_EXTENDED_REGISTER + +#ifndef DLMS_IGNORE_GPRS_SETUP +int cosem_getQualityOfService(gxQualityOfService* service, gxByteBuffer* ba) +{ + int ret; + if ((ret = cosem_setStructure(ba, 5)) != 0 || + //Precedence + (ret = cosem_setUInt8(ba, service->precedence)) != 0 || + //Delay + (ret = cosem_setUInt8(ba, service->delay)) != 0 || + //Reliability + (ret = cosem_setUInt8(ba, service->reliability)) != 0 || + //PeakThroughput + (ret = cosem_setUInt8(ba, service->peakThroughput)) != 0 || + //MeanThroughput + (ret = cosem_setUInt8(ba, service->meanThroughput)) != 0) + { + } + return ret; +} + +int cosem_getGprsSetup( + gxValueEventArg* e) +{ + int ret; + gxGPRSSetup* object = (gxGPRSSetup*)e->target; + gxByteBuffer* data = e->value.byteArr; + if (e->index == 2) + { + ret = cosem_setOctetString(data, &object->apn); + } + else if (e->index == 3) + { + ret = cosem_setUInt16(data, object->pinCode); + } + else if (e->index == 4) + { + if ((ret = cosem_setStructure(data, 2)) != 0 || + (ret = cosem_getQualityOfService(&object->defaultQualityOfService, data)) != 0 || + (ret = cosem_getQualityOfService(&object->requestedQualityOfService, data)) != 0) + { + return ret; + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_GPRS_SETUP +#ifndef DLMS_IGNORE_SECURITY_SETUP +int cosem_getSecuritySetup( + gxValueEventArg* e) +{ + int ret; + gxSecuritySetup* object = (gxSecuritySetup*)e->target; + gxByteBuffer* data = e->value.byteArr; + if (e->index == 2) + { + ret = cosem_setEnum(data, object->securityPolicy); + } + else if (e->index == 3) + { + ret = cosem_setEnum(data, object->securitySuite); + } + else if (e->index == 4) + { + ret = cosem_setOctetString(data, &object->clientSystemTitle); + } + else if (e->index == 5) + { + ret = cosem_setOctetString(data, &object->serverSystemTitle); + } + else if (e->index == 6) + { + gxCertificateInfo* it; + uint16_t pos, len; + if ((ret = cosem_setArray(data, object->certificates.size)) == 0) + { + for (pos = 0; pos != object->certificates.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->certificates, pos, (void**)&it, sizeof(gxCertificateInfo))) != 0 || +#else + if ((ret = arr_getByIndex(&object->certificates, pos, (void**)&it)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = cosem_setStructure(data, 6)) != 0 || + (ret = cosem_setEnum(data, it->entity)) != 0 || + (ret = cosem_setEnum(data, it->type)) != 0) + { + break; + } + len = (uint16_t)strlen(it->serialNumber); + if ((ret = cosem_setOctetString2(data, (unsigned char*)it->serialNumber, len)) != 0) + { + break; + } + len = (uint16_t)strlen(it->issuer); + if ((ret = cosem_setOctetString2(data, (unsigned char*)it->issuer, len)) != 0) + { + break; + } + len = (uint16_t)strlen(it->subject); + if ((ret = cosem_setOctetString2(data, (unsigned char*)it->subject, len)) != 0) + { + break; + } + len = (uint16_t)strlen(it->subjectAltName); + if ((ret = cosem_setOctetString2(data, (unsigned char*)it->subjectAltName, len)) != 0) + { + break; + } + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} + +#endif //DLMS_IGNORE_SECURITY_SETUP +#ifndef DLMS_IGNORE_IEC_HDLC_SETUP +int cosem_getIecHdlcSetup( + gxValueEventArg* e) +{ + int ret; + gxIecHdlcSetup* object = (gxIecHdlcSetup*)e->target; + switch (e->index) + { + case 2: + ret = cosem_setEnum(e->value.byteArr, object->communicationSpeed); + break; + case 3: + ret = cosem_setUInt8(e->value.byteArr, object->windowSizeTransmit); + break; + case 4: + ret = cosem_setUInt8(e->value.byteArr, object->windowSizeReceive); + break; + case 5: + ret = cosem_setUInt16(e->value.byteArr, object->maximumInfoLengthTransmit); + break; + case 6: + ret = cosem_setUInt16(e->value.byteArr, object->maximumInfoLengthReceive); + break; + case 7: + ret = cosem_setUInt16(e->value.byteArr, object->interCharachterTimeout); + break; + case 8: + ret = cosem_setUInt16(e->value.byteArr, object->inactivityTimeout); + break; + case 9: + ret = cosem_setUInt16(e->value.byteArr, object->deviceAddress); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_IEC_HDLC_SETUP +#ifndef DLMS_IGNORE_IEC_LOCAL_PORT_SETUP +int cosem_getIecLocalPortSetup( + gxValueEventArg* e) +{ + int ret; + gxLocalPortSetup* object = (gxLocalPortSetup*)e->target; + if (e->index == 2) + { + ret = cosem_setEnum(e->value.byteArr, object->defaultMode); + } + else if (e->index == 3) + { + ret = cosem_setEnum(e->value.byteArr, object->defaultBaudrate); + } + else if (e->index == 4) + { + ret = cosem_setEnum(e->value.byteArr, object->proposedBaudrate); + } + else if (e->index == 5) + { + ret = cosem_setEnum(e->value.byteArr, object->responseTime); + } + else if (e->index == 6) + { + ret = cosem_setOctetString(e->value.byteArr, &object->deviceAddress); + } + else if (e->index == 7) + { + ret = cosem_setOctetString(e->value.byteArr, &object->password1); + } + else if (e->index == 8) + { + ret = cosem_setOctetString(e->value.byteArr, &object->password2); + } + else if (e->index == 9) + { + ret = cosem_setOctetString(e->value.byteArr, &object->password5); + } + else + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif // DLMS_IGNORE_IEC_LOCAL_PORT_SETUP + +#ifndef DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP +int cosem_getIecTwistedPairSetup( + gxValueEventArg* e) +{ + unsigned char ch; + int pos, ret = 0; + gxIecTwistedPairSetup* object = (gxIecTwistedPairSetup*)e->target; + gxByteBuffer* data = e->value.byteArr; + if (e->index == 2) + { + ret = cosem_setEnum(e->value.byteArr, object->mode); + } + else if (e->index == 3) + { + ret = cosem_setEnum(e->value.byteArr, object->speed); + } + else if (e->index == 4) + { + if ((ret = cosem_setArray(data, (unsigned short)object->primaryAddresses.size)) == 0) + { + for (pos = 0; pos != object->primaryAddresses.size; ++pos) + { + if ((ret = bb_getUInt8ByIndex(&object->primaryAddresses, pos, &ch)) != 0 || + (ret = cosem_setUInt8(data, ch)) != 0) + { + break; + } + } + } + } + else if (e->index == 5) + { + if ((ret = cosem_setArray(data, (unsigned short)object->tabis.size)) == 0) + { + for (pos = 0; pos != object->tabis.size; ++pos) + { + if ((ret = bb_getUInt8ByIndex(&object->tabis, pos, &ch)) != 0 || + (ret = cosem_setInt8(data, (char)ch)) != 0) + { + break; + } + } + } + } + else + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP + +#ifndef DLMS_IGNORE_IP4_SETUP +int cosem_getIP4Setup( + gxValueEventArg* e) +{ + int ret = 0; + uint16_t pos; +#if !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + dlmsVARIANT* tmp; +#endif //!defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + gxip4SetupIpOption* it; + gxIp4Setup* object = (gxIp4Setup*)e->target; + gxByteBuffer* data = e->value.byteArr; + if (e->index == 2) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if (object->dataLinkLayer == NULL) + { + ret = cosem_setOctetString2(data, EMPTY_LN, 6); + } + else + { + ret = cosem_setOctetString2(data, object->dataLinkLayer->logicalName, 6); + //Error code is returned at the end of the function. + } +#else + ret = cosem_setOctetString2(e->value.byteArr, object->dataLinkLayerReference, 6); + { + //Error code is returned at the end of the function. + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + else if (e->index == 3) + { + ret = cosem_setUInt32(data, object->ipAddress); + } + else if (e->index == 4) + { + if ((ret = cosem_setArray(data, object->multicastIPAddress.size)) == 0) + { +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + uint32_t* v; + for (pos = 0; pos != object->multicastIPAddress.size; ++pos) + { + if ((ret = arr_getByIndex2(&object->multicastIPAddress, pos, (void**)&v, sizeof(uint32_t))) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT32)) != 0 || + (ret = bb_setUInt32(data, *v)) != 0) + { + break; + } + } +#else + for (pos = 0; pos != object->multicastIPAddress.size; ++pos) + { + if ((ret = va_getByIndex(&object->multicastIPAddress, pos, &tmp)) != 0 || + (ret = var_getBytes(tmp, data)) != 0) + { + break; + } + } +#endif //DLMS_IGNORE_MALLOC + } + } + else if (e->index == 5) + { + if ((ret = cosem_setArray(data, object->ipOptions.size)) == 0) + { + for (pos = 0; pos != object->ipOptions.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->ipOptions, pos, (void**)&it, sizeof(gxip4SetupIpOption))) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 3)) != 0 || + //Type + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT8)) != 0 || + (ret = bb_setUInt8(data, it->type)) != 0 || + //Len + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT8)) != 0 || + (ret = bb_setUInt8(data, (unsigned char)it->length)) != 0 || + //Data + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(data, (unsigned char)it->data.size)) != 0 || + (ret = bb_set(data, it->data.value, it->data.size)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->ipOptions, pos, (void**)&it)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 3)) != 0 || + //Type + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT8)) != 0 || + (ret = bb_setUInt8(data, it->type)) != 0 || + //Len + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT8)) != 0 || + (ret = bb_setUInt8(data, (unsigned char)it->length)) != 0 || + //Data + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(data, (unsigned char)bb_size(&it->data))) != 0 || + (ret = bb_set2(data, &it->data, 0, bb_size(&it->data))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + } + else if (e->index == 6) + { + ret = cosem_setUInt32(e->value.byteArr, object->subnetMask); + } + else if (e->index == 7) + { + ret = cosem_setUInt32(e->value.byteArr, object->gatewayIPAddress); + } + else if (e->index == 8) + { + ret = cosem_setBoolean(e->value.byteArr, object->useDHCP); + } + else if (e->index == 9) + { + ret = cosem_setUInt32(e->value.byteArr, object->primaryDNSAddress); + } + else if (e->index == 10) + { + ret = cosem_setUInt32(e->value.byteArr, object->secondaryDNSAddress); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_IP4_SETUP + +#ifndef DLMS_IGNORE_IP6_SETUP + +int getIpv6Address(IN6_ADDR* address, gxValueEventArg* e) +{ + unsigned char* tmp; +#if defined(_WIN32) || defined(_WIN64)//Windows includes + tmp = address->u.Byte; +#else //Linux includes. + tmp = address->s6_addr; +#endif + return cosem_setOctetString2(e->value.byteArr, tmp, 16); +} + +int getAddressList(gxArray* list, gxValueEventArg* e) +{ + IN6_ADDR* it; + int ret = 0; + uint16_t pos; + if ((ret = cosem_setArray(e->value.byteArr, list->size)) == 0) + { + for (pos = 0; pos != list->size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(list, pos, (void**)&it, sizeof(IN6_ADDR))) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(list, pos, (void**)&it)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = getIpv6Address(it, e)) != 0) + { + break; + } + } + } + return ret; +} + +int cosem_getIP6Setup( + gxValueEventArg* e) +{ + int ret = 0; + gxIp6Setup* object = (gxIp6Setup*)e->target; + switch (e->index) + { + case 2: + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if (object->dataLinkLayer == NULL) + { + ret = cosem_setOctetString2(e->value.byteArr, EMPTY_LN, 6); + } + else + { + ret = cosem_setOctetString2(e->value.byteArr, object->dataLinkLayer->logicalName, 6); + //Error code is returned at the end of the function. + } +#else + ret = cosem_setOctetString2(e->value.byteArr, object->dataLinkLayerReference, 6); + { + //Error code is returned at the end of the function. + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + break; + case 3: + ret = cosem_setEnum(e->value.byteArr, object->addressConfigMode); + break; + case 4: + ret = getAddressList(&object->unicastIPAddress, e); + break; + case 5: + ret = getAddressList(&object->multicastIPAddress, e); + break; + case 6: + ret = getAddressList(&object->gatewayIPAddress, e); + break; + case 7: + ret = getIpv6Address(&object->primaryDNSAddress, e); + break; + case 8: + ret = getIpv6Address(&object->secondaryDNSAddress, e); + break; + case 9: + ret = cosem_setUInt8(e->value.byteArr, object->trafficClass); + break; + case 10: + { + gxNeighborDiscoverySetup* it; + uint16_t pos; + if ((ret = cosem_setArray(e->value.byteArr, object->neighborDiscoverySetup.size)) == 0) + { + for (pos = 0; pos != object->neighborDiscoverySetup.size; ++pos) + { + if ((ret = arr_getByIndex2(&object->neighborDiscoverySetup, pos, (void**)&it, sizeof(gxNeighborDiscoverySetup))) != 0) + { + break; + } + if ((ret = cosem_setStructure(e->value.byteArr, 3)) != 0 || + (ret = cosem_setUInt8(e->value.byteArr, it->maxRetry)) != 0 || + (ret = cosem_setUInt16(e->value.byteArr, it->retryWaitTime)) != 0 || + (ret = cosem_setUInt32(e->value.byteArr, it->sendPeriod)) != 0) + { + break; + } + } + } + } + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_IP6_SETUP + +#ifndef DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP +int cosem_getMbusSlavePortSetup( + gxValueEventArg* e) +{ + int ret; + gxMbusSlavePortSetup* object = (gxMbusSlavePortSetup*)e->target; + if (e->index == 2) + { + ret = cosem_setEnum(e->value.byteArr, object->defaultBaud); + } + else if (e->index == 3) + { + ret = cosem_setEnum(e->value.byteArr, object->availableBaud); + } + else if (e->index == 4) + { + ret = cosem_setEnum(e->value.byteArr, object->addressState); + } + else if (e->index == 5) + { + ret = cosem_setUInt8(e->value.byteArr, object->busAddress); + } + else + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP +#ifndef DLMS_IGNORE_IMAGE_TRANSFER +int cosem_getImageTransfer( + gxValueEventArg* e) +{ + int ret = 0; + uint16_t pos; + gxImageActivateInfo* ai; + gxImageTransfer* object = (gxImageTransfer*)e->target; + gxByteBuffer* data = e->value.byteArr; + if (e->index == 2) + { + ret = cosem_setUInt32(e->value.byteArr, object->imageBlockSize); + } + else if (e->index == 3) + { + if ((ret = bb_setUInt8(e->value.byteArr, DLMS_DATA_TYPE_BIT_STRING)) != 0 || + (ret = hlp_setObjectCount(object->imageTransferredBlocksStatus.size, e->value.byteArr)) != 0) + { + return ret; + } + if (object->imageTransferredBlocksStatus.size != 0) + { + ret = bb_set(e->value.byteArr, object->imageTransferredBlocksStatus.data, + ba_getByteCount(object->imageTransferredBlocksStatus.size)); + } + } + else if (e->index == 4) + { + ret = cosem_setUInt32(e->value.byteArr, object->imageFirstNotTransferredBlockNumber); + } + else if (e->index == 5) + { + ret = cosem_setBoolean(e->value.byteArr, object->imageTransferEnabled); + } + else if (e->index == 6) + { + ret = cosem_setEnum(e->value.byteArr, object->imageTransferStatus); + } + else if (e->index == 7) + { + //ImageActivateInfo is returned only after verification is succeeded. + if (object->imageTransferStatus != DLMS_IMAGE_TRANSFER_STATUS_VERIFICATION_SUCCESSFUL) + { + if ((ret = cosem_setArray(data, 0)) != 0) + { + return ret; + } + } + else + { + if ((ret = cosem_setArray(data, object->imageActivateInfo.size)) == 0) + { + for (pos = 0; pos != object->imageActivateInfo.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->imageActivateInfo, pos, (void**)&ai, sizeof(gxImageActivateInfo))) != 0 || +#else + if ((ret = arr_getByIndex(&object->imageActivateInfo, pos, (void**)&ai)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 3)) != 0 || + //Size + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT32)) != 0 || + (ret = bb_setUInt32(data, ai->size)) != 0 || + //Add identification. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = hlp_setObjectCount(ai->identification.size, data)) != 0 || + (ret = bb_set(data, ai->identification.data, ai->identification.size)) != 0 || + //Add signature. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = hlp_setObjectCount(ai->signature.size, data)) != 0 || + (ret = bb_set(data, ai->signature.data, ai->signature.size)) != 0) + { + break; + } + } + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_IMAGE_TRANSFER + +#if !(defined(DLMS_IGNORE_PROFILE_GENERIC) && defined(DLMS_IGNORE_COMPACT_DATA)) +int getColumns( + dlmsSettings* settings, + gxArray* list, + gxByteBuffer* ba, + gxValueEventArg* e) +{ + uint16_t pduSize = 0; + int ret = 0; + uint32_t pos; +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + gxTarget* it; +#else + gxKey* it; + if ((ret = bb_capacity(ba, (list->size * 19) + 2)) != 0) + { + return ret; + } +#endif //DLMS_IGNORE_MALLOC + //Add count only for first time. + if (!e->transaction) + { + e->transactionEndIndex = list->size; + if ((ret = cosem_setArray(ba, list->size)) != 0) + { + return ret; + } + } + for (pos = e->transactionStartIndex; pos != list->size; ++pos) + { + pduSize = (uint16_t)ba->size; +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(list, (uint16_t)pos, (void**)&it, sizeof(gxTarget))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC +#ifdef DLMS_COSEM_EXACT_DATA_TYPES + if ((ret = arr_getByIndex(list, pos, (void**)&it)) != 0) + { + break; + } +#endif //DLMS_COSEM_EXACT_DATA_TYPES +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + if ((ret = bb_setUInt8(ba, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(ba, 4)) != 0 || + //ClassID + (ret = bb_setUInt8(ba, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(ba, OBJECT_TYPE)) != 0 || + //LN + (ret = bb_setUInt8(ba, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(ba, 6)) != 0 || +#ifdef DLMS_IGNORE_OBJECT_POINTERS + (ret = bb_set(ba, it->logicalName, 6)) != 0 || +#else + (ret = bb_set(ba, it->target->logicalName, 6)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + //Attribute Index + (ret = bb_setUInt8(ba, DLMS_DATA_TYPE_INT8)) != 0 || + (ret = bb_setInt8(ba, it->attributeIndex)) != 0 || + //Data Index + (ret = bb_setUInt8(ba, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(ba, it->dataIndex)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(list, (uint16_t)pos, (void**)&it)) != 0 || + (ret = bb_setUInt8(ba, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(ba, 4)) != 0 || + //ClassID + (ret = bb_setUInt8(ba, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(ba, ((gxObject*)it->key)->objectType)) != 0 || + //LN + (ret = bb_setUInt8(ba, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(ba, 6)) != 0 || + (ret = bb_set(ba, ((gxObject*)it->key)->logicalName, 6)) != 0 || + //Attribute Index + (ret = bb_setUInt8(ba, DLMS_DATA_TYPE_INT8)) != 0 || + (ret = bb_setInt8(ba, ((gxTarget*)it->value)->attributeIndex)) != 0 || + //Data Index + (ret = bb_setUInt8(ba, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(ba, ((gxTarget*)it->value)->dataIndex)) != 0) + { + break; + } +#endif //defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + if (settings->server) + { + //If PDU is full. + if (dlms_isPduFull(settings, ba, NULL)) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + } + ++e->transactionStartIndex; + } + if (ret == DLMS_ERROR_CODE_OUTOFMEMORY) + { + ba->size = pduSize; + ret = 0; + } + return ret; +} + +#endif //!(defined(DLMS_IGNORE_PROFILE_GENERIC) && defined(DLMS_IGNORE_COMPACT_DATA)) + +#ifndef DLMS_IGNORE_PROFILE_GENERIC + +#ifndef DLMS_IGNORE_MALLOC +int cosem_getRow( + gxArray* table, + int index, + gxArray* captureObjects, + gxArray* columns, + gxByteBuffer* data) +{ + int ret, pos; + dlmsVARIANT* col; + variantArray* row; + if ((ret = arr_getByIndex(table, (uint16_t)index, (void**)&row)) != 0) + { + return ret; + } + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0) + { + return ret; + } + if (columns->size != 0) + { + if ((ret = hlp_setObjectCount(columns->size, data)) != 0) + { + return ret; + } + } + else + { + if ((ret = hlp_setObjectCount(captureObjects->size, data)) != 0) + { + return ret; + } + } + int colPos = 0; + for (pos = 0; pos != captureObjects->size; ++pos) + { + if (columns->size != 0) + { + if (captureObjects->data[pos] != columns->data[colPos]) + { + continue; + } + ++colPos; + } + if ((ret = va_getByIndex(row, pos, &col)) != 0) + { + return ret; + } + if (col->vt == DLMS_DATA_TYPE_DATETIME) + { + if ((ret = var_getBytes2(col, DLMS_DATA_TYPE_OCTET_STRING, data)) != 0) + { + return ret; + } + } + else + { + if ((ret = dlms_setData(data, col->vt, col)) != 0) + { + return ret; + } + } + } + return 0; +} + +int profileGeneric_getData( + dlmsSettings* settings, + gxValueEventArg* e, + gxArray* table, + gxArray* captureObjects, + gxByteBuffer* data) +{ + gxArray columns; + uint16_t pduSize = 0; + int ret = 0, pos; + //Add count only for first time. + if (!e->transaction) + { + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_ARRAY)) != 0) + { + return ret; + } + if (e->transactionEndIndex != 0) + { + if ((ret = hlp_setObjectCount(e->transactionEndIndex - e->transactionStartIndex, data)) != 0) + { + return ret; + } + } + else + { + e->transactionEndIndex = table->size; + if ((ret = hlp_setObjectCount(e->transactionEndIndex, data)) != 0) + { + return ret; + } + } + } + arr_init(&columns); + if (e->selector == 2) + { + if ((ret = cosem_getColumns(captureObjects, e->selector, &e->parameters, &columns)) != 0) + { + return ret; + } + } + for (pos = 0; pos != table->size; ++pos) + { + pduSize = (uint16_t)data->size; + if ((ret = cosem_getRow(table, pos, captureObjects, &columns, data)) != 0) + { + break; + } + //If PDU is full. + if (data->size > (uint16_t)(settings->maxPduSize - PDU_MAX_HEADER_SIZE)) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + ++e->transactionStartIndex; + } + arr_empty(&columns); + if (ret == DLMS_ERROR_CODE_OUTOFMEMORY) + { + data->size = pduSize; + ret = 0; + } + return ret; +} + +int getProfileGenericData( + dlmsSettings* settings, + gxProfileGeneric* object, + gxValueEventArg* e, + gxByteBuffer* reply) +{ + int ret; + gxArray items; + variantArray* row; + dlmsVARIANT* it; + gxArray captureObjects; + //If all data is read. + if (e->selector == 0 || e->parameters.vt == DLMS_DATA_TYPE_NONE || e->transactionEndIndex != 0) + { + return profileGeneric_getData(settings, e, &object->buffer, &object->captureObjects, reply); + } + arr_init(&captureObjects); + if ((ret = cosem_getColumns(&object->captureObjects, e->selector, &e->parameters, &captureObjects)) == 0) + { + //Do not clear items. + arr_init(&items); + if (e->selector == 1) //Read by range + { + uint16_t cnt = 0; + gxtime start, end; + dlmsVARIANT value; + var_init(&value); + if ((ret = va_getByIndex(e->parameters.Arr, 1, &it)) == 0) + { + if (it->vt == DLMS_DATA_TYPE_UINT32) + { + time_initUnix(&start, it->ulVal); + } + else + { + if ((ret = dlms_changeType(it->byteArr, DLMS_DATA_TYPE_DATETIME, &value)) != 0) + { + arr_empty(&items); + var_clear(&value); + return ret; + } + start = *value.dateTime; + var_clear(&value); + } + if ((ret = va_getByIndex(e->parameters.Arr, 2, &it)) != 0) + { + return ret; + } + if (it->vt == DLMS_DATA_TYPE_UINT32) + { + time_initUnix(&end, it->ulVal); + } + else + { + if ((ret = dlms_changeType(it->byteArr, DLMS_DATA_TYPE_DATETIME, &value)) != 0) + { + arr_empty(&items); + var_clear(&value); + return ret; + } + end = *value.dateTime; + var_clear(&value); + } + gxtime* t; + uint16_t pos; + for (pos = 0; pos != object->buffer.size; ++pos) + { + if ((ret = arr_getByIndex(&object->buffer, pos, (void**)&row)) != 0 || + (ret = va_getByIndex(row, 0, &it)) != 0) + { + break; + } + t = it->dateTime; + if (time_compare(&start, t) != -1 && time_compare(t, &end) != -1) + { + ++cnt; + //If Size of PDU is full. + if (reply->size < settings->maxPduSize) + { + ++e->transactionEndIndex; + if ((ret = cosem_getRow(&object->buffer, pos, &captureObjects, &object->captureObjects, reply)) != 0) + { + break; + } + } + else if (e->transactionEndIndex != 0) + { + ++e->transactionStartIndex; + //We must loop items throught if count is unknown. + break; + } + } + } + //Update count if items are read first time. + if (ret == 0 && bb_size(e->value.byteArr) == 0) + { + if ((ret = cosem_setArray(e->value.byteArr, cnt)) != 0 || + (ret = bb_set(e->value.byteArr, reply->data, reply->size)) != 0) + { + return ret; + } + reply->position = reply->size = 0; + if ((ret = bb_set(reply, e->value.byteArr->data, e->value.byteArr->size)) != 0) + { + return ret; + } + } + } + } + else if (e->selector == 2) //Read by entry. + { + if ((ret = va_getByIndex(e->parameters.Arr, 0, &it)) == 0) + { + e->transactionStartIndex = (uint16_t)var_toInteger(it); + if (e->transactionStartIndex == 0) + { + e->transactionStartIndex = 1; + } + if ((ret = va_getByIndex(e->parameters.Arr, 1, &it)) == 0) + { + e->transactionEndIndex = (uint16_t)var_toInteger(it); + if (e->transactionEndIndex == 0) + { + e->transactionEndIndex = object->buffer.size; + } + if (e->transactionStartIndex + e->transactionEndIndex > (uint32_t)(object->buffer.size + 1)) + { + e->transactionEndIndex = object->buffer.size; + } + if (e->transactionStartIndex == 0) + { + e->transactionEndIndex = (uint16_t)object->buffer.size; + if ((ret = bb_setUInt8(reply, DLMS_DATA_TYPE_ARRAY)) != 0 || + (ret = hlp_setObjectCount(e->transactionEndIndex, reply)) != 0) + { + return ret; + } + } + for (; e->transactionStartIndex < e->transactionEndIndex; ++e->transactionStartIndex) + { + if ((ret = arr_getByIndex(&object->buffer, (uint16_t)e->transactionStartIndex, (void**)&row)) != 0 || + (ret = cosem_getRow(&object->buffer, e->transactionStartIndex, &captureObjects, &object->captureObjects, reply)) != 0) + { + break; + } + } + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + } + arr_empty(&captureObjects); + arr_empty(&items); + return ret; +} +#endif //DLMS_IGNORE_MALLOC + +int cosem_getProfileGeneric( + dlmsSettings* settings, + gxValueEventArg* e) +{ + unsigned char empty[6] = { 0 }; + int ret = 0; + gxProfileGeneric* object = (gxProfileGeneric*)e->target; + if (e->index == 2) + { +#ifndef DLMS_IGNORE_MALLOC + ret = getProfileGenericData(settings, object, e, e->value.byteArr); +#else + ret = DLMS_ERROR_CODE_NOT_IMPLEMENTED; +#endif //DLMS_IGNORE_MALLOC + } + else if (e->index == 3) + { + ret = getColumns(settings, &object->captureObjects, e->value.byteArr, e); + } + else if (e->index == 4) + { + ret = cosem_setUInt32(e->value.byteArr, object->capturePeriod); + } + else if (e->index == 5) + { + ret = cosem_setEnum(e->value.byteArr, object->sortMethod); + } + else if (e->index == 6) + { + gxByteBuffer* data = e->value.byteArr; + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 4)) != 0) + { + return ret; + } + if (object->sortObject == NULL) + { + //ClassID + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(data, 0)) != 0 || + //LN + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(data, 6)) != 0 || + (ret = bb_set(data, empty, 6)) != 0 || + //Selected Attribute Index + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_INT8)) != 0 || + (ret = bb_setUInt8(data, 0)) != 0 || + //Selected Data Index + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(data, 0)) != 0) + { + return ret; + } + } + else + { + //ClassID + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(data, object->sortObject->objectType)) != 0 || + //LN + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(data, 6)) != 0 || + (ret = bb_set(data, object->sortObject->logicalName, 6)) != 0 || + //Selected Attribute Index + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_INT8)) != 0 || + (ret = bb_setUInt8(data, object->sortObjectAttributeIndex)) != 0 || + //Selected Data Index + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(data, object->sortObjectDataIndex)) != 0) + { + return ret; + } + } + } + else if (e->index == 7) + { + ret = cosem_setUInt32(e->value.byteArr, object->entriesInUse); + } + else if (e->index == 8) + { + ret = cosem_setUInt32(e->value.byteArr, object->profileEntries); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_PROFILE_GENERIC + +#ifndef DLMS_IGNORE_DISCONNECT_CONTROL +int cosem_getDisconnectControl( + gxValueEventArg* e) +{ + int ret = 0; + gxDisconnectControl* object = (gxDisconnectControl*)e->target; + if (e->index == 2) + { + ret = cosem_setBoolean(e->value.byteArr, object->outputState); + } + else if (e->index == 3) + { + ret = cosem_setEnum(e->value.byteArr, object->controlState); + } + else if (e->index == 4) + { + ret = cosem_setEnum(e->value.byteArr, object->controlMode); + } + else + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_DISCONNECT_CONTROL +#ifndef DLMS_IGNORE_LIMITER +int cosem_getLimiter( + gxValueEventArg* e) +{ + int ret = 0, pos; + gxLimiter* object = (gxLimiter*)e->target; + gxByteBuffer* data = e->value.byteArr; +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + uint16_t* it; +#else + dlmsVARIANT* it; +#endif //defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + if (e->index == 2) + { + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 3)) != 0 || + //objectType + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT16)) != 0) + { + return ret; + } + if (object->monitoredValue == NULL) + { + if ((ret = bb_setUInt16(data, 0)) != 0 || + //LN. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(data, 6)) != 0 || + (ret = bb_set(data, EMPTY_LN, 6)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_INT8)) != 0 || + (ret = bb_setUInt8(data, 0)) != 0) + { + return ret; + } + } + else + { + if ((ret = bb_setUInt16(data, object->monitoredValue->objectType)) != 0 || + //LN. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(data, 6)) != 0 || + (ret = bb_set(data, object->monitoredValue->logicalName, 6)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_INT8)) != 0 || + (ret = bb_setUInt8(data, object->selectedAttributeIndex)) != 0) + { + return ret; + } + } + } + else if (e->index == 3) + { + ret = cosem_setVariant(e->value.byteArr, &object->thresholdActive); + } + else if (e->index == 4) + { + ret = cosem_setVariant(e->value.byteArr, &object->thresholdNormal); + } + else if (e->index == 5) + { + ret = cosem_setVariant(e->value.byteArr, &object->thresholdEmergency); + } + else if (e->index == 6) + { + ret = cosem_setUInt32(e->value.byteArr, object->minOverThresholdDuration); + } + else if (e->index == 7) + { + ret = cosem_setUInt32(e->value.byteArr, object->minUnderThresholdDuration); + } + else if (e->index == 8) + { + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 3)) != 0 || + //Id + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(data, object->emergencyProfile.id)) != 0 || + //Datetime + (ret = cosem_setDateTimeAsOctetString(data, &object->emergencyProfile.activationTime)) != 0 || + //Duration + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT32)) != 0 || + (ret = bb_setUInt32(data, object->emergencyProfile.duration)) != 0) + { + //Error code is returned at the end of the function. + } + } + else if (e->index == 9) + { + if ((ret = cosem_setArray(data, object->emergencyProfileGroupIDs.size)) == 0) + { + for (pos = 0; pos != object->emergencyProfileGroupIDs.size; ++pos) + { +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + if ((ret = arr_getByIndex2(&object->emergencyProfileGroupIDs, pos, (void**)&it, sizeof(uint16_t))) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(data, *it)) != 0) + { + break; + } +#else + if ((ret = va_getByIndex(&object->emergencyProfileGroupIDs, pos, &it)) != 0 || + (ret = var_getBytes(it, data)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + } + else if (e->index == 10) + { + ret = cosem_setBoolean(e->value.byteArr, object->emergencyProfileActive); + } + else if (e->index == 11) + { + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 2)) != 0 || + //Action over threshold + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 2)) != 0 || + //LN + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(data, 6)) != 0 || +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = bb_set(data, obj_getLogicalName((gxObject*)object->actionOverThreshold.script), 6)) != 0 || +#else + (ret = bb_set(data, object->actionOverThreshold.logicalName, 6)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + //Script selector + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(data, object->actionOverThreshold.scriptSelector)) != 0 || + //Action under threshold + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 2)) != 0 || + //LN + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(data, 6)) != 0 || +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = bb_set(data, obj_getLogicalName((gxObject*)object->actionUnderThreshold.script), 6)) != 0 || +#else + (ret = bb_set(data, object->actionUnderThreshold.logicalName, 6)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + //Script selector + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(data, object->actionUnderThreshold.scriptSelector)) != 0) + { + //Error code is returned at the end of the function. + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_LIMITER +#ifndef DLMS_IGNORE_MBUS_CLIENT +int cosem_getmMbusClient( + gxValueEventArg* e) +{ + int ret = 0; + uint16_t pos; + gxMBusClient* object = (gxMBusClient*)e->target; + gxByteBuffer* data = e->value.byteArr; +#ifdef DLMS_IGNORE_MALLOC + gxCaptureDefinition* it; +#else + gxKey* it; +#endif //DLMS_IGNORE_MALLOC + if (e->index == 2) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if (object->mBusPort == NULL) + { + ret = cosem_setOctetString2(e->value.byteArr, EMPTY_LN, 6); + } + else + { + ret = cosem_setOctetString2(e->value.byteArr, object->mBusPort->logicalName, 6); + } +#else + ret = cosem_setOctetString2(e->value.byteArr, object->mBusPortReference, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + else if (e->index == 3) + { + if ((ret = cosem_setArray(data, object->captureDefinition.size)) == 0) + { + for (pos = 0; pos != object->captureDefinition.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->captureDefinition, pos, (void**)&it, sizeof(gxCaptureDefinition))) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 2)) != 0 || + // + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = hlp_setObjectCount(it->data.size, data)) != 0 || + (ret = bb_set(data, it->data.value, it->data.size)) != 0 || + // + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = hlp_setObjectCount(it->value.size, data)) != 0 || + (ret = bb_set(data, it->value.value, it->value.size)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->captureDefinition, pos, (void**)&it)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 2)) != 0 || + // + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = hlp_setObjectCount(((gxByteBuffer*)it->key)->size, data)) != 0 || + (ret = bb_set2(data, (gxByteBuffer*)it->key, 0, bb_size((gxByteBuffer*)it->key))) != 0 || + // + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = hlp_setObjectCount(((gxByteBuffer*)it->value)->size, data)) != 0 || + (ret = bb_set2(data, (gxByteBuffer*)it->value, 0, bb_size((gxByteBuffer*)it->value))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + } + else if (e->index == 4) + { + ret = cosem_setUInt32(e->value.byteArr, object->capturePeriod); + } + else if (e->index == 5) + { + ret = cosem_setUInt8(e->value.byteArr, object->primaryAddress); + } + else if (e->index == 6) + { + ret = cosem_setUInt32(e->value.byteArr, object->identificationNumber); + } + else if (e->index == 7) + { + ret = cosem_setUInt16(e->value.byteArr, object->manufacturerID); + } + else if (e->index == 8) + { + ret = cosem_setUInt8(e->value.byteArr, object->dataHeaderVersion); + } + else if (e->index == 9) + { + ret = cosem_setUInt8(e->value.byteArr, object->deviceType); + } + else if (e->index == 10) + { + ret = cosem_setUInt8(e->value.byteArr, object->accessNumber); + } + else if (e->index == 11) + { + ret = cosem_setUInt8(e->value.byteArr, object->status); + } + else if (e->index == 12) + { + ret = cosem_setUInt8(e->value.byteArr, object->alarm); + } + else if (e->index == 13 && object->base.version != 0) + { + ret = cosem_setUInt16(e->value.byteArr, object->configuration); + } + else if (e->index == 14 && object->base.version != 0) + { + ret = cosem_setEnum(e->value.byteArr, object->encryptionKeyStatus); + } + else + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_MBUS_CLIENT +#ifndef DLMS_IGNORE_MODEM_CONFIGURATION + +int cosem_add(gxByteBuffer* data, const char* value, unsigned char len) +{ + int ret; + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = hlp_setObjectCount(len, data)) != 0 || + (ret = bb_set(data, (unsigned char*)value, len)) != 0) + { + return ret; + } + return 0; +} + +int cosem_getModemConfiguration( + dlmsSettings* settings, + gxValueEventArg* e) +{ + int ret = 0; + uint16_t pos; + gxModemInitialisation* mi; +#ifdef DLMS_IGNORE_MALLOC + gxModemProfile* ba; +#else + gxByteBuffer* ba; +#endif //DLMS_IGNORE_MALLOC + gxModemConfiguration* target = ((gxModemConfiguration*)e->target); + gxByteBuffer* data = e->value.byteArr; + if (e->index == 2) + { + ret = cosem_setEnum(e->value.byteArr, target->communicationSpeed); + } + else if (e->index == 3) + { + if ((ret = cosem_setArray(data, target->initialisationStrings.size)) == 0) + { + for (pos = 0; pos != target->initialisationStrings.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&target->initialisationStrings, pos, (void**)&mi, sizeof(gxModemInitialisation))) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 3)) != 0 || + //Add request. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = hlp_setObjectCount(mi->request.size, data)) != 0 || + (ret = bb_set(data, mi->request.value, mi->request.size)) != 0 || + //Add response. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = hlp_setObjectCount(mi->response.size, data)) != 0 || + (ret = bb_set(data, mi->response.value, mi->response.size)) != 0 || + //Add delay. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(data, mi->delay)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&target->initialisationStrings, pos, (void**)&mi)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 3)) != 0 || + //Add request. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = hlp_setObjectCount(mi->request.size, data)) != 0 || + (ret = bb_set(data, mi->request.data, mi->request.size)) != 0 || + //Add response. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = hlp_setObjectCount(mi->response.size, data)) != 0 || + (ret = bb_set(data, mi->response.data, mi->response.size)) != 0 || + //Add delay. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(data, mi->delay)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + } + else if (e->index == 4) + { + //Modem profile is defined on DLMS standard. Add default values. + if (settings->server && target->modemProfile.size == 0) + { + if ((ret = cosem_setArray(data, 17)) != 0 || + (ret = cosem_add(data, "OK", 2) != 0) || + (ret = cosem_add(data, "CONNECT", 7) != 0) || + (ret = cosem_add(data, "RING", 4) != 0) || + (ret = cosem_add(data, "NO CARRIER", 10) != 0) || + (ret = cosem_add(data, "ERROR", 5) != 0) || + (ret = cosem_add(data, "CONNECT 1200", 12) != 0) || + (ret = cosem_add(data, "NO DIAL TONE", 12) != 0) || + (ret = cosem_add(data, "BUSY", 4) != 0) || + (ret = cosem_add(data, "NO ANSWER", 9) != 0) || + (ret = cosem_add(data, "CONNECT 600", 11) != 0) || + (ret = cosem_add(data, "CONNECT 2400", 12) != 0) || + (ret = cosem_add(data, "CONNECT 4800", 12) != 0) || + (ret = cosem_add(data, "CONNECT 9600", 12) != 0) || + (ret = cosem_add(data, "CONNECT 14 400", 14) != 0) || + (ret = cosem_add(data, "CONNECT 28 800", 14) != 0) || + (ret = cosem_add(data, "CONNECT 33 600", 14) != 0) || + (ret = cosem_add(data, "CONNECT 56 000", 14) != 0)) + { + return ret; + } + } + else + { + if ((ret = cosem_setArray(data, target->modemProfile.size)) == 0) + { + for (pos = 0; pos != target->modemProfile.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&target->modemProfile, pos, (void**)&ba, sizeof(gxModemProfile))) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = hlp_setObjectCount(ba->size, data)) != 0 || + (ret = bb_set(data, ba->value, ba->size)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&target->modemProfile, pos, (void**)&ba)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = hlp_setObjectCount(ba->size, data)) != 0 || + (ret = bb_set(data, ba->data, ba->size)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_MODEM_CONFIGURATION +#ifndef DLMS_IGNORE_PPP_SETUP +int cosem_getPppSetup( + gxValueEventArg* e) +{ + int ret = 0; + uint16_t pos; + gxpppSetupLcpOption* lcpItem; + gxpppSetupIPCPOption* ipcpItem; + gxPppSetup* object = (gxPppSetup*)e->target; + gxByteBuffer* data = e->value.byteArr; + if (e->index == 2) + { +#ifdef DLMS_IGNORE_MALLOC +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if (object->phy == NULL) + { + ret = cosem_setOctetString2(e->value.byteArr, EMPTY_LN, 6); + } + else + { + ret = cosem_setOctetString2(e->value.byteArr, object->phy->logicalName, 6); + } +#else + ret = cosem_setOctetString2(e->value.byteArr, object->PHYReference, sizeof(object->PHYReference)); +#endif //DLMS_IGNORE_OBJECT_POINTERS +#else +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if (object->phy == NULL) + { + ret = cosem_setOctetString2(e->value.byteArr, EMPTY_LN, 6); + } + else + { + ret = cosem_setOctetString2(e->value.byteArr, object->phy->logicalName, 6); + } +#else + ret = cosem_setOctetString2(e->value.byteArr, object->PHYReference, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS +#endif //DLMS_IGNORE_MALLOC + } + else if (e->index == 3) + { + if ((ret = cosem_setArray(data, object->lcpOptions.size)) == 0) + { + for (pos = 0; pos != object->lcpOptions.size; ++pos) + { + +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->lcpOptions, pos, (void**)&lcpItem, sizeof(gxpppSetupLcpOption))) != 0 || +#else + if ((ret = arr_getByIndex(&object->lcpOptions, pos, (void**)&lcpItem)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 3)) != 0 || + //Add type. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT8)) != 0 || + (ret = bb_setUInt8(data, lcpItem->type)) != 0 || + //Add length. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT8)) != 0 || + (ret = bb_setUInt8(data, (unsigned char)lcpItem->length)) != 0 || + (ret = var_getBytes(&lcpItem->data, data)) != 0) + { + break; + } + } + } + } + else if (e->index == 4) + { + if ((ret = cosem_setArray(data, object->ipcpOptions.size)) == 0) + { + for (pos = 0; pos != object->ipcpOptions.size; ++pos) + { + +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->ipcpOptions, pos, (void**)&ipcpItem, sizeof(gxpppSetupIPCPOption))) != 0 || +#else + if ((ret = arr_getByIndex(&object->ipcpOptions, pos, (void**)&ipcpItem)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 3)) != 0 || + //Add type. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT8)) != 0 || + (ret = bb_setUInt8(data, ipcpItem->type)) != 0 || + //Add length. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT8)) != 0 || + (ret = bb_setUInt8(data, (unsigned char)ipcpItem->length)) != 0 || + (ret = var_getBytes(&ipcpItem->data, data)) != 0) + { + break; + } + } + } + } + else if (e->index == 5) + { + if (bb_size(&object->userName) == 0) + { + ret = bb_setUInt8(data, DLMS_DATA_TYPE_NONE); + } + else + { + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 2)) != 0 || + //Add user name. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = hlp_setObjectCount(object->userName.size, data)) != 0 || + (ret = bb_set2(data, &object->userName, 0, bb_size(&object->userName))) != 0 || + //Add pw. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = hlp_setObjectCount(object->password.size, data)) != 0 || + (ret = bb_set2(data, &object->password, 0, bb_size(&object->password))) != 0) + { + return ret; + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_PPP_SETUP +#ifndef DLMS_IGNORE_REGISTER_ACTIVATION +int cosem_getRegisterActivation( + dlmsSettings* settings, + gxValueEventArg* e) +{ + int ret; + uint16_t pos; +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + gxObject* od; +#else +#ifdef DLMS_IGNORE_OBJECT_POINTERS + gxObjectDefinition* od; +#else + gxObject* od; +#endif //DLMS_IGNORE_OBJECT_POINTERS +#endif //DLMS_IGNORE_MALLOC + gxRegisterActivation* object = (gxRegisterActivation*)e->target; + gxByteBuffer* data = e->value.byteArr; + if (e->index == 2) + { + //Add count only for first time. + uint16_t pduSize = 0; + if (!e->transaction) + { + e->transactionEndIndex = object->registerAssignment.size; + ret = cosem_setArray(data, object->registerAssignment.size); + } + else + { + ret = 0; + } + if (ret == 0) + { + for (pos = (uint16_t)e->transactionStartIndex; pos != object->registerAssignment.size; ++pos) + { + pduSize = (uint16_t)data->size; +#if !(defined(DLMS_IGNORE_OBJECT_POINTERS) || defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES)) + if ((ret = oa_getByIndex(&object->registerAssignment, pos, &od)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 2)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(data, od->objectType)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(data, 6)) != 0 || + (ret = bb_set(data, od->logicalName, 6)) != 0) + { + break; + } +#else +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndexRef(&object->registerAssignment, pos, (void**)&od)) != 0 || +#else + if ((ret = arr_getByIndex(&object->registerAssignment, pos, (void**)&od)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 2)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(data, od->objectType)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(data, 6)) != 0 || + (ret = bb_set(data, od->logicalName, 6)) != 0) + { + break; + } +#endif //!(defined(DLMS_IGNORE_OBJECT_POINTERS) || defined(DLMS_IGNORE_MALLOC)) + if (settings->server) + { + //If PDU is full. + if (!e->skipMaxPduSize && dlms_isPduFull(settings, data, NULL)) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + } + ++e->transactionStartIndex; + } + if (ret == DLMS_ERROR_CODE_OUTOFMEMORY) + { + data->size = pduSize; + ret = 0; + } + } + } + else if (e->index == 3) + { +#ifdef DLMS_IGNORE_MALLOC + gxRegisterActivationMask* a; +#else + gxKey* a; +#endif //DLMS_IGNORE_MALLOC + uint32_t pos2; + if ((ret = cosem_setArray(data, object->maskList.size)) == 0) + { + for (pos = 0; pos != object->maskList.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->maskList, pos, (void**)&a, sizeof(gxRegisterActivationMask))) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 2)) != 0) + { + break; + } + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(data, a->length)) != 0 || + (ret = bb_set(data, a->name, a->length)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_ARRAY)) != 0 || + (ret = bb_setUInt8(data, a->count)) != 0) + { + break; + } + for (pos2 = 0; pos2 != a->count; ++pos2) + { + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT8)) != 0 || + (ret = bb_setUInt8(data, a->indexes[pos2])) != 0) + { + return ret; + } + } +#else + if ((ret = arr_getByIndex(&object->maskList, pos, (void**)&a)) != 0 || + (ret = cosem_setStructure(data, 2)) != 0 || + (ret = cosem_setOctetString(data, ((gxByteBuffer*)a->key))) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_ARRAY)) != 0 || + (ret = bb_setUInt8(data, (unsigned char)bb_size((gxByteBuffer*)a->value))) != 0) + { + break; + } + for (pos2 = 0; pos2 != bb_size((gxByteBuffer*)a->value); ++pos2) + { + if ((ret = cosem_setUInt8(data, ((gxByteBuffer*)a->value)->data[pos2])) != 0) + { + break; + } + } + if (ret != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + } + else if (e->index == 4) + { + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = hlp_setObjectCount(object->activeMask.size, data)) != 0 || + (ret = bb_set2(data, &object->activeMask, 0, bb_size(&object->activeMask))) != 0) + { + return ret; + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_REGISTER_ACTIVATION +#ifndef DLMS_IGNORE_REGISTER_MONITOR +int cosem_getRegisterMonitor( + gxValueEventArg* e) +{ + int ret = DLMS_ERROR_CODE_OK; + uint16_t pos; + dlmsVARIANT_PTR tmp; + gxActionSet* actionSet; + gxRegisterMonitor* object = (gxRegisterMonitor*)e->target; + gxByteBuffer* data = e->value.byteArr; + if (e->index == 2) + { + //Add count + if ((ret = cosem_setArray(data, object->thresholds.size)) == 0) + { + for (pos = 0; pos != object->thresholds.size; ++pos) + { + + if ((ret = va_getByIndex(&object->thresholds, pos, &tmp)) != 0 || + (ret = var_getBytes(tmp, data)) != 0) + { + break; + } + } + } + } + else if (e->index == 3) + { + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 3)) != 0 || +#ifndef DLMS_IGNORE_OBJECT_POINTERS + //Object type + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(data, object->monitoredValue.target != NULL ? object->monitoredValue.target->objectType : 0)) != 0 || + //LN + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = hlp_setObjectCount(6, data)) != 0 || + (ret = bb_set(data, obj_getLogicalName(object->monitoredValue.target), 6)) != 0 || +#else + //Object type + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(data, object->monitoredValue.objectType)) != 0 || + //LN + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = hlp_setObjectCount(6, data)) != 0 || + (ret = bb_set(data, object->monitoredValue.logicalName, 6)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + //attribute index. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_INT8)) != 0 || + (ret = bb_setUInt8(data, object->monitoredValue.attributeIndex)) != 0) + { + //Error code is returned at the end of the function. + } + } + else if (e->index == 4) + { + //Add count + if ((ret = cosem_setArray(data, object->actions.size)) == 0) + { + for (pos = 0; pos != object->actions.size; ++pos) + { + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 2)) != 0 || + +#ifdef DLMS_IGNORE_MALLOC + (ret = arr_getByIndex(&object->actions, pos, (void**)&actionSet, sizeof(gxActionSet))) != 0 || +#else + (ret = arr_getByIndex(&object->actions, pos, (void**)&actionSet)) != 0 || +#endif //DLMS_IGNORE_MALLOC + + + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 2)) != 0 || + //Add LN. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(data, 6)) != 0 || +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = bb_set(data, obj_getLogicalName((gxObject*)actionSet->actionUp.script), 6)) != 0 || +#else + (ret = bb_set(data, actionSet->actionUp.logicalName, 6)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + //Add script selector. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(data, actionSet->actionUp.scriptSelector)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 2)) != 0 || + //Add LN. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(data, 6)) != 0 || +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = bb_set(data, obj_getLogicalName((gxObject*)actionSet->actionDown.script), 6)) != 0 || +#else + (ret = bb_set(data, actionSet->actionDown.logicalName, 6)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + //Add script selector. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(data, actionSet->actionDown.scriptSelector)) != 0) + { + break; + } + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_REGISTER_MONITOR +#ifndef DLMS_IGNORE_SAP_ASSIGNMENT +int cosem_getSapAssignment( + gxValueEventArg* e) +{ + int ret; + uint16_t pos; + gxSapItem* it; + gxSapAssignment* object = (gxSapAssignment*)e->target; + gxByteBuffer* data = e->value.byteArr; + if (e->index == 2) + { + if ((ret = cosem_setArray(data, object->sapAssignmentList.size)) == 0) + { + for (pos = 0; pos != object->sapAssignmentList.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 2)) != 0 || + (ret = arr_getByIndex(&object->sapAssignmentList, pos, (void**)&it, sizeof(gxSapItem))) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(data, it->id)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = hlp_setObjectCount(it->name.size, data)) != 0 || + (ret = bb_set(data, it->name.value, it->name.size)) != 0) + { + break; + } +#else + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 2)) != 0 || + (ret = arr_getByIndex(&object->sapAssignmentList, pos, (void**)&it)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(data, it->id)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = hlp_setObjectCount(it->name.size, data)) != 0 || + (ret = bb_set2(data, &it->name, 0, bb_size(&it->name))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SAP_ASSIGNMENT +#ifndef DLMS_IGNORE_SCHEDULE +int cosem_getSchedule( + gxValueEventArg* e) +{ + int ret = DLMS_ERROR_CODE_OK; + uint16_t pos; + gxScheduleEntry* se; + gxSchedule* object = (gxSchedule*)e->target; + gxByteBuffer* data = e->value.byteArr; + if (e->index == 2) + { + if ((ret = cosem_setArray(data, object->entries.size)) != 0) + { + return ret; + } + bitArray ba; + ba_init(&ba); + for (pos = 0; pos != object->entries.size; ++pos) + { + if ((ret = cosem_setStructure(data, 10)) != 0 || +#ifdef DLMS_IGNORE_MALLOC + (ret = arr_getByIndex(&object->entries, pos, (void**)&se, sizeof(gxScheduleEntry))) != 0 || +#else + (ret = arr_getByIndex(&object->entries, pos, (void**)&se)) != 0 || +#endif //DLMS_IGNORE_MALLOC + //Add index. + (ret = cosem_setUInt16(data, se->index)) != 0 || + //Add enable. + (ret = cosem_setBoolean(data, se->enable)) != 0 || + //Add logical Name. +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_setOctetString2(data, obj_getLogicalName((gxObject*)se->scriptTable), 6)) != 0 || +#else + (ret = cosem_setOctetString2(data, se->logicalName, 6)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + //Add script selector. + (ret = cosem_setUInt16(data, se->scriptSelector)) != 0 || + //Add switch time. + (ret = cosem_setTimeAsOctetString(data, &se->switchTime)) != 0 || + //Add validity window. + (ret = cosem_setUInt16(data, se->validityWindow)) != 0 || + //Add exec week days. + (ret = cosem_setBitString(data, se->execWeekdays, 7)) != 0 || + //Add exec spec days. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_BIT_STRING)) != 0 || + (ret = hlp_setObjectCount(se->execSpecDays.size, data)) != 0 || + (ret = bb_set(data, se->execSpecDays.data, ba_getByteCount(se->execSpecDays.size))) != 0 || + //Add begin date. + (ret = cosem_setDateTimeAsOctetString(data, &se->beginDate)) != 0 || + //Add end date. + (ret = cosem_setDateTimeAsOctetString(data, &se->endDate)) != 0) + { + break; + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SCHEDULE +#ifndef DLMS_IGNORE_SCRIPT_TABLE +int cosem_getScriptTable( + gxValueEventArg* e) +{ + int ret; + uint16_t pos, pos2; + gxScript* it; + gxScriptAction* a; + gxScriptTable* object = (gxScriptTable*)e->target; + gxByteBuffer* data = e->value.byteArr; + if (e->index == 2) + { + if ((ret = cosem_setArray(data, object->scripts.size)) == 0) + { + for (pos = 0; pos != object->scripts.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->scripts, pos, (void**)&it, sizeof(gxScript))) != 0 || +#else + if ((ret = arr_getByIndex(&object->scripts, pos, (void**)&it)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = cosem_setStructure(data, 2)) != 0 || + //Script_identifier: + (ret = cosem_setUInt16(data, it->id)) != 0 || + (ret = cosem_setArray(data, it->actions.size)) != 0) + { + break; + } + for (pos2 = 0; pos2 != it->actions.size; ++pos2) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&it->actions, pos2, (void**)&a, sizeof(gxScriptAction))) != 0 || +#else + if ((ret = arr_getByIndex(&it->actions, pos2, (void**)&a)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = cosem_setStructure(data, 5)) != 0 || + //service_id + (ret = cosem_setEnum(data, a->type)) != 0 || + //class_id +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_setUInt16(data, a->target == NULL ? 0 : a->target->objectType)) != 0 || +#else + (ret = cosem_setUInt16(data, a->objectType)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + //logical_name +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_setOctetString2(data, obj_getLogicalName(a->target), 6)) != 0 || +#else + (ret = cosem_setOctetString2(data, a->logicalName, 6)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + //index + (ret = cosem_setInt8(data, a->index)) != 0 || + //parameter + (ret = cosem_setVariant(data, &a->parameter)) != 0) + { + break; + } + } + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SCRIPT_TABLE +#ifndef DLMS_IGNORE_SPECIAL_DAYS_TABLE +int cosem_getSpecialDaysTable( + gxValueEventArg* e) +{ + int ret; + uint16_t pos; + dlmsVARIANT tmp; + gxSpecialDay* sd; + gxSpecialDaysTable* object = (gxSpecialDaysTable*)e->target; + gxByteBuffer* data = e->value.byteArr; + if (e->index == 2) + { + if ((ret = var_init(&tmp)) != 0 || + (ret = cosem_setArray(data, object->entries.size)) == 0) + { + for (pos = 0; pos != object->entries.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->entries, pos, (void**)&sd, sizeof(gxSpecialDay))) != 0 || +#else + if ((ret = arr_getByIndex(&object->entries, pos, (void**)&sd)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = cosem_setStructure(data, 3)) != 0 || + //Index + (ret = cosem_setUInt16(data, sd->index)) != 0 || + //Date + (ret = cosem_setDateAsOctetString(data, &sd->date)) != 0 || + //DayId + (ret = cosem_setUInt8(data, sd->dayId)) != 0) + { + break; + } + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SPECIAL_DAYS_TABLE +#ifndef DLMS_IGNORE_TCP_UDP_SETUP +int cosem_getTcpUdpSetup( + gxValueEventArg* e) +{ + int ret; + gxTcpUdpSetup* object = (gxTcpUdpSetup*)e->target; + if (e->index == 2) + { + ret = cosem_setUInt16(e->value.byteArr, object->port); + } + else if (e->index == 3) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + ret = cosem_setOctetString2(e->value.byteArr, obj_getLogicalName(object->ipSetup), 6); +#else + ret = cosem_setOctetString2(e->value.byteArr, object->ipReference, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + else if (e->index == 4) + { + ret = cosem_setUInt16(e->value.byteArr, object->maximumSegmentSize); + } + else if (e->index == 5) + { + ret = cosem_setUInt8(e->value.byteArr, object->maximumSimultaneousConnections); + } + else if (e->index == 6) + { + ret = cosem_setUInt16(e->value.byteArr, object->inactivityTimeout); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_TCP_UDP_SETUP + +#ifndef DLMS_IGNORE_MBUS_DIAGNOSTIC +int cosem_getMbusDiagnostic( + gxValueEventArg* e) +{ + int pos, ret; + dlmsVARIANT tmp; + gxBroadcastFrameCounter* item; + gxMbusDiagnostic* object = (gxMbusDiagnostic*)e->target; + if (e->index == 2) + { + ret = cosem_setUInt8(e->value.byteArr, object->receivedSignalStrength); + } + else if (e->index == 3) + { + ret = cosem_setUInt8(e->value.byteArr, object->channelId); + } + else if (e->index == 4) + { + ret = cosem_setEnum(e->value.byteArr, object->linkStatus); + } + else if (e->index == 5) + { + if ((ret = var_init(&tmp)) != 0 || + (ret = cosem_setArray(e->value.byteArr, object->broadcastFrames.size)) == 0) + { + for (pos = 0; pos != object->broadcastFrames.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->broadcastFrames, pos, (void**)&item, sizeof(gxBroadcastFrameCounter))) != 0 || +#else + if ((ret = arr_getByIndex(&object->broadcastFrames, pos, (void**)&item)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = cosem_setStructure(e->value.byteArr, 3)) != 0 || + (ret = cosem_setUInt8(e->value.byteArr, item->clientId)) != 0 || + (ret = cosem_setUInt32(e->value.byteArr, item->counter)) != 0 || + (ret = cosem_setDateTime(e->value.byteArr, &item->timeStamp)) != 0) + { + break; + } + } + } + } + else if (e->index == 6) + { + ret = cosem_setUInt32(e->value.byteArr, object->transmissions); + } + else if (e->index == 7) + { + ret = cosem_setUInt32(e->value.byteArr, object->receivedFrames); + } + else if (e->index == 8) + { + ret = cosem_setUInt32(e->value.byteArr, object->failedReceivedFrames); + } + else if (e->index == 9) + { + if ((ret = cosem_setStructure(e->value.byteArr, 2)) != 0 || + (ret = cosem_setUInt8(e->value.byteArr, object->captureTime.attributeId)) != 0 || + (ret = cosem_setDateTime(e->value.byteArr, &object->captureTime.timeStamp)) != 0) + { + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_MBUS_DIAGNOSTIC + +#ifndef DLMS_IGNORE_MBUS_PORT_SETUP +int cosem_getMbusPortSetup( + gxValueEventArg* e) +{ + int pos, ret; + gxMBusPortSetup* object = (gxMBusPortSetup*)e->target; + if (e->index == 2) + { + ret = cosem_setOctetString2(e->value.byteArr, object->profileSelection, 6); + } + else if (e->index == 3) + { + ret = cosem_setEnum(e->value.byteArr, object->portCommunicationStatus); + } + else if (e->index == 4) + { + ret = cosem_setEnum(e->value.byteArr, object->dataHeaderType); + } + else if (e->index == 5) + { + ret = cosem_setUInt8(e->value.byteArr, object->primaryAddress); + } + else if (e->index == 6) + { + ret = cosem_setUInt32(e->value.byteArr, object->identificationNumber); + } + else if (e->index == 7) + { + ret = cosem_setUInt16(e->value.byteArr, object->manufacturerId); + } + else if (e->index == 8) + { + ret = cosem_setUInt8(e->value.byteArr, object->mBusVersion); + } + else if (e->index == 9) + { + ret = cosem_setUInt8(e->value.byteArr, object->deviceType); + } + else if (e->index == 10) + { + ret = cosem_setUInt16(e->value.byteArr, object->maxPduSize); + } + else if (e->index == 11) + { +#ifndef DLMS_IGNORE_MALLOC + gxKey* kv; +#else + gxTimePair* kv; +#endif //DLMS_IGNORE_MALLOC + if ((ret = cosem_setArray(e->value.byteArr, object->listeningWindow.size)) == 0) + { + for (pos = 0; pos != object->listeningWindow.size; ++pos) + { + if ((ret = cosem_setStructure(e->value.byteArr, 2)) != 0) + { + break; + } +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->listeningWindow, pos, (void**)&kv)) != 0 || + (ret = cosem_setDateTimeAsOctetString(e->value.byteArr, (gxtime*)kv->key)) != 0 || + (ret = cosem_setDateTimeAsOctetString(e->value.byteArr, (gxtime*)kv->value)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->listeningWindow, pos, (void**)&kv, sizeof(gxTimePair))) != 0 || + //start_time + (ret = cosem_setDateTimeAsOctetString(e->value.byteArr, &kv->first)) != 0 || + //end_time + (ret = cosem_setDateTimeAsOctetString(e->value.byteArr, &kv->second)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_MBUS_PORT_SETUP + +#ifndef DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS +int cosem_getG3PlcMacLayerCounters( + gxValueEventArg* e) +{ + int ret; + gxG3PlcMacLayerCounters* object = (gxG3PlcMacLayerCounters*)e->target; + if (e->index == 2) + { + ret = cosem_setUInt32(e->value.byteArr, object->txDataPacketCount); + } + else if (e->index == 3) + { + ret = cosem_setUInt32(e->value.byteArr, object->rxDataPacketCount); + } + else if (e->index == 4) + { + ret = cosem_setUInt32(e->value.byteArr, object->txCmdPacketCount); + } + else if (e->index == 5) + { + ret = cosem_setUInt32(e->value.byteArr, object->rxCmdPacketCount); + } + else if (e->index == 6) + { + ret = cosem_setUInt32(e->value.byteArr, object->cSMAFailCount); + } + else if (e->index == 7) + { + ret = cosem_setUInt32(e->value.byteArr, object->cSMANoAckCount); + } + else if (e->index == 8) + { + ret = cosem_setUInt32(e->value.byteArr, object->badCrcCount); + } + else if (e->index == 9) + { + ret = cosem_setUInt32(e->value.byteArr, object->txDataBroadcastCount); + } + else if (e->index == 10) + { + ret = cosem_setUInt32(e->value.byteArr, object->rxDataBroadcastCount); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS + +#ifndef DLMS_IGNORE_G3_PLC_MAC_SETUP +int cosem_getG3PlcMacSetupNeighbourTables( + gxArray* tables, + uint16_t address, + uint16_t count, + gxValueEventArg* e) +{ + int ret; + uint16_t pos; + gxNeighbourTable* it; + if ((ret = cosem_setArray(e->value.byteArr, count)) != 0) + { + return ret; + } + for (pos = 0; pos < tables->size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(tables, pos, (void**)&it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(tables, pos, (void**)&it, sizeof(gxNeighbourTable))) != 0) + { + break; + } + gxNeighbourTableTransmitterGain* txCoeff = &it->txCoeff[pos]; + gxNeighbourTableToneMap* toneMap = &it->toneMap[pos]; +#endif //DLMS_IGNORE_MALLOC + if (address != 0 && it->shortAddress != address) + { + //If values are read using the filter. + continue; + } + // Count + if ((ret = cosem_setStructure(e->value.byteArr, 11)) != 0 || + (ret = cosem_setUInt16(e->value.byteArr, it->shortAddress)) != 0 || + (ret = cosem_setBoolean(e->value.byteArr, it->payloadModulationScheme)) != 0 || + (ret = bb_setUInt8(e->value.byteArr, DLMS_DATA_TYPE_BIT_STRING)) != 0 || +#ifndef DLMS_IGNORE_MALLOC + (ret = hlp_setObjectCount(it->toneMap.size, e->value.byteArr)) != 0 || + (ret = bb_set(e->value.byteArr, it->toneMap.data, ba_getByteCount(it->toneMap.size))) != 0 || +#else + (ret = hlp_setObjectCount(toneMap->size, e->value.byteArr)) != 0 || + (ret = bb_set(e->value.byteArr, toneMap->value, ba_getByteCount(toneMap->size))) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = cosem_setEnum(e->value.byteArr, it->modulation)) != 0 || + (ret = cosem_setInt8(e->value.byteArr, it->txGain)) != 0 || + (ret = cosem_setEnum(e->value.byteArr, it->txRes)) != 0 || + (ret = bb_setUInt8(e->value.byteArr, DLMS_DATA_TYPE_BIT_STRING)) != 0 || +#ifndef DLMS_IGNORE_MALLOC + (ret = hlp_setObjectCount(it->txCoeff.size, e->value.byteArr)) != 0 || + (ret = bb_set(e->value.byteArr, it->txCoeff.data, ba_getByteCount(it->txCoeff.size))) != 0 || +#else + (ret = hlp_setObjectCount(txCoeff->size, e->value.byteArr)) != 0 || + (ret = bb_set(e->value.byteArr, txCoeff->value, ba_getByteCount(txCoeff->size))) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = cosem_setUInt8(e->value.byteArr, it->lqi)) != 0 || + (ret = cosem_setInt8(e->value.byteArr, it->phaseDifferential)) != 0 || + (ret = cosem_setUInt8(e->value.byteArr, it->tmrValidTime)) != 0 || + (ret = cosem_setUInt8(e->value.byteArr, it->noData)) != 0) + { + break; + } + } + return ret; +} + +int cosem_getG3PlcMacSetupPosTables( + gxArray* tables, + uint16_t address, + uint16_t count, + gxValueEventArg* e) +{ + int ret; + uint16_t pos; + gxMacPosTable* it; + if ((ret = cosem_setArray(e->value.byteArr, count)) != 0) + { + return ret; + } + for (pos = 0; pos < tables->size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(tables, pos, (void**)&it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(tables, pos, (void**)&it, sizeof(gxMacPosTable))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if (address != 0 && it->shortAddress != address) + { + //If values are read using the filter. + continue; + } + // Count + if ((ret = cosem_setStructure(e->value.byteArr, 3)) != 0 || + // Id + (ret = cosem_setUInt16(e->value.byteArr, it->shortAddress)) != 0 || + (ret = cosem_setUInt8(e->value.byteArr, it->lqi)) != 0 || + (ret = cosem_setUInt8(e->value.byteArr, it->validTime)) != 0) + { + break; + } + } + return ret; +} + +int cosem_getG3PlcMacSetup( + gxValueEventArg* e) +{ + int ret; + uint16_t pos; + gxG3PlcMacSetup* object = (gxG3PlcMacSetup*)e->target; + if (e->index == 2) + { + ret = cosem_setUInt16(e->value.byteArr, object->shortAddress); + } + else if (e->index == 3) + { + ret = cosem_setUInt16(e->value.byteArr, object->rcCoord); + } + else if (e->index == 4) + { + ret = cosem_setUInt16(e->value.byteArr, object->panId); + } + else if (e->index == 5) + { + gxG3MacKeyTable* it; + if ((ret = cosem_setArray(e->value.byteArr, object->keyTable.size)) != 0) + { + return ret; + } + for (pos = 0; pos < object->keyTable.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->keyTable, pos, (void**)&it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->keyTable, pos, (void**)&it, sizeof(gxG3MacKeyTable))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + // Count + if ((ret = cosem_setStructure(e->value.byteArr, 2)) != 0 || + // Id + (ret = cosem_setUInt8(e->value.byteArr, (unsigned char)it->id)) != 0 || + // Key + (ret = cosem_setOctetString2(e->value.byteArr, it->key, MAX_G3_MAC_KEY_TABLE_KEY_SIZE)) != 0) + { + break; + } + } + } + else if (e->index == 6) + { + ret = cosem_setUInt32(e->value.byteArr, object->frameCounter); + } + else if (e->index == 7) + { + if ((ret = bb_setUInt8(e->value.byteArr, DLMS_DATA_TYPE_BIT_STRING)) == 0 && + (ret = hlp_setObjectCount(ba_size(&object->toneMask), e->value.byteArr)) == 0 && + (ret = bb_set(e->value.byteArr, object->toneMask.data, ba_getByteCount(object->toneMask.size))) == 0) + { + } + } + else if (e->index == 8) + { + ret = cosem_setUInt8(e->value.byteArr, object->tmrTtl); + } + else if (e->index == 9) + { + ret = cosem_setUInt8(e->value.byteArr, object->maxFrameRetries); + } + else if (e->index == 10) + { + ret = cosem_setUInt8(e->value.byteArr, object->neighbourTableEntryTtl); + } + else if (e->index == 11) + { + ret = cosem_getG3PlcMacSetupNeighbourTables(&object->neighbourTable, + 0, object->neighbourTable.size, e); + } + else if (e->index == 12) + { + ret = cosem_setUInt8(e->value.byteArr, object->highPriorityWindowSize); + } + else if (e->index == 13) + { + ret = cosem_setUInt8(e->value.byteArr, object->cscmFairnessLimit); + } + else if (e->index == 14) + { + ret = cosem_setUInt8(e->value.byteArr, object->beaconRandomizationWindowLength); + } + else if (e->index == 15) + { + ret = cosem_setUInt8(e->value.byteArr, object->macA); + } + else if (e->index == 16) + { + ret = cosem_setUInt8(e->value.byteArr, object->macK); + } + else if (e->index == 17) + { + ret = cosem_setUInt8(e->value.byteArr, object->minCwAttempts); + } + else if (e->index == 18) + { + ret = cosem_setUInt8(e->value.byteArr, object->cenelecLegacyMode); + } + else if (e->index == 19) + { + ret = cosem_setUInt8(e->value.byteArr, object->fccLegacyMode); + } + else if (e->index == 20) + { + ret = cosem_setUInt8(e->value.byteArr, object->maxBe); + } + else if (e->index == 21) + { + ret = cosem_setUInt8(e->value.byteArr, object->maxCsmaBackoffs); + } + else if (e->index == 22) + { + ret = cosem_setUInt8(e->value.byteArr, object->minBe); + } + else if (e->index == 23) + { + ret = cosem_setBoolean(e->value.byteArr, object->macBroadcastMaxCwEnabled); + } + else if (e->index == 24) + { + ret = cosem_setUInt8(e->value.byteArr, object->macTransmitAtten); + } + else if (e->index == 25) + { + ret = cosem_getG3PlcMacSetupPosTables(&object->macPosTable, + 0, object->macPosTable.size, e); + } + else if (object->base.version > 2 && e->index == 26) + { + //macDuplicateDetectionTTL is added in version 3. + ret = cosem_setUInt8(e->value.byteArr, object->macDuplicateDetectionTTL); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_G3_PLC_MAC_SETUP + +#ifndef DLMS_IGNORE_G3_PLC_6LO_WPAN + +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) +int cosem_getUInt16Array(gxArray* arr, gxByteBuffer* byteArr) +{ + int ret; + uint16_t pos; + uint16_t* it; + if ((ret = cosem_setArray(byteArr, arr->size)) != 0) + { + return ret; + } + for (pos = 0; pos < arr->size; ++pos) + { + if ((ret = arr_getByIndex(arr, pos, (void**)&it, sizeof(uint16_t))) != 0) + { + break; + } + if ((ret = cosem_setUInt16(byteArr, *it)) != 0) + { + break; + } + } + return ret; +} +#else +int cosem_getUInt16Array(variantArray* arr, gxByteBuffer* byteArr) +{ + int ret; + uint16_t pos; + dlmsVARIANT* it; + if ((ret = cosem_setArray(byteArr, arr->size)) != 0) + { + return ret; + } + for (pos = 0; pos < arr->size; ++pos) + { + if ((ret = va_getByIndex(arr, pos, &it)) != 0) + { + break; + } + if ((ret = cosem_setUInt16(byteArr, it->uiVal)) != 0) + { + break; + } + } + return ret; +} +#endif //DLMS_IGNORE_MALLOC + +int cosem_getG3Plc6LoWPAN( + gxValueEventArg* e) +{ + uint16_t pos; + int ret = 0; + gxG3Plc6LoWPAN* object = (gxG3Plc6LoWPAN*)e->target; + if (e->index == 2) + { + ret = cosem_setUInt8(e->value.byteArr, object->maxHops); + } + else if (e->index == 3) + { + ret = cosem_setUInt8(e->value.byteArr, object->weakLqiValue); + } + else if (e->index == 4) + { + ret = cosem_setUInt8(e->value.byteArr, object->securityLevel); + } + else if (e->index == 5) + { + unsigned char ch; + if ((ret = cosem_setArray(e->value.byteArr, (uint16_t)object->prefixTable.size)) != 0) + { + return ret; + } + for (pos = 0; pos < object->prefixTable.size; ++pos) + { + if ((ret = bb_getUInt8ByIndex(&object->prefixTable, pos, &ch)) != 0) + { + break; + } + if ((ret = cosem_setUInt8(e->value.byteArr, ch)) != 0) + { + break; + } + } + } + else if (e->index == 6) + { + gxRoutingConfiguration* it; + if ((ret = cosem_setArray(e->value.byteArr, object->routingConfiguration.size)) != 0) + { + return ret; + } + for (pos = 0; pos < object->routingConfiguration.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->routingConfiguration, pos, (void**)&it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->routingConfiguration, pos, (void**)&it, sizeof(gxRoutingConfiguration))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = cosem_setStructure(e->value.byteArr, 14)) != 0 || + (ret = cosem_setUInt8(e->value.byteArr, it->netTraversalTime)) != 0 || + (ret = cosem_setUInt16(e->value.byteArr, it->routingTableEntryTtl)) != 0 || + (ret = cosem_setUInt8(e->value.byteArr, it->kr)) != 0 || + (ret = cosem_setUInt8(e->value.byteArr, it->km)) != 0 || + (ret = cosem_setUInt8(e->value.byteArr, it->kc)) != 0 || + (ret = cosem_setUInt8(e->value.byteArr, it->kq)) != 0 || + (ret = cosem_setUInt8(e->value.byteArr, it->kh)) != 0 || + (ret = cosem_setUInt8(e->value.byteArr, it->krt)) != 0 || + (ret = cosem_setUInt8(e->value.byteArr, it->rReqRetries)) != 0 || + (ret = cosem_setUInt8(e->value.byteArr, it->rReqReqWait)) != 0 || + (ret = cosem_setUInt16(e->value.byteArr, it->blacklistTableEntryTtl)) != 0 || + (ret = cosem_setBoolean(e->value.byteArr, it->unicastRreqGenEnable)) != 0 || + (ret = cosem_setBoolean(e->value.byteArr, it->rlcEnabled)) != 0 || + (ret = cosem_setUInt8(e->value.byteArr, it->addRevLinkCost)) != 0) + { + break; + } + } + } + else if (e->index == 7) + { + ret = cosem_setUInt16(e->value.byteArr, object->broadcastLogTableEntryTtl); + } + else if (e->index == 8) + { + gxRoutingTable* it; + if ((ret = cosem_setArray(e->value.byteArr, object->routingTable.size)) != 0) + { + return ret; + } + for (pos = 0; pos < object->routingTable.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->routingTable, pos, (void**)&it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->routingTable, pos, (void**)&it, sizeof(gxRoutingTable))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = cosem_setStructure(e->value.byteArr, 6)) != 0 || + (ret = cosem_setUInt16(e->value.byteArr, it->destinationAddress)) != 0 || + (ret = cosem_setUInt16(e->value.byteArr, it->nextHopAddress)) != 0 || + (ret = cosem_setUInt16(e->value.byteArr, it->routeCost)) != 0 || + (ret = cosem_setUInt8(e->value.byteArr, it->hopCount)) != 0 || + (ret = cosem_setUInt8(e->value.byteArr, it->weakLinkCount)) != 0 || + (ret = cosem_setUInt16(e->value.byteArr, it->validTime)) != 0) + { + break; + } + } + } + else if (e->index == 9) + { + gxContextInformationTable* it; + if ((ret = cosem_setArray(e->value.byteArr, object->contextInformationTable.size)) != 0) + { + return ret; + } + for (pos = 0; pos < object->contextInformationTable.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->contextInformationTable, pos, (void**)&it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->contextInformationTable, pos, (void**)&it, sizeof(gxContextInformationTable))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = cosem_setStructure(e->value.byteArr, 5)) != 0 || + (ret = cosem_setBitString(e->value.byteArr, it->cid, 4)) != 0 || + (ret = cosem_setUInt8(e->value.byteArr, it->contextLength)) != 0 || + (ret = cosem_setOctetString2(e->value.byteArr, it->context, 16)) != 0 || + (ret = cosem_setBoolean(e->value.byteArr, it->compression)) != 0 || + (ret = cosem_setUInt16(e->value.byteArr, it->validLifetime)) != 0) + { + break; + } + } + } + else if (e->index == 10) + { + gxBlacklistTable* it; + if ((ret = cosem_setArray(e->value.byteArr, object->blacklistTable.size)) != 0) + { + return ret; + } + for (pos = 0; pos < object->blacklistTable.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->blacklistTable, pos, (void**)&it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->blacklistTable, pos, (void**)&it, sizeof(gxBlacklistTable))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = cosem_setStructure(e->value.byteArr, 2)) != 0 || + (ret = cosem_setUInt16(e->value.byteArr, it->neighbourAddress)) != 0 || + (ret = cosem_setUInt16(e->value.byteArr, it->validTime)) != 0) + { + break; + } + } + } + else if (e->index == 11) + { + gxBroadcastLogTable* it; + if ((ret = cosem_setArray(e->value.byteArr, object->broadcastLogTable.size)) != 0) + { + return ret; + } + for (pos = 0; pos < object->broadcastLogTable.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->broadcastLogTable, pos, (void**)&it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->broadcastLogTable, pos, (void**)&it, sizeof(gxBroadcastLogTable))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = cosem_setStructure(e->value.byteArr, 3)) != 0 || + (ret = cosem_setUInt16(e->value.byteArr, it->sourceAddress)) != 0 || + (ret = cosem_setUInt8(e->value.byteArr, it->sequenceNumber)) != 0 || + (ret = cosem_setUInt16(e->value.byteArr, it->validTime)) != 0) + { + break; + } + } + } + else if (e->index == 12) + { + ret = cosem_getUInt16Array(&object->groupTable, e->value.byteArr); + } + else if (e->index == 13) + { + ret = cosem_setUInt16(e->value.byteArr, object->maxJoinWaitTime); + } + else if (e->index == 14) + { + ret = cosem_setUInt8(e->value.byteArr, object->pathDiscoveryTime); + } + else if (e->index == 15) + { + ret = cosem_setUInt8(e->value.byteArr, object->activeKeyIndex); + } + else if (e->index == 16) + { + ret = cosem_setUInt8(e->value.byteArr, object->metricType); + } + else if (e->index == 17) + { + ret = cosem_setUInt16(e->value.byteArr, object->coordShortAddress); + } + else if (e->index == 18) + { + ret = cosem_setBoolean(e->value.byteArr, object->disableDefaultRouting); + } + else if (e->index == 19) + { + ret = cosem_setEnum(e->value.byteArr, object->deviceType); + } + else if (e->index == 20) + { + ret = cosem_setBoolean(e->value.byteArr, object->defaultCoordRouteEnabled); + } + else if (e->index == 21) + { + ret = cosem_getUInt16Array(&object->destinationAddress, e->value.byteArr); + } + else if (e->index == 22) + { + ret = cosem_setUInt8(e->value.byteArr, object->lowLQI); + } + else if (e->index == 23) + { + ret = cosem_setUInt8(e->value.byteArr, object->highLQI); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_G3_PLC_6LO_WPAN + +#ifndef DLMS_IGNORE_FUNCTION_CONTROL +int cosem_getFunctionControl( + gxValueEventArg* e) +{ + uint16_t pos, pos2, count; + int ret = 0; + gxFunctionControl* object = (gxFunctionControl*)e->target; + if (e->index == 2) + { + functionStatus* status; + if ((ret = cosem_setArray(e->value.byteArr, (uint16_t)object->activationStatus.size)) == 0) + { + for (pos = 0; pos < object->activationStatus.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->activationStatus, pos, (void**)&status)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->activationStatus, pos, (void**)&status, sizeof(functionStatus))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + + if ((ret = cosem_setStructure(e->value.byteArr, 2)) != 0) + { + break; + } +#ifndef DLMS_IGNORE_MALLOC + if ((ret = cosem_setOctetString(e->value.byteArr, &status->name)) != 0) + { + break; + } +#else + if ((ret = cosem_setOctetString2(e->value.byteArr, status->name, status->size)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = cosem_setBoolean(e->value.byteArr, status->status)) != 0) + { + break; + } + } + } + } + else if (e->index == 3) + { + functionalBlock* block; + gxObject* target; + if ((ret = cosem_setArray(e->value.byteArr, (uint16_t)object->functions.size)) == 0) + { + for (pos = 0; pos < object->functions.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->functions, pos, (void**)&block)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->functions, pos, (void**)&block, sizeof(functionalBlock))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + + if ((ret = cosem_setStructure(e->value.byteArr, 2)) != 0) + { + break; + } +#ifndef DLMS_IGNORE_MALLOC + if ((ret = cosem_setOctetString(e->value.byteArr, &block->name)) != 0 || + (ret = cosem_setArray(e->value.byteArr, (uint16_t)block->functionSpecifications.size)) != 0) + { + break; + } + count = (uint16_t)block->functionSpecifications.size; +#else + if ((ret = cosem_setOctetString2(e->value.byteArr, block->name, block->nameSize)) != 0 || + (ret = cosem_setArray(e->value.byteArr, (uint16_t)block->functionSpecificationsSize)) != 0) + { + break; + } + count = (uint16_t)block->functionSpecificationsSize; +#endif //DLMS_IGNORE_MALLOC + for (pos2 = 0; pos2 < count; ++pos2) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = oa_getByIndex(&block->functionSpecifications, pos2, &target)) != 0) + { + break; + } +#else + target = block->functionSpecifications[pos2]; +#endif //DLMS_IGNORE_MALLOC + if ((ret = cosem_setStructure(e->value.byteArr, 2)) != 0) + { + break; + } + if ((ret = cosem_setUInt16(e->value.byteArr, target->objectType)) != 0 || + (ret = cosem_setOctetString2(e->value.byteArr, target->logicalName, 6)) != 0) + { + break; + } + } + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; + } +#endif //DLMS_IGNORE_FUNCTION_CONTROL + +#ifndef DLMS_IGNORE_ARRAY_MANAGER +int cosem_getArrayManager( + gxValueEventArg* e) +{ + uint16_t pos; + int ret = 0; + gxArrayManager* object = (gxArrayManager*)e->target; + if (e->index == 2) + { + gxArrayManagerItem* it; + if ((ret = cosem_setArray(e->value.byteArr, object->elements.size)) != 0) + { + return ret; + } + for (pos = 0; pos < object->elements.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->elements, pos, (void**)&it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->elements, pos, (void**)&it, sizeof(gxArrayManagerItem))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = cosem_setStructure(e->value.byteArr, 2)) != 0 || + (ret = cosem_setUInt8(e->value.byteArr, it->id)) != 0 || + (ret = cosem_setStructure(e->value.byteArr, 3)) != 0 || + (ret = cosem_setUInt16(e->value.byteArr, it->element.target->objectType)) != 0 || + (ret = cosem_setOctetString2(e->value.byteArr, it->element.target->logicalName, 6)) != 0 || + (ret = cosem_setInt8(e->value.byteArr, it->element.attributeIndex)) != 0) + { + break; + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_ARRAY_MANAGER + + +#ifndef DLMS_IGNORE_UTILITY_TABLES +int cosem_getUtilityTables( + gxValueEventArg* e) +{ + int ret = 0; + gxUtilityTables* object = (gxUtilityTables*)e->target; + if (e->index == 2) + { + ret = cosem_setUInt16(e->value.byteArr, object->tableId); + } + else if (e->index == 3) + { + //Skip length. + } + else if (e->index == 4) + { + ret = cosem_setOctetString(e->value.byteArr, &object->buffer); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_UTILITY_TABLES + +#ifndef DLMS_IGNORE_MBUS_MASTER_PORT_SETUP +int cosem_getMbusMasterPortSetup( + gxValueEventArg* e) +{ + int ret; + gxMBusMasterPortSetup* object = (gxMBusMasterPortSetup*)e->target; + if (e->index == 2) + { + ret = cosem_setEnum(e->value.byteArr, object->commSpeed); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_MBUS_MASTER_PORT_SETUP + +#ifndef DLMS_IGNORE_PUSH_SETUP +int cosem_getPushSetup( + gxValueEventArg* e) +{ + int ret = 0; + uint16_t pos; +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + gxTarget* it; + gxTimePair* d; +#else + gxKey* it; +#endif //DLMS_IGNORE_MALLOC + gxPushSetup* object = (gxPushSetup*)e->target; + gxByteBuffer* data = e->value.byteArr; + if (e->index == 2) + { + if ((ret = cosem_setArray(data, object->pushObjectList.size)) == 0) + { + for (pos = 0; pos != object->pushObjectList.size; ++pos) + { +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->pushObjectList, pos, (void**)&it, sizeof(gxTarget))) != 0 || +#else + if ((ret = arr_getByIndex(&object->pushObjectList, pos, (void**)&it)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = cosem_setStructure(data, 4)) != 0 || + //Type. + (ret = cosem_setUInt16(data, OBJECT_TYPE)) != 0 || + //LN +#ifdef DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_setOctetString2(data, it->logicalName, 6)) != 0 || +#else + (ret = cosem_setOctetString2(data, it->target->logicalName, 6)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + //attributeIndex + (ret = cosem_setInt8(data, it->attributeIndex)) != 0 || + //dataIndex + (ret = cosem_setUInt16(data, it->dataIndex)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->pushObjectList, pos, (void**)&it)) != 0 || + (ret = cosem_setStructure(data, 4)) != 0 || + //Type. + (ret = cosem_setUInt16(data, ((gxObject*)it->key)->objectType)) != 0 || + //LN + (ret = cosem_setOctetString2(data, ((gxObject*)it->key)->logicalName, 6)) != 0 || + //attributeIndex + (ret = cosem_setInt8(data, ((gxTarget*)it->value)->attributeIndex)) != 0 || + //dataIndex + (ret = cosem_setUInt16(data, ((gxTarget*)it->value)->dataIndex)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } +} +} + else if (e->index == 3) + { + if ((ret = cosem_setStructure(data, 3)) != 0 || + //Service + (ret = cosem_setEnum(data, object->service)) != 0 || + (ret = cosem_setOctetString(data, &object->destination)) != 0 || + //Message + (ret = cosem_setEnum(data, object->message)) != 0) + { + } + } + else if (e->index == 4) + { + if ((ret = cosem_setArray(data, object->communicationWindow.size)) == 0) + { + for (pos = 0; pos != object->communicationWindow.size; ++pos) + { +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->communicationWindow, pos, (void**)&d, sizeof(gxTimePair))) != 0 || +#else + if ((ret = arr_getByIndex(&object->communicationWindow, pos, (void**)&d)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = cosem_setStructure(data, 2)) != 0 || + //Start date time. + (ret = cosem_setDateTimeAsOctetString(data, &d->first)) != 0 || + //End date time. + (ret = cosem_setDateTimeAsOctetString(data, &d->second)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->communicationWindow, pos, (void**)&it)) != 0 || + (ret = cosem_setStructure(data, 2)) != 0 || + //Start date time. + (ret = cosem_setDateTimeAsOctetString(data, (gxtime*)it->key)) != 0 || + //End date time. + (ret = cosem_setDateTimeAsOctetString(data, (gxtime*)it->value)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + } + else if (e->index == 5) + { + ret = cosem_setUInt16(e->value.byteArr, object->randomisationStartInterval); + } + else if (e->index == 6) + { + ret = cosem_setUInt8(e->value.byteArr, object->numberOfRetries); + } + else if (e->index == 7) + { + ret = cosem_setUInt16(e->value.byteArr, object->repetitionDelay); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_PUSH_SETUP +#ifndef DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL +int cosem_getZigbeeNetworkControl( + gxValueEventArg* e) +{ + gxZigBeeNetworkControl* object = (gxZigBeeNetworkControl*)e->target; + int ret = 0; + uint16_t pos; + gxActiveDevice* it; + gxByteBuffer* data = e->value.byteArr; + if (e->index == 2) + { + ret = cosem_setUInt8(e->value.byteArr, object->enableDisableJoining); + } + else if (e->index == 3) + { + ret = cosem_setUInt16(e->value.byteArr, object->joinTimeout); + } + else if (e->index == 4) + { + if ((ret = cosem_setArray(data, object->activeDevices.size)) != 0) + { + return ret; + } + for (pos = 0; pos != object->activeDevices.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->activeDevices, pos, (void**)&it, sizeof(gxActiveDevice))) != 0 || +#else + if ((ret = arr_getByIndex(&object->activeDevices, pos, (void**)&it)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = cosem_setStructure(data, 14)) != 0 || + //mac address. + (ret = cosem_setOctetString(data, &it->macAddress)) != 0 || + //status + (ret = cosem_setBitString(data, it->status, 5)) != 0 || + //max RSSI + (ret = cosem_setInt8(data, it->maxRSSI)) != 0 || + //average RSSI + (ret = cosem_setInt8(data, it->averageRSSI)) != 0 || + //min RSSI + (ret = cosem_setInt8(data, it->minRSSI)) != 0 || + //max LQI + (ret = cosem_setUInt8(data, it->maxLQI)) != 0 || + //average LQI + (ret = cosem_setUInt8(data, it->averageLQI)) != 0 || + //min LQI + (ret = cosem_setUInt8(data, it->minLQI)) != 0 || + //last communication date time + (ret = cosem_setDateTimeAsOctetString(data, &it->lastCommunicationDateTime)) != 0 || + //number of hops + (ret = cosem_setUInt8(data, it->numberOfHops)) != 0 || + //transmission failures + (ret = cosem_setUInt8(data, it->transmissionFailures)) != 0 || + //transmission successes + (ret = cosem_setUInt8(data, it->transmissionSuccesses)) != 0 || + //application version + (ret = cosem_setUInt8(data, it->applicationVersion)) != 0 || + //stack version + (ret = cosem_setUInt8(data, it->stackVersion)) != 0) + { + break; + } + } +} + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL +#ifndef DLMS_IGNORE_CHARGE +int getUnitCharge(gxUnitCharge* target, gxValueEventArg* e) +{ + int ret = 0; + uint16_t pos; + gxChargeTable* it; + gxByteBuffer* data = e->value.byteArr; + if ((ret = cosem_setStructure(data, 3)) != 0 || + //------------- + //charge per unit scaling + (ret = cosem_setStructure(data, 2)) != 0 || + //commodity scale + (ret = cosem_setInt8(data, target->chargePerUnitScaling.commodityScale)) != 0 || + //price scale + (ret = cosem_setInt8(data, target->chargePerUnitScaling.priceScale)) != 0 || + //------------- + //commodity + (ret = cosem_setStructure(data, 3)) != 0 || + //type +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_setUInt16(data, target->commodity.target == 0 ? 0 : target->commodity.target->objectType)) != 0 || +#else + (ret = cosem_setUInt16(data, target->commodity.type)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + //logicalName +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_setOctetString2(data, obj_getLogicalName(target->commodity.target), 6)) != 0 || +#else + (ret = cosem_setOctetString2(data, target->commodity.logicalName, 6)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + //attributeIndex + (ret = cosem_setInt8(data, target->commodity.attributeIndex)) != 0 || + //------------- + //chargeTables + (ret = cosem_setArray(data, target->chargeTables.size)) != 0) + { + return ret; + } + for (pos = 0; pos != target->chargeTables.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&target->chargeTables, pos, (void**)&it, sizeof(gxChargeTable))) != 0 || + (ret = cosem_setStructure(data, 2)) != 0 || + //index + (ret = cosem_setOctetString2(data, it->index.data, it->index.size)) != 0 || + //chargePerUnit + (ret = cosem_setInt16(data, it->chargePerUnit)) != 0) + { + break; +} +#else + if ((ret = arr_getByIndex(&target->chargeTables, pos, (void**)&it)) != 0 || + (ret = cosem_setStructure(data, 2)) != 0 || + //index + (ret = cosem_setOctetString(data, &it->index)) != 0 || + //chargePerUnit + (ret = cosem_setInt16(data, it->chargePerUnit)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +int cosem_getCharge( + gxValueEventArg* e) +{ + gxCharge* object = (gxCharge*)e->target; + int ret = 0; + if (e->index == 2) + { + ret = cosem_setInt32(e->value.byteArr, object->totalAmountPaid); + } + else if (e->index == 3) + { + ret = cosem_setEnum(e->value.byteArr, object->chargeType); + } + else if (e->index == 4) + { + ret = cosem_setUInt8(e->value.byteArr, object->priority); + } + else if (e->index == 5) + { + ret = getUnitCharge(&object->unitChargeActive, e); + } + else if (e->index == 6) + { + ret = getUnitCharge(&object->unitChargePassive, e); + } + else if (e->index == 7) + { + ret = cosem_setDateTimeAsOctetString(e->value.byteArr, &object->unitChargeActivationTime); + } + else if (e->index == 8) + { + ret = cosem_setUInt32(e->value.byteArr, object->period); + } + else if (e->index == 9) + { + ret = cosem_setBitString(e->value.byteArr, object->chargeConfiguration, 2); + } + else if (e->index == 10) + { + ret = cosem_setDateTime(e->value.byteArr, &object->lastCollectionTime); + } + else if (e->index == 11) + { + ret = cosem_setInt32(e->value.byteArr, object->lastCollectionAmount); + } + else if (e->index == 12) + { + ret = cosem_setInt32(e->value.byteArr, object->totalAmountRemaining); + } + else if (e->index == 13) + { + ret = cosem_setUInt16(e->value.byteArr, object->proportion); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_CHARGE +#ifndef DLMS_IGNORE_TOKEN_GATEWAY +int cosem_getTokenGateway( + gxValueEventArg* e) +{ + int ret = 0; + uint16_t pos; + gxByteBuffer* data = e->value.byteArr; +#ifdef DLMS_IGNORE_MALLOC + gxTokenGatewayDescription* it; +#else + gxByteBuffer* it; +#endif //DLMS_IGNORE_MALLOC + gxTokenGateway* object = (gxTokenGateway*)e->target; + switch (e->index) + { + case 2: + ret = cosem_setOctetString2(data, object->token.data, (uint16_t)object->token.size); + break; + case 3: + ret = cosem_setDateTimeAsOctetString(data, &object->time); + break; + case 4: + if ((ret = cosem_setArray(data, object->descriptions.size)) == 0) + { + for (pos = 0; pos != object->descriptions.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->descriptions, pos, (void**)&it, sizeof(gxTokenGatewayDescription))) != 0) + { + break; + } + if ((ret = cosem_setOctetString2(data, it->value, it->size)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->descriptions, pos, (void**)&it)) != 0 || + (ret = cosem_setOctetString(data, it)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } +} + break; + case 5: + ret = cosem_setEnum(e->value.byteArr, object->deliveryMethod); + break; + case 6: + if ((ret = cosem_setStructure(data, 2)) != 0 || + (ret = cosem_setEnum(data, object->status)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_BIT_STRING)) != 0 || + (ret = hlp_setObjectCount(object->dataValue.size, data)) != 0 || + (ret = bb_set(data, object->dataValue.data, ba_getByteCount(object->dataValue.size))) != 0) + { + } + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_TOKEN_GATEWAY +#ifndef DLMS_IGNORE_CREDIT +int cosem_getCredit( + gxValueEventArg* e) +{ + gxCredit* object = (gxCredit*)e->target; + int ret = 0; + if (e->index == 2) + { + ret = cosem_setInt32(e->value.byteArr, object->currentCreditAmount); + } + else if (e->index == 3) + { + ret = cosem_setEnum(e->value.byteArr, object->type); + } + else if (e->index == 4) + { + ret = cosem_setUInt8(e->value.byteArr, object->priority); + } + else if (e->index == 5) + { + ret = cosem_setInt32(e->value.byteArr, object->warningThreshold); + } + else if (e->index == 6) + { + ret = cosem_setInt32(e->value.byteArr, object->limit); + } + else if (e->index == 7) + { + ret = cosem_setBitString(e->value.byteArr, object->creditConfiguration, 5); + } + else if (e->index == 8) + { + ret = cosem_setEnum(e->value.byteArr, object->status); + } + else if (e->index == 9) + { + ret = cosem_setInt32(e->value.byteArr, object->presetCreditAmount); + } + else if (e->index == 10) + { + ret = cosem_setInt32(e->value.byteArr, object->creditAvailableThreshold); + } + else if (e->index == 11) + { + ret = cosem_setDateTimeAsOctetString(e->value.byteArr, &object->period); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_CREDIT +#ifndef DLMS_IGNORE_ACCOUNT +int cosem_getAccount( + gxValueEventArg* e) +{ + int ret = 0; + uint16_t pos; + unsigned char* it; + gxCreditChargeConfiguration* ccc; + gxTokenGatewayConfiguration* gwc; + gxAccount* object = (gxAccount*)e->target; + gxByteBuffer* data = e->value.byteArr; + if (e->index == 2) + { + if ((ret = cosem_setStructure(data, 2)) != 0 || + //payment mode + (ret = cosem_setEnum(data, object->paymentMode & 0x3)) != 0 || + //account status + (ret = cosem_setEnum(data, object->accountStatus & 0x3)) != 0) + { + } + } + else if (e->index == 3) + { + ret = cosem_setUInt8(e->value.byteArr, object->currentCreditInUse); + } + else if (e->index == 4) + { + ret = cosem_setBitString(e->value.byteArr, object->currentCreditStatus, 7); + } + else if (e->index == 5) + { + ret = cosem_setInt32(e->value.byteArr, object->availableCredit); + } + else if (e->index == 6) + { + ret = cosem_setInt32(e->value.byteArr, object->amountToClear); + } + else if (e->index == 7) + { + ret = cosem_setInt32(e->value.byteArr, object->clearanceThreshold); + } + else if (e->index == 8) + { + ret = cosem_setInt32(e->value.byteArr, object->aggregatedDebt); + } + else if (e->index == 9) + { + if ((ret = cosem_setArray(data, object->creditReferences.size)) == 0) + { + for (pos = 0; pos != object->creditReferences.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->creditReferences, pos, (void**)&it, 6)) != 0 || +#else + if ((ret = arr_getByIndex(&object->creditReferences, pos, (void**)&it)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = cosem_setOctetString2(data, it, 6)) != 0) + { + break; + } + } + } +} + else if (e->index == 10) + { + if ((ret = cosem_setArray(data, object->chargeReferences.size)) == 0) + { + for (pos = 0; pos != object->chargeReferences.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->chargeReferences, pos, (void**)&it, 6)) != 0 || +#else + if ((ret = arr_getByIndex(&object->chargeReferences, pos, (void**)&it)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = cosem_setOctetString2(data, it, 6)) != 0) + { + break; + } + } + } + } + else if (e->index == 11) + { + if ((ret = cosem_setArray(data, object->creditChargeConfigurations.size)) == 0) + { + for (pos = 0; pos != object->creditChargeConfigurations.size; ++pos) +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->creditChargeConfigurations, pos, (void**)&ccc, sizeof(gxCreditChargeConfiguration))) != 0 || +#else + if ((ret = arr_getByIndex(&object->creditChargeConfigurations, pos, (void**)&ccc)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = cosem_setStructure(data, 3)) != 0 || + //credit reference + (ret = cosem_setOctetString2(data, ccc->creditReference, 6)) != 0 || + //charge reference + (ret = cosem_setOctetString2(data, ccc->chargeReference, 6)) != 0 || + //collection configuration + (ret = cosem_setBitString(data, ccc->collectionConfiguration, 3)) != 0) + { + break; + } + } + } + else if (e->index == 12) + { + if ((ret = cosem_setArray(data, object->tokenGatewayConfigurations.size)) == 0) + { + for (pos = 0; pos != object->tokenGatewayConfigurations.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->tokenGatewayConfigurations, pos, (void**)&gwc, sizeof(gxTokenGatewayConfiguration))) != 0 || +#else + if ((ret = arr_getByIndex(&object->tokenGatewayConfigurations, pos, (void**)&gwc)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = cosem_setStructure(data, 2)) != 0 || + //credit reference + (ret = cosem_setOctetString2(data, gwc->creditReference, 6)) != 0 || + //token proportion + (ret = cosem_setUInt8(data, gwc->tokenProportion)) != 0) + { + break; + } + } + } + } + else if (e->index == 13) + { + ret = cosem_setDateTimeAsOctetString(e->value.byteArr, &object->accountActivationTime); + } + else if (e->index == 14) + { + ret = cosem_setDateTimeAsOctetString(e->value.byteArr, &object->accountClosureTime); + } + else if (e->index == 15) + { + if ((ret = cosem_setStructure(data, 3)) != 0 || + //Name + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRING_UTF8)) != 0) + { + return ret; + } +#ifndef DLMS_IGNORE_MALLOC + if ((ret = hlp_setObjectCount(object->currency.name.size, data)) != 0 || + (ret = bb_set(data, object->currency.name.data, object->currency.name.size)) != 0) + { + return ret; + } +#else + if ((ret = hlp_setObjectCount(object->currency.name.size, data)) != 0 || + (ret = bb_set(data, (unsigned char*)object->currency.name.value, object->currency.name.size)) != 0) + { + return ret; + } +#endif //DLMS_IGNORE_MALLOC + //scale + if ((ret = cosem_setInt8(data, object->currency.scale)) != 0 || + //unit + (ret = cosem_setEnum(data, object->currency.unit)) != 0) + { + return ret; + } + } + else if (e->index == 16) + { + ret = cosem_setInt32(e->value.byteArr, object->lowCreditThreshold); + } + else if (e->index == 17) + { + ret = cosem_setInt32(e->value.byteArr, object->nextCreditAvailableThreshold); + } + else if (e->index == 18) + { + ret = cosem_setUInt16(e->value.byteArr, object->maxProvision); + } + else if (e->index == 19) + { + ret = cosem_setInt32(e->value.byteArr, object->maxProvisionPeriod); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_ACCOUNT + +#ifndef DLMS_IGNORE_COMPACT_DATA + +//Convert compact data buffer to array of values. +int compactData_getValues2( + dlmsSettings* settings, + gxByteBuffer* templateDescription, + gxByteBuffer* buffer, + variantArray* values, + unsigned char appendAA) +{ + int ret; + gxDataInfo info; + dlmsVARIANT tmp; + gxByteBuffer data; + //If templateDescription or buffer is not given. + if (values == NULL || bb_size(templateDescription) == 0 || bb_size(buffer) == 0) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + va_clear(values); + BYTE_BUFFER_INIT(&data); + bb_set(&data, templateDescription->data, templateDescription->size); + hlp_setObjectCount(buffer->size, &data); + bb_set(&data, buffer->data, buffer->size); + var_init(&tmp); + di_init(&info); +#ifdef DLMS_ITALIAN_STANDARD + info.appendAA = appendAA; +#endif //DLMS_ITALIAN_STANDARD + info.type = DLMS_DATA_TYPE_COMPACT_ARRAY; + if ((ret = dlms_getData(&data, &info, &tmp)) == 0 && tmp.Arr != NULL) + { + va_attach2(values, tmp.Arr); + } + var_clear(&tmp); + bb_clear(&data); + return ret; +} + +//Convert compact data buffer to array of values. +int compactData_getValues( + dlmsSettings* settings, + gxByteBuffer* templateDescription, + gxByteBuffer* buffer, + variantArray* values) +{ + return compactData_getValues2(settings, templateDescription, buffer, values, 0); +} + +int cosem_getCompactData( + dlmsSettings* settings, + gxValueEventArg* e) +{ + gxByteBuffer* data = data = e->value.byteArr; + gxCompactData* object = (gxCompactData*)e->target; + int ret; + switch (e->index) + { + case 2: + ret = cosem_setOctetString(data, &object->buffer); + break; + case 3: + ret = getColumns(settings, &object->captureObjects, data, e); + break; + case 4: + ret = cosem_setUInt8(e->value.byteArr, object->templateId); + break; + case 5: + ret = cosem_setOctetString(data, &object->templateDescription); + break; + case 6: + ret = cosem_setEnum(e->value.byteArr, object->captureMethod); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_COMPACT_DATA + +int cosem_getValue( + dlmsSettings* settings, + gxValueEventArg* e) +{ + int ret; + if ((ret = cosem_getByteBuffer(e)) != 0) + { + return ret; + } + if (e->index == 1) + { + if ((ret = bb_setUInt8(e->value.byteArr, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(e->value.byteArr, 6)) != 0 || + (ret = bb_set(e->value.byteArr, e->target->logicalName, 6)) != 0) + { + } + return ret; + } + switch (e->target->objectType) + { +#ifndef DLMS_IGNORE_DATA + case DLMS_OBJECT_TYPE_DATA: + ret = cosem_getData(e); + break; +#endif //DLMS_IGNORE_DATA +#ifndef DLMS_IGNORE_REGISTER + case DLMS_OBJECT_TYPE_REGISTER: + ret = cosem_getRegister(e); + break; +#endif //DLMS_IGNORE_REGISTER +#ifndef DLMS_IGNORE_CLOCK + case DLMS_OBJECT_TYPE_CLOCK: + ret = cosem_getClock(e); + break; +#endif //DLMS_IGNORE_CLOCK +#ifndef DLMS_IGNORE_ACTION_SCHEDULE + case DLMS_OBJECT_TYPE_ACTION_SCHEDULE: + ret = cosem_getActionSchedule(e); + break; +#endif //DLMS_IGNORE_ACTION_SCHEDULE +#ifndef DLMS_IGNORE_ACTIVITY_CALENDAR + case DLMS_OBJECT_TYPE_ACTIVITY_CALENDAR: + ret = cosem_getActivityCalendar(e); + break; +#endif //DLMS_IGNORE_ACTIVITY_CALENDAR +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + case DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME: + ret = cosem_getAssociationLogicalName(settings, e); + break; +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME +#ifndef DLMS_IGNORE_SERVER + case DLMS_OBJECT_TYPE_ASSOCIATION_SHORT_NAME: + ret = cosem_getAssociationShortName(settings, e); + break; +#endif //DLMS_IGNORE_SERVER +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME +#ifndef DLMS_IGNORE_AUTO_ANSWER + case DLMS_OBJECT_TYPE_AUTO_ANSWER: + ret = cosem_getAutoAnswer(e); + break; +#endif //DLMS_IGNORE_AUTO_ANSWER +#ifndef DLMS_IGNORE_AUTO_CONNECT + case DLMS_OBJECT_TYPE_AUTO_CONNECT: + ret = cosem_getAutoConnect(e); + break; +#endif //DLMS_IGNORE_AUTO_CONNECT +#ifndef DLMS_IGNORE_DEMAND_REGISTER + case DLMS_OBJECT_TYPE_DEMAND_REGISTER: + ret = cosem_getDemandRegister(e); + break; +#endif //DLMS_IGNORE_DEMAND_REGISTER +#ifndef DLMS_IGNORE_MAC_ADDRESS_SETUP + case DLMS_OBJECT_TYPE_MAC_ADDRESS_SETUP: + ret = cosem_getMacAddressSetup(e); + break; +#endif //DLMS_IGNORE_MAC_ADDRESS_SETUP +#ifndef DLMS_IGNORE_EXTENDED_REGISTER + case DLMS_OBJECT_TYPE_EXTENDED_REGISTER: + ret = cosem_getExtendedRegister(e); + break; +#endif //DLMS_IGNORE_EXTENDED_REGISTER +#ifndef DLMS_IGNORE_GPRS_SETUP + case DLMS_OBJECT_TYPE_GPRS_SETUP: + ret = cosem_getGprsSetup(e); + break; +#endif //DLMS_IGNORE_GPRS_SETUP +#ifndef DLMS_IGNORE_SECURITY_SETUP + case DLMS_OBJECT_TYPE_SECURITY_SETUP: + ret = cosem_getSecuritySetup(e); + break; +#endif //DLMS_IGNORE_SECURITY_SETUP +#ifndef DLMS_IGNORE_IEC_HDLC_SETUP + case DLMS_OBJECT_TYPE_IEC_HDLC_SETUP: + ret = cosem_getIecHdlcSetup(e); + break; +#endif //DLMS_IGNORE_IEC_HDLC_SETUP +#ifndef DLMS_IGNORE_IEC_LOCAL_PORT_SETUP + case DLMS_OBJECT_TYPE_IEC_LOCAL_PORT_SETUP: + ret = cosem_getIecLocalPortSetup(e); + break; +#endif //DLMS_IGNORE_IEC_LOCAL_PORT_SETUP +#ifndef DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP + case DLMS_OBJECT_TYPE_IEC_TWISTED_PAIR_SETUP: + ret = cosem_getIecTwistedPairSetup(e); + break; +#endif //DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP +#ifndef DLMS_IGNORE_IP4_SETUP + case DLMS_OBJECT_TYPE_IP4_SETUP: + ret = cosem_getIP4Setup(e); + break; +#endif //DLMS_IGNORE_IP4_SETUP +#ifndef DLMS_IGNORE_IP6_SETUP + case DLMS_OBJECT_TYPE_IP6_SETUP: + ret = cosem_getIP6Setup(e); + break; +#endif //DLMS_IGNORE_IP6_SETUP +#ifndef DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP + case DLMS_OBJECT_TYPE_MBUS_SLAVE_PORT_SETUP: + ret = cosem_getMbusSlavePortSetup(e); + break; +#endif //DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP +#ifndef DLMS_IGNORE_IMAGE_TRANSFER + case DLMS_OBJECT_TYPE_IMAGE_TRANSFER: + ret = cosem_getImageTransfer(e); + break; +#endif //DLMS_IGNORE_IMAGE_TRANSFER +#ifndef DLMS_IGNORE_DISCONNECT_CONTROL + case DLMS_OBJECT_TYPE_DISCONNECT_CONTROL: + ret = cosem_getDisconnectControl(e); + break; +#endif //DLMS_IGNORE_DISCONNECT_CONTROL +#ifndef DLMS_IGNORE_LIMITER + case DLMS_OBJECT_TYPE_LIMITER: + ret = cosem_getLimiter(e); + break; +#endif //DLMS_IGNORE_LIMITER +#ifndef DLMS_IGNORE_MBUS_CLIENT + case DLMS_OBJECT_TYPE_MBUS_CLIENT: + ret = cosem_getmMbusClient(e); + break; +#endif //DLMS_IGNORE_MBUS_CLIENT +#ifndef DLMS_IGNORE_MODEM_CONFIGURATION + case DLMS_OBJECT_TYPE_MODEM_CONFIGURATION: + ret = cosem_getModemConfiguration(settings, e); + break; +#endif //DLMS_IGNORE_MODEM_CONFIGURATION +#ifndef DLMS_IGNORE_PPP_SETUP + case DLMS_OBJECT_TYPE_PPP_SETUP: + ret = cosem_getPppSetup(e); + break; +#endif //DLMS_IGNORE_PPP_SETUP +#ifndef DLMS_IGNORE_PROFILE_GENERIC + case DLMS_OBJECT_TYPE_PROFILE_GENERIC: + ret = cosem_getProfileGeneric(settings, e); + break; +#endif //DLMS_IGNORE_PROFILE_GENERIC +#ifndef DLMS_IGNORE_REGISTER_ACTIVATION + case DLMS_OBJECT_TYPE_REGISTER_ACTIVATION: + ret = cosem_getRegisterActivation(settings, e); + break; +#endif //DLMS_IGNORE_REGISTER_ACTIVATION +#ifndef DLMS_IGNORE_REGISTER_MONITOR + case DLMS_OBJECT_TYPE_REGISTER_MONITOR: + ret = cosem_getRegisterMonitor(e); + break; +#endif //DLMS_IGNORE_REGISTER_MONITOR +#ifndef DLMS_IGNORE_REGISTER_TABLE + case DLMS_OBJECT_TYPE_REGISTER_TABLE: + ret = cosem_getRegisterTable(e); + break; +#endif //DLMS_IGNORE_REGISTER_TABLE +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_STARTUP + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_STARTUP: + //TODO: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + ret = DLMS_ERROR_CODE_NOT_IMPLEMENTED; + break; +#endif //DLMS_IGNORE_ZIG_BEE_SAS_STARTUP +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_JOIN + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_JOIN: + //TODO: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + ret = DLMS_ERROR_CODE_NOT_IMPLEMENTED; + break; +#endif //DLMS_IGNORE_ZIG_BEE_SAS_JOIN +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_APS_FRAGMENTATION + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_APS_FRAGMENTATION: + //TODO: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + ret = DLMS_ERROR_CODE_NOT_IMPLEMENTED; + break; +#endif //DLMS_IGNORE_ZIG_BEE_SAS_APS_FRAGMENTATION +#ifndef DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL + case DLMS_OBJECT_TYPE_ZIG_BEE_NETWORK_CONTROL: + ret = cosem_getZigbeeNetworkControl(e); + break; +#endif //DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL +#ifndef DLMS_IGNORE_SAP_ASSIGNMENT + case DLMS_OBJECT_TYPE_SAP_ASSIGNMENT: + ret = cosem_getSapAssignment(e); + break; +#endif //DLMS_IGNORE_SAP_ASSIGNMENT +#ifndef DLMS_IGNORE_SCHEDULE + case DLMS_OBJECT_TYPE_SCHEDULE: + ret = cosem_getSchedule(e); + break; +#endif //DLMS_IGNORE_SCHEDULE +#ifndef DLMS_IGNORE_SCRIPT_TABLE + case DLMS_OBJECT_TYPE_SCRIPT_TABLE: + ret = cosem_getScriptTable(e); + break; +#endif //DLMS_IGNORE_SCRIPT_TABLE +#ifndef DLMS_IGNORE_SPECIAL_DAYS_TABLE + case DLMS_OBJECT_TYPE_SPECIAL_DAYS_TABLE: + ret = cosem_getSpecialDaysTable(e); + break; +#endif //DLMS_IGNORE_SPECIAL_DAYS_TABLE +#ifndef DLMS_IGNORE_STATUS_MAPPING + case DLMS_OBJECT_TYPE_STATUS_MAPPING: + //TODO: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + ret = DLMS_ERROR_CODE_NOT_IMPLEMENTED; + break; +#endif //DLMS_IGNORE_STATUS_MAPPING +#ifndef DLMS_IGNORE_TCP_UDP_SETUP + case DLMS_OBJECT_TYPE_TCP_UDP_SETUP: + ret = cosem_getTcpUdpSetup(e); + break; +#endif //DLMS_IGNORE_TCP_UDP_SETUP +#ifndef DLMS_IGNORE_MBUS_DIAGNOSTIC + case DLMS_OBJECT_TYPE_MBUS_DIAGNOSTIC: + ret = cosem_getMbusDiagnostic(e); + break; +#endif //DLMS_IGNORE_MBUS_DIAGNOSTIC +#ifndef DLMS_IGNORE_MBUS_PORT_SETUP + case DLMS_OBJECT_TYPE_MBUS_PORT_SETUP: + ret = cosem_getMbusPortSetup(e); + break; +#endif //DLMS_IGNORE_MBUS_PORT_SETUP +#ifndef DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS + case DLMS_OBJECT_TYPE_G3_PLC_MAC_LAYER_COUNTERS: + ret = cosem_getG3PlcMacLayerCounters(e); + break; +#endif //DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS +#ifndef DLMS_IGNORE_G3_PLC_MAC_SETUP + case DLMS_OBJECT_TYPE_G3_PLC_MAC_SETUP: + ret = cosem_getG3PlcMacSetup(e); + break; +#endif //DLMS_IGNORE_G3_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_G3_PLC_6LO_WPAN + case DLMS_OBJECT_TYPE_G3_PLC_6LO_WPAN: + ret = cosem_getG3Plc6LoWPAN(e); + break; +#endif //DLMS_IGNORE_G3_PLC_6LO_WPAN +#ifndef DLMS_IGNORE_FUNCTION_CONTROL + case DLMS_OBJECT_TYPE_FUNCTION_CONTROL: + ret = cosem_getFunctionControl(e); + break; +#endif //DLMS_IGNORE_FUNCTION_CONTROL +#ifndef DLMS_IGNORE_ARRAY_MANAGER + case DLMS_OBJECT_TYPE_ARRAY_MANAGER: + ret = cosem_getArrayManager(e); + break; +#endif //DLMS_IGNORE_ARRAY_MANAGER +#ifndef DLMS_IGNORE_UTILITY_TABLES + case DLMS_OBJECT_TYPE_UTILITY_TABLES: + ret = cosem_getUtilityTables(e); + break; +#endif //DLMS_IGNORE_UTILITY_TABLES +#ifndef DLMS_IGNORE_MBUS_MASTER_PORT_SETUP + case DLMS_OBJECT_TYPE_MBUS_MASTER_PORT_SETUP: + ret = cosem_getMbusMasterPortSetup(e); + break; +#endif // +#ifndef DLMS_IGNORE_PUSH_SETUP + case DLMS_OBJECT_TYPE_PUSH_SETUP: + ret = cosem_getPushSetup(e); + break; +#endif //DLMS_IGNORE_PUSH_SETUP +#ifndef DLMS_IGNORE_DATA_PROTECTION + case DLMS_OBJECT_TYPE_DATA_PROTECTION: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + ret = DLMS_ERROR_CODE_NOT_IMPLEMENTED; + break; +#endif //DLMS_IGNORE_DATA_PROTECTION +#ifndef DLMS_IGNORE_ACCOUNT + case DLMS_OBJECT_TYPE_ACCOUNT: + ret = cosem_getAccount(e); + break; +#endif //DLMS_IGNORE_ACCOUNT +#ifndef DLMS_IGNORE_CREDIT + case DLMS_OBJECT_TYPE_CREDIT: + ret = cosem_getCredit(e); + break; +#endif //DLMS_IGNORE_CREDIT +#ifndef DLMS_IGNORE_CHARGE + case DLMS_OBJECT_TYPE_CHARGE: + ret = cosem_getCharge(e); + break; +#endif //DLMS_IGNORE_CHARGE +#ifndef DLMS_IGNORE_TOKEN_GATEWAY + case DLMS_OBJECT_TYPE_TOKEN_GATEWAY: + ret = cosem_getTokenGateway(e); + break; +#endif //DLMS_IGNORE_TOKEN_GATEWAY +#ifndef DLMS_IGNORE_GSM_DIAGNOSTIC + case DLMS_OBJECT_TYPE_GSM_DIAGNOSTIC: + ret = cosem_getGsmDiagnostic(e); + break; +#endif //DLMS_IGNORE_GSM_DIAGNOSTIC +#ifndef DLMS_IGNORE_COMPACT_DATA + case DLMS_OBJECT_TYPE_COMPACT_DATA: + ret = cosem_getCompactData(settings, e); + break; +#endif //DLMS_IGNORE_COMPACT_DATA +#ifndef DLMS_IGNORE_PARAMETER_MONITOR + case DLMS_OBJECT_TYPE_PARAMETER_MONITOR: + ret = cosem_getParameterMonitor(e); + break; +#endif //DLMS_IGNORE_PARAMETER_MONITOR +#ifndef DLMS_IGNORE_LLC_SSCS_SETUP + case DLMS_OBJECT_TYPE_LLC_SSCS_SETUP: + ret = cosem_getLlcSscsSetup(e); + break; +#endif //DLMS_IGNORE_LLC_SSCS_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS: + ret = cosem_getPrimeNbOfdmPlcPhysicalLayerCounters(e); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_SETUP: + ret = cosem_getPrimeNbOfdmPlcMacSetup(e); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS: + ret = cosem_getPrimeNbOfdmPlcMacFunctionalParameters(e); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_COUNTERS: + ret = cosem_getPrimeNbOfdmPlcMacCounters(e); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA: + ret = cosem_getPrimeNbOfdmPlcMacNetworkAdministrationData(e); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION: + ret = cosem_getPrimeNbOfdmPlcApplicationsIdentification(e); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION +#ifndef DLMS_IGNORE_ARBITRATOR + case DLMS_OBJECT_TYPE_ARBITRATOR: + ret = cosem_getArbitrator(e); + break; +#endif //DLMS_IGNORE_ARBITRATOR +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE1_SETUP: + ret = cosem_getIec8802LlcType1Setup(e); + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE2_SETUP: + ret = cosem_getIec8802LlcType2Setup(e); + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE3_SETUP: + ret = cosem_getIec8802LlcType3Setup(e); + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP +#ifndef DLMS_IGNORE_SFSK_ACTIVE_INITIATOR + case DLMS_OBJECT_TYPE_SFSK_ACTIVE_INITIATOR: + ret = cosem_getSFSKActiveInitiator(e); + break; +#endif //DLMS_IGNORE_SFSK_ACTIVE_INITIATOR +#ifndef DLMS_IGNORE_SFSK_MAC_COUNTERS + case DLMS_OBJECT_TYPE_SFSK_MAC_COUNTERS: + ret = cosem_getFSKMacCounters(e); + break; +#endif //DLMS_IGNORE_SFSK_MAC_COUNTERS +#ifndef DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS + case DLMS_OBJECT_TYPE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS: + ret = cosem_getSFSKMacSynchronizationTimeouts(e); + break; +#endif //DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS +#ifndef DLMS_IGNORE_SFSK_PHY_MAC_SETUP + case DLMS_OBJECT_TYPE_SFSK_PHY_MAC_SETUP: + ret = cosem_getSFSKPhyMacSetUp(e); + break; +#endif //DLMS_IGNORE_SFSK_PHY_MAC_SETUP +#ifndef DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST + case DLMS_OBJECT_TYPE_SFSK_REPORTING_SYSTEM_LIST: + ret = cosem_getSFSKReportingSystemList(e); + break; +#endif //DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST +#ifdef DLMS_ITALIAN_STANDARD + case DLMS_OBJECT_TYPE_TARIFF_PLAN: + ret = cosem_getTariffPlan(e); + break; +#endif //DLMS_ITALIAN_STANDARD + default: + //Unknown type. + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} + +#ifdef DLMS_ITALIAN_STANDARD + +unsigned char getInterval(gxInterval* interval) +{ + unsigned char b = (unsigned char)(interval->useInterval ? 1 : 0); + b |= (unsigned char)(interval->intervalTariff << 1); + b |= (unsigned char)(interval->startHour << 3); + return b; +} + +int getIntervals(gxInterval* interval, gxByteBuffer* data) +{ + int ret; + if ((ret = cosem_setArray(data, 5)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT8)) != 0 || + (ret = bb_setUInt8(data, getInterval(interval))) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT8)) != 0 || + (ret = bb_setUInt8(data, getInterval(interval + 1))) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT8)) != 0 || + (ret = bb_setUInt8(data, getInterval(interval + 2))) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT8)) != 0 || + (ret = bb_setUInt8(data, getInterval(interval + 3))) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT8)) != 0 || + (ret = bb_setUInt8(data, getInterval(interval + 4))) != 0) + { + return ret; + } + return ret; +} + +int getSeason(gxBandDescriptor* season, gxByteBuffer* data) +{ + int ret; + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 5)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT8)) != 0 || + (ret = bb_setUInt8(data, season->dayOfMonth)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT8)) != 0 || + (ret = bb_setUInt8(data, season->month)) != 0 || + (ret = getIntervals(season->workingDayIntervals, data)) != 0 || + (ret = getIntervals(season->saturdayIntervals, data)) != 0 || + (ret = getIntervals(season->holidayIntervals, data)) != 0) + { + return ret; + } + return ret; +} + +int cosem_getTariffPlan(gxValueEventArg* e) +{ + uint16_t it; + int pos, ret; + gxByteBuffer* data; + gxTariffPlan* object = (gxTariffPlan*)e->target; + switch (e->index) + { + case 2: + if (object->calendarName == NULL) + { + ret = cosem_setString(e->value.byteArr, object->calendarName, 0); + } + else + { + ret = cosem_setString(e->value.byteArr, object->calendarName, (uint16_t)strlen(object->calendarName)); + } + break; + case 3: + ret = cosem_setBoolean(e->value.byteArr, object->enabled); + break; + case 4: + { + data = e->value.byteArr; + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 4)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT8)) != 0 || + (ret = bb_setUInt8(data, object->plan.defaultTariffBand)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_ARRAY)) != 0 || + (ret = bb_setUInt8(data, 2)) != 0 || + (ret = getSeason(&object->plan.winterSeason, data)) != 0 || + (ret = getSeason(&object->plan.summerSeason, data)) != 0 || + + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_BIT_STRING)) != 0 || + (ret = hlp_setObjectCount(object->plan.weeklyActivation.size, data)) != 0 || + (ret = bb_set(data, object->plan.weeklyActivation.data, ba_getByteCount(object->plan.weeklyActivation.size))) != 0 || + + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_ARRAY)) != 0 || + (ret = bb_setUInt8(data, (unsigned char)object->plan.specialDays.size)) != 0) + { + return ret; + } + for (pos = 0; pos != object->plan.specialDays.size; ++pos) + { + if ((ret = arr_getByIndex(&object->plan.specialDays, pos, (void**)&it)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(data, it)) != 0) + { + return ret; + } + } + } + break; + case 5: + { + data = e->value.byteArr; + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + //Count + (ret = bb_setUInt8(data, 2)) != 0 || + //Time + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(data, 4)) != 0 || + (ret = var_getTime(&object->activationTime, data)) != 0 || + //Date + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(data, 5)) != 0 || + (ret = var_getDate(&object->activationTime, data)) != 0) + { + return ret; + } + } + break; + default: + ret = DLMS_ERROR_CODE_READ_WRITE_DENIED; + } + return ret; +} +#endif //DLMS_ITALIAN_STANDARD + +#ifndef DLMS_IGNORE_GSM_DIAGNOSTIC +int cosem_getGsmDiagnostic( + gxValueEventArg* e) +{ + gxAdjacentCell* it; + gxByteBuffer* data = e->value.byteArr; + gxGsmDiagnostic* object = (gxGsmDiagnostic*)e->target; + int ret; + uint16_t pos; + switch (e->index) + { + case 2: +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + ret = cosem_setString2(e->value.byteArr, &object->operatorName); +#else + ret = cosem_setString(e->value.byteArr, object->operatorName, + object->operatorName != NULL ? (uint16_t)strlen(object->operatorName) : 0); +#endif //DLMS_IGNORE_MALLOC + break; + case 3: + ret = cosem_setEnum(e->value.byteArr, object->status); + break; + case 4: + ret = cosem_setEnum(e->value.byteArr, object->circuitSwitchStatus); + break; + case 5: + ret = cosem_setEnum(e->value.byteArr, object->packetSwitchStatus); + break; + case 6: + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) == 0) + { + if (object->base.version == 0) + { + if ((ret = bb_setUInt8(data, 4)) != 0 || + //cellId. + (ret = cosem_setUInt16(data, (uint16_t)object->cellInfo.cellId)) != 0) + { + return ret; + } + } + else + { + if ((ret = bb_setUInt8(data, 7)) != 0 || + //cellId. + (ret = cosem_setUInt32(data, object->cellInfo.cellId)) != 0) + { + return ret; + } + } + //LocationId. + if ((ret = cosem_setUInt16(data, object->cellInfo.locationId)) != 0 || + //SignalQuality. + (ret = cosem_setUInt8(data, object->cellInfo.signalQuality)) != 0 || + //Ber. + (ret = cosem_setUInt8(data, object->cellInfo.ber)) != 0) + { + return ret; + } + if (object->base.version > 0) + { + if (//mobileCountryCode. + (ret = cosem_setUInt16(data, object->cellInfo.mobileCountryCode)) != 0 || + //MobileNetworkCode. + (ret = cosem_setUInt16(data, object->cellInfo.mobileNetworkCode)) != 0 || + //ChannelNumber. + (ret = cosem_setUInt32(data, object->cellInfo.channelNumber)) != 0) + { + } + } + } + break; + case 7: + if ((ret = cosem_setArray(data, object->adjacentCells.size)) == 0) + { + for (pos = 0; pos != object->adjacentCells.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->adjacentCells, pos, (void**)&it, sizeof(gxAdjacentCell))) != 0 || +#else + if ((ret = arr_getByIndex(&object->adjacentCells, pos, (void**)&it)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = cosem_setStructure(data, 2)) != 0) + { + break; + } + if (object->base.version == 0) + { + //cellId. + if ((ret = cosem_setUInt16(data, (uint16_t)it->cellId)) != 0) + { + break; + } + } + else + { + //cellId. + if ((ret = cosem_setUInt32(data, it->cellId)) != 0) + { + break; + } + } + //SignalQuality. + if ((ret = cosem_setUInt8(data, it->signalQuality)) != 0) + { + break; + } + } + } + break; + case 8: + ret = cosem_setDateTime(e->value.byteArr, &object->captureTime); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; +} + return ret; +} +#endif //DLMS_IGNORE_GSM_DIAGNOSTIC + +#ifndef DLMS_IGNORE_PARAMETER_MONITOR +int cosem_getParameterMonitor( + gxValueEventArg* e) +{ + int ret = 0; + uint16_t pos; + gxByteBuffer* data = e->value.byteArr; + gxParameterMonitor* object = (gxParameterMonitor*)e->target; + switch (e->index) + { + case 2: + { + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 4)) != 0) + { + return ret; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if (object->changedParameter.target == NULL) + { + if ((ret = cosem_setUInt16(data, 0)) != 0 || + (ret = cosem_setOctetString2(data, EMPTY_LN, 6)) != 0 || + (ret = cosem_setInt8(data, 0)) != 0 || + (ret = bb_setUInt8(data, 0)) != 0) + { + //Error code is returned at the end of the function. + } + } + else + { + if ((ret = cosem_setUInt16(data, object->changedParameter.target->objectType)) != 0 || + (ret = cosem_setOctetString2(data, object->changedParameter.target->logicalName, 6)) != 0 || + (ret = cosem_setInt8(data, object->changedParameter.attributeIndex)) != 0 || + (ret = cosem_setVariant(data, &object->changedParameter.value)) != 0) + { + //Error code is returned at the end of the function. + } + } +#else + if ((ret = cosem_setUInt16(data, object->changedParameter.type)) != 0 || + (ret = cosem_setOctetString2(data, object->changedParameter.logicalName, 6)) != 0 || + (ret = cosem_setInt8(data, object->changedParameter.attributeIndex)) != 0 || + (ret = cosem_setVariant(data, &object->changedParameter.value)) != 0) + { + //Error code is returned at the end of the function. + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + break; + case 3: + ret = cosem_setDateTimeAsOctetString(e->value.byteArr, &object->captureTime); + break; + case 4: + { +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + gxTarget* it; +#else + gxKey* it; +#endif //DLMS_IGNORE_MALLOC + if ((ret = cosem_setArray(data, object->parameters.size)) == 0) + { + for (pos = 0; pos != object->parameters.size; ++pos) + { +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->parameters, pos, (void**)&it, sizeof(gxTarget))) != 0 || +#else + if ((ret = arr_getByIndex(&object->parameters, pos, (void**)&it)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + (ret = bb_setUInt8(data, 3)) != 0 || + //Type. + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_UINT16)) != 0 || + (ret = bb_setUInt16(data, OBJECT_TYPE)) != 0 || + //LN + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(data, 6)) != 0 || +#ifdef DLMS_IGNORE_OBJECT_POINTERS + (ret = bb_set(data, it->logicalName, 6)) != 0 || +#else + (ret = bb_set(data, it->target->logicalName, 6)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + //attributeIndex + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_INT8)) != 0 || + (ret = bb_setUInt8(data, it->attributeIndex)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->parameters, pos, (void**)&it)) != 0 || + (ret = cosem_setStructure(data, 3)) != 0 || + //Type. + (ret = cosem_setUInt16(data, ((gxObject*)it->key)->objectType)) != 0 || + //LN + (ret = cosem_setOctetString2(data, ((gxObject*)it->key)->logicalName, 6)) != 0 || + //attributeIndex + (ret = cosem_setInt8(data, ((gxTarget*)it->value)->attributeIndex)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } +} + } + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; + } +#endif //DLMS_IGNORE_PARAMETER_MONITOR + +#ifndef DLMS_IGNORE_LLC_SSCS_SETUP +int cosem_getLlcSscsSetup( + gxValueEventArg* e) +{ + int ret; + gxLlcSscsSetup* object = (gxLlcSscsSetup*)e->target; + switch (e->index) + { + case 2: + ret = cosem_setUInt16(e->value.byteArr, object->serviceNodeAddress); + break; + case 3: + ret = cosem_setUInt16(e->value.byteArr, object->baseNodeAddress); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_LLC_SSCS_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +int cosem_getPrimeNbOfdmPlcPhysicalLayerCounters( + gxValueEventArg* e) +{ + int ret; + gxPrimeNbOfdmPlcPhysicalLayerCounters* object = (gxPrimeNbOfdmPlcPhysicalLayerCounters*)e->target; + switch (e->index) + { + case 2: + ret = cosem_setUInt16(e->value.byteArr, object->crcIncorrectCount); + break; + case 3: + ret = cosem_setUInt16(e->value.byteArr, object->crcFailedCount); + break; + case 4: + ret = cosem_setUInt16(e->value.byteArr, object->txDropCount); + break; + case 5: + ret = cosem_setUInt16(e->value.byteArr, object->rxDropCount); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} + +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +int cosem_getPrimeNbOfdmPlcMacSetup( + gxValueEventArg* e) +{ + int ret; + gxPrimeNbOfdmPlcMacSetup* object = (gxPrimeNbOfdmPlcMacSetup*)e->target; + switch (e->index) + { + case 2: + ret = cosem_setUInt8(e->value.byteArr, object->macMinSwitchSearchTime); + break; + case 3: + ret = cosem_setUInt8(e->value.byteArr, object->macMaxPromotionPdu); + break; + case 4: + ret = cosem_setUInt8(e->value.byteArr, object->macPromotionPduTxPeriod); + break; + case 5: + ret = cosem_setUInt8(e->value.byteArr, object->macBeaconsPerFrame); + break; + case 6: + ret = cosem_setUInt8(e->value.byteArr, object->macScpMaxTxAttempts); + break; + case 7: + ret = cosem_setUInt8(e->value.byteArr, object->macCtlReTxTimer); + break; + case 8: + ret = cosem_setUInt8(e->value.byteArr, object->macMaxCtlReTx); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +int cosem_getPrimeNbOfdmPlcMacFunctionalParameters( + gxValueEventArg* e) +{ + int ret; + gxPrimeNbOfdmPlcMacFunctionalParameters* object = (gxPrimeNbOfdmPlcMacFunctionalParameters*)e->target; + switch (e->index) + { + case 2: + ret = cosem_setInt16(e->value.byteArr, object->lnId); + break; + case 3: + ret = cosem_setUInt8(e->value.byteArr, object->lsId); + break; + case 4: + ret = cosem_setUInt8(e->value.byteArr, object->sId); + break; + case 5: + { + ret = cosem_setOctetString(e->value.byteArr, &object->sna); + } + break; + case 6: + ret = cosem_setEnum(e->value.byteArr, object->state); + break; + case 7: + ret = cosem_setUInt16(e->value.byteArr, object->scpLength); + break; + case 8: + ret = cosem_setUInt8(e->value.byteArr, object->nodeHierarchyLevel); + break; + case 9: + ret = cosem_setUInt8(e->value.byteArr, object->beaconSlotCount); + break; + case 10: + ret = cosem_setUInt8(e->value.byteArr, object->beaconRxSlot); + break; + case 11: + ret = cosem_setUInt8(e->value.byteArr, object->beaconTxSlot); + break; + case 12: + ret = cosem_setUInt8(e->value.byteArr, object->beaconRxFrequency); + break; + case 13: + ret = cosem_setUInt8(e->value.byteArr, object->beaconTxFrequency); + break; + case 14: + ret = cosem_setEnum(e->value.byteArr, (unsigned char)object->capabilities); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +int cosem_getPrimeNbOfdmPlcMacCounters( + gxValueEventArg* e) +{ + int ret; + gxPrimeNbOfdmPlcMacCounters* object = (gxPrimeNbOfdmPlcMacCounters*)e->target; + switch (e->index) + { + case 2: + ret = cosem_setUInt32(e->value.byteArr, object->txDataPktCount); + break; + case 3: + ret = cosem_setUInt32(e->value.byteArr, object->rxDataPktCount); + break; + case 4: + ret = cosem_setUInt32(e->value.byteArr, object->txCtrlPktCount); + break; + case 5: + ret = cosem_setUInt32(e->value.byteArr, object->rxCtrlPktCount); + break; + case 6: + ret = cosem_setUInt32(e->value.byteArr, object->csmaFailCount); + break; + case 7: + ret = cosem_setUInt32(e->value.byteArr, object->csmaChBusyCount); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + +int cosem_getMulticastEntries(gxValueEventArg* e) +{ + gxMacMulticastEntry* it; + int ret; + uint16_t pos; + gxPrimeNbOfdmPlcMacNetworkAdministrationData* object = (gxPrimeNbOfdmPlcMacNetworkAdministrationData*)e->target; + gxByteBuffer* data = e->value.byteArr; + if ((ret = cosem_setArray(data, object->multicastEntries.size)) == 0) + { + for (pos = 0; pos != object->multicastEntries.size; ++pos) + { + if ((ret = cosem_setStructure(data, 2)) != 0) + { + break; + } +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->multicastEntries, pos, (void**)&it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->multicastEntries, pos, (void**)&it, sizeof(gxMacMulticastEntry))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + + if ((ret = cosem_setInt8(data, it->id)) != 0 || + (ret = cosem_setInt16(data, it->members)) != 0) + { + break; + } + } + } + return ret; +} + +int cosem_getSwitchTable(gxValueEventArg* e) +{ + uint16_t* it; + int ret; + uint16_t pos; + gxPrimeNbOfdmPlcMacNetworkAdministrationData* object = (gxPrimeNbOfdmPlcMacNetworkAdministrationData*)e->target; + gxByteBuffer* data = e->value.byteArr; + if ((ret = cosem_setArray(data, object->switchTable.size)) == 0) + { + for (pos = 0; pos != object->switchTable.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->switchTable, pos, (void**)&it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->switchTable, pos, (void**)&it, sizeof(short))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = cosem_setInt16(data, *it)) != 0) + { + break; + } + } + } + return ret; +} + +int cosem_getDirectTable(gxValueEventArg* e) +{ + gxMacDirectTable* it; + int ret; + uint16_t pos; + gxPrimeNbOfdmPlcMacNetworkAdministrationData* object = (gxPrimeNbOfdmPlcMacNetworkAdministrationData*)e->target; + gxByteBuffer* data = e->value.byteArr; + if ((ret = cosem_setArray(data, object->directTable.size)) == 0) + { + for (pos = 0; pos != object->directTable.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->directTable, pos, (void**)&it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->directTable, pos, (void**)&it, sizeof(gxMacDirectTable))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + + if ((ret = cosem_setStructure(data, 7)) != 0 || + (ret = cosem_setInt16(data, it->sourceSId)) != 0 || + (ret = cosem_setInt16(data, it->sourceLnId)) != 0 || + (ret = cosem_setInt16(data, it->sourceLcId)) != 0 || + (ret = cosem_setInt16(data, it->destinationSId)) != 0 || + (ret = cosem_setInt16(data, it->destinationLnId)) != 0 || + (ret = cosem_setInt16(data, it->destinationLcId)) != 0 || + (ret = cosem_setOctetString2(data, it->did, sizeof(it->did))) != 0) + { + break; + } + } + } + return ret; +} + +int cosem_getAvailableSwitches(gxValueEventArg* e) +{ + gxMacAvailableSwitch* it; + int ret; + uint16_t pos; + gxPrimeNbOfdmPlcMacNetworkAdministrationData* object = (gxPrimeNbOfdmPlcMacNetworkAdministrationData*)e->target; + gxByteBuffer* data = e->value.byteArr; + if ((ret = cosem_setArray(data, object->availableSwitches.size)) == 0) + { + for (pos = 0; pos != object->availableSwitches.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->availableSwitches, pos, (void**)&it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->availableSwitches, pos, (void**)&it, sizeof(gxMacAvailableSwitch))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + + if ((ret = cosem_setStructure(data, 5)) != 0 || + (ret = cosem_setOctetString2(data, it->sna.data, (uint16_t)it->sna.size)) != 0 || + (ret = cosem_setInt16(data, it->lsId)) != 0 || + (ret = cosem_setInt8(data, it->level)) != 0 || + (ret = cosem_setInt8(data, it->rxLevel)) != 0 || + (ret = cosem_setInt8(data, it->rxSnr)) != 0) + { + break; + } + } + } + return ret; +} + +int cosem_getCommunications(gxValueEventArg* e) +{ + gxMacPhyCommunication* it; + int ret; + uint16_t pos; + gxPrimeNbOfdmPlcMacNetworkAdministrationData* object = (gxPrimeNbOfdmPlcMacNetworkAdministrationData*)e->target; + gxByteBuffer* data = e->value.byteArr; + if ((ret = cosem_setArray(data, object->communications.size)) == 0) + { + for (pos = 0; pos != object->communications.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->communications, pos, (void**)&it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->communications, pos, (void**)&it, sizeof(gxMacPhyCommunication))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + + if ((ret = cosem_setStructure(data, 9)) != 0 || + (ret = cosem_setOctetString2(data, it->eui, sizeof(it->eui))) != 0 || + (ret = cosem_setInt8(data, it->txPower)) != 0 || + (ret = cosem_setInt8(data, it->txCoding)) != 0 || + (ret = cosem_setInt8(data, it->rxCoding)) != 0 || + (ret = cosem_setInt8(data, it->rxLvl)) != 0 || + (ret = cosem_setInt8(data, it->snr)) != 0 || + (ret = cosem_setInt8(data, it->txPowerModified)) != 0 || + (ret = cosem_setInt8(data, it->txCodingModified)) != 0 || + (ret = cosem_setInt8(data, it->rxCodingModified)) != 0) + { + break; + } + } + } + return ret; +} + +int cosem_getPrimeNbOfdmPlcMacNetworkAdministrationData( + gxValueEventArg* e) +{ + int ret; + switch (e->index) + { + case 2: + ret = cosem_getMulticastEntries(e); + break; + case 3: + ret = cosem_getSwitchTable(e); + break; + case 4: + ret = cosem_getDirectTable(e); + break; + case 5: + ret = cosem_getAvailableSwitches(e); + break; + case 6: + ret = cosem_getCommunications(e); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION +int cosem_getPrimeNbOfdmPlcApplicationsIdentification( + gxValueEventArg* e) +{ + int ret; + gxPrimeNbOfdmPlcApplicationsIdentification* object = (gxPrimeNbOfdmPlcApplicationsIdentification*)e->target; + switch (e->index) + { + case 2: + { + ret = cosem_setOctetString2(e->value.byteArr, object->firmwareVersion.data, (uint16_t)object->firmwareVersion.size); + } + break; + case 3: + ret = cosem_setUInt16(e->value.byteArr, object->vendorId); + break; + case 4: + ret = cosem_setUInt16(e->value.byteArr, object->productId); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION +#ifndef DLMS_IGNORE_ARBITRATOR +int cosem_getArbitrator(gxValueEventArg* e) +{ + int ret; + uint16_t pos; + gxActionItem* it; + gxByteBuffer* data = e->value.byteArr; + gxArbitrator* object = (gxArbitrator*)e->target; + switch (e->index) + { + case 2: + { + if ((ret = cosem_setArray(data, object->actions.size)) == 0) + { + for (pos = 0; pos != object->actions.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->actions, pos, (void**)&it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->actions, pos, (void**)&it, sizeof(gxMacAvailableSwitch))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_STRUCTURE)) != 0 || + //Count + (ret = bb_setUInt8(data, 2)) != 0 || + (ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(data, 6)) != 0 || +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = bb_set(data, obj_getLogicalName((gxObject*)it->script), 6)) != 0 || +#else + (ret = bb_set(data, it->script->executedScriptLogicalName, 6)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_setUInt16(data, it->scriptSelector)) != 0) + { + break; + } + } + } + } + break; + case 3: + { + bitArray* a; + if ((ret = cosem_setArray(data, object->permissionsTable.size)) == 0) + { + for (pos = 0; pos != object->permissionsTable.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->permissionsTable, pos, (void**)&a)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->permissionsTable, pos, (void**)&a, sizeof(bitArray))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_BIT_STRING)) != 0 || + (ret = hlp_setObjectCount(a->size, data)) != 0) + { + break; + } + ret = bb_set(e->value.byteArr, a->data, ba_getByteCount(a->size)); + } + } + } + break; + case 4: + { + dlmsVARIANT* v; + if ((ret = cosem_setArray(data, object->weightingsTable.size)) == 0) + { + for (pos = 0; pos != object->weightingsTable.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->weightingsTable, pos, (void**)&v)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->weightingsTable, pos, (void**)&v, sizeof(dlmsVARIANT))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = cosem_setVariant(data, v)) != 0) + { + break; + } + } + } + } + break; + case 5: + { + bitArray* a; + if ((ret = cosem_setArray(data, object->mostRecentRequestsTable.size)) == 0) + { + for (pos = 0; pos != object->mostRecentRequestsTable.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->mostRecentRequestsTable, pos, (void**)&a)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->mostRecentRequestsTable, pos, (void**)&a, sizeof(bitArray))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_BIT_STRING)) != 0 || + (ret = hlp_setObjectCount(a->size, data)) != 0) + { + break; + } + ret = bb_set(e->value.byteArr, a->data, ba_getByteCount(a->size)); + } + } + } + break; + case 6: + ret = cosem_setUInt8(data, object->lastOutcome); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_ARBITRATOR + +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +int cosem_getIec8802LlcType1Setup( + gxValueEventArg* e) +{ + int ret = 0; + gxByteBuffer* data = e->value.byteArr; + gxIec8802LlcType1Setup* object = (gxIec8802LlcType1Setup*)e->target; + if (e->index == 2) + { + ret = cosem_setUInt16(data, object->maximumOctetsUiPdu); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP +int cosem_getIec8802LlcType2Setup( + gxValueEventArg* e) +{ + int ret = 0; + gxByteBuffer* data = e->value.byteArr; + gxIec8802LlcType2Setup* object = (gxIec8802LlcType2Setup*)e->target; + switch (e->index) + { + case 2: + ret = cosem_setUInt8(data, object->transmitWindowSizeK); + break; + case 3: + ret = cosem_setUInt8(data, object->transmitWindowSizeRW); + break; + case 4: + ret = cosem_setUInt16(data, object->maximumOctetsPdu); + break; + case 5: + ret = cosem_setUInt8(data, object->maximumNumberTransmissions); + break; + case 6: + ret = cosem_setUInt16(data, object->acknowledgementTimer); + break; + case 7: + ret = cosem_setUInt16(data, object->bitTimer); + break; + case 8: + ret = cosem_setUInt16(data, object->rejectTimer); + break; + case 9: + ret = cosem_setUInt16(data, object->busyStateTimer); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} + +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP +int cosem_getIec8802LlcType3Setup( + gxValueEventArg* e) +{ + int ret = 0; + gxByteBuffer* data = e->value.byteArr; + gxIec8802LlcType3Setup* object = (gxIec8802LlcType3Setup*)e->target; + switch (e->index) + { + case 2: + ret = cosem_setUInt16(data, object->maximumOctetsACnPdu); + break; + case 3: + ret = cosem_setUInt8(data, object->maximumTransmissions); + break; + case 4: + ret = cosem_setUInt16(data, object->acknowledgementTime); + break; + case 5: + ret = cosem_setUInt16(data, object->receiveLifetime); + break; + case 6: + ret = cosem_setUInt16(data, object->transmitLifetime); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP +#ifndef DLMS_IGNORE_SFSK_ACTIVE_INITIATOR +int cosem_getSFSKActiveInitiator( + gxValueEventArg* e) +{ + int ret; + gxByteBuffer* data = e->value.byteArr; + gxSFSKActiveInitiator* object = (gxSFSKActiveInitiator*)e->target; + if (e->index == 2) + { + if ((ret = cosem_setStructure(data, 3)) == 0 && + (ret = cosem_setOctetString(data, &object->systemTitle)) == 0 && + (ret = cosem_setUInt16(data, object->macAddress)) == 0 && + (ret = cosem_setUInt8(data, object->lSapSelector)) == 0) + { + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SFSK_ACTIVE_INITIATOR +#ifndef DLMS_IGNORE_SFSK_MAC_COUNTERS +int cosem_getFSKMacCounters( + gxValueEventArg* e) +{ + int ret = 0; + uint16_t pos; + gxByteBuffer* data = e->value.byteArr; + gxFSKMacCounters* object = (gxFSKMacCounters*)e->target; + switch (e->index) + { + case 2: + { + gxUint16PairUint32* it; + if ((ret = cosem_setArray(data, object->synchronizationRegister.size)) == 0) + { + for (pos = 0; pos != object->synchronizationRegister.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->synchronizationRegister, pos, (void**)&it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->synchronizationRegister, pos, (void**)&it, sizeof(gxFSKMacCounters))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = cosem_setStructure(data, 2)) != 0 || + (ret = cosem_setUInt16(data, it->first)) != 0 || + (ret = cosem_setUInt32(data, it->second)) != 0) + { + break; + } + } + } + } + break; + case 3: + { + if ((ret = cosem_setStructure(data, 5)) == 0 && + (ret = cosem_setUInt32(data, object->physicalLayerDesynchronization)) == 0 && + (ret = cosem_setUInt32(data, object->timeOutNotAddressedDesynchronization)) == 0 && + (ret = cosem_setUInt32(data, object->timeOutFrameNotOkDesynchronization)) == 0 && + (ret = cosem_setUInt32(data, object->writeRequestDesynchronization)) == 0 && + (ret = cosem_setUInt32(data, object->wrongInitiatorDesynchronization)) == 0) + { + } + } + break; + case 4: + { + gxUint16PairUint32* it; + if ((ret = cosem_setArray(data, object->broadcastFramesCounter.size)) == 0) + { + for (pos = 0; pos != object->broadcastFramesCounter.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->broadcastFramesCounter, pos, (void**)&it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->broadcastFramesCounter, pos, (void**)&it, sizeof(gxFSKMacCounters))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = cosem_setStructure(data, 2)) != 0 || + (ret = cosem_setUInt16(data, it->first)) != 0 || + (ret = cosem_setUInt32(data, it->second)) != 0) + { + break; + } + } + } + } + break; + case 5: + ret = cosem_setUInt32(data, object->repetitionsCounter); + break; + case 6: + ret = cosem_setUInt32(data, object->transmissionsCounter); + break; + case 7: + ret = cosem_setUInt32(data, object->crcOkFramesCounter); + break; + case 8: + ret = cosem_setUInt32(data, object->crcNOkFramesCounter); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SFSK_MAC_COUNTERS + +#ifndef DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS +int cosem_getSFSKMacSynchronizationTimeouts( + gxValueEventArg* e) +{ + int ret = 0; + gxByteBuffer* data = e->value.byteArr; + gxSFSKMacSynchronizationTimeouts* object = (gxSFSKMacSynchronizationTimeouts*)e->target; + switch (e->index) + { + case 2: + ret = cosem_setUInt16(data, object->searchInitiatorTimeout); + break; + case 3: + ret = cosem_setUInt16(data, object->synchronizationConfirmationTimeout); + break; + case 4: + ret = cosem_setUInt16(data, object->timeOutNotAddressed); + break; + case 5: + ret = cosem_setUInt16(data, object->timeOutFrameNotOK); + break; + default: + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS +#ifndef DLMS_IGNORE_SFSK_PHY_MAC_SETUP +int cosem_getSFSKPhyMacSetUp( + gxValueEventArg* e) +{ + int ret = 0; + gxByteBuffer* data = e->value.byteArr; + gxSFSKPhyMacSetUp* object = (gxSFSKPhyMacSetUp*)e->target; + switch (e->index) + { + case 2: + ret = cosem_setEnum(data, object->initiatorElectricalPhase); + break; + case 3: + ret = cosem_setEnum(data, object->deltaElectricalPhase); + break; + case 4: + ret = cosem_setUInt8(data, object->maxReceivingGain); + break; + case 5: + ret = cosem_setUInt8(data, object->maxTransmittingGain); + break; + case 6: + ret = cosem_setUInt8(data, object->searchInitiatorThreshold); + break; + case 7: + { + if ((ret = cosem_setStructure(data, 2)) == 0 && + (ret = cosem_setUInt32(data, object->markFrequency)) == 0 && + (ret = cosem_setUInt32(data, object->spaceFrequency)) == 0) + { + } + break; + } + case 8: + ret = cosem_setUInt16(data, object->macAddress); + break; + case 9: + { + uint16_t pos; + uint16_t* it; + if ((ret = cosem_setArray(data, object->macGroupAddresses.size)) == 0) + { + for (pos = 0; pos != object->macGroupAddresses.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->macGroupAddresses, pos, (void**)&it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->macGroupAddresses, pos, (void**)&it, sizeof(uint16_t))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = cosem_setUInt16(data, *it)) != 0) + { + break; + } + } + } + } + break; + case 10: + ret = cosem_setEnum(data, object->repeater); + break; + case 11: + ret = cosem_setBoolean(data, object->repeaterStatus); + break; + case 12: + ret = cosem_setUInt8(data, object->minDeltaCredit); + break; + case 13: + ret = cosem_setUInt16(data, object->initiatorMacAddress); + break; + case 14: + ret = cosem_setBoolean(data, object->synchronizationLocked); + break; + case 15: + ret = cosem_setEnum(data, object->transmissionSpeed); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_SFSK_PHY_MAC_SETUP +#ifndef DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST +int cosem_getSFSKReportingSystemList( + gxValueEventArg* e) +{ + int ret = DLMS_ERROR_CODE_OK; + gxByteBuffer* data = e->value.byteArr; + gxSFSKReportingSystemList* object = (gxSFSKReportingSystemList*)e->target; + if (e->index == 2) + { + uint16_t pos; + gxByteBuffer* it; + if ((ret = cosem_setArray(data, object->reportingSystemList.size)) == 0) + { + for (pos = 0; pos != object->reportingSystemList.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->reportingSystemList, pos, (void**)&it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->reportingSystemList, pos, (void**)&it, sizeof(uint16_t))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = cosem_setOctetString(data, it)) != 0) + { + break; + } + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST diff --git a/components/xt211/gxget.h b/components/xt211/gxget.h new file mode 100644 index 0000000..e1b5421 --- /dev/null +++ b/components/xt211/gxget.h @@ -0,0 +1,296 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef COSEM_GET_H +#define COSEM_GET_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "gxobjects.h" +#include "dlmssettings.h" + + int cosem_getData( + gxValueEventArg* e); + + int cosem_getRegister( + gxValueEventArg* e); + +#ifndef DLMS_IGNORE_CLOCK + int cosem_getClock( + gxValueEventArg* e); + + //Update Daylight Saving time flag if DST is used. + void clock_updateDST( + gxClock* object, + gxtime* value); + + //Convert UTC date time to meter date time. + int clock_utcToMeterTime( + gxClock* object, + gxtime* value); + +#endif // DLMS_IGNORE_CLOCK + + int cosem_getActionSchedule( + gxValueEventArg* e); + + int cosem_getActivityCalendar( + gxValueEventArg* e); + + int cosem_getAssociationLogicalName( + dlmsSettings* settings, + gxValueEventArg* e); + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + int cosem_getAssociationShortName( + dlmsSettings* settings, + gxValueEventArg* e); +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + + int cosem_getAutoAnswer( + gxValueEventArg* e); + + int cosem_getAutoConnect( + gxValueEventArg* e); + + int cosem_getDemandRegister( + gxValueEventArg* e); + + int cosem_getMacAddressSetup( + gxValueEventArg* e); + + int cosem_getExtendedRegister( + gxValueEventArg* e); + + int cosem_getGprsSetup( + gxValueEventArg* e); + + int cosem_getSecuritySetup( + gxValueEventArg* e); + + int cosem_getIecHdlcSetup( + gxValueEventArg* e); + + int cosem_getIecLocalPortSetup( + gxValueEventArg* e); + + int cosem_getIP4Setup( + gxValueEventArg* e); + + int cosem_getProfileGeneric( + dlmsSettings* settings, + gxValueEventArg* e); + + int cosem_getMbusSlavePortSetup( + gxValueEventArg* e); + + int cosem_getDisconnectControl( + gxValueEventArg* e); + + int cosem_getLimiter( + gxValueEventArg* e); + + int cosem_getmMbusClient( + gxValueEventArg* e); + + int cosem_getModemConfiguration( + dlmsSettings* settings, + gxValueEventArg* e); + + int cosem_getPppSetup( + gxValueEventArg* e); + + int cosem_getRegisterActivation( + dlmsSettings* settings, + gxValueEventArg* e); + + int cosem_getRegisterMonitor( + gxValueEventArg* e); + + int cosem_getSapAssignment( + gxValueEventArg* e); + + int cosem_getSchedule( + gxValueEventArg* e); + + int cosem_getScriptTable( + gxValueEventArg* e); + + int cosem_getSpecialDaysTable( + gxValueEventArg* e); + + int cosem_getTcpUdpSetup( + gxValueEventArg* e); + + int cosem_getMbusMasterPortSetup( + gxValueEventArg* e); + + int cosem_getMessageHandler( + gxValueEventArg* e); + + int cosem_getPushSetup( + gxValueEventArg* e); + + int cosem_getValue( + dlmsSettings* settings, + gxValueEventArg* e); + + +#ifndef DLMS_IGNORE_G3_PLC_MAC_SETUP + int cosem_getG3PlcMacSetupNeighbourTables( + gxArray* tables, + uint16_t address, + uint16_t count, + gxValueEventArg* e); + + int cosem_getG3PlcMacSetupPosTables( + gxArray* tables, + uint16_t address, + uint16_t count, + gxValueEventArg* e); +#endif //DLMS_IGNORE_G3_PLC_MAC_SETUP + +#ifndef DLMS_IGNORE_MALLOC + int cosem_getRow( + gxArray* table, + int index, + gxArray* captureObjects, + gxArray* columns, + gxByteBuffer* data); +#endif //DLMS_IGNORE_MALLOC + + int cosem_getTariffPlan( + gxValueEventArg* e); + +#ifndef DLMS_IGNORE_GSM_DIAGNOSTIC + int cosem_getGsmDiagnostic( + gxValueEventArg* e); +#endif //DLMS_IGNORE_GSM_DIAGNOSTIC + +#ifndef DLMS_IGNORE_PARAMETER_MONITOR + int cosem_getParameterMonitor( + gxValueEventArg* e); +#endif //DLMS_IGNORE_PARAMETER_MONITOR + +#ifndef DLMS_IGNORE_COMPACT_DATA + //Convert compact data buffer to array of values. + int compactData_getValues( + dlmsSettings* settings, + gxByteBuffer* templateDescription, + gxByteBuffer* buffer, + variantArray* values); +#endif //DLMS_IGNORE_COMPACT_DATA + +#ifndef DLMS_IGNORE_LLC_SSCS_SETUP + int cosem_getLlcSscsSetup( + gxValueEventArg* e); +#endif //DLMS_IGNORE_LLC_SSCS_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS + int cosem_getPrimeNbOfdmPlcPhysicalLayerCounters( + gxValueEventArg* e); +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP + int cosem_getPrimeNbOfdmPlcMacSetup( + gxValueEventArg* e); +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS + int cosem_getPrimeNbOfdmPlcMacFunctionalParameters( + gxValueEventArg* e); +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS + int cosem_getPrimeNbOfdmPlcMacCounters( + gxValueEventArg* e); +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + int cosem_getPrimeNbOfdmPlcMacNetworkAdministrationData( + gxValueEventArg* e); +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION + int cosem_getPrimeNbOfdmPlcApplicationsIdentification( + gxValueEventArg* e); +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION +#ifndef DLMS_IGNORE_ARBITRATOR + int cosem_getArbitrator( + gxValueEventArg* e); +#endif //DLMS_IGNORE_ARBITRATOR +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP + int cosem_getIec8802LlcType1Setup( + gxValueEventArg* e); +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP + int cosem_getIec8802LlcType2Setup( + gxValueEventArg* e); +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP + int cosem_getIec8802LlcType3Setup( + gxValueEventArg* e); +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP +#ifndef DLMS_IGNORE_SFSK_ACTIVE_INITIATOR + int cosem_getSFSKActiveInitiator( + gxValueEventArg* e); +#endif //DLMS_IGNORE_SFSK_ACTIVE_INITIATOR +#ifndef DLMS_IGNORE_SFSK_MAC_COUNTERS + int cosem_getFSKMacCounters( + gxValueEventArg* e); +#endif //DLMS_IGNORE_SFSK_MAC_COUNTERS +#ifndef DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS + int cosem_getSFSKMacSynchronizationTimeouts( + gxValueEventArg* e); +#endif //DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS +#ifndef DLMS_IGNORE_SFSK_PHY_MAC_SETUP + int cosem_getSFSKPhyMacSetUp( + gxValueEventArg* e); +#endif //DLMS_IGNORE_SFSK_PHY_MAC_SETUP +#ifndef DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST + int cosem_getSFSKReportingSystemList( + gxValueEventArg* e); +#endif //DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST + +#ifdef DLMS_ITALIAN_STANDARD + //Convert compact data buffer to array of values. + //Some Italy meters require that there is a array count in data. + //This is against compact data structure defined in DLMS standard. + int compactData_getValues2( + dlmsSettings* settings, + gxByteBuffer* templateDescription, + gxByteBuffer* buffer, + variantArray* values, + unsigned char appendAA); +#endif //DLMS_ITALIAN_STANDARD + +#ifdef __cplusplus +} +#endif + +#endif //COSEM_GET_H diff --git a/components/xt211/gxignore.h b/components/xt211/gxignore.h new file mode 100644 index 0000000..23bbc59 --- /dev/null +++ b/components/xt211/gxignore.h @@ -0,0 +1,252 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- +#ifndef GXIGNORE_H +#define GXIGNORE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Uncomment defines to ignore non-needed parts to make image size smaller. */ + +// #define DLMS_IGNORE_HDLC +// #define DLMS_IGNORE_WRAPPER +// #define DLMS_IGNORE_PLC +// #define DLMS_IGNORE_IEC +// #define DLMS_IGNORE_NOTIFY +// #define DLMS_IGNORE_SERVER +// #define DLMS_IGNORE_CLIENT +// #define GX_DLMS_MICROCONTROLLER +// #define DLMS_IGNORE_HIGH_SHA256 +// #define DLMS_IGNORE_HIGH_SHA1 +// #define DLMS_IGNORE_HIGH_MD5 +// #define DLMS_IGNORE_AES +// #define DLMS_IGNORE_HIGH_GMAC +// #define DLMS_IGNORE_DATA +// #define DLMS_IGNORE_REGISTER +// #define DLMS_IGNORE_EXTENDED_REGISTER +// #define DLMS_IGNORE_DEMAND_REGISTER +// #define DLMS_IGNORE_REGISTER_ACTIVATION +// #define DLMS_IGNORE_PROFILE_GENERIC +// #define DLMS_IGNORE_CLOCK +// #define DLMS_IGNORE_SCRIPT_TABLE +// #define DLMS_IGNORE_SCHEDULE +// #define DLMS_IGNORE_SPECIAL_DAYS_TABLE +// #define DLMS_IGNORE_ASSOCIATION_SHORT_NAME +// #define DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME +// #define DLMS_IGNORE_SAP_ASSIGNMENT +// #define DLMS_IGNORE_IMAGE_TRANSFER +// #define DLMS_IGNORE_IEC_LOCAL_PORT_SETUP +// #define DLMS_IGNORE_ACTIVITY_CALENDAR +// #define DLMS_IGNORE_REGISTER_MONITOR +// #define DLMS_IGNORE_ACTION_SCHEDULE +// #define DLMS_IGNORE_IEC_HDLC_SETUP +// #define DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP +// #define DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP +// #define DLMS_IGNORE_UTILITY_TABLES +// #define DLMS_IGNORE_MODEM_CONFIGURATION +// #define DLMS_IGNORE_AUTO_ANSWER +// #define DLMS_IGNORE_AUTO_CONNECT +// #define DLMS_IGNORE_TCP_UDP_SETUP +// #define DLMS_IGNORE_IP4_SETUP +// #define DLMS_IGNORE_IP6_SETUP +// #define DLMS_IGNORE_MAC_ADDRESS_SETUP +// #define DLMS_IGNORE_PPP_SETUP +// #define DLMS_IGNORE_GPRS_SETUP +// #define DLMS_IGNORE_SMTP_SETUP +// #define DLMS_IGNORE_GSM_DIAGNOSTIC +// #define DLMS_IGNORE_REGISTER_TABLE +// #define DLMS_IGNORE_STATUS_MAPPING +// #define DLMS_IGNORE_SECURITY_SETUP +// #define DLMS_IGNORE_DISCONNECT_CONTROL +// #define DLMS_IGNORE_LIMITER +// #define DLMS_IGNORE_MBUS_CLIENT +// #define DLMS_IGNORE_PUSH_SETUP +// #define DLMS_IGNORE_PARAMETER_MONITOR +// #define DLMS_IGNORE_WIRELESS_MODE_Q_CHANNEL +// #define DLMS_IGNORE_MBUS_MASTER_PORT_SETUP +// #define DLMS_IGNORE_ZIG_BEE_SAS_STARTUP +// #define DLMS_IGNORE_ZIG_BEE_SAS_JOIN +// #define DLMS_IGNORE_ZIG_BEE_SAS_APS_FRAGMENTATION +// #define DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL +// #define DLMS_IGNORE_DATA_PROTECTION +// #define DLMS_IGNORE_ACCOUNT +// #define DLMS_IGNORE_CREDIT +// #define DLMS_IGNORE_CHARGE +// #define DLMS_IGNORE_TOKEN_GATEWAY +// #define DLMS_IGNORE_COMPACT_DATA +// #define DLMS_IGNORE_LLC_SSCS_SETUP +// #define DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +// #define DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +// #define DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +// #define DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +// #define DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA +// #define DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION +// #define DLMS_IGNORE_ARBITRATOR +// #define DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS +// #define DLMS_IGNORE_G3_PLC_MAC_SETUP +// #define DLMS_IGNORE_G3_PLC_6LO_WPAN +// #define DLMS_IGNORE_FUNCTION_CONTROL +// #define DLMS_IGNORE_ARRAY_MANAGER + +// #define DLMS_IGNORE_MALLOC +// #define DLMS_USE_CUSTOM_MALLOC + +// #define DLMS_IGNORE_OBJECT_POINTERS + +// #define DLMS_IGNORE_FLOAT32 +// #define DLMS_IGNORE_FLOAT64 + +//Use EPOCH time. This can be used to improve memory usage. +// #define DLMS_USE_EPOCH_TIME + +//Use UTC time zone. Read more: https://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSClock +// #define DLMS_USE_UTC_TIME_ZONE + +// #define DLMS_IGNORE_SET +// #define DLMS_IGNORE_ACTION + +// String converters are not used. +// #define DLMS_IGNORE_STRING_CONVERTER + +//Framework send debug information that can be used in debugging. +// #define DLMS_DEBUG + +//Defined if AVR is used. +// #define USE_AVR + +//Defined if program memory (flash) is used instead of SRAM. +// #define USE_PROGMEM + +// COSEM objects are using DLMS standard data types. +// Using exact data types will save memory, but reading failes if meter returns wrong data type, +// ex. Int8 when data type should be UInt8. +// #define DLMS_COSEM_EXACT_DATA_TYPES + +// If innovation counter size is UInt64 and not default UInt32. +// #define DLMS_COSEM_INVOCATION_COUNTER_SIZE64 + +// Use 32 bit max size bytebuffer instead of 16 bit. +// This might be used in client side if a lot of data is read from the meter. +// #define GX_DLMS_BYTE_BUFFER_SIZE_32 + +//Serializer is not used. +//DLMS_IGNORE_SERIALIZER +//Serializer is used instead of file system. +//#define GX_DLMS_SERIALIZER + +//GENERAL_CIPHERING is not used. +//#define DLMS_IGNORE_GENERAL_CIPHERING + +/** +* Ignore HDLC Control field check. +Some meters are sending invalid control field. +Note! It's not recommended to use this. +*/ +//#define DLMS_IGNORE_HDLC_CHECK + +// #define DLMS_ITALIAN_STANDARD +// #define DLMS_INDONESIA_STANDARD + +#ifdef ARDUINO +///////////////////////////////////////////////////////////////////////////// +//If Arduino is used. +#include "ArduinoIgnore.h" +///////////////////////////////////////////////////////////////////////////// +#endif //ARDUINO + +#ifdef ARDUINO_ARCH_AVR +///////////////////////////////////////////////////////////////////////////// +//If Arduino is used. +#include "ArduinoIgnore.h" +#define DLMS_IGNORE_IP6_SETUP +#define DLMS_USE_EPOCH_TIME +#define DLMS_IGNORE_NOTIFY +#define GX_DLMS_MICROCONTROLLER +#define DLMS_IGNORE_HIGH_SHA256 +#define DLMS_IGNORE_HIGH_SHA1 +#define DLMS_IGNORE_HIGH_MD5 +#define USE_PROGMEM +///////////////////////////////////////////////////////////////////////////// +#endif //ARDUINO_ARCH_AVR + +#ifdef ARDUINO_ARCH_ESP32 +///////////////////////////////////////////////////////////////////////////// +//If Arduino ESP32 is used. +#include "ArduinoIgnore.h" +#define DLMS_IGNORE_IP6_SETUP +#define DLMS_USE_EPOCH_TIME +#define DLMS_IGNORE_NOTIFY +#define GX_DLMS_MICROCONTROLLER +#define DLMS_IGNORE_HIGH_SHA256 +#define DLMS_IGNORE_HIGH_SHA1 +#define DLMS_IGNORE_HIGH_MD5 +///////////////////////////////////////////////////////////////////////////// +#endif //ARDUINO_ARCH_ESP32 + +#ifdef ARDUINO_ARCH_ESP8266 +///////////////////////////////////////////////////////////////////////////// +//If Arduino ESP is used. +#include "ArduinoIgnore.h" +#ifndef ESP_PLATFORM +#define ESP_PLATFORM +#endif +#define DLMS_IGNORE_IP6_SETUP +#define DLMS_USE_EPOCH_TIME +#define DLMS_IGNORE_NOTIFY +#define GX_DLMS_MICROCONTROLLER +#define DLMS_IGNORE_HIGH_SHA256 +#define DLMS_IGNORE_HIGH_SHA1 +#define DLMS_IGNORE_HIGH_MD5 +///////////////////////////////////////////////////////////////////////////// +#endif //ARDUINO_ARCH_ESP8266 + +#ifdef USE_ESP32_FRAMEWORK_ESP_IDF +#include "ArduinoIgnore.h" +#ifndef ESP_PLATFORM +#define ESP_PLATFORM +#endif +#define DLMS_IGNORE_IP6_SETUP +#define DLMS_USE_EPOCH_TIME +#define DLMS_IGNORE_NOTIFY +#define DLMS_IGNORE_FUNCTION_CONTROL +#define GX_DLMS_MICROCONTROLLER +#define DLMS_IGNORE_HIGH_SHA256 +#define DLMS_IGNORE_HIGH_SHA1 +#define DLMS_IGNORE_HIGH_MD5 +#endif + +#ifdef __cplusplus +} +#endif + +#endif //GXIGNORE_H diff --git a/components/xt211/gxint.h b/components/xt211/gxint.h new file mode 100644 index 0000000..99d4736 --- /dev/null +++ b/components/xt211/gxint.h @@ -0,0 +1,65 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef GXINT_H +#define GXINT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif +#if !(defined uint16_t) && !(defined _UINT16_T_DECLARED) +#define uint16_t unsigned short +#endif //!(defined uint16_t) && !(defined _UINT16_T_DECLARED) +#if !(defined uint32_t) && !(defined _UINT32_T_DECLARED) +#define uint32_t unsigned long +#endif //!(defined uint32_t) && !(defined _UINT32_T_DECLARED) +#if !(defined uint64_t) && !(defined _UINT64_T_DECLARED) +#define uint64_t unsigned long long +#endif //#!(defined uint64_t) && !(defined _UINT64_T_DECLARED) + +#if !(defined int16_t) && !(defined _INT16_T_DECLARED) +#define int16_t short +#endif //!(defined int16_t) && !(defined _INT16_T_DECLARED) +#if !(defined int32_t) && !(defined _INT32_T_DECLARED) +#define int32_t long +#endif //!(defined int32_t) && !(defined _INT32_T_DECLARED) +#if !(defined int64_t) && !(defined _INT64_T_DECLARED) +#define int64_t long long +#endif //!(defined int64_t) && !(defined _INT64_T_DECLARED) + +#ifdef __cplusplus +} +#endif + +#endif //GXINT_H diff --git a/components/xt211/gxkey.c b/components/xt211/gxkey.c new file mode 100644 index 0000000..84aa073 --- /dev/null +++ b/components/xt211/gxkey.c @@ -0,0 +1,57 @@ +// +// -------------------------------------------------------------------------- +// 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" +#include "gxkey.h" +#ifndef DLMS_IGNORE_MALLOC +gxKey* key_init(void* key, void* value) +{ + gxKey* obj = (gxKey*) gxmalloc(sizeof(gxKey)); + if (obj != NULL) + { + obj->key = key; + obj->value = value; + } + return obj; +} + +gxKey2* key_init2(unsigned char key, void* value) +{ + gxKey2* obj = (gxKey2*)gxmalloc(sizeof(gxKey2)); + if (obj != NULL) + { + obj->key = key; + obj->value = value; + } + return obj; +} +#endif //DLMS_IGNORE_MALLOC diff --git a/components/xt211/gxkey.h b/components/xt211/gxkey.h new file mode 100644 index 0000000..fa54238 --- /dev/null +++ b/components/xt211/gxkey.h @@ -0,0 +1,60 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef GXKEY_H +#define GXKEY_H +#include "gxignore.h" +#ifdef __cplusplus +extern "C" { +#endif +#ifndef DLMS_IGNORE_MALLOC + +typedef struct { + void *key; + void *value; +} gxKey; + +typedef struct { + unsigned char key; + void *value; +} gxKey2; + +//Make key. + gxKey* key_init(void* key, void* value); + + gxKey2* key_init2(unsigned char key, void* value); + +#endif //DLMS_IGNORE_MALLOC +#ifdef __cplusplus +} +#endif +#endif //GXKEY_H diff --git a/components/xt211/gxmem.h b/components/xt211/gxmem.h new file mode 100644 index 0000000..c1d6e4a --- /dev/null +++ b/components/xt211/gxmem.h @@ -0,0 +1,68 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef GX_MEM +#define GX_MEM +#include "gxignore.h" +#if !defined(DLMS_USE_CUSTOM_MALLOC) && !defined(DLMS_IGNORE_MALLOC) + +#ifdef __cplusplus +extern "C" { +#endif + +#include // malloc and free needs this or error is generated. +#if _MSC_VER > 1400 +#include +#endif + +#ifndef gxfree +#define gxfree(p) free(p) +#endif + +#ifndef gxmalloc +#define gxmalloc(s) malloc(s) +#endif + +#ifndef gxcalloc +#define gxcalloc(p, s) calloc(p, s) +#endif + + +#ifndef gxrealloc +#define gxrealloc(p, s) realloc(p, s) +#endif + +#ifdef __cplusplus +} +#endif +#endif //!defined(DLMS_USE_CUSTOM_MALLOC) && !defined(DLMS_IGNORE_MALLOC) +#endif //GX_MEM diff --git a/components/xt211/gxobjects.c b/components/xt211/gxobjects.c new file mode 100644 index 0000000..896eee8 --- /dev/null +++ b/components/xt211/gxobjects.c @@ -0,0 +1,2162 @@ +// +// -------------------------------------------------------------------------- +// 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 +#ifndef GX_DLMS_MICROCONTROLLER +#include //printf needs this or error is generated. +#endif +#endif +#include "gxmem.h" +#if _MSC_VER > 1400 +#include +#endif +#include + +#include "helpers.h" +#include "gxobjects.h" +#include "objectarray.h" + +const unsigned char* obj_getLogicalName(gxObject* target) +{ + if (target == NULL) + { + return EMPTY_LN; + } + return target->logicalName; +} + +#ifndef DLMS_IGNORE_PROFILE_GENERIC +#ifndef DLMS_IGNORE_MALLOC +//Create capture object with given attribute and data indexes. +gxTarget* co_init( + unsigned char attributeIndex, + unsigned char dataIndex) +{ + gxTarget* obj = (gxTarget*)gxmalloc(sizeof(gxTarget)); + obj->attributeIndex = attributeIndex; + obj->dataIndex = dataIndex; + return obj; +} +#endif //DLMS_IGNORE_MALLOC + +int obj_clearProfileGenericBuffer(gxArray* buffer) +{ + //Clear data rows. +#ifndef DLMS_IGNORE_MALLOC + variantArray* va; + int pos, ret; + for (pos = 0; pos != buffer->size; ++pos) + { + ret = arr_getByIndex(buffer, pos, (void**)&va); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + va_clear(va); + } +#endif //DLMS_IGNORE_MALLOC + arr_clear(buffer); + return 0; +} +#endif //DLMS_IGNORE_PROFILE_GENERIC + +#if !(defined(DLMS_IGNORE_PROFILE_GENERIC) && defined(DLMS_IGNORE_COMPACT_DATA) && defined(DLMS_IGNORE_PUSH_SETUP)) +int obj_clearPushObjectList(gxArray* buffer) +{ + int ret = 0; +#if !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + int pos; + gxKey* kv; + //Objects are not cleared because client owns them and clears them later. + for (pos = 0; pos != buffer->size; ++pos) + { + ret = arr_getByIndex(buffer, pos, (void**)&kv); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + gxfree(kv->value); + } +#endif // !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + arr_clear(buffer); + return ret; +} +#endif //!(defined(DLMS_IGNORE_PROFILE_GENERIC) && defined(DLMS_OBJECT_TYPE_PUSH_SETUP) && defined(DLMS_IGNORE_PUSH_SETUP)) + +#ifndef DLMS_IGNORE_ACCOUNT + +int obj_clearCreditChargeConfigurations(gxArray* list) +{ + int ret = DLMS_ERROR_CODE_OK; +#ifndef DLMS_IGNORE_MALLOC + gxCreditChargeConfiguration* it; + int pos; + //Clear push objects. + for (pos = 0; pos != list->size; ++pos) + { + ret = arr_getByIndex(list, pos, (void**)&it); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + memset(it->creditReference, 0, sizeof(it->creditReference)); + memset(it->chargeReference, 0, sizeof(it->creditReference)); + it->collectionConfiguration = DLMS_CREDIT_COLLECTION_CONFIGURATION_DISCONNECTED; + } +#endif //DLMS_IGNORE_MALLOC + arr_clear(list); + return ret; +} + +int obj_clearTokenGatewayConfigurations(gxArray* list) +{ + int ret = DLMS_ERROR_CODE_OK; +#ifndef DLMS_IGNORE_MALLOC + gxTokenGatewayConfiguration* it; + int pos; + //Clear push objects. + for (pos = 0; pos != list->size; ++pos) + { + ret = arr_getByIndex(list, pos, (void**)&it); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + memset(it->creditReference, 0, 6); + } +#endif //DLMS_IGNORE_MALLOC + arr_clear(list); + return ret; +} +#endif //DLMS_IGNORE_ACCOUNT +#ifndef DLMS_IGNORE_SAP_ASSIGNMENT +int obj_clearSapList(gxArray* buffer) +{ + int ret = DLMS_ERROR_CODE_OK; +#ifndef DLMS_IGNORE_MALLOC + int pos; + gxSapItem* it; + //Objects are not cleared because client owns them and clears them later. + for (pos = 0; pos != buffer->size; ++pos) + { + ret = arr_getByIndex(buffer, pos, (void**)&it); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + bb_clear(&it->name); + } +#endif //DLMS_IGNORE_MALLOC + arr_clear(buffer); + return ret; +} +#endif //DLMS_IGNORE_SAP_ASSIGNMENT +#if !(defined(DLMS_IGNORE_PROFILE_GENERIC) && defined(DLMS_IGNORE_COMPACT_DATA)) +int obj_clearProfileGenericCaptureObjects(gxArray* captureObjects) +{ + int ret = DLMS_ERROR_CODE_OK; +#if !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + int pos; + gxKey* kv; + //Objects are not cleared because client owns them and clears them later. + for (pos = 0; pos != captureObjects->size; ++pos) + { + ret = arr_getByIndex(captureObjects, pos, (void**)&kv); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + gxfree(kv->value); + } +#endif // !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + arr_clear(captureObjects); + return ret; +} +#endif //!(defined(DLMS_IGNORE_PROFILE_GENERIC) && defined(DLMS_IGNORE_COMPACT_DATA)) + +#ifndef DLMS_IGNORE_ACTIVITY_CALENDAR +int obj_clearSeasonProfile(gxArray* list) +{ + int ret = DLMS_ERROR_CODE_OK; +#ifndef DLMS_IGNORE_MALLOC + int pos; + gxSeasonProfile* sp; + for (pos = 0; pos != list->size; ++pos) + { + ret = arr_getByIndex(list, pos, (void**)&sp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + bb_clear(&sp->name); + bb_clear(&sp->weekName); + }; +#endif //DLMS_IGNORE_MALLOC + arr_clear(list); + return ret; +} + +int obj_clearWeekProfileTable(gxArray* list) +{ + int ret = DLMS_ERROR_CODE_OK; +#ifndef DLMS_IGNORE_MALLOC + int pos; + gxWeekProfile* wp; + for (pos = 0; pos != list->size; ++pos) + { + ret = arr_getByIndex(list, pos, (void**)&wp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + bb_clear(&wp->name); + } +#endif //DLMS_IGNORE_MALLOC + arr_clear(list); + return ret; +} + +int obj_clearDayProfileTable(gxArray* list) +{ + int ret = DLMS_ERROR_CODE_OK; +#ifndef DLMS_IGNORE_MALLOC + int pos, pos2; + gxDayProfile* it; + gxDayProfileAction* dp; + for (pos = 0; pos != list->size; ++pos) + { + if ((ret = arr_getByIndex(list, pos, (void**)&it)) != DLMS_ERROR_CODE_OK) + { + break; + } + for (pos2 = 0; pos2 != it->daySchedules.size; ++pos2) + { + if ((ret = arr_getByIndex(&it->daySchedules, pos2, (void**)&dp)) != DLMS_ERROR_CODE_OK) + { + break; + } + if (ret != 0) + { + break; + } + } + arr_clear(&it->daySchedules); + }; +#endif //DLMS_IGNORE_MALLOC + arr_clear(list); + return ret; +} +#endif //DLMS_IGNORE_ACTIVITY_CALENDAR +#ifndef DLMS_IGNORE_REGISTER_MONITOR +int obj_clearRegisterMonitorActions(gxArray* list) +{ + arr_clear(list); + return 0; +} +#endif //DLMS_IGNORE_REGISTER_MONITOR +#ifndef DLMS_IGNORE_MODEM_CONFIGURATION +int obj_clearModemConfigurationInitialisationStrings(gxArray* list) +{ + int ret = DLMS_ERROR_CODE_OK; +#ifndef DLMS_IGNORE_MALLOC + int pos; + gxModemInitialisation* it; + for (pos = 0; pos != list->size; ++pos) + { + ret = arr_getByIndex(list, pos, (void**)&it); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + bb_clear(&it->request); + bb_clear(&it->response); + } +#endif //DLMS_IGNORE_MALLOC + arr_clear(list); + return ret; +} +#endif //DLMS_IGNORE_MODEM_CONFIGURATION + +#ifndef DLMS_IGNORE_SCHEDULE +int obj_clearScheduleEntries(gxArray* list) +{ + int ret = DLMS_ERROR_CODE_OK; +#ifndef DLMS_IGNORE_MALLOC + int pos; + gxScheduleEntry* it; + for (pos = 0; pos != list->size; ++pos) + { + if ((ret = arr_getByIndex(list, pos, (void**)&it)) != 0) + { + break; + } + ba_clear(&it->execSpecDays); + } +#endif //DLMS_IGNORE_MALLOC + arr_clear(list); + return ret; +} +#endif //DLMS_IGNORE_SCHEDULE + +int obj_clearByteBufferList(gxArray* list) +{ +#ifdef DLMS_IGNORE_MALLOC + list->size = 0; + return 0; +#else + int pos, ret = 0; + gxByteBuffer* it; + for (pos = 0; pos != list->size; ++pos) + { + ret = arr_getByIndex(list, pos, (void**)&it); + if (ret != 0) + { + return ret; + } + bb_clear(it); + } + arr_clear(list); + return ret; +#endif //DLMS_IGNORE_MALLOC +} + +#ifndef DLMS_IGNORE_SCRIPT_TABLE +int obj_clearScriptTable(gxArray* list) +{ + int ret = DLMS_ERROR_CODE_OK; +#ifndef DLMS_IGNORE_MALLOC + int pos, pos2; + gxScript* s; + gxScriptAction* sa; + for (pos = 0; pos != list->size; ++pos) + { + ret = arr_getByIndex(list, pos, (void**)&s); + if (ret != 0) + { + break; + } + for (pos2 = 0; pos2 != s->actions.size; ++pos2) + { + ret = arr_getByIndex(&s->actions, pos2, (void**)&sa); + if (ret != 0) + { + break; + } + var_clear(&sa->parameter); + } + arr_clear(&s->actions); + } +#endif //DLMS_IGNORE_MALLOC + arr_clear(list); + return ret; +} +#endif //DLMS_IGNORE_SCRIPT_TABLE + +#ifndef DLMS_IGNORE_CHARGE +int obj_clearChargeTables(gxArray* list) +{ + int ret = DLMS_ERROR_CODE_OK; +#ifndef DLMS_IGNORE_MALLOC + int pos; + gxChargeTable* it; + for (pos = 0; pos != list->size; ++pos) + { + if ((ret = arr_getByIndex(list, pos, (void**)&it)) != 0) + { + break; + } + bb_clear(&it->index); + } +#endif //DLMS_IGNORE_MALLOC + arr_clear(list); + return ret; +} +#endif //DLMS_IGNORE_CHARGE + +#ifndef DLMS_IGNORE_REGISTER_ACTIVATION +#if !(defined(DLMS_IGNORE_OBJECT_POINTERS) || defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES)) +int obj_clearRegisterActivationAssignment(objectArray* list) +{ + oa_empty(list); + return 0; +} +#else +int obj_clearRegisterActivationAssignment(gxArray* list) +{ + arr_empty(list); + return 0; +} +#endif //!(defined(DLMS_IGNORE_OBJECT_POINTERS) || defined(DLMS_IGNORE_MALLOC)) + +int obj_clearRegisterActivationMaskList(gxArray* list) +{ +#ifdef DLMS_IGNORE_MALLOC + list->size = 0; + return 0; +#else +#ifdef DLMS_COSEM_EXACT_DATA_TYPES + int ret = 0, pos; + gxRegisterActivationMask* it; + for (pos = 0; pos != list->size; ++pos) + { + ret = arr_getByIndex(list, pos, (void**)&it); + if (ret != 0) + { + break; + } + bb_clear(&it->name); + bb_clear(&it->indexes); + } + arr_clear(list); + return ret; +#else + int ret = 0, pos; + gxKey* it; + for (pos = 0; pos != list->size; ++pos) + { + ret = arr_getByIndex(list, pos, (void**)&it); + if (ret != 0) + { + break; + } + bb_clear((gxByteBuffer*)it->key); + bb_clear((gxByteBuffer*)it->value); + } + arr_clearKeyValuePair(list); + return ret; +#endif //DLMS_COSEM_EXACT_DATA_TYPES +#endif //DLMS_IGNORE_MALLOC +} +#endif //DLMS_IGNORE_REGISTER_ACTIVATION +#ifndef DLMS_IGNORE_IP4_SETUP +int obj_clearIP4SetupOptions(gxArray* list) +{ + int ret = 0; +#ifndef DLMS_IGNORE_MALLOC + int pos; + gxip4SetupIpOption* it; + for (pos = 0; pos != list->size; ++pos) + { + ret = arr_getByIndex(list, pos, (void**)&it); + if (ret != 0) + { + return ret; + } + bb_clear(&it->data); + } +#endif //DLMS_IGNORE_MALLOC + arr_clear(list); + return ret; +} +#endif //DLMS_IGNORE_IP4_SETUP + +#ifndef DLMS_IGNORE_PPP_SETUP +int obj_clearPPPSetupIPCPOptions(gxArray* list) +{ + int ret = 0; +#ifndef DLMS_IGNORE_MALLOC + int pos; + gxpppSetupIPCPOption* it; + for (pos = 0; pos != list->size; ++pos) + { + ret = arr_getByIndex(list, pos, (void**)&it); + if (ret != 0) + { + return ret; + } + var_clear(&it->data); + } +#endif //DLMS_IGNORE_MALLOC + arr_clear(list); + return ret; +} + +int obj_clearPPPSetupLCPOptions(gxArray* list) +{ + int ret = 0; +#ifndef DLMS_IGNORE_MALLOC + int pos; + gxpppSetupLcpOption* it; + for (pos = 0; pos != list->size; ++pos) + { + ret = arr_getByIndex(list, pos, (void**)&it); + if (ret != 0) + { + return ret; + } + var_clear(&it->data); + } +#endif //DLMS_IGNORE_MALLOC + arr_clear(list); + return ret; +} +#endif //DLMS_IGNORE_PPP_SETUP +#ifndef DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL +int obj_clearActiveDevices(gxArray* list) +{ + int ret = 0; +#ifndef DLMS_IGNORE_MALLOC + int pos; + gxActiveDevice* it; + for (pos = 0; pos != list->size; ++pos) + { + ret = arr_getByIndex(list, pos, (void**)&it); + if (ret != 0) + { + return ret; + } + bb_clear(&it->macAddress); + } +#endif //DLMS_IGNORE_MALLOC + arr_clear(list); + return ret; +} +#endif //DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL + +int obj_clearUserList(gxArray* list) +{ + int ret = 0; +#ifndef DLMS_IGNORE_MALLOC + int pos; + gxKey2* it; + for (pos = 0; pos != list->size; ++pos) + { + ret = arr_getByIndex(list, pos, (void**)&it); + if (ret != 0) + { + return ret; + } + gxfree(it->value); + } +#endif //DLMS_IGNORE_MALLOC + arr_clear(list); + return ret; +} + +#ifndef DLMS_IGNORE_G3_PLC_MAC_SETUP +int obj_clearNeighbourTable(gxArray* list) +{ + int ret = 0; +#ifndef DLMS_IGNORE_MALLOC + int pos; + gxNeighbourTable* it; + for (pos = 0; pos != list->size; ++pos) + { + ret = arr_getByIndex(list, pos, (void**)&it); + if (ret != 0) + { + return ret; + } + ba_clear(&it->txCoeff); + } +#endif //DLMS_IGNORE_MALLOC + arr_clear(list); + return ret; +} +#endif //DLMS_IGNORE_G3_PLC_MAC_SETUP + +#ifndef DLMS_IGNORE_FUNCTION_CONTROL + +int obj_clearActivationStatus(gxArray* list) +{ + int ret = 0; +#ifndef DLMS_IGNORE_MALLOC + int pos; + functionStatus* it; + for (pos = 0; pos != list->size; ++pos) + { + if ((ret = arr_getByIndex(list, pos, (void**)&it)) != 0) + { + break; + } + bb_clear(&it->name); + } +#endif //DLMS_IGNORE_MALLOC + arr_clear(list); + return ret; +} + +int obj_clearFunctionList(gxArray* list) +{ + int ret = 0; +#ifndef DLMS_IGNORE_MALLOC + int pos; + functionalBlock* it; + for (pos = 0; pos != list->size; ++pos) + { + if ((ret = arr_getByIndex(list, pos, (void**)&it)) != 0) + { + break; + } + bb_clear(&it->name); + oa_empty(&it->functionSpecifications); + } +#endif //DLMS_IGNORE_MALLOC + arr_clear(list); + return ret; +} + +#endif //DLMS_IGNORE_FUNCTION_CONTROL + +int obj_clearBitArrayList( + gxArray* list) +{ + int ret = 0; +#ifndef DLMS_IGNORE_MALLOC + int pos; + bitArray* it; + for (pos = 0; pos != list->size; ++pos) + { + ret = arr_getByIndex(list, pos, (void**)&it); + if (ret != 0) + { + return ret; + } + ba_clear(it); + } +#endif //DLMS_IGNORE_MALLOC + arr_clear(list); + return ret; +} + +int obj_clearVariantList( + gxArray* list) +{ + int ret = 0; +#ifndef DLMS_IGNORE_MALLOC + int pos; + dlmsVARIANT* it; + for (pos = 0; pos != list->size; ++pos) + { + ret = arr_getByIndex(list, pos, (void**)&it); + if (ret != 0) + { + return ret; + } + var_clear(it); + } +#endif //DLMS_IGNORE_MALLOC + arr_clear(list); + return ret; +} + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA +//Clear available switches. +int obj_clearAvailableSwitches( + gxArray* list) +{ + int ret = 0; +#ifndef DLMS_IGNORE_MALLOC + int pos; + gxMacAvailableSwitch* it; + for (pos = 0; pos != list->size; ++pos) + { + ret = arr_getByIndex(list, pos, (void**)&it); + if (ret != 0) + { + return ret; + } + bb_clear(&it->sna); + } +#endif //DLMS_IGNORE_MALLOC + arr_clear(list); + return ret; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + +#ifndef DLMS_IGNORE_SECURITY_SETUP +int obj_clearCertificateInfo(gxArray* arr) +{ + int ret = 0; +#ifndef DLMS_IGNORE_MALLOC + gxCertificateInfo* it; + uint16_t pos; + for (pos = 0; pos != arr->size; ++pos) + { + if ((ret = arr_getByIndex(arr, pos, (void**)&it)) != 0) + { + break; + } + gxfree(it->serialNumber); + gxfree(it->issuer); + gxfree(it->subject); + gxfree(it->subjectAltName); + } +#endif //DLMS_IGNORE_MALLOC + arr_clear(arr); + return ret; +} +#endif //DLMS_IGNORE_SECURITY_SETUP + +void obj_clear(gxObject* object) +{ + int ret = 0; + if (object != NULL) + { + if (object->access != NULL) + { + bb_clear(&object->access->attributeAccessModes); + bb_clear(&object->access->methodAccessModes); +#ifndef DLMS_IGNORE_MALLOC + gxfree(object->access); + object->access = NULL; +#endif //DLMS_IGNORE_MALLOC + } +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + object->shortName = 0; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + switch (object->objectType) + { +#ifndef DLMS_IGNORE_DATA + case DLMS_OBJECT_TYPE_DATA: + var_clear(&((gxData*)object)->value); + break; +#endif //DLMS_IGNORE_DATA +#ifndef DLMS_IGNORE_REGISTER + case DLMS_OBJECT_TYPE_REGISTER: + var_clear(&((gxRegister*)object)->value); + break; +#endif //DLMS_IGNORE_REGISTER +#ifndef DLMS_IGNORE_CLOCK + case DLMS_OBJECT_TYPE_CLOCK: + //Clock object do not need to clean. + break; +#endif //DLMS_IGNORE_CLOCK +#ifndef DLMS_IGNORE_ACTION_SCHEDULE + case DLMS_OBJECT_TYPE_ACTION_SCHEDULE: + arr_clear(&((gxActionSchedule*)object)->executionTime); + break; +#endif //DLMS_IGNORE_ACTION_SCHEDULE +#ifndef DLMS_IGNORE_ACTIVITY_CALENDAR + case DLMS_OBJECT_TYPE_ACTIVITY_CALENDAR: + bb_clear(&((gxActivityCalendar*)object)->calendarNameActive); + bb_clear(&((gxActivityCalendar*)object)->calendarNamePassive); + if ((ret = obj_clearSeasonProfile(&((gxActivityCalendar*)object)->seasonProfileActive)) != 0 || + (ret = obj_clearWeekProfileTable(&((gxActivityCalendar*)object)->weekProfileTableActive)) != 0 || + (ret = obj_clearDayProfileTable(&((gxActivityCalendar*)object)->dayProfileTableActive)) != 0 || + (ret = obj_clearSeasonProfile(&((gxActivityCalendar*)object)->seasonProfilePassive)) != 0 || + (ret = obj_clearWeekProfileTable(&((gxActivityCalendar*)object)->weekProfileTablePassive)) != 0 || + (ret = obj_clearDayProfileTable(&((gxActivityCalendar*)object)->dayProfileTablePassive)) != 0) + { + } + break; +#endif //DLMS_IGNORE_ACTIVITY_CALENDAR +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + case DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME: + oa_empty(&((gxAssociationLogicalName*)object)->objectList); + ((gxAssociationLogicalName*)object)->xDLMSContextInfo.conformance = (DLMS_CONFORMANCE)0; + bb_clear(&((gxAssociationLogicalName*)object)->xDLMSContextInfo.cypheringInfo); + bb_clear(&((gxAssociationLogicalName*)object)->secret); + obj_clearUserList(&((gxAssociationLogicalName*)object)->userList); +#ifdef DLMS_IGNORE_MALLOC + ((gxAssociationLogicalName*)object)->currentUser.id = -1; + ((gxAssociationLogicalName*)object)->currentUser.name[0] = 0; +#else + if (((gxAssociationLogicalName*)object)->currentUser.value != NULL) + { + gxfree(((gxAssociationLogicalName*)object)->currentUser.value); + ((gxAssociationLogicalName*)object)->currentUser.value = NULL; + } +#endif //DLMS_IGNORE_MALLOC + break; +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + case DLMS_OBJECT_TYPE_ASSOCIATION_SHORT_NAME: +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + oa_empty(&((gxAssociationShortName*)object)->objectList); + bb_clear(&((gxAssociationShortName*)object)->secret); +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + break; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME +#ifndef DLMS_IGNORE_AUTO_ANSWER + case DLMS_OBJECT_TYPE_AUTO_ANSWER: + arr_clearKeyValuePair(&((gxAutoAnswer*)object)->listeningWindow); + break; +#endif //DLMS_IGNORE_AUTO_ANSWER +#ifndef DLMS_IGNORE_AUTO_CONNECT + case DLMS_OBJECT_TYPE_AUTO_CONNECT: + arr_clearKeyValuePair(&((gxAutoConnect*)object)->callingWindow); + arr_clearStrings(&((gxAutoConnect*)object)->destinations); + break; +#endif //DLMS_IGNORE_AUTO_CONNECT +#ifndef DLMS_IGNORE_DEMAND_REGISTER + case DLMS_OBJECT_TYPE_DEMAND_REGISTER: + var_clear(&((gxDemandRegister*)object)->currentAverageValue); + var_clear(&((gxDemandRegister*)object)->lastAverageValue); + var_clear(&((gxDemandRegister*)object)->status); + break; +#endif //DLMS_IGNORE_DEMAND_REGISTER +#ifndef DLMS_IGNORE_MAC_ADDRESS_SETUP + case DLMS_OBJECT_TYPE_MAC_ADDRESS_SETUP: + bb_clear(&((gxMacAddressSetup*)object)->macAddress); + break; +#endif //DLMS_IGNORE_MAC_ADDRESS_SETUP +#ifndef DLMS_IGNORE_EXTENDED_REGISTER + case DLMS_OBJECT_TYPE_EXTENDED_REGISTER: + var_clear(&((gxExtendedRegister*)object)->status); + break; +#endif //DLMS_IGNORE_EXTENDED_REGISTER +#ifndef DLMS_IGNORE_GPRS_SETUP + case DLMS_OBJECT_TYPE_GPRS_SETUP: + bb_clear(&((gxGPRSSetup*)object)->apn); + break; +#endif //DLMS_IGNORE_GPRS_SETUP +#ifndef DLMS_IGNORE_SECURITY_SETUP + case DLMS_OBJECT_TYPE_SECURITY_SETUP: + bb_clear(&((gxSecuritySetup*)object)->clientSystemTitle); + bb_clear(&((gxSecuritySetup*)object)->serverSystemTitle); + obj_clearCertificateInfo(&((gxSecuritySetup*)object)->certificates); + break; +#endif //DLMS_IGNORE_SECURITY_SETUP +#ifndef DLMS_IGNORE_IEC_HDLC_SETUP + case DLMS_OBJECT_TYPE_IEC_HDLC_SETUP: + //Do nothing. + break; +#endif //DLMS_IGNORE_IEC_HDLC_SETUP +#ifndef DLMS_IGNORE_IEC_LOCAL_PORT_SETUP + case DLMS_OBJECT_TYPE_IEC_LOCAL_PORT_SETUP: + bb_clear(&((gxLocalPortSetup*)object)->password1); + bb_clear(&((gxLocalPortSetup*)object)->password2); + bb_clear(&((gxLocalPortSetup*)object)->password5); + bb_clear(&((gxLocalPortSetup*)object)->deviceAddress); + break; +#endif //DLMS_IGNORE_IEC_LOCAL_PORT_SETUP +#ifndef DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP + case DLMS_OBJECT_TYPE_IEC_TWISTED_PAIR_SETUP: + bb_clear(&((gxIecTwistedPairSetup*)object)->primaryAddresses); + bb_clear(&((gxIecTwistedPairSetup*)object)->tabis); + break; +#endif //DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP +#ifndef DLMS_IGNORE_IP4_SETUP + case DLMS_OBJECT_TYPE_IP4_SETUP: +#ifndef DLMS_IGNORE_OBJECT_POINTERS + ((gxIp4Setup*)object)->dataLinkLayer = NULL; +#else + memset(((gxIp4Setup*)object)->dataLinkLayerReference, 0, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + var_clear(&((gxIp4Setup*)object)->value); +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + arr_clear(&((gxIp4Setup*)object)->multicastIPAddress); +#else + va_clear(&((gxIp4Setup*)object)->multicastIPAddress); +#endif //DLMS_IGNORE_MALLOC + + obj_clearIP4SetupOptions(&((gxIp4Setup*)object)->ipOptions); + break; +#endif //DLMS_IGNORE_IP4_SETUP +#ifndef DLMS_IGNORE_IP6_SETUP + case DLMS_OBJECT_TYPE_IP6_SETUP: +#ifndef DLMS_IGNORE_OBJECT_POINTERS + ((gxIp4Setup*)object)->dataLinkLayer = NULL; +#else + memset(((gxIp6Setup*)object)->dataLinkLayerReference, 0, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS +#ifdef DLMS_IGNORE_MALLOC + arr_clear(&((gxIp6Setup*)object)->multicastIPAddress); + arr_clear(&((gxIp6Setup*)object)->unicastIPAddress); + arr_clear(&((gxIp6Setup*)object)->gatewayIPAddress); + arr_clear(&((gxIp6Setup*)object)->neighborDiscoverySetup); +#else + arr_clear(&((gxIp6Setup*)object)->multicastIPAddress); + arr_clear(&((gxIp6Setup*)object)->unicastIPAddress); + arr_clear(&((gxIp6Setup*)object)->gatewayIPAddress); + arr_clear(&((gxIp6Setup*)object)->neighborDiscoverySetup); +#endif //DLMS_IGNORE_MALLOC + break; +#endif //DLMS_IGNORE_IP6_SETUP +#ifndef DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP + case DLMS_OBJECT_TYPE_MBUS_SLAVE_PORT_SETUP: + //Do nothing. + break; +#endif //DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP +#ifndef DLMS_IGNORE_IMAGE_TRANSFER + case DLMS_OBJECT_TYPE_IMAGE_TRANSFER: + { +#ifndef DLMS_IGNORE_MALLOC + gxImageActivateInfo* it; + int pos = 0; + while (pos != ((gxImageTransfer*)object)->imageActivateInfo.size) + { + if (arr_getByIndex(&((gxImageTransfer*)object)->imageActivateInfo, pos, (void**)&it) == 0) + { + bb_clear(&it->identification); + bb_clear(&it->signature); + } + ++pos; + } +#endif //DLMS_IGNORE_MALLOC + ba_clear(&((gxImageTransfer*)object)->imageTransferredBlocksStatus); + arr_clear(&((gxImageTransfer*)object)->imageActivateInfo); + break; + } +#endif //DLMS_IGNORE_IMAGE_TRANSFER +#ifndef DLMS_IGNORE_DISCONNECT_CONTROL + case DLMS_OBJECT_TYPE_DISCONNECT_CONTROL: + //Do nothing. + break; +#endif //DLMS_IGNORE_DISCONNECT_CONTROL +#ifndef DLMS_IGNORE_LIMITER + case DLMS_OBJECT_TYPE_LIMITER: + var_clear(&((gxLimiter*)object)->thresholdActive); + var_clear(&((gxLimiter*)object)->thresholdNormal); + var_clear(&((gxLimiter*)object)->thresholdEmergency); +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + arr_clear(&((gxLimiter*)object)->emergencyProfileGroupIDs); +#else + va_clear(&((gxLimiter*)object)->emergencyProfileGroupIDs); +#endif //DLMS_IGNORE_MALLOC + break; +#endif //DLMS_IGNORE_LIMITER +#ifndef DLMS_IGNORE_MBUS_CLIENT + case DLMS_OBJECT_TYPE_MBUS_CLIENT: +#ifndef DLMS_IGNORE_OBJECT_POINTERS + ((gxMBusClient*)object)->mBusPort = NULL; +#else + memset(((gxMBusClient*)object)->mBusPortReference, 0, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + arr_clearKeyValuePair(&((gxMBusClient*)object)->captureDefinition); + break; +#endif //DLMS_IGNORE_MBUS_CLIENT +#ifndef DLMS_IGNORE_MODEM_CONFIGURATION + case DLMS_OBJECT_TYPE_MODEM_CONFIGURATION: + ret = obj_clearModemConfigurationInitialisationStrings(&((gxModemConfiguration*)object)->initialisationStrings); +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(ret == 0); +#endif + arr_clearStrings(&((gxModemConfiguration*)object)->modemProfile); + break; +#endif //DLMS_IGNORE_MODEM_CONFIGURATION +#ifndef DLMS_IGNORE_PPP_SETUP + case DLMS_OBJECT_TYPE_PPP_SETUP: +#ifndef DLMS_IGNORE_OBJECT_POINTERS + ((gxPppSetup*)object)->phy = NULL; +#else + memset(((gxPppSetup*)object)->PHYReference, 0, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + bb_clear(&((gxPppSetup*)object)->userName); + bb_clear(&((gxPppSetup*)object)->password); + obj_clearPPPSetupIPCPOptions(&((gxPppSetup*)object)->ipcpOptions); + obj_clearPPPSetupLCPOptions(&((gxPppSetup*)object)->lcpOptions); + break; +#endif //DLMS_IGNORE_PPP_SETUP +#ifndef DLMS_IGNORE_PROFILE_GENERIC + case DLMS_OBJECT_TYPE_PROFILE_GENERIC: +#ifndef DLMS_IGNORE_MALLOC + obj_clearProfileGenericBuffer(&((gxProfileGeneric*)object)->buffer); +#endif //DLMS_IGNORE_MALLOC + obj_clearProfileGenericCaptureObjects(&((gxProfileGeneric*)object)->captureObjects); + break; +#endif //DLMS_IGNORE_PROFILE_GENERIC +#ifndef DLMS_IGNORE_REGISTER_ACTIVATION + case DLMS_OBJECT_TYPE_REGISTER_ACTIVATION: +#if !(defined(DLMS_IGNORE_OBJECT_POINTERS) || defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES)) + oa_empty(&((gxRegisterActivation*)object)->registerAssignment); +#else + obj_clearRegisterActivationAssignment(&((gxRegisterActivation*)object)->registerAssignment); +#endif //!(defined(DLMS_IGNORE_OBJECT_POINTERS) || defined(DLMS_IGNORE_MALLOC)) + obj_clearRegisterActivationMaskList(&((gxRegisterActivation*)object)->maskList); + bb_clear(&((gxRegisterActivation*)object)->activeMask); + break; +#endif //DLMS_IGNORE_REGISTER_ACTIVATION +#ifndef DLMS_IGNORE_REGISTER_MONITOR + case DLMS_OBJECT_TYPE_REGISTER_MONITOR: + va_clear(&((gxRegisterMonitor*)object)->thresholds); + obj_clearRegisterMonitorActions(&((gxRegisterMonitor*)object)->actions); + break; +#endif //DLMS_IGNORE_REGISTER_MONITOR +#ifndef DLMS_IGNORE_REGISTER_TABLE + case DLMS_OBJECT_TYPE_REGISTER_TABLE: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_REGISTER_TABLE +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_STARTUP + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_STARTUP: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_ZIG_BEE_SAS_STARTUP +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_JOIN + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_JOIN: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_ZIG_BEE_SAS_JOIN +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_APS_FRAGMENTATION + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_APS_FRAGMENTATION: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_ZIG_BEE_SAS_APS_FRAGMENTATION +#ifndef DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL + case DLMS_OBJECT_TYPE_ZIG_BEE_NETWORK_CONTROL: + obj_clearActiveDevices(&((gxZigBeeNetworkControl*)object)->activeDevices); + break; +#endif //DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL +#ifndef DLMS_IGNORE_SAP_ASSIGNMENT + case DLMS_OBJECT_TYPE_SAP_ASSIGNMENT: + obj_clearSapList(&((gxSapAssignment*)object)->sapAssignmentList); + break; +#endif //DLMS_IGNORE_SAP_ASSIGNMENT +#ifndef DLMS_IGNORE_SCHEDULE + case DLMS_OBJECT_TYPE_SCHEDULE: + obj_clearScheduleEntries(&((gxSchedule*)object)->entries); + break; +#endif //DLMS_IGNORE_SCHEDULE +#ifndef DLMS_IGNORE_SCRIPT_TABLE + case DLMS_OBJECT_TYPE_SCRIPT_TABLE: + obj_clearScriptTable(&((gxScriptTable*)object)->scripts); + break; +#endif //DLMS_IGNORE_SCRIPT_TABLE +#ifndef DLMS_IGNORE_SMTP_SETUP + case DLMS_OBJECT_TYPE_SMTP_SETUP: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_SMTP_SETUP +#ifndef DLMS_IGNORE_SPECIAL_DAYS_TABLE + case DLMS_OBJECT_TYPE_SPECIAL_DAYS_TABLE: + arr_clear(&((gxSpecialDaysTable*)object)->entries); + break; +#endif //DLMS_IGNORE_SPECIAL_DAYS_TABLE +#ifndef DLMS_IGNORE_STATUS_MAPPING + case DLMS_OBJECT_TYPE_STATUS_MAPPING: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_STATUS_MAPPING +#ifndef DLMS_IGNORE_TCP_UDP_SETUP + case DLMS_OBJECT_TYPE_TCP_UDP_SETUP: +#ifndef DLMS_IGNORE_OBJECT_POINTERS + ((gxTcpUdpSetup*)object)->ipSetup = NULL; +#else + memset(&((gxTcpUdpSetup*)object)->ipReference, 0, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + + break; +#endif //DLMS_IGNORE_TCP_UDP_SETUP +#ifndef DLMS_IGNORE_MBUS_DIAGNOSTIC + case DLMS_OBJECT_TYPE_MBUS_DIAGNOSTIC: + arr_clear(&((gxMbusDiagnostic*)object)->broadcastFrames); + break; +#endif //DLMS_IGNORE_MBUS_DIAGNOSTIC +#ifndef DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS + case DLMS_OBJECT_TYPE_G3_PLC_MAC_LAYER_COUNTERS: + break; +#endif //DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS +#ifndef DLMS_IGNORE_G3_PLC_MAC_SETUP + case DLMS_OBJECT_TYPE_G3_PLC_MAC_SETUP: + arr_clear(&((gxG3PlcMacSetup*)object)->keyTable); + ba_clear(&((gxG3PlcMacSetup*)object)->toneMask); + obj_clearNeighbourTable(&((gxG3PlcMacSetup*)object)->neighbourTable); + arr_clear(&((gxG3PlcMacSetup*)object)->macPosTable); + break; +#endif //DLMS_IGNORE_G3_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_G3_PLC_6LO_WPAN + case DLMS_OBJECT_TYPE_G3_PLC_6LO_WPAN: + bb_clear(&((gxG3Plc6LoWPAN*)object)->prefixTable); + arr_clear(&((gxG3Plc6LoWPAN*)object)->routingConfiguration); + arr_clear(&((gxG3Plc6LoWPAN*)object)->routingTable); + arr_clear(&((gxG3Plc6LoWPAN*)object)->contextInformationTable); + arr_clear(&((gxG3Plc6LoWPAN*)object)->blacklistTable); + arr_clear(&((gxG3Plc6LoWPAN*)object)->broadcastLogTable); +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + arr_clear(&((gxG3Plc6LoWPAN*)object)->groupTable); + arr_clear(&((gxG3Plc6LoWPAN*)object)->destinationAddress); +#else + va_clear(&((gxG3Plc6LoWPAN*)object)->groupTable); + va_clear(&((gxG3Plc6LoWPAN*)object)->destinationAddress); +#endif //DLMS_IGNORE_MALLOC + break; +#endif //DLMS_IGNORE_G3_PLC_6LO_WPAN +#ifndef DLMS_IGNORE_FUNCTION_CONTROL + case DLMS_OBJECT_TYPE_FUNCTION_CONTROL: + obj_clearActivationStatus(&((gxFunctionControl*)object)->activationStatus); + obj_clearFunctionList(&((gxFunctionControl*)object)->functions); + break; +#endif //DLMS_IGNORE_FUNCTION_CONTROL +#ifndef DLMS_IGNORE_ARRAY_MANAGER + case DLMS_OBJECT_TYPE_ARRAY_MANAGER: + arr_clear(&((gxArrayManager*)object)->elements); + break; +#endif //DLMS_IGNORE_ARRAY_MANAGER +#ifndef DLMS_IGNORE_MBUS_PORT_SETUP + case DLMS_OBJECT_TYPE_MBUS_PORT_SETUP: + arr_clearKeyValuePair(&((gxMBusPortSetup*)object)->listeningWindow); + break; +#endif //DLMS_IGNORE_MBUS_PORT_SETUP +#ifndef DLMS_IGNORE_UTILITY_TABLES + case DLMS_OBJECT_TYPE_UTILITY_TABLES: + bb_clear(&((gxUtilityTables*)object)->buffer); + break; +#endif //DLMS_IGNORE_UTILITY_TABLES +#ifndef DLMS_IGNORE_MBUS_MASTER_PORT_SETUP + case DLMS_OBJECT_TYPE_MBUS_MASTER_PORT_SETUP: + //Do nothing. + break; +#endif //DLMS_IGNORE_MBUS_MASTER_PORT_SETUP +#ifndef DLMS_IGNORE_PUSH_SETUP + case DLMS_OBJECT_TYPE_PUSH_SETUP: + obj_clearPushObjectList(&((gxPushSetup*)object)->pushObjectList); +#ifdef DLMS_IGNORE_MALLOC + ((gxPushSetup*)object)->destination.size = 0; +#else + bb_clear(&((gxPushSetup*)object)->destination); +#endif //DLMS_IGNORE_MALLOC + arr_clearKeyValuePair(&((gxPushSetup*)object)->communicationWindow); + break; + case DLMS_OBJECT_TYPE_DATA_PROTECTION: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_PUSH_SETUP +#ifndef DLMS_IGNORE_ACCOUNT + case DLMS_OBJECT_TYPE_ACCOUNT: + arr_clear(&((gxAccount*)object)->creditReferences); + arr_clear(&((gxAccount*)object)->chargeReferences); + arr_clear(&((gxAccount*)object)->creditChargeConfigurations); + arr_clear(&((gxAccount*)object)->tokenGatewayConfigurations); +#ifdef DLMS_IGNORE_MALLOC + ((gxAccount*)object)->currency.name.size = 0; +#else + bb_clear(&((gxAccount*)object)->currency.name); +#endif //DLMS_IGNORE_MALLOC + break; +#endif //DLMS_IGNORE_ACCOUNT +#ifndef DLMS_IGNORE_CREDIT + case DLMS_OBJECT_TYPE_CREDIT: + ((gxCredit*)object)->creditConfiguration = DLMS_CREDIT_CONFIGURATION_NONE; + break; +#endif //DLMS_IGNORE_CREDIT +#ifndef DLMS_IGNORE_CHARGE + case DLMS_OBJECT_TYPE_CHARGE: + ((gxCharge*)object)->chargeConfiguration = DLMS_CHARGE_CONFIGURATION_NONE; + obj_clearChargeTables(&((gxCharge*)object)->unitChargeActive.chargeTables); + obj_clearChargeTables(&((gxCharge*)object)->unitChargePassive.chargeTables); + break; +#endif //DLMS_IGNORE_CHARGE +#ifndef DLMS_IGNORE_TOKEN_GATEWAY + case DLMS_OBJECT_TYPE_TOKEN_GATEWAY: + bb_clear(&((gxTokenGateway*)object)->token); + obj_clearByteBufferList(&((gxTokenGateway*)object)->descriptions); + ba_clear(&((gxTokenGateway*)object)->dataValue); + break; +#endif //DLMS_IGNORE_TOKEN_GATEWAY +#ifndef DLMS_IGNORE_GSM_DIAGNOSTIC + case DLMS_OBJECT_TYPE_GSM_DIAGNOSTIC: +#if !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + gxfree(((gxGsmDiagnostic*)object)->operatorName); + ((gxGsmDiagnostic*)object)->operatorName = NULL; +#else + bb_clear(&((gxGsmDiagnostic*)object)->operatorName); +#endif //!defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + arr_clear(&((gxGsmDiagnostic*)object)->adjacentCells); + break; +#endif //DLMS_IGNORE_GSM_DIAGNOSTIC +#ifndef DLMS_IGNORE_COMPACT_DATA + case DLMS_OBJECT_TYPE_COMPACT_DATA: + bb_clear(&((gxCompactData*)object)->buffer); + obj_clearProfileGenericCaptureObjects(&((gxCompactData*)object)->captureObjects); + bb_clear(&((gxCompactData*)object)->templateDescription); + break; +#endif //DLMS_IGNORE_COMPACT_DATA +#ifndef DLMS_IGNORE_PARAMETER_MONITOR + case DLMS_OBJECT_TYPE_PARAMETER_MONITOR: +#ifndef DLMS_IGNORE_OBJECT_POINTERS + ((gxParameterMonitor*)object)->changedParameter.target = NULL; +#else + ((gxParameterMonitor*)object)->changedParameter.type = DLMS_OBJECT_TYPE_NONE; + memset(((gxParameterMonitor*)object)->changedParameter.logicalName, 0, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + var_clear(&((gxParameterMonitor*)object)->changedParameter.value); + obj_clearParametersList(&((gxParameterMonitor*)object)->parameters); + break; +#endif //DLMS_IGNORE_PARAMETER_MONITOR +#ifndef DLMS_IGNORE_LLC_SSCS_SETUP + case DLMS_OBJECT_TYPE_LLC_SSCS_SETUP: + break; +#endif //DLMS_IGNORE_LLC_SSCS_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS: + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_SETUP: + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS: + bb_clear(&((gxPrimeNbOfdmPlcMacFunctionalParameters*)object)->sna); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_COUNTERS: + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA: + arr_clear(&((gxPrimeNbOfdmPlcMacNetworkAdministrationData*)object)->multicastEntries); + arr_clear(&((gxPrimeNbOfdmPlcMacNetworkAdministrationData*)object)->switchTable); + arr_clear(&((gxPrimeNbOfdmPlcMacNetworkAdministrationData*)object)->directTable); + obj_clearAvailableSwitches(&((gxPrimeNbOfdmPlcMacNetworkAdministrationData*)object)->availableSwitches); + arr_clear(&((gxPrimeNbOfdmPlcMacNetworkAdministrationData*)object)->communications); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION: + bb_clear(&((gxPrimeNbOfdmPlcApplicationsIdentification*)object)->firmwareVersion); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION +#ifndef DLMS_IGNORE_ARBITRATOR + case DLMS_OBJECT_TYPE_ARBITRATOR: + arr_clear(&((gxArbitrator*)object)->actions); + obj_clearBitArrayList(&((gxArbitrator*)object)->permissionsTable); + obj_clearVariantList(&((gxArbitrator*)object)->weightingsTable); + obj_clearBitArrayList(&((gxArbitrator*)object)->mostRecentRequestsTable); + break; +#endif //DLMS_IGNORE_ARBITRATOR +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE1_SETUP: + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE2_SETUP: + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE3_SETUP: + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP +#ifndef DLMS_IGNORE_SFSK_ACTIVE_INITIATOR + case DLMS_OBJECT_TYPE_SFSK_ACTIVE_INITIATOR: + bb_clear(&((gxSFSKActiveInitiator*)object)->systemTitle); + break; +#endif //DLMS_IGNORE_SFSK_ACTIVE_INITIATOR +#ifndef DLMS_IGNORE_SFSK_MAC_COUNTERS + case DLMS_OBJECT_TYPE_SFSK_MAC_COUNTERS: + arr_clear(&((gxFSKMacCounters*)object)->synchronizationRegister); + arr_clear(&((gxFSKMacCounters*)object)->broadcastFramesCounter); + break; +#endif //DLMS_IGNORE_SFSK_MAC_COUNTERS +#ifndef DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS + case DLMS_OBJECT_TYPE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS: + break; +#endif //DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS +#ifndef DLMS_IGNORE_SFSK_PHY_MAC_SETUP + case DLMS_OBJECT_TYPE_SFSK_PHY_MAC_SETUP: + arr_clear(&((gxSFSKPhyMacSetUp*)object)->macGroupAddresses); + break; +#endif //DLMS_IGNORE_SFSK_PHY_MAC_SETUP +#ifndef DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST + case DLMS_OBJECT_TYPE_SFSK_REPORTING_SYSTEM_LIST: + obj_clearByteBufferList(&((gxSFSKReportingSystemList*)object)->reportingSystemList); + break; +#endif //DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST +#ifdef DLMS_ITALIAN_STANDARD + case DLMS_OBJECT_TYPE_TARIFF_PLAN: + { + gxfree(((gxTariffPlan*)object)->calendarName); + ba_clear(&((gxTariffPlan*)object)->plan.weeklyActivation); + arr_clear(&((gxTariffPlan*)object)->plan.specialDays); + break; + } +#endif //DLMS_ITALIAN_STANDARD + default://Unknown type. +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; + } + } +#if !(defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + if (ret == 0) + { + //Remove warning. + } +#endif + +} + +unsigned char obj_attributeCount(gxObject* object) +{ + unsigned char ret; + switch (object->objectType) + { + case DLMS_OBJECT_TYPE_DATA: + ret = 2; + break; + case DLMS_OBJECT_TYPE_REGISTER: + ret = 3; + break; + case DLMS_OBJECT_TYPE_ACTION_SCHEDULE: + ret = 4; + break; + case DLMS_OBJECT_TYPE_ACTIVITY_CALENDAR: + ret = 10; + break; + case DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME: + //user_list and current_user are in version 2. + if (object->version > 1) + { + ret = 11; + } + //Security Setup Reference is from version 1. + else if (object->version > 0) + { + ret = 9; + } + + else + { + ret = 8; + } + break; + case DLMS_OBJECT_TYPE_ASSOCIATION_SHORT_NAME: + if (object->version < 2) + { + ret = 2; + } + else if (object->version < 3) + { + ret = 4; + } + else + { + ret = 6; + } + break; + case DLMS_OBJECT_TYPE_AUTO_ANSWER: + ret = 6; + break; + case DLMS_OBJECT_TYPE_AUTO_CONNECT: + ret = 6; + break; + case DLMS_OBJECT_TYPE_CLOCK: + ret = 9; + break; + case DLMS_OBJECT_TYPE_DEMAND_REGISTER: + ret = 9; + break; + case DLMS_OBJECT_TYPE_MAC_ADDRESS_SETUP: + ret = 2; + break; + case DLMS_OBJECT_TYPE_EXTENDED_REGISTER: + ret = 5; + break; + case DLMS_OBJECT_TYPE_GPRS_SETUP: + ret = 4; + break; + case DLMS_OBJECT_TYPE_SECURITY_SETUP: + if (object->version == 0) + { + ret = 5; + } + else + { + ret = 6; + } + break; + case DLMS_OBJECT_TYPE_IEC_HDLC_SETUP: + ret = 9; + break; + case DLMS_OBJECT_TYPE_IEC_LOCAL_PORT_SETUP: + ret = 9; + break; + case DLMS_OBJECT_TYPE_IEC_TWISTED_PAIR_SETUP: + ret = 5; + break; + case DLMS_OBJECT_TYPE_IP4_SETUP: + ret = 10; + break; + case DLMS_OBJECT_TYPE_IP6_SETUP: + ret = 10; + break; + case DLMS_OBJECT_TYPE_MBUS_SLAVE_PORT_SETUP: + ret = 5; + break; + case DLMS_OBJECT_TYPE_IMAGE_TRANSFER: + ret = 7; + break; + case DLMS_OBJECT_TYPE_DISCONNECT_CONTROL: + ret = 4; + break; + case DLMS_OBJECT_TYPE_LIMITER: + ret = 11; + break; + case DLMS_OBJECT_TYPE_MBUS_CLIENT: + ret = 12; + break; + case DLMS_OBJECT_TYPE_MODEM_CONFIGURATION: + ret = 4; + break; + case DLMS_OBJECT_TYPE_PPP_SETUP: + ret = 5; + break; + case DLMS_OBJECT_TYPE_PROFILE_GENERIC: + ret = 8; + break; + case DLMS_OBJECT_TYPE_REGISTER_ACTIVATION: + ret = 4; + break; + case DLMS_OBJECT_TYPE_REGISTER_MONITOR: + ret = 4; + break; + case DLMS_OBJECT_TYPE_REGISTER_TABLE: + ret = 1; + break; + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_STARTUP: + ret = 12; + break; + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_JOIN: + ret = 5; + break; + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_APS_FRAGMENTATION: + ret = 3; + break; + case DLMS_OBJECT_TYPE_ZIG_BEE_NETWORK_CONTROL: + ret = 4; + break; + case DLMS_OBJECT_TYPE_SAP_ASSIGNMENT: + ret = 2; + break; +#ifndef DLMS_IGNORE_SCHEDULE + case DLMS_OBJECT_TYPE_SCHEDULE: + ret = 2; + break; +#endif //DLMS_IGNORE_SCHEDULE +#ifndef DLMS_IGNORE_SCRIPT_TABLE + case DLMS_OBJECT_TYPE_SCRIPT_TABLE: + ret = 2; + break; +#endif //DLMS_IGNORE_SCRIPT_TABLE + case DLMS_OBJECT_TYPE_SMTP_SETUP: + ret = 1; + break; + case DLMS_OBJECT_TYPE_SPECIAL_DAYS_TABLE: + ret = 2; + break; + case DLMS_OBJECT_TYPE_STATUS_MAPPING: + ret = 1; + break; + case DLMS_OBJECT_TYPE_TCP_UDP_SETUP: + ret = 6; + break; + case DLMS_OBJECT_TYPE_MBUS_DIAGNOSTIC: + ret = 9; + break; + case DLMS_OBJECT_TYPE_MBUS_PORT_SETUP: + ret = 11; + break; + case DLMS_OBJECT_TYPE_G3_PLC_MAC_LAYER_COUNTERS: + ret = 10; + break; + case DLMS_OBJECT_TYPE_G3_PLC_MAC_SETUP: + if (object->version < 3) + { + ret = 25; + } + else + { + ret = 26; + } + break; + case DLMS_OBJECT_TYPE_G3_PLC_6LO_WPAN: + ret = 21; + break; + case DLMS_OBJECT_TYPE_FUNCTION_CONTROL: + ret = 3; + break; + case DLMS_OBJECT_TYPE_ARRAY_MANAGER: + ret = 2; + break; + case DLMS_OBJECT_TYPE_UTILITY_TABLES: + ret = 4; + break; + case DLMS_OBJECT_TYPE_MBUS_MASTER_PORT_SETUP: + ret = 2; + break; + case DLMS_OBJECT_TYPE_PUSH_SETUP: + ret = 7; + break; + case DLMS_OBJECT_TYPE_DATA_PROTECTION: + ret = 6; + break; + case DLMS_OBJECT_TYPE_ACCOUNT: + ret = 19; + break; + case DLMS_OBJECT_TYPE_CREDIT: + ret = 11; + break; + case DLMS_OBJECT_TYPE_CHARGE: + ret = 13; + break; + case DLMS_OBJECT_TYPE_TOKEN_GATEWAY: + ret = 6; + break; + case DLMS_OBJECT_TYPE_COMPACT_DATA: + return 6; +#ifdef DLMS_ITALIAN_STANDARD + case DLMS_OBJECT_TYPE_TARIFF_PLAN: + ret = 5; + break; +#endif //DLMS_ITALIAN_STANDARD + case DLMS_OBJECT_TYPE_GSM_DIAGNOSTIC: + ret = 8; + break; + case DLMS_OBJECT_TYPE_PARAMETER_MONITOR: + ret = 4; + break; +#ifndef DLMS_IGNORE_LLC_SSCS_SETUP + case DLMS_OBJECT_TYPE_LLC_SSCS_SETUP: + ret = 3; + break; +#endif //DLMS_IGNORE_LLC_SSCS_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS: + ret = 5; + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_SETUP: + ret = 8; + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS: + ret = 14; + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_COUNTERS: + ret = 7; + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA: + ret = 6; + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION: + ret = 4; + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION +#ifndef DLMS_IGNORE_ARBITRATOR + case DLMS_OBJECT_TYPE_ARBITRATOR: + ret = 6; + break; +#endif //DLMS_IGNORE_ARBITRATOR +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE1_SETUP: + ret = 1; + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE2_SETUP: + ret = 9; + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE3_SETUP: + ret = 6; + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP +#ifndef DLMS_IGNORE_SFSK_ACTIVE_INITIATOR + case DLMS_OBJECT_TYPE_SFSK_ACTIVE_INITIATOR: + ret = 2; + break; +#endif //DLMS_IGNORE_SFSK_ACTIVE_INITIATOR +#ifndef DLMS_IGNORE_SFSK_MAC_COUNTERS + case DLMS_OBJECT_TYPE_SFSK_MAC_COUNTERS: + ret = 8; + break; +#endif //DLMS_IGNORE_SFSK_MAC_COUNTERS +#ifndef DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS + case DLMS_OBJECT_TYPE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS: + ret = 5; + break; +#endif //DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS +#ifndef DLMS_IGNORE_SFSK_PHY_MAC_SETUP + case DLMS_OBJECT_TYPE_SFSK_PHY_MAC_SETUP: + ret = 14; + break; +#endif //DLMS_IGNORE_SFSK_PHY_MAC_SETUP +#ifndef DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST + case DLMS_OBJECT_TYPE_SFSK_REPORTING_SYSTEM_LIST: + ret = 2; + break; +#endif //DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST + default: + //Unknown type. +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + ret = 1; + break; + } + return ret; +} + +//Returns collection of attributes to read. +int obj_getAttributeIndexToRead(gxObject* object, gxByteBuffer* ba) +{ + unsigned char ch, pos; + int ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + unsigned char cnt; + bb_clear(ba); + + //If register unit and scaler are read first if not read yet + if (object->objectType == DLMS_OBJECT_TYPE_REGISTER) + { +#ifndef DLMS_IGNORE_REGISTER + if (object->access == NULL) + { + if ((ret = bb_setUInt8(ba, 3)) == 0 && + (ret = bb_setUInt8(ba, 2)) == 0) + { + + } + } + else + { + ret = 0; + if (!((gxRegister*)object)->unitRead) + { + ret = bb_getUInt8ByIndex(&object->access->attributeAccessModes, 3 - 1, &ch); + if (ret == 0 && ch != DLMS_ACCESS_MODE_NONE) + { + ret = bb_setUInt8(ba, 3); + } + } + if (ret == 0) + { + ret = bb_getUInt8ByIndex(&object->access->attributeAccessModes, 2 - 1, &ch); + if (ret == 0 && ch != DLMS_ACCESS_MODE_NONE) + { + ret = bb_setUInt8(ba, 2); + } + } + } +#endif //DLMS_IGNORE_REGISTER + } + else if (object->objectType == DLMS_OBJECT_TYPE_EXTENDED_REGISTER) + { +#ifndef DLMS_IGNORE_EXTENDED_REGISTER + if (((gxExtendedRegister*)object)->unit != 0) + { + ret = bb_setUInt8(ba, 3); + } + if (ret == 0 && (ret = bb_setUInt8(ba, 2)) == 0 && + (ret = bb_setUInt8(ba, 4)) == 0 && + (ret = bb_setUInt8(ba, 5)) == 0) + { + + } +#endif //DLMS_IGNORE_EXTENDED_REGISTER + } + else if (object->objectType == DLMS_OBJECT_TYPE_DEMAND_REGISTER) + { +#ifndef DLMS_IGNORE_DEMAND_REGISTER + if (!((gxDemandRegister*)object)->unitRead) + { + ret = bb_setUInt8(ba, 4); + } + else + { + ret = 0; + } + if (ret == 0 && (ret = bb_setUInt8(ba, 2)) == 0 && + (ret = bb_setUInt8(ba, 3)) == 0 && + (ret = bb_setUInt8(ba, 5)) == 0 && + (ret = bb_setUInt8(ba, 6)) == 0 && + (ret = bb_setUInt8(ba, 7)) == 0 && + (ret = bb_setUInt8(ba, 8)) == 0 && + (ret = bb_setUInt8(ba, 9)) == 0) + { + + } +#endif //DLMS_IGNORE_DEMAND_REGISTER + } + else + { + cnt = obj_attributeCount(object) + 1; + if ((ret = bb_capacity(ba, cnt)) == 0) + { + for (pos = 2; pos < cnt; ++pos) + { + if (object->access == NULL) + { + if ((ret = bb_setUInt8(ba, pos)) != 0) + { + break; + } + } + else + { + ret = bb_getUInt8ByIndex(&object->access->attributeAccessModes, pos - 1, &ch); + if (ret == 0 || ch != DLMS_ACCESS_MODE_NONE) + { + ret = bb_setUInt8(ba, pos); + } + else + { +#if !defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + printf("Attribute access is denied."); +#endif + } + } + } + } + } + return ret; +} + + +unsigned char obj_methodCount(gxObject* object) +{ + unsigned char ret; + switch (object->objectType) + { + case DLMS_OBJECT_TYPE_DATA: + ret = 0; + break; + case DLMS_OBJECT_TYPE_REGISTER: + ret = 1; + break; + case DLMS_OBJECT_TYPE_ACTION_SCHEDULE: + ret = 0; + break; + case DLMS_OBJECT_TYPE_ACTIVITY_CALENDAR: + ret = 1; + break; + case DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME: + if (object->version > 1) + { + ret = 6; + } + else + { + ret = 4; + } + break; + case DLMS_OBJECT_TYPE_ASSOCIATION_SHORT_NAME: + if (object->version < 3) + { + ret = 8; + } + else + { + ret = 10; + } + break; + case DLMS_OBJECT_TYPE_AUTO_ANSWER: + ret = 0; + break; + case DLMS_OBJECT_TYPE_AUTO_CONNECT: + ret = 1; + break; + case DLMS_OBJECT_TYPE_CLOCK: + ret = 6; + break; + case DLMS_OBJECT_TYPE_DEMAND_REGISTER: + ret = 2; + break; + case DLMS_OBJECT_TYPE_MAC_ADDRESS_SETUP: + ret = 0; + break; + case DLMS_OBJECT_TYPE_EXTENDED_REGISTER: + ret = 1; + break; + case DLMS_OBJECT_TYPE_GPRS_SETUP: + ret = 0; + break; + case DLMS_OBJECT_TYPE_SECURITY_SETUP: + ret = 2; + break; + case DLMS_OBJECT_TYPE_IEC_HDLC_SETUP: + ret = 0; + break; + case DLMS_OBJECT_TYPE_IEC_LOCAL_PORT_SETUP: + ret = 0; + break; + case DLMS_OBJECT_TYPE_IEC_TWISTED_PAIR_SETUP: + ret = 1; + break; + case DLMS_OBJECT_TYPE_IP4_SETUP: + ret = 3; + break; + case DLMS_OBJECT_TYPE_IP6_SETUP: + ret = 2; + break; + case DLMS_OBJECT_TYPE_MBUS_SLAVE_PORT_SETUP: + ret = 0; + break; + case DLMS_OBJECT_TYPE_IMAGE_TRANSFER: + ret = 4; + break; + case DLMS_OBJECT_TYPE_DISCONNECT_CONTROL: + ret = 2; + break; + case DLMS_OBJECT_TYPE_LIMITER: + ret = 0; + break; + case DLMS_OBJECT_TYPE_MBUS_CLIENT: + ret = 8; + break; + case DLMS_OBJECT_TYPE_MODEM_CONFIGURATION: + ret = 0; + break; + case DLMS_OBJECT_TYPE_PPP_SETUP: + ret = 0; + break; + case DLMS_OBJECT_TYPE_PROFILE_GENERIC: + ret = 2; + break; + case DLMS_OBJECT_TYPE_REGISTER_ACTIVATION: + ret = 3; + break; + case DLMS_OBJECT_TYPE_REGISTER_MONITOR: + ret = 0; + break; + case DLMS_OBJECT_TYPE_REGISTER_TABLE: + ret = 1; + break; + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_STARTUP: + ret = 0; + break; + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_JOIN: + ret = 0; + break; + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_APS_FRAGMENTATION: + ret = 0; + break; + case DLMS_OBJECT_TYPE_SAP_ASSIGNMENT: + ret = 1; + break; +#ifndef DLMS_IGNORE_SCHEDULE + case DLMS_OBJECT_TYPE_SCHEDULE: + ret = 3; + break; +#endif //DLMS_IGNORE_SCHEDULE +#ifndef DLMS_IGNORE_SCRIPT_TABLE + case DLMS_OBJECT_TYPE_SCRIPT_TABLE: + ret = 1; + break; +#endif //DLMS_IGNORE_SCRIPT_TABLE + case DLMS_OBJECT_TYPE_SMTP_SETUP: + ret = 1; + break; + case DLMS_OBJECT_TYPE_SPECIAL_DAYS_TABLE: + ret = 2; + break; + case DLMS_OBJECT_TYPE_STATUS_MAPPING: + ret = 1; + break; + case DLMS_OBJECT_TYPE_TCP_UDP_SETUP: + ret = 0; + break; + case DLMS_OBJECT_TYPE_MBUS_DIAGNOSTIC: + ret = 1; + break; + case DLMS_OBJECT_TYPE_MBUS_PORT_SETUP: + ret = 0; + break; + case DLMS_OBJECT_TYPE_G3_PLC_MAC_LAYER_COUNTERS: + ret = 1; + break; + case DLMS_OBJECT_TYPE_G3_PLC_MAC_SETUP: + if (object->version < 3) + { + ret = 1; + } + else + { + ret = 2; + } + break; + case DLMS_OBJECT_TYPE_G3_PLC_6LO_WPAN: + ret = 0; + break; + case DLMS_OBJECT_TYPE_FUNCTION_CONTROL: + ret = 3; + break; + case DLMS_OBJECT_TYPE_ARRAY_MANAGER: + ret = 5; + break; + case DLMS_OBJECT_TYPE_UTILITY_TABLES: + ret = 1; + break; + case DLMS_OBJECT_TYPE_MBUS_MASTER_PORT_SETUP: + ret = 0; + break; + case DLMS_OBJECT_TYPE_PUSH_SETUP: + ret = 1; + break; + case DLMS_OBJECT_TYPE_DATA_PROTECTION: + ret = 3; + break; + case DLMS_OBJECT_TYPE_ACCOUNT: + ret = 3; + break; + case DLMS_OBJECT_TYPE_CREDIT: + ret = 3; + break; + case DLMS_OBJECT_TYPE_CHARGE: + ret = 5; + break; + case DLMS_OBJECT_TYPE_TOKEN_GATEWAY: + ret = 1; + break; + case DLMS_OBJECT_TYPE_ZIG_BEE_NETWORK_CONTROL: + ret = 11; + break; + case DLMS_OBJECT_TYPE_GSM_DIAGNOSTIC: + ret = 0; + break; + case DLMS_OBJECT_TYPE_COMPACT_DATA: + ret = 2; + break; + case DLMS_OBJECT_TYPE_PARAMETER_MONITOR: + ret = 2; + break; +#ifndef DLMS_IGNORE_LLC_SSCS_SETUP + case DLMS_OBJECT_TYPE_LLC_SSCS_SETUP: + ret = 1; + break; +#endif //DLMS_IGNORE_LLC_SSCS_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS: + ret = 1; + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_SETUP: + ret = 0; + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS: + ret = 0; + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_COUNTERS: + ret = 1; + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA: + ret = 1; + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION: + ret = 0; + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION +#ifndef DLMS_IGNORE_ARBITRATOR + case DLMS_OBJECT_TYPE_ARBITRATOR: + ret = 2; + break; +#endif //DLMS_IGNORE_ARBITRATOR +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE1_SETUP: + ret = 0; + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE2_SETUP: + ret = 0; + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE3_SETUP: + ret = 0; + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP +#ifndef DLMS_IGNORE_SFSK_ACTIVE_INITIATOR + case DLMS_OBJECT_TYPE_SFSK_ACTIVE_INITIATOR: + ret = 1; + break; +#endif //DLMS_IGNORE_SFSK_ACTIVE_INITIATOR +#ifndef DLMS_IGNORE_SFSK_MAC_COUNTERS + case DLMS_OBJECT_TYPE_SFSK_MAC_COUNTERS: + ret = 1; + break; +#endif //DLMS_IGNORE_SFSK_MAC_COUNTERS +#ifndef DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS + case DLMS_OBJECT_TYPE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS: + ret = 0; + break; +#endif //DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS +#ifndef DLMS_IGNORE_SFSK_PHY_MAC_SETUP + case DLMS_OBJECT_TYPE_SFSK_PHY_MAC_SETUP: + ret = 0; + break; +#endif //DLMS_IGNORE_SFSK_PHY_MAC_SETUP +#ifndef DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST + case DLMS_OBJECT_TYPE_SFSK_REPORTING_SYSTEM_LIST: + ret = 0; + break; +#endif //DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST +#ifdef DLMS_ITALIAN_STANDARD + case DLMS_OBJECT_TYPE_TARIFF_PLAN: + ret = 0; + break; +#endif //DLMS_ITALIAN_STANDARD + default: + //Unknown type. +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + ret = 0; + } + return ret; +} + +#ifndef DLMS_IGNORE_DATA_PROTECTION +void init_ProtectionParameter(gxProtectionParameter* target) +{ + target->type = DLMS_PROTECTION_TYPE_AUTHENTICATION; + target->options.info.identifiedOptions = DLMS_IDENTIFIED_KEY_INFO_OPTIONS_GLOBAL_UNICAST_ENCRYPTION_KEY; + target->options.info.type = DLMS_KEY_INFO_TYPE_IDENTIFIED_KEY; + BYTE_BUFFER_INIT(&target->options.id); + BYTE_BUFFER_INIT(&target->options.info.agreedOptions.cipheredData); + BYTE_BUFFER_INIT(&target->options.info.agreedOptions.parameters); + BYTE_BUFFER_INIT(&target->options.info.wrappedKeyoptions.data); + BYTE_BUFFER_INIT(&target->options.information); + BYTE_BUFFER_INIT(&target->options.originator); + BYTE_BUFFER_INIT(&target->options.recipient); +} + +void clear_ProtectionParameter(gxProtectionParameter* target) +{ + target->type = DLMS_PROTECTION_TYPE_AUTHENTICATION; + target->options.info.identifiedOptions = DLMS_IDENTIFIED_KEY_INFO_OPTIONS_GLOBAL_UNICAST_ENCRYPTION_KEY; + target->options.info.type = DLMS_KEY_INFO_TYPE_IDENTIFIED_KEY; + bb_clear(&target->options.id); + bb_clear(&target->options.info.agreedOptions.cipheredData); + bb_clear(&target->options.info.agreedOptions.parameters); + bb_clear(&target->options.info.wrappedKeyoptions.data); + bb_clear(&target->options.information); + bb_clear(&target->options.originator); + bb_clear(&target->options.recipient); +} +#endif //DLMS_IGNORE_DATA_PROTECTION + + +#ifndef DLMS_IGNORE_PARAMETER_MONITOR +int obj_clearParametersList(gxArray* buffer) +{ + int ret = 0; +#if !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + int pos; + gxKey* kv; + //Objects are not cleared because client owns them and clears them later. + for (pos = 0; pos != buffer->size; ++pos) + { + ret = arr_getByIndex(buffer, pos, (void**)&kv); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + gxfree(kv->value); + } +#endif // !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + arr_clear(buffer); + return ret; +} +#endif //DLMS_IGNORE_PARAMETER_MONITOR + +#ifndef DLMS_IGNORE_CLOCK +#ifndef DLMS_IGNORE_SERVER +void clock_updateDST(gxClock* object, gxtime* value) +{ + if (object->enabled && time_compare(&object->begin, value) != 1 && time_compare(&object->end, value) != -1) + { + object->status |= DLMS_CLOCK_STATUS_DAYLIGHT_SAVE_ACTIVE; + } + else + { + object->status &= ~DLMS_CLOCK_STATUS_DAYLIGHT_SAVE_ACTIVE; + } + object->time.status = object->status; +} +#endif //DLMS_IGNORE_SERVER + +int clock_utcToMeterTime(gxClock* object, gxtime* value) +{ + if (value->deviation == 0 && object->timeZone != 0 && object->timeZone != -32768) //-32768 = 0x8000 + { +#ifdef DLMS_USE_UTC_TIME_ZONE + time_addMinutes(value, object->timeZone); +#else + time_addMinutes(value, -object->timeZone); +#endif //DLMS_USE_UTC_TIME_ZONE + value->deviation = object->timeZone; + } + //If DST is enabled for the meter and it's not set for the time. + if ((object->status & DLMS_CLOCK_STATUS_DAYLIGHT_SAVE_ACTIVE) != 0) + { +#ifdef DLMS_USE_UTC_TIME_ZONE + time_addMinutes(value, object->deviation); + value->deviation += object->deviation; +#else + time_addMinutes(value, object->deviation); + value->deviation -= object->deviation; +#endif //DLMS_USE_UTC_TIME_ZONE + value->status |= DLMS_CLOCK_STATUS_DAYLIGHT_SAVE_ACTIVE; + } + else if ((object->status & DLMS_CLOCK_STATUS_DAYLIGHT_SAVE_ACTIVE) == 0) + { + value->status &= ~DLMS_CLOCK_STATUS_DAYLIGHT_SAVE_ACTIVE; + } + else if ((object->status & DLMS_CLOCK_STATUS_DAYLIGHT_SAVE_ACTIVE) != 0 && (value->status & DLMS_CLOCK_STATUS_DAYLIGHT_SAVE_ACTIVE) != 0) + { +#ifdef DLMS_USE_UTC_TIME_ZONE + value->deviation += object->deviation; +#else + value->deviation -= object->deviation; +#endif //DLMS_USE_UTC_TIME_ZONE + } + return 0; +} + +#endif //DLMS_IGNORE_CLOCK diff --git a/components/xt211/gxobjects.h b/components/xt211/gxobjects.h new file mode 100644 index 0000000..d9e4fb6 --- /dev/null +++ b/components/xt211/gxobjects.h @@ -0,0 +1,4299 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef GXOBJECTS_H +#define GXOBJECTS_H + +#include "gxignore.h" +#if defined(_WIN32) || defined(_WIN64)//Windows includes +#include +#else //Linux includes. +#ifndef DLMS_IGNORE_IP6_SETUP +#include +#include +#include +#define IN6_ADDR struct in6_addr +#endif //DLMS_IGNORE_IP6_SETUP +#endif +#include "enums.h" +#include "variant.h" +#include "date.h" +#include "gxarray.h" +#include "gxkey.h" +#include "gxdefine.h" + +#ifdef __cplusplus +extern "C" { +#endif + typedef enum + { + /* + * Write attribute. + */ + DLMS_SCRIPT_ACTION_TYPE_WRITE = 1, + /* + * Execute specific method + */ + DLMS_SCRIPT_ACTION_TYPE_EXECUTE = 2 + } DLMS_SCRIPT_ACTION_TYPE; + + typedef enum + { + /* + First in first out + When circle buffer is full first item is removed. + */ + DLMS_SORT_METHOD_FIFO = 1, + /* + Last in first out. + When circle buffer is full last item is removed. + */ + DLMS_SORT_METHOD_LIFO = 2, + /* + Largest is first. + */ + DLMS_SORT_METHOD_LARGEST = 3, + /* + Smallest is first. + */ + DLMS_SORT_METHOD_SMALLEST = 4, + /* + Nearst to zero is first. + */ + DLMS_SORT_METHOD_NEAREST_TO_ZERO = 5, + /* + Farest from zero is first. + */ + DLMS_SORT_METHOD_FAREST_FROM_ZERO = 6 + } DLMS_SORT_METHOD; + + typedef enum + { + /// Not defined + DLMS_CLOCK_BASE_NONE, + /// Internal Crystal + DLMS_CLOCK_BASE_CRYSTAL, + /// Mains frequency 50 Hz, + DLMS_CLOCK_BASE_FREQUENCY_50, + /// Mains frequency 60 Hz, + DLMS_CLOCK_BASE_FREQUENCY_60, + /// Global Positioning System. + DLMS_CLOCK_BASE_GPS, + /// Radio controlled. + DLMS_CLOCK_BASE_RADIO + } DLMS_CLOCK_BASE; + + typedef enum + { + /* + * The device never connects. + */ + DLMS_AUTO_CONNECT_MODE_NO_AUTO_CONNECT = 0, + /* + * Auto dialling allowed anytime, + */ + DLMS_AUTO_CONNECT_MODE_AUTO_DIALLING_ALLOWED_ANYTIME = 1, + /* + * Auto dialling allowed within the validity time of the calling window. + */ + DLMS_AUTO_CONNECT_MODE_AUTO_DIALLING_ALLOWED_CALLING_WINDOW = 2, + /* + * Regular auto dialling allowed within the validity time + * of the calling window; alarm initiated auto dialling allowed anytime, + */ + DLMS_AUTO_CONNECT_MODE_REGULAR_AUTO_DIALLING_ALLOWED_CALLING_WINDOW = 3, + /* + * SMS sending via Public Land Mobile Network (PLMN), + */ + DLMS_AUTO_CONNECT_MODE_SMS_SENDING_PLMN = 4, + /* + * SMS sending via PSTN. + */ + DLMS_AUTO_CONNECT_MODE_SMS_SENDING_PSTN = 5, + /* + * Email sending. + */ + DLMS_AUTO_CONNECT_MODE_EMAIL_SENDING = 6, + /* + * The device is permanently connected to the communication network. + */ + DLMS_AUTO_CONNECT_MODE_PERMANENTLY_CONNECT = 101, + /* + * The device is permanently connected to the communication network. No + * connection possible outside the calling window. + */ + DLMS_AUTO_CONNECT_MODE_CONNECT_WITH_CALLING_WINDOW = 102, + /* + * The device is permanently connected to the communication network. + * Connection is possible as soon as the connect method is invoked. + */ + DLMS_AUTO_CONNECT_MODE_CONNECT_INVOKED = 103, + /* + * The device is usually disconnected. It connects to the communication + * network as soon as the connect method is invoked + */ + DLMS_AUTO_CONNECT_MODE_DISCONNECT_CONNECT_INVOKED = 104, + /* + * (200..255) manufacturer specific modes + */ + DLMS_AUTO_CONNECT_MODE_MANUFACTURE_SPESIFIC = 200 + } DLMS_AUTO_CONNECT_MODE; + + typedef enum + { + DLMS_AUTO_ANSWER_STATUS_INACTIVE = 0, + DLMS_AUTO_ANSWER_STATUS_ACTIVE = 1, + DLMS_AUTO_ANSWER_STATUS_LOCKED = 2 + } DLMS_AUTO_ANSWER_STATUS; + + typedef enum + { + // Line dedicated to the device. + DLMS_AUTO_ANSWER_MODE_DEVICE = 0, + // Shared line management with a limited number of calls allowed. Once the number of calls is reached, + // the window status becomes inactive until the next start date, whatever the result of the call, + DLMS_AUTO_ANSWER_MODE_CALL = 1, + // Shared line management with a limited number of successful calls allowed. Once the number of + //// successful communications is reached, the window status becomes inactive until the next start date, + DLMS_AUTO_ANSWER_MODE_CONNECTED = 2, + // Currently no modem connected. + DLMS_AUTO_ANSWER_MODE_NONE = 3 + } DLMS_AUTO_ANSWER_MODE; + + /* + Defines the protocol used by the meter on the port. + */ + typedef enum + { + /* + Protocol according to IEC 62056-21 (modes A�E), + */ + DLMS_OPTICAL_PROTOCOL_MODE_DEFAULT = 0, + /* + Protocol according to IEC 62056-46. + Using this enumeration value all other attributes of this IC are not applicable. + */ + DLMS_OPTICAL_PROTOCOL_MODE_NET = 1, + /* + Protocol not specified. Using this enumeration value, + ProposedBaudrate is used for setting the communication speed on the port. + All other attributes are not applicable. + */ + DLMS_OPTICAL_PROTOCOL_MODE_UNKNOWN = 2 + } DLMS_OPTICAL_PROTOCOL_MODE; + + typedef enum + { + /* + Minimium time is 20 ms. + */ + DLMS_LOCAL_PORT_RESPONSE_TIME_20_MS = 0, + /* + Minimium time is 200 ms. + */ + DLMS_LOCAL_PORT_RESPONSE_TIME_200_MS = 1 + } DLMS_LOCAL_PORT_RESPONSE_TIME; + + /* + * + * Defines the baud rates. + */ + typedef enum + { + /* + Baudrate is 300. + */ + DLMS_BAUD_RATE_300 = 0, + /* + Baudrate is 600. + */ + DLMS_BAUD_RATE_600, + /* + Baudrate is 1200. + */ + DLMS_BAUD_RATE_1200, + /* + Baudrate is 2400. + */ + DLMS_BAUD_RATE_2400, + /* + Baudrate is 4800. + */ + DLMS_BAUD_RATE_4800, + /* + Baudrate is 9600. + */ + DLMS_BAUD_RATE_9600, + /* + Baudrate is 19200. + */ + DLMS_BAUD_RATE_19200, + /* + Baudrate is 38400. + */ + DLMS_BAUD_RATE_38400, + /* + Baudrate is 57600. + */ + DLMS_BAUD_RATE_57600, + /* + Baudrate is 115200. + */ + DLMS_BAUD_RATE_115200 + } DLMS_BAUD_RATE; + + typedef enum + { + /* + * The output_state is set to false and the consumer is disconnected. + */ + DLMS_CONTROL_STATE_DISCONNECTED = 0, + /* + * The output_state is set to 1 and the consumer is connected. + */ + DLMS_CONTROL_STATE_CONNECTED, + /* + * The output_state is set to false and the consumer is disconnected. + */ + DLMS_CONTROL_STATE_READY_FOR_RECONNECTION + } DLMS_CONTROL_STATE; + + /* + * Configures the behaviour of the disconnect control object for all + triggers, i.e. the possible state transitions. + */ + typedef enum + { + /* + * The disconnect control object is always in 'connected' state, + */ + DLMS_CONTROL_MODE_NONE = 0, + /* + * Disconnection: Remote (b, c), manual (f), local (g) + * Reconnection: Remote (d), manual (e). + */ + DLMS_CONTROL_MODE_MODE_1, + /* + * Disconnection: Remote (b, c), manual (f), local (g) + * Reconnection: Remote (a), manual (e). + */ + DLMS_CONTROL_MODE_MODE_2, + /* + * Disconnection: Remote (b, c), manual (-), local (g) + * Reconnection: Remote (d), manual (e). + */ + DLMS_CONTROL_MODE_MODE_3, + /* + * Disconnection: Remote (b, c), manual (-), local (g) + * Reconnection: Remote (a), manual (e) + */ + DLMS_CONTROL_MODE_MODE_4, + /* + * Disconnection: Remote (b, c), manual (f), local (g) + * Reconnection: Remote (d), manual (e), local (h), + */ + DLMS_CONTROL_MODE_MODE_5, + /* + * Disconnection: Remote (b, c), manual (-), local (g) + * Reconnection: Remote (d), manual (e), local (h) + */ + DLMS_CONTROL_MODE_MODE_6, + } DLMS_CONTROL_MODE; + + /* + PPP Authentication Type + */ + typedef enum + { + /* + No authentication. + */ + DLMS_PPP_AUTHENTICATION_TYPE_NONE = 0, + /* + PAP Login + */ + DLMS_PPP_AUTHENTICATION_TYPE_PAP = 1, + /* + CHAP-algorithm + */ + DLMS_PPP_AUTHENTICATION_TYPE_CHAP = 2 + } DLMS_PPP_AUTHENTICATION_TYPE; + +#ifdef DLMS_IGNORE_MALLOC + typedef struct + { + unsigned char value[MAX_DESTINATION_LENGTH]; + uint16_t size; + }gxDestination; +#endif //DLMS_IGNORE_MALLOC + + //Access modes are saved structure because they are not needed on server side and we want to save memory. + /* + --------------------------------------------------------------------------- + */ + typedef struct + { + gxByteBuffer attributeAccessModes; + gxByteBuffer methodAccessModes; + }gxAccess; + + typedef struct + { + uint16_t objectType; + unsigned char version; +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + uint16_t shortName; +#endif // DLMS_IGNORE_ASSOCIATION_SHORT_NAME + unsigned char logicalName[6]; + gxAccess* access; + } gxObject; + + //Returns object's logical name. + const unsigned char* obj_getLogicalName(gxObject* target); + + typedef struct + { + gxObject* key; + unsigned char value; + } gxListItem; + + typedef struct + { + gxObject** data; + uint16_t capacity; + uint16_t size; +#if !(defined(GX_DLMS_MICROCONTROLLER) || defined(DLMS_IGNORE_MALLOC)) + uint16_t position; +#endif //!(defined(GX_DLMS_MICROCONTROLLER) || defined(DLMS_IGNORE_MALLOC)) + } objectArray; + + //--------------------------------------------------------------------------- + // Online help: + // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSData +#ifndef DLMS_IGNORE_DATA + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + dlmsVARIANT value; + } gxData; +#endif //DLMS_IGNORE_DATA + + //--------------------------------------------------------------------------- + // Online help: + // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSRegister +#ifndef DLMS_IGNORE_REGISTER + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + dlmsVARIANT value; + signed char scaler; + unsigned char unit; + unsigned char unitRead; + } gxRegister; +#endif // DLMS_IGNORE_REGISTER + + //--------------------------------------------------------------------------- + // Online help: + // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSExtendedRegister +#ifndef DLMS_IGNORE_EXTENDED_REGISTER + typedef struct + { + gxObject base; + dlmsVARIANT value; + signed char scaler; + unsigned char unit; + gxtime captureTime; + dlmsVARIANT status; + } gxExtendedRegister; +#endif //DLMS_IGNORE_EXTENDED_REGISTER + + //--------------------------------------------------------------------------- + // Online help: + // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSDemandRegister +#ifndef DLMS_IGNORE_DEMAND_REGISTER + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + dlmsVARIANT currentAverageValue; + dlmsVARIANT lastAverageValue; + signed char scaler; + unsigned char unit; + unsigned char unitRead; + dlmsVARIANT status; + gxtime captureTime; + gxtime startTimeCurrent; + uint16_t numberOfPeriods; + uint32_t period; + } gxDemandRegister; +#endif // DLMS_IGNORE_DEMAND_REGISTER + +#ifdef DLMS_IGNORE_OBJECT_POINTERS + typedef struct + { + uint16_t objectType; + unsigned char logicalName[6]; + } gxObjectDefinition; +#endif //DLMS_IGNORE_OBJECT_POINTERS + +#ifndef DLMS_IGNORE_REGISTER_ACTIVATION + typedef struct + { +#ifdef DLMS_IGNORE_MALLOC + //Name length. + unsigned char length; + //Name of the mask. + unsigned char name[MAX_REGISTER_ACTIVATION_MASK_NAME_LENGTH]; + //Index count + unsigned char count; + //Mask index list. + unsigned char indexes[9]; +#else + gxByteBuffer name; + gxByteBuffer indexes; +#endif //DLMS_IGNORE_MALLOC + } gxRegisterActivationMask; + + //--------------------------------------------------------------------------- + // Online help: + // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSRegisterActivation + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; +#if !defined(DLMS_IGNORE_OBJECT_POINTERS) && !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + objectArray registerAssignment; +#else + gxArray registerAssignment; +#endif //DLMS_IGNORE_OBJECT_POINTERS + gxArray maskList; + gxByteBuffer activeMask; + } gxRegisterActivation; +#endif //DLMS_IGNORE_REGISTER_ACTIVATION + +#if !(defined(DLMS_IGNORE_PROFILE_GENERIC) && defined(DLMS_IGNORE_COMPACT_DATA) && defined(DLMS_IGNORE_PUSH_SETUP) && defined(DLMS_IGNORE_PARAMETER_MONITOR)) + //--------------------------------------------------------------------------- + // Online help: + // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSProfileGeneric + // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSCompactData + // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSParameterMonitor + typedef struct + { + signed char attributeIndex; + uint16_t dataIndex; +#ifdef DLMS_IGNORE_OBJECT_POINTERS + unsigned char logicalName[6]; + uint16_t objectType; +#else +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + gxObject* target; +#endif //defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) +#endif //DLMS_IGNORE_OBJECT_POINTERS + } gxTarget; + + + //--------------------------------------------------------------------------- + //deprecated: User gxTarget instead of gxCaptureObject. + typedef struct + { + char attributeIndex; + uint16_t dataIndex; + } gxCaptureObject; + +#endif //!(defined(DLMS_IGNORE_PROFILE_GENERIC) && defined(DLMS_IGNORE_COMPACT_DATA) && defined(DLMS_IGNORE_PUSH_SETUP) && defined(DLMS_IGNORE_PARAMETER_MONITOR)) + +#ifndef DLMS_IGNORE_PROFILE_GENERIC +#ifndef DLMS_IGNORE_MALLOC + //Create capture object with given attribute and data indexes. + gxTarget* co_init(unsigned char attributeIndex, unsigned char dataIndex); +#endif //DLMS_IGNORE_MALLOC + + //--------------------------------------------------------------------------- + // Online help: + // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSProfileGeneric + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + +#ifndef DLMS_IGNORE_MALLOC + //There is no buffer is malloc is not used. + //Reason for this is that we don't know the structure of the data and where example octect string is saved. + //User must do this manually! + gxArray buffer; +#endif //DLMS_IGNORE_MALLOC + gxArray captureObjects; + uint32_t capturePeriod; + DLMS_SORT_METHOD sortMethod; + gxObject* sortObject; + uint32_t profileEntries; + uint32_t entriesInUse; + signed char sortObjectAttributeIndex; + uint16_t sortObjectDataIndex; + //Executed time. This is for internal use. + uint32_t executedTime; + } gxProfileGeneric; +#endif //DLMS_IGNORE_PROFILE_GENERIC + + //--------------------------------------------------------------------------- + // Online help: + // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSClock +#ifndef DLMS_IGNORE_CLOCK + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + + DLMS_CLOCK_BASE clockBase : 8; + signed char deviation; + unsigned char enabled; + gxtime end; + DLMS_CLOCK_STATUS status : 8; + gxtime begin; + int16_t timeZone; + gxtime time; + gxtime presetTime; + } gxClock; + +#ifndef DLMS_IGNORE_CLOCK + //Update Daylight Saving time flag if DST is used. + void clock_updateDST( + gxClock* object, + gxtime* value); + + //Convert UTC date time to meter date time. + int clock_utcToMeterTime( + gxClock* object, + gxtime* value); +#endif // DLMS_IGNORE_CLOCK + +#endif //DLMS_IGNORE_CLOCK + +#ifndef DLMS_IGNORE_SCRIPT_TABLE + //--------------------------------------------------------------------------- + // Online help: + // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSScriptTable + typedef struct + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + gxObject* target; +#else + uint16_t objectType; + unsigned char logicalName[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + DLMS_SCRIPT_ACTION_TYPE type; + dlmsVARIANT parameter; + signed char index; + } gxScriptAction; + + //--------------------------------------------------------------------------- + // Online help: + // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSScriptTable + typedef struct + { + //Script ID. + uint16_t id; + //Script actions. + gxArray actions; + } gxScript; + + //--------------------------------------------------------------------------- + // Online help: + // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSScriptTable + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + gxArray scripts; + } gxScriptTable; +#endif //DLMS_IGNORE_SCRIPT_TABLE + +#ifndef DLMS_IGNORE_SCHEDULE + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSSchedule + */ + typedef struct + { + /* + * Schedule entry index. + */ + uint16_t index; + + /* + * Is Schedule entry enabled. + */ + unsigned char enable; +#ifndef DLMS_IGNORE_OBJECT_POINTERS + gxScriptTable* scriptTable; +#else + /* + * Logical name of the Script table object. + */ + unsigned char logicalName[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + + /* + * Script identifier of the script to be executed. + */ + uint16_t scriptSelector; + + /* + * + */ + gxtime switchTime; + + /* + * Defines a period in minutes, in which an entry shall be processed after power fail. + */ + uint16_t validityWindow; + + /* + * BitArray days of the week on which the entry is valid. + */ + DLMS_WEEKDAYS execWeekdays : 7; + + /* + * Perform the link to the IC Special days table, day_id. + */ + bitArray execSpecDays; + + /* + * Date starting period in which the entry is valid. + */ + gxtime beginDate; + + /* + * Date starting period in which the entry is valid. + */ + gxtime endDate; + } + gxScheduleEntry; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSSchedule + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + + /* + * Specifies the scripts to be executed at given times. + */ + gxArray entries; //gxScheduleEntry + } gxSchedule; +#endif //DLMS_IGNORE_SCHEDULE + +#ifndef DLMS_IGNORE_SPECIAL_DAYS_TABLE + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSSpecialDaysTable + */ + typedef struct + { + uint16_t index; + gxtime date; + unsigned char dayId; + } gxSpecialDay; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSSpecialDaysTable + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + gxArray entries;//gxSpecialDay[] + } gxSpecialDaysTable; +#endif //DLMS_IGNORE_SPECIAL_DAYS_TABLE + +#ifndef DLMS_IGNORE_SECURITY_SETUP + typedef struct + { + // Used certificate entity. + DLMS_CERTIFICATE_ENTITY entity; + + // Used certificate type. + DLMS_CERTIFICATE_TYPE type; + +#ifdef DLMS_IGNORE_MALLOC + // Certificate serial number. + char serialNumber[MAX_CERTIFICATE_SERIAL_NUMBER_LENGTH]; + + // Certificate issuer. + char issuer[MAX_CERTIFICATE_ISSUER_LENGTH]; + + // Certificate subject. + char subject[MAX_CERTIFICATE_SUBJECT_LENGTH]; + // Certificate subject alt name. + char subjectAltName[MAX_CERTIFICATE_SUBJECT_ALT_LENGTH]; +#else + // Certificate serial number. + char* serialNumber; + + // Certificate issuer. + char* issuer; + + // Certificate subject. + char* subject; + // Certificate subject alt name. + char* subjectAltName; +#endif //DLMS_IGNORE_MALLOC + }gxCertificateInfo; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSSecuritySetup + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + DLMS_SECURITY_POLICY securityPolicy; + DLMS_SECURITY_SUITE securitySuite; + gxByteBuffer serverSystemTitle; + gxByteBuffer clientSystemTitle; + gxArray certificates; + //Minimum client invocation counter value. Server can use this. +#ifdef DLMS_COSEM_INVOCATION_COUNTER_SIZE64 + uint64_t minimumInvocationCounter; +#else + uint32_t minimumInvocationCounter; +#endif //DLMS_COSEM_INVOCATION_COUNTER_SIZE64 + } gxSecuritySetup; +#endif //DLMS_IGNORE_SECURITY_SETUP + +#ifdef DLMS_IGNORE_MALLOC + typedef struct + { + //User ID. + unsigned char id; + //User name + char name[MAX_USER_NAME_LENGTH]; + }gxUser; +#endif //DLMS_IGNORE_MALLOC + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAssociationShortName + */ +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + objectArray objectList; +#if !(defined(DLMS_IGNORE_OBJECT_POINTERS) || defined(DLMS_IGNORE_SECURITY_SETUP)) + gxSecuritySetup* securitySetup; +#else + unsigned char securitySetupReference[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + gxByteBuffer secret; + /* + * User list. + */ + gxArray userList; + /* + * Current user. + */ +#ifdef DLMS_IGNORE_MALLOC + gxUser currentUser; +#else + gxKey2 currentUser; +#endif //DLMS_IGNORE_MALLOC + } gxAssociationShortName; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAssociationLogicalName + */ + typedef struct + { + unsigned char logicalName[6]; + unsigned char jointIsoCtt; + unsigned char country; + uint16_t countryName; + unsigned char identifiedOrganization; + unsigned char dlmsUA; + unsigned char applicationContext; + unsigned char contextId; + } gxApplicationContextName; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAssociationLogicalName + */ + typedef struct + { + DLMS_CONFORMANCE conformance; + uint16_t maxReceivePduSize; + uint16_t maxSendPduSize; + unsigned char dlmsVersionNumber; + signed char qualityOfService; + gxByteBuffer cypheringInfo; + } gxXDLMSContextType; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAssociationLogicalName + */ + typedef struct + { + unsigned char jointIsoCtt; + unsigned char country; + uint16_t countryName; + unsigned char identifiedOrganization; + unsigned char dlmsUA; + unsigned char authenticationMechanismName; + DLMS_AUTHENTICATION mechanismId; + } gxAuthenticationMechanismName; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAssociationLogicalName + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + + DLMS_ASSOCIATION_STATUS associationStatus; + objectArray objectList; + signed char clientSAP; + uint16_t serverSAP; + gxApplicationContextName applicationContextName; + gxXDLMSContextType xDLMSContextInfo; + gxAuthenticationMechanismName authenticationMechanismName; + gxByteBuffer secret; +#if !(defined(DLMS_IGNORE_OBJECT_POINTERS) || defined(DLMS_IGNORE_SECURITY_SETUP)) + gxSecuritySetup* securitySetup; +#else + unsigned char securitySetupReference[6]; +#endif //!(defined(DLMS_IGNORE_OBJECT_POINTERS) || defined(DLMS_IGNORE_SECURITY_SETUP)) + /* + * User list. + */ + gxArray userList; + /* + * Current user. + */ +#ifdef DLMS_IGNORE_MALLOC + gxUser currentUser; +#else + gxKey2 currentUser; +#endif //DLMS_IGNORE_MALLOC + } gxAssociationLogicalName; + +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + +#ifndef DLMS_IGNORE_SAP_ASSIGNMENT + + typedef struct + { + unsigned char value[MAX_SAP_ITEM_NAME_LENGTH]; + uint16_t size; + }gxSapItemName; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSSapAssignment + */ + typedef struct + { + uint16_t id; +#ifdef DLMS_IGNORE_MALLOC + gxSapItemName name; +#else + gxByteBuffer name; +#endif //DLMS_IGNORE_MALLOC + } gxSapItem; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSSapAssignment + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + gxArray sapAssignmentList;//List of gxSapItems. + } gxSapAssignment; + +#endif //DLMS_IGNORE_SAP_ASSIGNMENT + +#ifndef DLMS_IGNORE_IMAGE_TRANSFER + +#ifdef DLMS_IGNORE_MALLOC + typedef struct + { + unsigned char data[MAX_IMAGE_IDENTIFICATION_LENGTH]; + uint16_t size; + }gxImageIdentification; + + typedef struct + { + unsigned char data[MAX_IMAGE_SIGNATURE_LENGTH]; + uint16_t size; + }gxImageSignature; +#endif //DLMS_IGNORE_MALLOC + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSImageTransfer + */ + typedef struct + { + uint32_t size; + +#ifdef DLMS_IGNORE_MALLOC + gxImageIdentification identification; + gxImageSignature signature; +#else + gxByteBuffer identification; + gxByteBuffer signature; +#endif //DLMS_IGNORE_MALLOC + } gxImageActivateInfo; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSImageTransfer + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + uint32_t imageBlockSize; + bitArray imageTransferredBlocksStatus; + uint32_t imageFirstNotTransferredBlockNumber; + unsigned char imageTransferEnabled; + DLMS_IMAGE_TRANSFER_STATUS imageTransferStatus; + gxArray imageActivateInfo; // gxImageActivateInfo + } gxImageTransfer; +#endif //DLMS_IGNORE_IMAGE_TRANSFER + +#ifndef DLMS_IGNORE_IEC_LOCAL_PORT_SETUP + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSIECLocalPortSetup + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + gxByteBuffer password1; + gxByteBuffer password2; + gxByteBuffer password5; + DLMS_OPTICAL_PROTOCOL_MODE defaultMode; + DLMS_BAUD_RATE defaultBaudrate; + DLMS_BAUD_RATE proposedBaudrate; + DLMS_LOCAL_PORT_RESPONSE_TIME responseTime; + gxByteBuffer deviceAddress; + } gxLocalPortSetup; +#endif //DLMS_IGNORE_IEC_LOCAL_PORT_SETUP + +#ifndef DLMS_IGNORE_ACTIVITY_CALENDAR + +#ifdef DLMS_IGNORE_MALLOC + typedef struct + { + unsigned char value[MAX_SEASON_PROFILE_NAME_LENGTH]; + uint16_t size; + }gxSeasonProfileName; +#endif //DLMS_IGNORE_MALLOC + +#ifdef DLMS_IGNORE_MALLOC + typedef struct + { + unsigned char value[MAX_SEASON_PROFILE_WEEK_NAME_LENGTH]; + uint16_t size; + }gxSeasonProfileWeekName; +#endif //DLMS_IGNORE_MALLOC + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSActivityCalendar + */ + typedef struct + { +#ifdef DLMS_IGNORE_MALLOC + gxSeasonProfileName name; +#else + gxByteBuffer name; +#endif //DLMS_IGNORE_MALLOC + gxtime start; +#ifdef DLMS_IGNORE_MALLOC + gxSeasonProfileWeekName weekName; +#else + gxByteBuffer weekName; +#endif //DLMS_IGNORE_MALLOC + } gxSeasonProfile; + +#ifdef DLMS_IGNORE_MALLOC + typedef struct + { + unsigned char value[MAX_SEASON_WEEK_PROFILE_NAME_LENGTH]; + uint16_t size; + }gxWeekProfileName; +#endif //DLMS_IGNORE_MALLOC + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSActivityCalendar + */ + typedef struct + { +#ifdef DLMS_IGNORE_MALLOC + gxWeekProfileName name; +#else + gxByteBuffer name; +#endif //DLMS_IGNORE_MALLOC + unsigned char monday; + unsigned char tuesday; + unsigned char wednesday; + unsigned char thursday; + unsigned char friday; + unsigned char saturday; + unsigned char sunday; + } gxWeekProfile; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSActivityCalendar + */ + typedef struct + { + gxtime startTime; +#ifndef DLMS_IGNORE_OBJECT_POINTERS + gxObject* script; +#else + unsigned char scriptLogicalName[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + uint16_t scriptSelector; + } gxDayProfileAction; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSActivityCalendar + */ + typedef struct + { + unsigned char dayId; + gxArray daySchedules; //gxDayProfileAction + } gxDayProfile; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSActivityCalendar + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + + gxByteBuffer calendarNameActive; + gxByteBuffer calendarNamePassive; + gxArray seasonProfileActive; // gxSeasonProfile + gxArray weekProfileTableActive;// gxWeekProfile + gxArray dayProfileTableActive;// gxDayProfile + gxArray seasonProfilePassive;// gxSeasonProfile + gxArray dayProfileTablePassive;// gxDayProfile + gxArray weekProfileTablePassive;// gxWeekProfile + //Activate passive calendar time. + gxtime time; + //Executed time. This is for internal use. + uint32_t executedTime; + } gxActivityCalendar; + +#endif // DLMS_IGNORE_ACTIVITY_CALENDAR + +#if !(defined(DLMS_IGNORE_LIMITER) && defined(DLMS_IGNORE_REGISTER_MONITOR)) + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSRegisterMonitor + */ + typedef struct + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + gxScriptTable* script; +#else + unsigned char logicalName[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + uint16_t scriptSelector; + } gxActionItem; + +#endif //!(defined(DLMS_IGNORE_LIMITER) && defined(DLMS_IGNORE_REGISTER_MONITOR)) + +#ifndef DLMS_IGNORE_REGISTER_MONITOR + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSRegisterMonitor + */ + typedef struct + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + gxObject* target; +#else + uint16_t objectType; + unsigned char logicalName[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + signed char attributeIndex; + } gxMonitoredValue; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSRegisterMonitor + */ + typedef struct + { + gxActionItem actionUp; + gxActionItem actionDown; + } gxActionSet; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSRegisterMonitor + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + gxArray actions; //gxActionSet + gxMonitoredValue monitoredValue; + //List of threshold values. + variantArray thresholds; //dlmsVARIANT + //List of last values. This is needed so script is not invoked several times. + variantArray lastValues; + } gxRegisterMonitor; + +#endif //DLMS_IGNORE_REGISTER_MONITOR + +#ifndef DLMS_IGNORE_ACTION_SCHEDULE + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSActionSchedule + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + +#ifndef DLMS_IGNORE_OBJECT_POINTERS + gxScriptTable* executedScript; +#else + unsigned char executedScriptLogicalName[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + uint16_t executedScriptSelector; + DLMS_SINGLE_ACTION_SCHEDULE_TYPE type; + gxArray executionTime; //gxTime + //Executed time. This is for internal use. + uint32_t executedTime; + } gxActionSchedule; + +#endif //DLMS_IGNORE_ACTION_SCHEDULE + +#ifndef DLMS_IGNORE_IEC_HDLC_SETUP + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSIecHdlcSetup + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + uint16_t inactivityTimeout; + uint16_t deviceAddress; + uint16_t maximumInfoLengthTransmit; + DLMS_BAUD_RATE communicationSpeed; + unsigned char windowSizeTransmit; + unsigned char windowSizeReceive; + uint16_t interCharachterTimeout; + uint16_t maximumInfoLengthReceive; + } gxIecHdlcSetup; + +#endif //DLMS_IGNORE_IEC_HDLC_SETUP + +#ifndef DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSIecTwistedPairSetup + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + + /* + * Working mode. + */ + DLMS_IEC_TWISTED_PAIR_SETUP_MODE mode; + + /* + * Communication speed. + */ + DLMS_BAUD_RATE speed; + + /* + * List of Primary Station Addresses. + */ + gxByteBuffer primaryAddresses; + + /* + * List of the TAB(i) for which the real equipment has been programmed in + * the case of forgotten station call. + */ + gxByteBuffer tabis; + } gxIecTwistedPairSetup; +#endif //DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP + +#ifndef DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSMbusSlavePortSetup + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + DLMS_BAUD_RATE defaultBaud; + DLMS_BAUD_RATE availableBaud; + DLMS_ADDRESS_STATE addressState; + unsigned char busAddress; + } gxMbusSlavePortSetup; + +#endif //DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP + + +#ifndef DLMS_IGNORE_MBUS_DIAGNOSTIC + /*Last changed value.*/ + typedef struct + { + /*Attribute ID.*/ + unsigned char attributeId; + gxtime timeStamp; + }gxCaptureTime; + + typedef struct + { + /*Client ID.*/ + unsigned char clientId; + /*Counter.*/ + uint32_t counter; + /*Time stamp.*/ + gxtime timeStamp; + }gxBroadcastFrameCounter; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSMbusDiagnostic + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + /*Received signal strength in dBm.*/ + unsigned char receivedSignalStrength; + /*Currently used channel ID.*/ + unsigned char channelId; + /*Link status.*/ + DLMS_MBUS_LINK_STATUS linkStatus; + /*Broadcast frame counters*/ + gxArray broadcastFrames; + /*Transmitted frames.*/ + uint32_t transmissions; + /*Received frames with a correct checksum.*/ + uint32_t receivedFrames; + /*Received frames with a incorrect checksum.*/ + uint32_t failedReceivedFrames; + /* Last time when receivedSignalStrength, linkStatus, transmissions, + receivedFrames or failedReceivedFrames was changed.*/ + gxCaptureTime captureTime; + } gxMbusDiagnostic; +#endif //DLMS_IGNORE_MBUS_DIAGNOSTIC + +#ifndef DLMS_IGNORE_MBUS_PORT_SETUP + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSMBusPortSetup + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + /*References an M-Bus communication port setup object describing + the physical capabilities for wired or wireless communication.*/ + unsigned char profileSelection[6]; + /*Communication status of the M-Bus node.*/ + DLMS_MBUS_PORT_COMMUNICATION_STATE portCommunicationStatus; + /*M-Bus data header type.*/ + DLMS_MBUS_DATA_HEADER_TYPE dataHeaderType; + /*he primary address of the M-Bus slave device.*/ + unsigned char primaryAddress; + /*Identification Number element of the data header.*/ + uint32_t identificationNumber; + /*Manufacturer Identification element.*/ + uint16_t manufacturerId; + /*M-Bus version.*/ + unsigned char mBusVersion; + /*Device type.*/ + DLMS_MBUS_METER_TYPE deviceType; + uint16_t maxPduSize; + gxArray listeningWindow; + } gxMBusPortSetup; +#endif //DLMS_IGNORE_MBUS_PORT_SETUP + +#ifndef DLMS_IGNORE_UTILITY_TABLES + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSUtilityTables + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + uint16_t tableId; + gxByteBuffer buffer; + } gxUtilityTables; +#endif //DLMS_IGNORE_UTILITY_TABLES + +#ifndef DLMS_IGNORE_MODEM_CONFIGURATION + +#ifdef DLMS_IGNORE_MALLOC + typedef struct + { + unsigned char value[MAX_MODEM_INITIALIZATION_STRING_LENGTH]; + uint16_t size; + }gxModemInitialisationString; +#endif //DLMS_IGNORE_MALLOC + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSModemConfiguration + */ + typedef struct + { +#ifdef DLMS_IGNORE_MALLOC + gxModemInitialisationString request; + gxModemInitialisationString response; +#else + gxByteBuffer request; + gxByteBuffer response; +#endif //DLMS_IGNORE_MALLOC + uint16_t delay; + } gxModemInitialisation; + +#ifdef DLMS_IGNORE_MALLOC + typedef struct + { + unsigned char value[MAX_MODEM_PROFILE_STRING_LENGTH]; + uint16_t size; + }gxModemProfile; +#endif //DLMS_IGNORE_MALLOC + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSModemConfiguration + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + gxArray initialisationStrings; //gxModemInitialisation + gxArray modemProfile; // gxByteBuffer + DLMS_BAUD_RATE communicationSpeed; + } gxModemConfiguration; + +#endif //DLMS_IGNORE_MODEM_CONFIGURATION + + typedef struct + { + gxtime first; + gxtime second; + }gxTimePair; + +#ifndef DLMS_IGNORE_AUTO_ANSWER + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAutoAnswer + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + unsigned char numberOfRingsInListeningWindow; + unsigned char numberOfRingsOutListeningWindow; + DLMS_AUTO_ANSWER_MODE mode; + gxArray listeningWindow; + DLMS_AUTO_ANSWER_STATUS status; + unsigned char numberOfCalls; + } gxAutoAnswer; + +#endif //DLMS_IGNORE_AUTO_ANSWER + +#ifndef DLMS_IGNORE_AUTO_CONNECT + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAutoConnect + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + DLMS_AUTO_CONNECT_MODE mode; + gxArray callingWindow; + //Array of destination strings. + gxArray destinations; + uint16_t repetitionDelay; + unsigned char repetitions; + //Executed time. This is for internal use. + uint32_t executedTime; + } gxAutoConnect; +#endif //DLMS_IGNORE_AUTO_CONNECT + +#ifndef DLMS_IGNORE_TCP_UDP_SETUP + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSTcpUdpSetup + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + uint16_t port; +#ifndef DLMS_IGNORE_OBJECT_POINTERS + gxObject* ipSetup; +#else + //Logical name. + unsigned char ipReference[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + unsigned char maximumSimultaneousConnections; + uint16_t inactivityTimeout; + uint16_t maximumSegmentSize; + } gxTcpUdpSetup; + +#endif //DLMS_IGNORE_TCP_UDP_SETUP + +#ifndef DLMS_IGNORE_IP4_SETUP +#ifdef DLMS_IGNORE_MALLOC + typedef struct + { + unsigned char value[MAX_IP4_SETUP_IP_OPTION_DATA_LENGTH]; + uint16_t size; + }gxip4SetupIpOptionData; +#endif //DLMS_IGNORE_MALLOC + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSip4SetupIpOption + */ + typedef struct + { + DLMS_IP_OPTION_TYPE type; + unsigned char length; +#ifdef DLMS_IGNORE_MALLOC + gxip4SetupIpOptionData data; +#else + gxByteBuffer data; +#endif //DLMS_IGNORE_MALLOC + } gxip4SetupIpOption; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSIp4Setup + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; +#ifndef DLMS_IGNORE_OBJECT_POINTERS + gxObject* dataLinkLayer; +#else + unsigned char dataLinkLayerReference[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + uint32_t ipAddress; +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + gxArray multicastIPAddress; +#else + variantArray multicastIPAddress; +#endif //DLMS_IGNORE_MALLOC + gxArray ipOptions; //gxip4SetupIpOption + uint32_t subnetMask; + uint32_t gatewayIPAddress; + unsigned char useDHCP; + uint32_t primaryDNSAddress; + uint32_t secondaryDNSAddress; + dlmsVARIANT value; + } gxIp4Setup; +#endif //DLMS_IGNORE_IP4_SETUP + +#ifndef DLMS_IGNORE_IP6_SETUP + + // Enumerated Address config modes. + typedef enum { + // Auto Configuration. + DLMS_IP6_ADDRESS_CONFIG_MODE_AUTO, + // DHCP v6. + DLMS_IP6_ADDRESS_CONFIG_MODE_DHCP_V6, + // Manual + DLMS_IP6_ADDRESS_CONFIG_MODE_MANUAL, + // Neighbour Discovery. + DLMS_IP6_ADDRESS_CONFIG_MODE_NEIGHBOUR_DISCOVERY + }DLMS_IP6_ADDRESS_CONFIG_MODE; + + typedef struct + { + /** + * Gives the maximum number of router solicitation retries to be performed + * by a node if the expected router advertisement has not been received. + */ + unsigned char maxRetry; + /** + * Gives the waiting time in milliseconds between two successive router + * solicitation retries. + */ + uint16_t retryWaitTime; + /** + * Gives the router advertisement transmission period in seconds. + */ + uint32_t sendPeriod; + }gxNeighborDiscoverySetup; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSIp6Setup + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; +#ifndef DLMS_IGNORE_OBJECT_POINTERS + gxObject* dataLinkLayer; +#else + unsigned char dataLinkLayerReference[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + DLMS_IP6_ADDRESS_CONFIG_MODE addressConfigMode; + gxArray unicastIPAddress; //List + gxArray multicastIPAddress; //List + gxArray gatewayIPAddress; //List + IN6_ADDR primaryDNSAddress; + IN6_ADDR secondaryDNSAddress; + unsigned char trafficClass; + gxArray neighborDiscoverySetup;//List + } gxIp6Setup; +#endif //DLMS_IGNORE_IP6_SETUP + +#ifndef DLMS_IGNORE_MAC_ADDRESS_SETUP + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSMacAddressSetup + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + gxByteBuffer macAddress; + } gxMacAddressSetup; +#endif //DLMS_IGNORE_MAC_ADDRESS_SETUP + +#ifndef DLMS_IGNORE_PPP_SETUP + typedef enum + { + DLMS_PPP_SETUP_LCP_OPTION_TYPE_MAX_REC_UNIT = 1, + DLMS_PPP_SETUP_LCP_OPTION_TYPE_ASYNC_CONTROL_CHAR_MAP = 2, + DLMS_PPP_SETUP_LCP_OPTION_TYPE_AUTH_PROTOCOL = 3, + DLMS_PPP_SETUP_LCP_OPTION_TYPE_MAGIC_NUMBER = 5, + DLMS_PPP_SETUP_LCP_OPTION_TYPE_PROTOCOL_FIELD_COMPRESSION = 7, + DLMS_PPP_SETUP_LCP_OPTION_TYPE_ADDRESS_AND_CTR_COMPRESSION = 8, + DLMS_PPP_SETUP_LCP_OPTION_TYPE_FCS_ALTERNATIVES = 9, + DLMS_PPP_SETUP_LCP_OPTION_TYPE_CALLBACK = 13 + } DLMS_PPP_SETUP_LCP_OPTION_TYPE; + + typedef enum + { + DLMS_PPP_SETUP_IPCP_OPTION_TYPE_IPCOMPRESSIONPROTOCOL = 2, + DLMS_PPP_SETUP_IPCP_OPTION_TYPE_PREFLOCALIP = 3, + DLMS_PPP_SETUP_IPCP_OPTION_TYPE_PREFPEERIP = 20, + DLMS_PPP_SETUP_IPCP_OPTION_TYPE_GAO = 21, + DLMS_PPP_SETUP_IPCP_OPTION_TYPE_USIP = 22 + } DLMS_PPP_SETUP_IPCP_OPTION_TYPE; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSPppSetup + */ + typedef struct + { + DLMS_PPP_SETUP_LCP_OPTION_TYPE type; + unsigned char length; + dlmsVARIANT data; + } gxpppSetupLcpOption; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSPppSetup + */ + typedef struct + { + DLMS_PPP_SETUP_IPCP_OPTION_TYPE type; + unsigned char length; + dlmsVARIANT data; + } gxpppSetupIPCPOption; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSPppSetup + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + gxArray ipcpOptions; // gxpppSetupIPCPOption +#ifndef DLMS_IGNORE_OBJECT_POINTERS + gxObject* phy; +#else + unsigned char PHYReference[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + gxArray lcpOptions; //CGXDLMSPppSetupLcpOption + gxByteBuffer userName; + gxByteBuffer password; + DLMS_PPP_AUTHENTICATION_TYPE authentication; + } gxPppSetup; +#endif //DLMS_IGNORE_PPP_SETUP + +#ifndef DLMS_IGNORE_GPRS_SETUP + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSGPRSSetup + */ + typedef struct + { + unsigned char precedence; + unsigned char delay; + unsigned char reliability; + unsigned char peakThroughput; + unsigned char meanThroughput; + } gxQualityOfService; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSGPRSSetup + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + gxByteBuffer apn; + uint16_t pinCode; + gxQualityOfService defaultQualityOfService; + gxQualityOfService requestedQualityOfService; + } gxGPRSSetup; +#endif //DLMS_IGNORE_GPRS_SETUP + +#ifndef DLMS_IGNORE_SMTP_SETUP + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSSmtpSetup + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + } gxSmtpSetup; +#endif //DLMS_IGNORE_SMTP_SETUP + +#ifndef DLMS_IGNORE_GSM_DIAGNOSTIC + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSGsmDiagnostic + */ + typedef struct + { + /* + * Cell ID. + */ + uint32_t cellId; + + /* + * Location area code (LAC). + */ + uint16_t locationId; + + /* + * Signal quality. + */ + unsigned char signalQuality; + /* + * Bit Error Rate. + */ + unsigned char ber; + /* + * Mobile Country Code. + */ + uint16_t mobileCountryCode; + + /* + * Mobile Network Code. + */ + uint16_t mobileNetworkCode; + + /* + * Absolute radio frequency channel number. + */ + uint32_t channelNumber; + }gxGSMCellInfo; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSGsmDiagnostic + */ + typedef struct + { + /* + * Four-byte cell ID. + */ + uint32_t cellId; + + /* + * Signal quality. + */ + unsigned char signalQuality; + }gxAdjacentCell; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSGsmDiagnostic + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + /* + * Name of network operator. + */ +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + gxByteBuffer operatorName; +#else + char* operatorName; +#endif //DLMS_IGNORE_MALLOC + + /* + * Registration status of the modem. + */ + DLMS_GSM_STATUS status; + + /* + * Registration status of the modem. + */ + DLMS_GSM_CIRCUIT_SWITCH_STATUS circuitSwitchStatus; + + /* + * Registration status of the modem. + */ + DLMS_GSM_PACKET_SWITCH_STATUS packetSwitchStatus; + + /* + * Registration status of the modem. + */ + gxGSMCellInfo cellInfo; + + /* + * Adjacent cells. + */ + gxArray adjacentCells; // + + /* + * Date and time when the data have been last captured. + */ + gxtime captureTime; + } gxGsmDiagnostic; +#endif //DLMS_IGNORE_GSM_DIAGNOSTIC + +#ifndef DLMS_IGNORE_REGISTER_TABLE + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSRegisterTable + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + + variantArray tableCellValues; + gxArray tableCellDefinition; + signed char scaler; + unsigned char unit; + unsigned char unitRead; + } gxRegisterTable; +#endif //DLMS_IGNORE_REGISTER_TABLE + +#ifndef DLMS_IGNORE_STATUS_MAPPING + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSStatusMapping + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + //TODO: + } gxStatusMapping; +#endif //DLMS_IGNORE_STATUS_MAPPING + +#ifndef DLMS_IGNORE_DISCONNECT_CONTROL + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSDisconnectControl + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + unsigned char outputState; + DLMS_CONTROL_STATE controlState; + DLMS_CONTROL_MODE controlMode; + } gxDisconnectControl; +#endif //DLMS_IGNORE_DISCONNECT_CONTROL + +#ifndef DLMS_IGNORE_LIMITER + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSLimiter + */ + typedef struct + { + uint16_t id; + gxtime activationTime; + uint32_t duration; + } gxEmergencyProfile; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSLimiter + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + + gxObject* monitoredValue; + //Selected attribute index of monitored value. + signed char selectedAttributeIndex; + + dlmsVARIANT thresholdActive; + dlmsVARIANT thresholdNormal; + dlmsVARIANT thresholdEmergency; + uint32_t minOverThresholdDuration; + uint32_t minUnderThresholdDuration; + gxEmergencyProfile emergencyProfile; +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + gxArray emergencyProfileGroupIDs; +#else + variantArray emergencyProfileGroupIDs; +#endif //DLMS_IGNORE_MALLOC + unsigned char emergencyProfileActive; + gxActionItem actionOverThreshold; + gxActionItem actionUnderThreshold; + /*Threshold activation time in seconds. + This is internally used and it's not serialized.*/ + uint32_t activationTime; + /*Is threshold over or under. + This is internally used and it's not serialized.*/ + unsigned char overThreshold; + } gxLimiter; +#endif //DLMS_IGNORE_LIMITER + +#ifndef DLMS_IGNORE_MBUS_CLIENT + + typedef enum + { + DLMS_MBUS_ENCRYPTION_KEY_STATUS_NO_ENCRYPTION_KEY = 0, + DLMS_MBUS_ENCRYPTION_KEY_STATUS_ENCRYPTION_KEY_SET, + DLMS_MBUS_ENCRYPTION_KEY_STATUS_ENCRYPTION_KEY_TRANSFERRED, + DLMS_MBUS_ENCRYPTION_KEY_STATUS_ENCRYPTION_KEY_SET_AND_TRANSFERRED, + DLMS_MBUS_ENCRYPTION_KEY_STATUS_ENCRYPTION_KEY_INUSE + }DLMS_MBUS_ENCRYPTION_KEY_STATUS; + +#ifdef DLMS_IGNORE_MALLOC + typedef struct + { + unsigned char value[MAX_CAPTURE_DEFINITION_ELEMENT_LENGTH]; + uint16_t size; + }gxCaptureDefinitionElement; + + typedef struct + { + gxCaptureDefinitionElement data; + gxCaptureDefinitionElement value; + }gxCaptureDefinition; +#endif //DLMS_IGNORE_MALLOC + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSMBusClient + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + uint32_t capturePeriod; + unsigned char primaryAddress; +#ifndef DLMS_IGNORE_OBJECT_POINTERS + gxObject* mBusPort; +#else + unsigned char mBusPortReference[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + gxArray captureDefinition; + uint32_t identificationNumber; + uint16_t manufacturerID; + unsigned char dataHeaderVersion; + unsigned char deviceType; + unsigned char accessNumber; + unsigned char status; + unsigned char alarm; + uint16_t configuration; + DLMS_MBUS_ENCRYPTION_KEY_STATUS encryptionKeyStatus; + } gxMBusClient; +#endif //DLMS_IGNORE_MBUS_CLIENT + +#ifndef DLMS_IGNORE_PUSH_SETUP + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSPushSetup + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + gxArray pushObjectList; + + DLMS_SERVICE_TYPE service; + + //Destination. + gxByteBuffer destination; + + DLMS_MESSAGE_TYPE message; + + gxArray communicationWindow; + uint16_t randomisationStartInterval; + unsigned char numberOfRetries; + uint16_t repetitionDelay; + //Executed time. This is for internal use. + uint32_t executedTime; + } gxPushSetup; +#endif //DLMS_IGNORE_PUSH_SETUP + +#ifndef DLMS_IGNORE_PARAMETER_MONITOR + + typedef struct + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + gxObject* target; +#else + DLMS_OBJECT_TYPE type; + //Logical name. + unsigned char logicalName[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + signed char attributeIndex; + dlmsVARIANT value; + } gxChangedParameter; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSParameterMonitor + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + + //Changed parameter. + gxChangedParameter changedParameter; + + // Capture time. + gxtime captureTime; + + // Changed Parameter + gxArray parameters; + } gxParameterMonitor; +#endif //DLMS_IGNORE_PARAMETER_MONITOR + +#ifndef DLMS_IGNORE_WIRELESS_MODE_Q_CHANNEL + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSWirelessModeQChannel + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + } gxWirelessModeQChannel; + +#endif //DLMS_IGNORE_WIRELESS_MODE_Q_CHANNEL + +#ifndef DLMS_IGNORE_MBUS_MASTER_PORT_SETUP + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSMBusMasterPortSetup + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + DLMS_BAUD_RATE commSpeed; + } gxMBusMasterPortSetup; + +#endif //DLMS_IGNORE_MBUS_MASTER_PORT_SETUP + typedef enum + { + DLMS_PROTECTION_TYPE_AUTHENTICATION = 1, + DLMS_PROTECTION_TYPE_ENCRYPTION = 2, + DLMS_PROTECTION_TYPE_AUTHENTICATION_ENCRYPTION = 3 + } DLMS_PROTECTION_TYPE; + + //Global key types. + typedef enum + { + /* + * Global unicast encryption key.
+ * Client and server uses this message to send Ephemeral Public Key to other + * party. + */ + DLMS_GLOBAL_KEY_TYPE_UNICAST_ENCRYPTION, + /* + * Global broadcast encryption key. + */ + DLMS_GLOBAL_KEY_TYPE_BROADCAST_ENCRYPTION, + /* + * Authentication key. + */ + DLMS_GLOBAL_KEY_TYPE_AUTHENTICATION, + /* + * Key Encrypting Key, also known as Master key. + */ + DLMS_GLOBAL_KEY_TYPE_KEK + }DLMS_GLOBAL_KEY_TYPE; + +#ifndef DLMS_IGNORE_DATA_PROTECTION + typedef enum + { + //Used with identified_key_info_options. + DLMS_KEY_INFO_TYPE_IDENTIFIED_KEY = 0, + //Used with wrapped_key_info_options. + DLMS_KEY_INFO_TYPE_WRAPPED_KEY = 1, + //Used with agreed_key_info_options. + DLMS_KEY_INFO_TYPE_AGREED_KEY = 2 + } DLMS_KEY_INFO_TYPE; + + typedef enum + { + DLMS_IDENTIFIED_KEY_INFO_OPTIONS_GLOBAL_UNICAST_ENCRYPTION_KEY = 0, + DLMS_IDENTIFIED_KEY_INFO_OPTIONS_GLOBAL_BROADCAST_ENCRYPTION_KEY = 1 + } DLMS_IDENTIFIED_KEY_INFO_OPTIONS; + + typedef enum + { + DLMS_RESTRICTION_TYPE_NONE = 0, + //Restriction by date. + DLMS_RESTRICTION_TYPE_DATE = 1, + //Restriction by entry. + DLMS_RESTRICTION_TYPE_ENTRY = 2 + } DLMS_RESTRICTION_TYPE; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMS + */ + typedef struct + { + unsigned char id; + //Key ciphered data. + gxByteBuffer data; + } gxWrappedKeyInfoOptions; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMS + */ + typedef struct + { + gxByteBuffer parameters; + gxByteBuffer cipheredData; + } + gxAgreedKeyInfoOptions; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMS + */ + typedef struct + { + DLMS_KEY_INFO_TYPE type; + DLMS_IDENTIFIED_KEY_INFO_OPTIONS identifiedOptions; + gxWrappedKeyInfoOptions wrappedKeyoptions; + gxAgreedKeyInfoOptions agreedOptions; + } gxKeyinfo; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMS + */ + typedef struct + { + //Transaction id. + gxByteBuffer id; + //Originator_system_title + gxByteBuffer originator; + //Recipient System title. + gxByteBuffer recipient; + //Other information + gxByteBuffer information; + gxKeyinfo info; + } gxProtectionOptions; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMS + */ + typedef struct + { + DLMS_PROTECTION_TYPE type; + gxProtectionOptions options; + } gxProtectionParameter; + +#endif //DLMS_IGNORE_DATA_PROTECTION + +#ifndef DLMS_IGNORE_EVENT + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSEvent + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + } gxEvent; +#endif //DLMS_IGNORE_EVENT + +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_STARTUP + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSZigBeeSasStartup + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + } gxZigBeeSasStartup; + +#endif //DLMS_IGNORE_ZIG_BEE_SAS_STARTUP + +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_JOIN + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSZigBeeSasJoin + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + } gxZigBeeSasJoin; +#endif //DLMS_IGNORE_ZIG_BEE_SAS_JOIN + +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_APS_FRAGMENTATION + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSZigBeeSasApsFragmentation + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + } gxZigBeeSasApsFragmentation; +#endif //DLMS_IGNORE_ZIG_BEE_SAS_APS_FRAGMENTATION + +#ifndef DLMS_IGNORE_DATA_PROTECTION + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSDataProtection + */ + typedef struct + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + gxObject* target; +#else + DLMS_OBJECT_TYPE type; + //Logical name. + unsigned char logicalName[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + //attribute index. + int attributeIndex; + //data index + int dataIndex; + }gxDataProtectionObject; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSDataProtection + */ + typedef struct + { + gxObject base; + gxByteBuffer protection_buffer; + objectArray protectionObjectList; + gxArray protectionParametersGet; //gxProtectionParameter. + gxArray protectionParametersSet; //gxProtectionParameter. + DLMS_REQUIRED_PROTECTION requiredProtection; + } gxDataProtection; +#endif //DLMS_IGNORE_DATA_PROTECTION + +#ifndef DLMS_IGNORE_ACCOUNT + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccountModeAndStatus + */ + typedef struct + { + //CREDIT_MODE = 1, PREPAYMENT_MODE = 2 + unsigned char paymentMode; + // NEW_INACTIVE_ACCOUNT = 1, ACCOUNT_ACTIVE = 2, ACCOUNT_CLOSED = 3 + unsigned char accountStatus; + }gxAccountModeAndStatus; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSCreditChargeConfiguration + */ + typedef struct + { + unsigned char creditReference[6]; + unsigned char chargeReference[6]; + DLMS_CREDIT_COLLECTION_CONFIGURATION collectionConfiguration; + }gxCreditChargeConfiguration; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSTokenGatewayConfiguration + */ + typedef struct + { + unsigned char creditReference[6]; + unsigned char tokenProportion; + }gxTokenGatewayConfiguration; + +#ifdef DLMS_IGNORE_MALLOC + typedef struct + { + char value[MAX_CURRENCY_NAME_LENGTH]; + uint16_t size; + }gxCurrencyName; +#endif //DLMS_IGNORE_MALLOC + + /* + Used currency. + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + typedef struct + { + // Currency name. +#ifdef DLMS_IGNORE_MALLOC + gxCurrencyName name; +#else + gxByteBuffer name; +#endif //DLMS_IGNORE_MALLOC + // Currency scale. + signed char scale; + // Currency unit. + DLMS_CURRENCY unit; + }gxCurrency; + + /* + * Online help:
+ * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + + /* + * Payment mode.
+ * Online help:
+ * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + DLMS_ACCOUNT_PAYMENT_MODE paymentMode; + + /* + * Account status.
+ * Online help:
+ * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + DLMS_ACCOUNT_STATUS accountStatus; + + /* + * Credit In Use.
+ * Online help:
+ * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + unsigned char currentCreditInUse; + + /* + * Credit status.
+ * Online help:
+ * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + DLMS_ACCOUNT_CREDIT_STATUS currentCreditStatus; + + /* + * The available_credit attribute is the sum of the positive current credit + * amount values in the instances of the Credit class.
+ * Online help:
+ * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + int32_t availableCredit; + + /* + * Amount to clear.
+ * Online help:
+ * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + int32_t amountToClear; + + /* + * Conjunction with the amount to clear, and is included in the description + * of that attribute.
+ * Online help:
+ * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + int32_t clearanceThreshold; + + /* + * Aggregated debt.
+ * Online help:
+ * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + int32_t aggregatedDebt; + + /* + * Credit references.
+ * Online help:
+ * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + gxArray creditReferences;//List + + /* + * Charge references.
+ * Online help:
+ * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + gxArray chargeReferences;//List + /* + * Credit charge configurations.
+ * Online help:
+ * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + gxArray creditChargeConfigurations;//List + + /* + * Token gateway configurations.
+ * Online help:
+ * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + gxArray tokenGatewayConfigurations;//List + /* + * Account activation time.
+ * Online help:
+ * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + gxtime accountActivationTime; + + /* + * Account closure time.
+ * Online help:
+ * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + gxtime accountClosureTime; + + /* + * Currency.
+ * Online help:
+ * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + gxCurrency currency; + /* + * Low credit threshold.
+ * Online help:
+ * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + int32_t lowCreditThreshold; + /* + * Next credit available threshold.
+ * Online help:
+ * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + int32_t nextCreditAvailableThreshold; + /* + * Max Provision.
+ * Online help:
+ * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + uint16_t maxProvision; + + /* + * Max provision period.
+ * Online help:
+ * http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSAccount + */ + int32_t maxProvisionPeriod; + } gxAccount; +#endif //DLMS_IGNORE_ACCOUNT + +#ifndef DLMS_IGNORE_CREDIT + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSCredit + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + + int32_t currentCreditAmount; + DLMS_CREDIT_TYPE type; + unsigned char priority; + int32_t warningThreshold; + int32_t limit; + DLMS_CREDIT_CONFIGURATION creditConfiguration; + unsigned char status; + int32_t presetCreditAmount; + int32_t creditAvailableThreshold; + gxtime period; + } gxCredit; + +#endif //DLMS_IGNORE_CREDIT + +#ifndef DLMS_IGNORE_CHARGE + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSCharge + */ + typedef struct + { + signed char commodityScale; + signed char priceScale; + } gxChargePerUnitScaling; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSCharge + */ + typedef struct + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + gxObject* target; +#else + DLMS_OBJECT_TYPE type; + unsigned char logicalName[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + signed char attributeIndex; + } gxCommodity; + +#ifdef DLMS_IGNORE_MALLOC + typedef struct + { + unsigned char data[MAX_CHARGE_TABLE_INDEX_LENGTH]; + uint16_t size; + }gxChargeTableIndex; +#endif //DLMS_IGNORE_MALLOC + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSCharge + */ + typedef struct + { +#ifdef DLMS_IGNORE_MALLOC + gxChargeTableIndex index; +#else + gxByteBuffer index; +#endif //DLMS_IGNORE_MALLOC + int16_t chargePerUnit; + } gxChargeTable; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSCharge + */ + typedef struct + { + gxChargePerUnitScaling chargePerUnitScaling; + gxCommodity commodity; + gxArray chargeTables; + } gxUnitCharge; + + //--------------------------------------------------------------------------- + // Online help: + // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSCharge + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + int32_t totalAmountPaid; + + DLMS_CHARGE_TYPE chargeType; + unsigned char priority; + gxUnitCharge unitChargeActive; + gxUnitCharge unitChargePassive; + gxtime unitChargeActivationTime; + uint32_t period; + DLMS_CHARGE_CONFIGURATION chargeConfiguration; + gxtime lastCollectionTime; + int32_t lastCollectionAmount; + int32_t totalAmountRemaining; + uint16_t proportion; + } gxCharge; +#endif //DLMS_IGNORE_CHARGE + +#ifndef DLMS_IGNORE_TOKEN_GATEWAY +#ifdef DLMS_IGNORE_MALLOC + typedef struct + { + unsigned char value[MAX_TOKEN_GATEWAY_DESCRIPTION_LENGTH]; + uint16_t size; + }gxTokenGatewayDescription; +#endif //DLMS_IGNORE_MALLOC + + //--------------------------------------------------------------------------- + // Online help: + // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSTokenGateway + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + // Token. + // Online help:
+ // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSTokenGateway + gxByteBuffer token; + + // Time. + // Online help:
+ // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSTokenGateway + gxtime time; + + // Descriptions. + // Online help:
+ // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSTokenGateway + gxArray descriptions; + + // Token Delivery method. + // Online help:
+ // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSTokenGateway + DLMS_TOKEN_DELIVERY deliveryMethod; + + // Token status code. + // Online help:
+ // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSTokenGateway + DLMS_TOKEN_STATUS_CODE status; + + // Token data value. + // Online help:
+ // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSTokenGateway + bitArray dataValue; + } gxTokenGateway; +#endif //DLMS_IGNORE_TOKEN_GATEWAY + +#ifndef DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSZigBeeNetworkControl + */ + typedef struct + { + gxByteBuffer macAddress; + DLMS_ZIG_BEE_STATUS status; + char maxRSSI; + char averageRSSI; + char minRSSI; + unsigned char maxLQI; + unsigned char averageLQI; + unsigned char minLQI; + gxtime lastCommunicationDateTime; + unsigned char numberOfHops; + unsigned char transmissionFailures; + unsigned char transmissionSuccesses; + unsigned char applicationVersion; + unsigned char stackVersion; + } gxActiveDevice; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSZigBeeNetworkControl + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + + unsigned char enableDisableJoining; + uint16_t joinTimeout; + gxArray activeDevices; + } gxZigBeeNetworkControl; + +#endif //DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL + +#ifndef DLMS_IGNORE_LLC_SSCS_SETUP + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSLlcSscsSetup + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + /*Address assigned to the service node during its registration by the base node.*/ + uint16_t serviceNodeAddress; + /* Base node address to which the service node is registered.*/ + uint16_t baseNodeAddress; + + } gxLlcSscsSetup; +#endif //DLMS_IGNORE_LLC_SSCS_SETUP + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSPrimeNbOfdmPlcPhysicalLayerCounters + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + + /*Number of bursts received on the physical layer for which the CRC was incorrect.*/ + uint16_t crcIncorrectCount; + + /* Number of bursts received on the physical layer for which the CRC was correct, but the Protocol field of PHY header had invalid value.*/ + uint16_t crcFailedCount; + + /*Number of times when PHY layer received new data to transmit.*/ + uint16_t txDropCount; + + /*Number of times when the PHY layer received new data on the channel.*/ + uint16_t rxDropCount; + }gxPrimeNbOfdmPlcPhysicalLayerCounters; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSPrimeNbOfdmPlcMacSetup + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + + /*PIB attribute 0x0010.*/ + unsigned char macMinSwitchSearchTime; + + /*PIB attribute 0x0011.*/ + unsigned char macMaxPromotionPdu; + + /*PIB attribute 0x0012.*/ + unsigned char macPromotionPduTxPeriod; + + /*PIB attribute 0x0013.*/ + unsigned char macBeaconsPerFrame; + + /*PIB attribute 0x0014.*/ + unsigned char macScpMaxTxAttempts; + + /*PIB attribute 0x0015.*/ + unsigned char macCtlReTxTimer; + + /*PIB attribute 0x0018.*/ + unsigned char macMaxCtlReTx; + }gxPrimeNbOfdmPlcMacSetup; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSPrimeNbOfdmPlcMacFunctionalParameters + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + + /*LNID allocated to this node at time of its registration.*/ + int16_t lnId; + + /*LSID allocated to this node at the time of its promotion.*/ + unsigned char lsId; + + /*SID of the switch node through which this node is connected to the subnetwork.*/ + unsigned char sId; + + /*Subnetwork address to which this node is registered.*/ + gxByteBuffer sna; + + /*Present functional state of the node.*/ + + DLMS_MAC_STATE state; + + /*The SCP length, in symbols, in present frame.*/ + int16_t scpLength; + + /*Level of this node in subnetwork hierarchy.*/ + unsigned char nodeHierarchyLevel; + + /*Number of beacon slots provisioned in present frame structure.*/ + unsigned char beaconSlotCount; + + /*Beacon slot in which this device’s switch node transmits its beacon.*/ + unsigned char beaconRxSlot; + + /*Beacon slot in which this device transmits its beacon.*/ + unsigned char beaconTxSlot; + + /*Number of frames between receptions of two successive beacons.*/ + unsigned char beaconRxFrequency; + + /*Number of frames between transmissions of two successive beacons.*/ + unsigned char beaconTxFrequency; + + /*This attribute defines the capabilities of the node.*/ + DLMS_MAC_CAPABILITIES capabilities; + }gxPrimeNbOfdmPlcMacFunctionalParameters; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSPrimeNbOfdmPlcMacCounters + */ + typedef struct + { + /*Base class where class is derived.*/ + gxObject base; + + /*Count of successfully transmitted MSDUs.*/ + uint32_t txDataPktCount; + + /*Count of successfully received MSDUs whose destination address was this node.*/ + uint32_t rxDataPktCount; + + /*Count of successfully transmitted MAC control packets.*/ + uint32_t txCtrlPktCount; + + /*Count of successfully received MAC control packets whose destination was this node.*/ + uint32_t rxCtrlPktCount; + + /*Count of failed CSMA transmit attempts.*/ + uint32_t csmaFailCount; + + /*Count of number of times this node has to back off SCP transmission due to channel busy state.*/ + uint32_t csmaChBusyCount; + }gxPrimeNbOfdmPlcMacCounters; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + /*Multicast switching table.*/ + typedef struct + { + /*LCID of multicast group.*/ + signed char id; + /*Number of child nodes.*/ + int16_t members; + }gxMacMulticastEntry; + + /*MAC direct table element.*/ + typedef struct + { + /*SID of switch through which the source service node is connected.*/ + int16_t sourceSId; + + /*NID allocated to the source service node.*/ + int16_t sourceLnId; + /*LCID allocated to this connection at the source.*/ + int16_t sourceLcId; + + /*SID of the switch through which the destination service node is connected.*/ + int16_t destinationSId; + /*NID allocated to the destination service node.*/ + int16_t destinationLnId; + + /*LCID allocated to this connection at the destination.*/ + int16_t destinationLcId; + /*Entry DID is the EUI-48 of the direct switch.*/ + unsigned char did[6]; + }gxMacDirectTable; + + /*MAC available switch.*/ + typedef struct + { + /*EUI-48 of the subnetwork.*/ + gxByteBuffer sna; + + /*SID of this switch.*/ + int16_t lsId; + + /*Level of this switch in subnetwork hierarchy.*/ + signed char level; + + /*The received signal level for this switch.*/ + signed char rxLevel; + /*The signal to noise ratio for this switch.*/ + signed char rxSnr; + }gxMacAvailableSwitch; + + /*MAC PHY communication parameters.*/ + typedef struct + { + /*EUI is the EUI-48 of the other device.*/ + unsigned char eui[6]; + + /*The tx power of GPDU packets sent to the device.*/ + signed char txPower; + + /*The Tx coding of GPDU packets sent to the device.*/ + signed char txCoding; + + /*The Rx coding of GPDU packets received from the device.*/ + signed char rxCoding; + + /*The Rx power level of GPDU packets received from the device.*/ + signed char rxLvl; + + /*SNR of GPDU packets received from the device.*/ + signed char snr; + + /*The number of times the Tx power was modified.*/ + signed char txPowerModified; + + /*The number of times the Tx coding was modified.*/ + signed char txCodingModified; + + /*The number of times the Rx coding was modified.*/ + signed char rxCodingModified; + }gxMacPhyCommunication; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSPrimeNbOfdmPlcMacNetworkAdministrationData + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + + /*List of entries in multicast switching table.*/ + gxArray multicastEntries;//gxMacMulticastEntry[] + + /*Switch table.*/ + gxArray switchTable;//uint16_t[] + + /*List of entries in multicast switching table.*/ + gxArray directTable; //gxMacDirectTable[] + + /*List of available switches.*/ + gxArray availableSwitches;//gxMacAvailableSwitch[] + + /*List of PHY communication parameters.*/ + gxArray communications; //gxMacPhyCommunication[] + + }gxPrimeNbOfdmPlcMacNetworkAdministrationData; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSPrimeNbOfdmPlcApplicationsIdentification + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + + /*Textual description of the firmware version running on the device.*/ + gxByteBuffer firmwareVersion; + + /*Unique vendor identifier assigned by PRIME Alliance.*/ + uint16_t vendorId; + + /*Vendor assigned unique identifier for specific product.*/ + uint16_t productId; + }gxPrimeNbOfdmPlcApplicationsIdentification; + +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION + +#ifndef DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSG3PlcMacLayerCounters + */ + typedef struct + { + /*Base class where class is derived.*/ + gxObject base; + /*Successfully transmitted data packets.*/ + uint32_t txDataPacketCount; + /*Successfully received data packets.*/ + uint32_t rxDataPacketCount; + /*Successfully transmitted command packets.*/ + uint32_t txCmdPacketCount; + /*Successfully received command packets.*/ + uint32_t rxCmdPacketCount; + /*Counts the number of times when CSMA backoffs reach macMaxCSMABackoffs.*/ + uint32_t cSMAFailCount; + /*Counts the number of times when an ACK is not received while transmitting a unicast data frame.*/ + uint32_t cSMANoAckCount; + /*Number of frames received with bad CRC.*/ + uint32_t badCrcCount; + /*The number of broadcast frames sent.*/ + uint32_t txDataBroadcastCount; + /*Successfully received broadcast packets.*/ + uint32_t rxDataBroadcastCount; + }gxG3PlcMacLayerCounters; +#endif //DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS + +#ifndef DLMS_IGNORE_G3_PLC_MAC_SETUP + + typedef struct + { + //Transmitter gain size. + unsigned char size; + //Gain + unsigned char value[MAX_G3_MAC_NEIGHBOUR_TABLE_GAIN_ITEM_SIZE]; + }gxNeighbourTableTransmitterGain; + + typedef struct + { + //Transmitter tone map. + unsigned char size; + //Tone map + unsigned char value[MAX_G3_MAC_NEIGHBOUR_TABLE_TONE_MAP_ITEM_SIZE]; + }gxNeighbourTableToneMap; + + typedef struct + { + /* + MAC Short Address of the node. + */ + uint16_t shortAddress; + /* + Is Payload Modulation scheme used. + */ + unsigned char payloadModulationScheme; + + /*Frequency sub-band can be used for communication with the device.*/ +#ifdef DLMS_IGNORE_MALLOC + gxNeighbourTableToneMap toneMap[MAX_G3_MAC_NEIGHBOUR_TABLE_TONE_MAP_SIZE]; +#else + bitArray toneMap; +#endif //DLMS_IGNORE_MALLOC + /*Modulation type.*/ + DLMS_G3_PLC_MODULATION modulation; + /*Tx Gain.*/ + signed char txGain; + /*Tx Gain resolution.*/ + DLMS_G3_PLC_GAIN_RESOLUTION txRes; + /*Transmitter gain for each group of tones represented by one valid bit of the tone map.*/ +#ifdef DLMS_IGNORE_MALLOC + gxNeighbourTableTransmitterGain txCoeff[MAX_G3_MAC_NEIGHBOUR_TABLE_GAIN_SIZE]; +#else + bitArray txCoeff; +#endif //DLMS_IGNORE_MALLOC + + /*Link Quality Indicator.*/ + unsigned char lqi; + /*Phase difference in multiples of 60 degrees between the mains phase of the local node + and the neighbour node. */ + signed char phaseDifferential; + /*Remaining time in minutes until which the tone map response parameters in the neighbour table are considered valid.*/ + unsigned char tmrValidTime; + /*Optinal data.*/ + unsigned char noData; + }gxNeighbourTable; + + typedef struct + { + // The 16-bit address the device is using to communicate through the PAN. + uint16_t shortAddress; + // Link Quality Indicator. + unsigned char lqi; + // Valid time. + unsigned char validTime; + }gxMacPosTable; + + typedef struct + { + //Key ID. + unsigned char id; + //Key + unsigned char key[MAX_G3_MAC_KEY_TABLE_KEY_SIZE]; + }gxG3MacKeyTable; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSG3PlcMacSetup + */ + typedef struct + { + /*Base class where class is derived.*/ + gxObject base; + uint16_t shortAddress; + uint16_t rcCoord; + uint16_t panId; + gxArray keyTable; + uint32_t frameCounter; + bitArray toneMask; + uint8_t tmrTtl; + uint8_t maxFrameRetries; + uint8_t neighbourTableEntryTtl; + gxArray neighbourTable; + uint8_t highPriorityWindowSize; + uint8_t cscmFairnessLimit; + uint8_t beaconRandomizationWindowLength; + uint8_t macA; + uint8_t macK; + uint8_t minCwAttempts; + uint8_t cenelecLegacyMode; + uint8_t fccLegacyMode; + uint8_t maxBe; + uint8_t maxCsmaBackoffs; + uint8_t minBe; + /*If true, MAC uses maximum contention window.*/ + unsigned char macBroadcastMaxCwEnabled; + /*Attenuation of the output level in dB.*/ + unsigned char macTransmitAtten; + /*The neighbour table contains some information + about all the devices within the POS of the device. + */ + gxArray macPosTable; + /*Duplicate frame detection time in seconds.*/ + unsigned char macDuplicateDetectionTTL; + }gxG3PlcMacSetup; +#endif //DLMS_IGNORE_G3_PLC_MAC_SETUP + +#ifndef DLMS_IGNORE_G3_PLC_6LO_WPAN + + // The routing configuration element specifies all parameters linked to the routing mechanism described in ITU-T G.9903:2014. + typedef struct + { + // Maximum time that a packet is expected to take to reach any node from any node in seconds. + // + // PIB attribute: 0x11. + unsigned char netTraversalTime; + + // Maximum time-to-live of a routing table entry (in minutes). + // + // PIB attribute: 0x12. + uint16_t routingTableEntryTtl; + + // A weight factor for the Robust Mode to calculate link cost. + // + // PIB attribute: 0x13. + unsigned char kr; + + // A weight factor for modulation to calculate link cost. + // + // PIB attribute: 0x14. + unsigned char km; + + // A weight factor for number of active tones to calculate link cost. + // + // PIB attribute: 0x15. + unsigned char kc; + + // A weight factor for LQI to calculate route cost. + // + // PIB attribute: 0x16. + unsigned char kq; + + // A weight factor for hop to calculate link cost. + // + // PIB attribute: 0x17. + unsigned char kh; + + // A weight factor for the number of active routes in the routing table to calculate link cost. + // + // PIB attribute: 0x1B. + unsigned char krt; + + // The number of RREQ retransmission in case of RREP reception time out. + // + // PIB attribute: 0x18. + unsigned char rReqRetries; + + // The number of seconds to wait between two consecutive RREQ – RERR generations. + // + // PIB attribute: 0x19. + unsigned char rReqReqWait; + + // Maximum time-to-live of a blacklisted neighbour entry (in minutes). + // + // PIB attribute: 0x1F. + uint16_t blacklistTableEntryTtl; + + // If TRUE, the RREQ shall be generated with its 'unicast RREQ'. + // + // PIB attribute: 0x0D. + unsigned char unicastRreqGenEnable; + + // Enable the sending of RLCREQ frame by the device. + // + // PIB attribute: 0x09. + unsigned char rlcEnabled; + + // It represents an additional cost to take into account a possible asymmetry in the link. + // + // PIB attribute: 0x0A. + unsigned char addRevLinkCost; + }gxRoutingConfiguration; + + typedef struct + { + // Address of the destination. + uint16_t destinationAddress; + + // Address of the next hop on the route towards the destination. + uint16_t nextHopAddress; + + // Cumulative link cost along the route towards the destination. + uint16_t routeCost; + + // Number of hops of the selected route to the destination. + unsigned char hopCount; + + // Number of weak links to destination. + unsigned char weakLinkCount; + + // Remaining time in minutes until when this entry in the routing table is considered valid. + uint16_t validTime; + } gxRoutingTable; + + typedef struct + { + + // Corresponds to the 4-bit context information used for source and destination addresses (SCI, DCI). + unsigned char cid; + + //The length of the carried context + unsigned char contextLength; + + // Context. + unsigned char context[16]; + + // Indicates if the context is valid for use in compression. + unsigned char compression; + + // Remaining time in minutes during which the context information table is considered valid. It is updated upon reception of the advertised context. + uint16_t validLifetime; + }gxContextInformationTable; + + /*Contains the list of the blacklisted neighbours.*/ + typedef struct + { + /*Blacklisted neighbour address.*/ + uint16_t neighbourAddress; + /*Remaining time in minutes until which this entry in + the blacklisted neighbour table is considered valid.*/ + uint16_t validTime; + }gxBlacklistTable; + + typedef struct + { + // Source address of a broadcast packet. + uint16_t sourceAddress; + + // The sequence number contained in the BC0 header + unsigned char sequenceNumber; + + // Remaining time in minutes until when this entry in the broadcast log table is considered valid. + uint16_t validTime; + }gxBroadcastLogTable; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSG3Plc6LoWPAN + */ + typedef struct + { + /*Base class where class is derived.*/ + gxObject base; + // Defines the maximum number of hops to be used by the routing algorithm. + + // + // PIB attribute 0x0F. + unsigned char maxHops; + + // The weak link value defines the LQI value below which a link to a neighbour is considered as a weak link. + // + // PIB attribute 0x1A. + unsigned char weakLqiValue; + + // The minimum security level to be used for incoming and outgoing adaptation frames. + // + // PIB attribute 0x00. + unsigned char securityLevel; + + // Contains the list of prefixes defined on this PAN + // + // PIB attribute 0x01. + gxByteBuffer prefixTable; + + // The routing configuration element specifies all parameters linked to the routing mechanism described in ITU-T G.9903:2014. + gxArray routingConfiguration; + + // Maximum time to live of an adpBroadcastLogTable entry (in minutes). + // + // PIB attribute 0x02. + uint16_t broadcastLogTableEntryTtl; + + // Routing table + // PIB attribute 0x03. + gxArray routingTable; + + // Contains the context information associated to each CID extension field. + // + // PIB attribute 0x07. + gxArray contextInformationTable; + + // Contains the list of the blacklisted neighbours.Key is 16-bit address of the blacklisted neighbour. + // Value is Remaining time in minutes until which this entry in the blacklisted neighbour table is considered valid. + // + // PIB attribute 0x1E. + gxArray blacklistTable; + + // Broadcast log table + // + // PIB attribute 0x0B. + gxArray broadcastLogTable; + + // Contains the group addresses to which the device belongs. + // + // PIB attribute 0x0E. +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + gxArray groupTable; +#else + variantArray groupTable; +#endif //DLMS_IGNORE_MALLOC + + // Network join timeout in seconds for LBD + // + // PIB attribute 0x20. + uint16_t maxJoinWaitTime; + + // Timeout for path discovery in seconds. + // + // PIB attribute 0x21. + unsigned char pathDiscoveryTime; + + // Index of the active GMK to be used for data transmission. + // + // PIB attribute 0x22. + unsigned char activeKeyIndex; + + // Metric Type to be used for routing purposes. + // + // PIB attribute 0x3. + unsigned char metricType; + + // Defines the short address of the coordinator. + // + // PIB attribute 0x8. + uint16_t coordShortAddress; + + // Is default routing (LOADng) disabled. + // + // PIB attribute 0xF0. + unsigned char disableDefaultRouting; + + // Defines the type of the device connected to the modem. + // + // PIB attribute 0x10. + DLMS_PAN_DEVICE_TYPE deviceType; + + // If true, the default route will be created. + // + // PIB attribute 0x24 + unsigned char defaultCoordRouteEnabled; + + // List of the addresses of the devices for which this LOADng + // router is providing connectivity. + // + // PIB attribute 0x23. +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + gxArray destinationAddress; +#else + variantArray destinationAddress; +#endif //DLMS_IGNORE_MALLOC + // PIB attribute 0x04. + unsigned char lowLQI; + // PIB attribute 0x04. + unsigned char highLQI; + }gxG3Plc6LoWPAN; + +#endif //DLMS_IGNORE_G3_PLC_6LO_WPAN + +#ifndef DLMS_IGNORE_FUNCTION_CONTROL + + typedef struct + { +#ifdef DLMS_IGNORE_MALLOC + // Function name. + unsigned char name[MAX_FUNCTION_NAME_LENGTH]; + // Function name size. + uint16_t size; +#else + //function name. + gxByteBuffer name; +#endif //DLMS_IGNORE_MALLOC + /*Function status.*/ + uint8_t status; + }functionStatus; + + typedef struct + { +#ifdef DLMS_IGNORE_MALLOC + // Function name. + unsigned char name[MAX_FUNCTION_NAME_LENGTH]; + // Function name size. + uint16_t nameSize; +#else + //function name. + gxByteBuffer name; +#endif //DLMS_IGNORE_MALLOC + /*Target objects.*/ + +#if !defined(DLMS_IGNORE_OBJECT_POINTERS) && !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + objectArray functionSpecifications; +#else + gxObject* functionSpecifications[MAX_FUNCTION_TARGET_LENGTH]; + // Function specifications size. + uint16_t functionSpecificationsSize; +#endif //DLMS_IGNORE_OBJECT_POINTERS + }functionalBlock; + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSG3Plc6LoWPAN + */ + typedef struct + { + gxObject base; + /*The current status of each functional block.*/ + gxArray activationStatus; + /*Function list.*/ + gxArray functions; + }gxFunctionControl; + + //Clear activation status of the function control. + int obj_clearActivationStatus(gxArray* list); + + //Clear function list of the function control. + int obj_clearFunctionList(gxArray* list); + +#endif //DLMS_IGNORE_FUNCTION_CONTROL + +#ifndef DLMS_IGNORE_ARRAY_MANAGER + typedef struct + { + // Target object. + gxObject* target; + // Attribute Index of DLMS object. + signed char attributeIndex; + }gxTargetObject; + + typedef struct + { + /// Array object ID. + unsigned char id; + /// + /// Array objects. + /// + gxTargetObject element; + }gxArrayManagerItem; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSArrayManager + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + gxArray elements; + }gxArrayManager; + +#endif //DLMS_IGNORE_ARRAY_MANAGER + +#ifndef DLMS_IGNORE_COMPACT_DATA + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSCompactData + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + + gxByteBuffer buffer; + gxArray captureObjects; //gxkey + unsigned char templateId; + gxByteBuffer templateDescription; + DLMS_CAPTURE_METHOD captureMethod; +#ifdef DLMS_ITALIAN_STANDARD + //Some meters require that there is a array count in data. + unsigned char appendAA; +#endif //DLMS_ITALIAN_STANDARD + } gxCompactData; +#endif //DLMS_IGNORE_COMPACT_DATA + + //--------------------------------------------------------------------------- + // Online help: + // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSArbitrator +#ifndef DLMS_IGNORE_ARBITRATOR + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + + /** + * Requested actions. + */ + gxArray actions; //List; + + /** + * Permissions for each actor to request actions. + */ + gxArray permissionsTable; //List + /** + * Weight allocated for each actor and to each possible action of that + * actor. + */ + gxArray weightingsTable; //List> + /** + * The most recent requests of each actor. + */ + gxArray mostRecentRequestsTable; //List + /** + * The number identifies a bit in the Actions. + */ + unsigned char lastOutcome; + } gxArbitrator; +#endif //DLMS_IGNORE_ARBITRATOR + +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP + //--------------------------------------------------------------------------- + // Online help: + // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSIec8802LlcType1Setup + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + /** + * Maximum number of octets in a UI PDU. + */ + uint16_t maximumOctetsUiPdu; + } gxIec8802LlcType1Setup; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP + //--------------------------------------------------------------------------- + // Online help: + // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSIec8802LlcType2Setup + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + /** + * Transmit Window Size K. + */ + unsigned char transmitWindowSizeK; + /** + * Transmit Window Size RW. + */ + unsigned char transmitWindowSizeRW; + /** + * Maximum octets in I Pdu N1. + */ + uint16_t maximumOctetsPdu; + /** + * Maximum number of transmissions, N2. + */ + unsigned char maximumNumberTransmissions; + /** + * Acknowledgement timer in seconds. + */ + uint16_t acknowledgementTimer; + /** + * P-bit timer in seconds. + */ + uint16_t bitTimer; + /** + * Reject timer. + */ + uint16_t rejectTimer; + /** + * Busy state timer. + */ + uint16_t busyStateTimer; + } gxIec8802LlcType2Setup; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP + +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP + //--------------------------------------------------------------------------- + // Online help: + // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSIec8802LlcType3Setup + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + /** + * Maximum number of octets in an ACn command PDU, N3. + */ + uint16_t maximumOctetsACnPdu; + /** + * Maximum number of times in transmissions N4. + */ + unsigned char maximumTransmissions; + /** + * Acknowledgement time, T1. + */ + uint16_t acknowledgementTime; + /** + * Receive lifetime variable, T2. + */ + uint16_t receiveLifetime; + /** + * Transmit lifetime variable, T3. + */ + uint16_t transmitLifetime; + } gxIec8802LlcType3Setup; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP + +#ifndef DLMS_IGNORE_SFSK_ACTIVE_INITIATOR + //--------------------------------------------------------------------------- + // Online help: + // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSSFSKActiveInitiator + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + /** + * System title of active initiator. + */ + gxByteBuffer systemTitle; + /** + * MAC address of active initiator. + */ + uint16_t macAddress; + /** + * L SAP selector of active initiator. + */ + unsigned char lSapSelector; + } gxSFSKActiveInitiator; +#endif //DLMS_IGNORE_SFSK_ACTIVE_INITIATOR + +#ifndef DLMS_IGNORE_SFSK_MAC_COUNTERS + typedef struct + { + uint16_t first; + uint32_t second; + }gxUint16PairUint32; + + //--------------------------------------------------------------------------- + // Online help: + // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSSFSKMacCounters + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + /** + * List of synchronization registers. + */ + gxArray synchronizationRegister; //List + + uint32_t physicalLayerDesynchronization; + uint32_t timeOutNotAddressedDesynchronization; + + uint32_t timeOutFrameNotOkDesynchronization; + + uint32_t writeRequestDesynchronization; + uint32_t wrongInitiatorDesynchronization; + /** + * List of broadcast frames counter. + */ + gxArray broadcastFramesCounter; //list + /** + * Repetitions counter. + */ + uint32_t repetitionsCounter; + /** + * Transmissions counter. + */ + uint32_t transmissionsCounter; + /** + * CRC OK frames counter. + */ + uint32_t crcOkFramesCounter; + /** + * CRC NOK frames counter. + */ + uint32_t crcNOkFramesCounter; + } gxFSKMacCounters; +#endif //DLMS_IGNORE_SFSK_MAC_COUNTERS + +#ifndef DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS + //--------------------------------------------------------------------------- + // Online help: + // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSSFSKMacSynchronizationTimeouts + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + /** + * Search initiator timeout. + */ + uint16_t searchInitiatorTimeout; + /** + * Synchronization confirmation timeout. + */ + uint16_t synchronizationConfirmationTimeout; + /** + * Time out not addressed. + */ + uint16_t timeOutNotAddressed; + /** + * Time out frame not OK. + */ + uint16_t timeOutFrameNotOK; + } gxSFSKMacSynchronizationTimeouts; +#endif //DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS + +#ifndef DLMS_IGNORE_SFSK_PHY_MAC_SETUP + //--------------------------------------------------------------------------- + // Online help: + // http://www.gurux.fi/Gurux.DLMS.Objects.CGXDLMSSFSKPhyMacSetUp + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + /** + * Initiator electrical phase. + */ + DLMS_INITIATOR_ELECTRICAL_PHASE initiatorElectricalPhase; + + /** + * Delta electrical phase. + */ + DLMS_DELTA_ELECTRICAL_PHASE deltaElectricalPhase; + + /** + * Corresponds to the maximum allowed gain bound to be used by the server + * system in the receiving mode. The default unit is dB. + */ + unsigned char maxReceivingGain; + /** + * Corresponds to the maximum attenuation bound to be used by the server + * system in the transmitting mode.The default unit is dB. + */ + unsigned char maxTransmittingGain; + /** + * Intelligent search initiator process. If the value of the initiator + * signal is above the value of this attribute, a fast synchronization + * process is possible. + */ + unsigned char searchInitiatorThreshold; + /** + * Mark frequency required for S-FSK modulation. + */ + uint32_t markFrequency; + /** + * Space frequency required for S-FSK modulation. + */ + uint32_t spaceFrequency; + /** + * Mac Address. + */ + uint16_t macAddress; + + /** + * MAC group addresses. + */ + gxArray macGroupAddresses; //List + /** + * Specifies are all frames repeated. + */ + DLMS_REPEATER repeater; + /** + * Repeater status. + */ + unsigned char repeaterStatus; + /** + * Min delta credit. + */ + unsigned char minDeltaCredit; + + /** + * Initiator MAC address. + */ + uint16_t initiatorMacAddress; + + /** + * Synchronization locked/unlocked state. + */ + unsigned char synchronizationLocked; + /** + * Transmission speed supported by the physical device. + */ + DLMS_BAUD_RATE transmissionSpeed; + } gxSFSKPhyMacSetUp; +#endif //DLMS_IGNORE_SFSK_PHY_MAC_SETUP + +#ifndef DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST + +#ifdef DLMS_IGNORE_MALLOC + typedef struct + { + //Reporting system list + unsigned char name[MAX_REPORTING_SYSTEM_ITEM_LENGTH]; + uint16_t size; + }gxReportingSystemItem; +#endif //DLMS_IGNORE_MALLOC + + + //--------------------------------------------------------------------------- + // Online help: + // http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSSFSKReportingSystemList + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + /** + * Contains the system titles of the server systems which have made a + * DiscoverReport request and which have not already been registered. + */ + gxArray reportingSystemList; + } gxSFSKReportingSystemList; +#endif //DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST + +#ifdef DLMS_ITALIAN_STANDARD + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSTariffPlan + */ + typedef enum + { + // 1st january of every year. + DLMS_WEEKLY_ACTIVATION_JANUARY_1, + // 6st january of every year. + DLMS_WEEKLY_ACTIVATION_JANUARY_6, + // Easter Monday of of every year. + DLMS_WEEKLY_ACTIVATION_EASTER_MONDAY, + // 25th April of every year + DLMS_WEEKLY_ACTIVATION_APRIL_25, + // 1st May of every year. + DLMS_WEEKLY_ACTIVATION_MAY_1, + // 2nd June of every year. + DLMS_WEEKLY_ACTIVATION_JUNE_2, + // 15th August of every year + DLMS_WEEKLY_ACTIVATION_AUGUST_15, + // 1st November of every year. + DLMS_WEEKLY_ACTIVATION_NOVEMBER_1, + // 8th December of every year + DLMS_WEEKLY_ACTIVATION_DECEMBER_8, + // 25th December of every year. + DLMS_WEEKLY_ACTIVATION_DECEMBER_25, + // 26th December of every year. + DLMS_WEEKLY_ACTIVATION_DECEMBER_26 + }DLMS_WEEKLY_ACTIVATION; + + + /* + The default tariff. + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSTariffPlan + */ + typedef enum + { + // Not active. + DLMS_DEFAULT_TARIFF_BAND_NONE = 0, + // Tariff band 1. + DLMS_DEFAULT_TARIFF_BAND_TARIFF_BAND_1, + // Tariff band 2. + DLMS_DEFAULT_TARIFF_BAND_TARIFF_BAND_2, + // Tariff band 3. + DLMS_DEFAULT_TARIFF_BAND_TARIFF_BAND_3 + }DLMS_DEFAULT_TARIFF_BAND; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSTariffPlan + */ + typedef struct + { + // Start hour of the interval. + unsigned char startHour; + // Tariff used in the current interval + DLMS_DEFAULT_TARIFF_BAND intervalTariff; + // Is interval used. + unsigned char useInterval; + } gxInterval; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSTariffPlan + */ + typedef struct + { + // Day of month when the season will become active. + unsigned char dayOfMonth; + // Month of the year when the season will become active. + unsigned char month; + // Working day intervals. + gxInterval workingDayIntervals[5]; + // Saturday intervals. + gxInterval saturdayIntervals[5]; + // Saturday intervals. + gxInterval holidayIntervals[5]; + } gxBandDescriptor; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSTariffPlan + */ + typedef struct + { + // Is tariff plan enabled. + unsigned char defaultTariffBand; + // Winter season. + gxBandDescriptor winterSeason; + // Summer season. + gxBandDescriptor summerSeason; + // Seasons. + bitArray weeklyActivation; + // Seasons. + gxArray specialDays; //UInt16[] + } gxPlan; + + /* + --------------------------------------------------------------------------- + Online help: + http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSTariffPlan + */ + typedef struct + { + /* + * Base class where class is derived. + */ + gxObject base; + + // Calendar Name. + char* calendarName; + //Is tariff plan enabled. + unsigned char enabled; + // Tariff plan. + gxPlan plan; + // Activation date and time. + gxtime activationTime; + } gxTariffPlan; + +#endif //DLMS_ITALIAN_STANDARD + + void obj_clear(gxObject* object); + + int obj_clearProfileGenericBuffer(gxArray* buffer); + + int obj_clearSapList(gxArray* buffer); + +#if !(defined(DLMS_IGNORE_PROFILE_GENERIC) && defined(DLMS_IGNORE_COMPACT_DATA) && defined(DLMS_IGNORE_PUSH_SETUP)) + int obj_clearPushObjectList(gxArray* buffer); + ///////////////////////////////////////////////////////////////////////// + // Clear capture object list. + // + // captureObjects: List of objects to clear. + int obj_clearProfileGenericCaptureObjects(gxArray* captureObjects); +#endif //!(defined(DLMS_IGNORE_PROFILE_GENERIC) && defined(DLMS_IGNORE_COMPACT_DATA)) + + int obj_clearSeasonProfile(gxArray* list); + + int obj_clearWeekProfileTable(gxArray* list); + + int obj_clearDayProfileTable(gxArray* list); + + int obj_clearRegisterMonitorActions(gxArray* list); + + int obj_clearModemConfigurationInitialisationStrings(gxArray* list); + + int obj_clearScheduleEntries(gxArray* list); + int obj_clearScriptTable(gxArray* list); + +#if !(defined(DLMS_IGNORE_OBJECT_POINTERS) || defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES)) + int obj_clearRegisterActivationAssignment(objectArray* list); +#else + int obj_clearRegisterActivationAssignment(gxArray* list); +#endif //!(defined(DLMS_IGNORE_OBJECT_POINTERS) || defined(DLMS_IGNORE_MALLOC)) + + int obj_clearRegisterActivationMaskList(gxArray* list); + + int obj_clearIP4SetupOptions(gxArray* list); + + int obj_clearPPPSetupIPCPOptions(gxArray* list); + int obj_clearPPPSetupLCPOptions(gxArray* list); + + int obj_clearActiveDevices(gxArray* list); + + //Clear bit array list. + int obj_clearBitArrayList(gxArray* list); + + //Clear variant array list. + int obj_clearVariantList(gxArray* list); + + int obj_clearChargeTables(gxArray* list); + + int obj_clearCreditChargeConfigurations(gxArray* list); + + int obj_clearTokenGatewayConfigurations(gxArray* list); + + //Get amount of attributes in COSEM object. + unsigned char obj_attributeCount( + gxObject* object); + + //Get amount of methods in COSEM object. + unsigned char obj_methodCount( + gxObject* object); + + int obj_getAttributeIndexToRead( + gxObject* object, + gxByteBuffer* ba); + + //Returns collection of attributes to read. + int obj_getAttributeIndexToRead( + gxObject* object, + gxByteBuffer* ba); + +#ifndef DLMS_IGNORE_DATA_PROTECTION + void clear_ProtectionParameter(gxProtectionParameter* target); + void init_ProtectionParameter(gxProtectionParameter* target); +#endif //DLMS_IGNORE_DATA_PROTECTION + +#ifndef DLMS_IGNORE_PARAMETER_MONITOR + int obj_clearParametersList(gxArray* buffer); +#endif //DLMS_IGNORE_PARAMETER_MONITOR + + int obj_clearCertificateInfo(gxArray* arr); + + //Clear user list. + int obj_clearUserList( + gxArray* list); + + //Clear neighbour table. + int obj_clearNeighbourTable( + gxArray* list); + + //Clear available switches. + int obj_clearAvailableSwitches( + gxArray* list); + + //Clear byte buffer list. + int obj_clearByteBufferList( + gxArray* list); + +#if _CVI_ //If LabWindows/CVI +#define BASE(X) &X.base +#define INIT_OBJECT(X, Y, Z) cosem_init4(&X, sizeof(X), Y, Z) +#else +#define BASE(X) &X.base +#define INIT_OBJECT(X, Y, Z) cosem_init4(&X.base, sizeof(X), Y, Z) +#endif //_CVI_ + + +#define SET_OCTET_STRING(X, V, S) memcpy(X.value, V, S);X.size=S + +#ifdef __cplusplus +} +#endif + +#endif //GXOBJECTS_H diff --git a/components/xt211/gxset.c b/components/xt211/gxset.c new file mode 100644 index 0000000..cab80c6 --- /dev/null +++ b/components/xt211/gxset.c @@ -0,0 +1,472 @@ +// +// -------------------------------------------------------------------------- +// 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 +#endif + +#include "gxmem.h" +#if _MSC_VER > 1400 +#include +#endif +#include "gxset.h" +#include "cosem.h" + +int cosem_setValue(dlmsSettings* settings, gxValueEventArg* e) +{ + int ret = DLMS_ERROR_CODE_OK; + if (e->index == 1) + { +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + ret = cosem_getOctetString2(e->value.byteArr, e->target->logicalName, 6, NULL); +#else + if (e->value.byteArr == NULL || e->value.byteArr->size - e->value.byteArr->position != 6) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + else + { + ret = bb_get(e->value.byteArr, e->target->logicalName, 6); + } +#endif //DLMS_IGNORE_MALLOC + return ret; + } + switch (e->target->objectType) + { +#ifndef DLMS_IGNORE_DATA + case DLMS_OBJECT_TYPE_DATA: + ret = cosem_setData(e); + break; +#endif //DLMS_IGNORE_DATA +#ifndef DLMS_IGNORE_REGISTER + case DLMS_OBJECT_TYPE_REGISTER: + ret = cosem_setRegister((gxRegister*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_REGISTER +#ifndef DLMS_IGNORE_CLOCK + case DLMS_OBJECT_TYPE_CLOCK: + ret = cosem_setClock(settings, (gxClock*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_CLOCK +#ifndef DLMS_IGNORE_ACTION_SCHEDULE + case DLMS_OBJECT_TYPE_ACTION_SCHEDULE: + ret = cosem_setActionSchedule(settings, (gxActionSchedule*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_ACTION_SCHEDULE +#ifndef DLMS_IGNORE_ACTIVITY_CALENDAR + case DLMS_OBJECT_TYPE_ACTIVITY_CALENDAR: + ret = cosem_setActivityCalendar(settings, (gxActivityCalendar*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_ACTIVITY_CALENDAR +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + case DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME: + ret = cosem_setAssociationLogicalName(settings, (gxAssociationLogicalName*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + case DLMS_OBJECT_TYPE_ASSOCIATION_SHORT_NAME: + ret = cosem_setAssociationShortName(settings, (gxAssociationShortName*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME +#ifndef DLMS_IGNORE_AUTO_ANSWER + case DLMS_OBJECT_TYPE_AUTO_ANSWER: + ret = cosem_setAutoAnswer((gxAutoAnswer*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_AUTO_ANSWER +#ifndef DLMS_IGNORE_AUTO_CONNECT + case DLMS_OBJECT_TYPE_AUTO_CONNECT: + ret = cosem_setAutoConnect((gxAutoConnect*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_AUTO_CONNECT +#ifndef DLMS_IGNORE_DEMAND_REGISTER + case DLMS_OBJECT_TYPE_DEMAND_REGISTER: + ret = cosem_setDemandRegister((gxDemandRegister*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_DEMAND_REGISTER +#ifndef DLMS_IGNORE_MAC_ADDRESS_SETUP + case DLMS_OBJECT_TYPE_MAC_ADDRESS_SETUP: + ret = cosem_setMacAddressSetup((gxMacAddressSetup*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_MAC_ADDRESS_SETUP +#ifndef DLMS_IGNORE_EXTENDED_REGISTER + case DLMS_OBJECT_TYPE_EXTENDED_REGISTER: + ret = cosem_setExtendedRegister((gxExtendedRegister*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_EXTENDED_REGISTER +#ifndef DLMS_IGNORE_GPRS_SETUP + case DLMS_OBJECT_TYPE_GPRS_SETUP: + ret = cosem_setGprsSetup((gxGPRSSetup*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_GPRS_SETUP +#ifndef DLMS_IGNORE_SECURITY_SETUP + case DLMS_OBJECT_TYPE_SECURITY_SETUP: + ret = cosem_setSecuritySetup(settings, (gxSecuritySetup*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_SECURITY_SETUP +#ifndef DLMS_IGNORE_IEC_HDLC_SETUP + case DLMS_OBJECT_TYPE_IEC_HDLC_SETUP: + ret = cosem_setIecHdlcSetup((gxIecHdlcSetup*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_IEC_HDLC_SETUP +#ifndef DLMS_IGNORE_IEC_LOCAL_PORT_SETUP + case DLMS_OBJECT_TYPE_IEC_LOCAL_PORT_SETUP: + ret = cosem_setIecLocalPortSetup((gxLocalPortSetup*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_IEC_LOCAL_PORT_SETUP +#ifndef DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP + case DLMS_OBJECT_TYPE_IEC_TWISTED_PAIR_SETUP: + ret = cosem_setIecTwistedPairSetup((gxIecTwistedPairSetup*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP +#ifndef DLMS_IGNORE_IP4_SETUP + case DLMS_OBJECT_TYPE_IP4_SETUP: + ret = cosem_setIP4Setup(settings, (gxIp4Setup*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_IP4_SETUP +#ifndef DLMS_IGNORE_IP6_SETUP + case DLMS_OBJECT_TYPE_IP6_SETUP: + ret = cosem_setIP6Setup(settings, (gxIp6Setup*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_IP6_SETUP +#ifndef DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP + case DLMS_OBJECT_TYPE_MBUS_SLAVE_PORT_SETUP: + ret = cosem_setMbusSlavePortSetup((gxMbusSlavePortSetup*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP +#ifndef DLMS_IGNORE_IMAGE_TRANSFER + case DLMS_OBJECT_TYPE_IMAGE_TRANSFER: + ret = cosem_setImageTransfer((gxImageTransfer*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_IMAGE_TRANSFER +#ifndef DLMS_IGNORE_DISCONNECT_CONTROL + case DLMS_OBJECT_TYPE_DISCONNECT_CONTROL: + ret = cosem_setDisconnectControl((gxDisconnectControl*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_DISCONNECT_CONTROL +#ifndef DLMS_IGNORE_LIMITER + case DLMS_OBJECT_TYPE_LIMITER: + ret = cosem_setLimiter(settings, (gxLimiter*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_LIMITER +#ifndef DLMS_IGNORE_MBUS_CLIENT + case DLMS_OBJECT_TYPE_MBUS_CLIENT: + ret = cosem_setmMbusClient(settings, (gxMBusClient*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_MBUS_CLIENT +#ifndef DLMS_IGNORE_MODEM_CONFIGURATION + case DLMS_OBJECT_TYPE_MODEM_CONFIGURATION: + ret = cosem_setModemConfiguration((gxModemConfiguration*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_MODEM_CONFIGURATION +#ifndef DLMS_IGNORE_PPP_SETUP + case DLMS_OBJECT_TYPE_PPP_SETUP: + ret = cosem_setPppSetup(settings, (gxPppSetup*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_PPP_SETUP +#ifndef DLMS_IGNORE_PROFILE_GENERIC + case DLMS_OBJECT_TYPE_PROFILE_GENERIC: + ret = cosem_setProfileGeneric(settings, (gxProfileGeneric*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_PROFILE_GENERIC +#ifndef DLMS_IGNORE_REGISTER_ACTIVATION + case DLMS_OBJECT_TYPE_REGISTER_ACTIVATION: + ret = cosem_setRegisterActivation(settings, e); + break; +#endif //DLMS_IGNORE_REGISTER_ACTIVATION +#ifndef DLMS_IGNORE_REGISTER_MONITOR + case DLMS_OBJECT_TYPE_REGISTER_MONITOR: + ret = cosem_setRegisterMonitor(settings, (gxRegisterMonitor*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_REGISTER_MONITOR +#ifndef DLMS_IGNORE_REGISTER_TABLE + case DLMS_OBJECT_TYPE_REGISTER_TABLE: + ret = cosem_setRegistertable((gxRegisterTable*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_REGISTER_TABLE +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_STARTUP + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_STARTUP: + //TODO: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_ZIG_BEE_SAS_STARTUP +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_JOIN + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_JOIN: + //TODO: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_ZIG_BEE_SAS_JOIN +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_APS_FRAGMENTATION + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_APS_FRAGMENTATION: + //TODO: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_ZIG_BEE_SAS_APS_FRAGMENTATION +#ifndef DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL + case DLMS_OBJECT_TYPE_ZIG_BEE_NETWORK_CONTROL: + //TODO: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL +#ifndef DLMS_IGNORE_SAP_ASSIGNMENT + case DLMS_OBJECT_TYPE_SAP_ASSIGNMENT: + ret = cosem_setSapAssignment((gxSapAssignment*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_SAP_ASSIGNMENT +#ifndef DLMS_IGNORE_SCHEDULE + case DLMS_OBJECT_TYPE_SCHEDULE: + ret = cosem_setSchedule(settings, (gxSchedule*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_SCHEDULE +#ifndef DLMS_IGNORE_SCRIPT_TABLE + case DLMS_OBJECT_TYPE_SCRIPT_TABLE: + ret = cosem_setScriptTable(settings, (gxScriptTable*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_SCRIPT_TABLE +#ifndef DLMS_IGNORE_SPECIAL_DAYS_TABLE + case DLMS_OBJECT_TYPE_SPECIAL_DAYS_TABLE: + ret = cosem_setSpecialDaysTable((gxSpecialDaysTable*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_SPECIAL_DAYS_TABLE +#ifndef DLMS_IGNORE_STATUS_MAPPING + case DLMS_OBJECT_TYPE_STATUS_MAPPING: + //TODO: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_STATUS_MAPPING +#ifndef DLMS_IGNORE_TCP_UDP_SETUP + case DLMS_OBJECT_TYPE_TCP_UDP_SETUP: + ret = cosem_setTcpUdpSetup(settings, (gxTcpUdpSetup*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_TCP_UDP_SETUP +#ifndef DLMS_IGNORE_MBUS_DIAGNOSTIC + case DLMS_OBJECT_TYPE_MBUS_DIAGNOSTIC: + ret = cosem_setMbusDiagnostic((gxMbusDiagnostic*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_MBUS_DIAGNOSTIC +#ifndef DLMS_IGNORE_MBUS_PORT_SETUP + case DLMS_OBJECT_TYPE_MBUS_PORT_SETUP: + ret = cosem_setMbusPortSetup((gxMBusPortSetup*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_MBUS_PORT_SETUP +#ifndef DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS + case DLMS_OBJECT_TYPE_G3_PLC_MAC_LAYER_COUNTERS: + ret = cosem_setG3PlcMacLayerCounters((gxG3PlcMacLayerCounters*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS +#ifndef DLMS_IGNORE_G3_PLC_MAC_SETUP + case DLMS_OBJECT_TYPE_G3_PLC_MAC_SETUP: + ret = cosem_setG3PlcMacSetup((gxG3PlcMacSetup*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_G3_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_G3_PLC_6LO_WPAN + case DLMS_OBJECT_TYPE_G3_PLC_6LO_WPAN: + ret = cosem_setG3Plc6LoWPAN((gxG3Plc6LoWPAN*)e->target, + e->index, &e->value); + break; +#endif //DLMS_IGNORE_G3_PLC_6LO_WPAN +#ifndef DLMS_IGNORE_FUNCTION_CONTROL + case DLMS_OBJECT_TYPE_FUNCTION_CONTROL: + ret = cosem_setFunctionControl(settings, + (gxFunctionControl*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_FUNCTION_CONTROL +#ifndef DLMS_IGNORE_ARRAY_MANAGER + case DLMS_OBJECT_TYPE_ARRAY_MANAGER: + ret = cosem_setArrayManager(settings, + (gxArrayManager*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_ARRAY_MANAGER +#ifndef DLMS_IGNORE_UTILITY_TABLES + case DLMS_OBJECT_TYPE_UTILITY_TABLES: + ret = cosem_setUtilityTables((gxUtilityTables*)e->target, + e->index, &e->value); + break; +#endif //DLMS_IGNORE_UTILITY_TABLES +#ifndef DLMS_IGNORE_MBUS_MASTER_PORT_SETUP + case DLMS_OBJECT_TYPE_MBUS_MASTER_PORT_SETUP: + ret = cosem_setMbusMasterPortSetup((gxMBusMasterPortSetup*)e->target, + e->index, &e->value); + break; +#endif //DLMS_IGNORE_MBUS_MASTER_PORT_SETUP +#ifndef DLMS_IGNORE_PUSH_SETUP + case DLMS_OBJECT_TYPE_PUSH_SETUP: + ret = cosem_setPushSetup(settings, (gxPushSetup*)e->target, + e->index, &e->value); + break; +#endif //DLMS_IGNORE_PUSH_SETUP +#ifndef DLMS_IGNORE_DATA_PROTECTION + case DLMS_OBJECT_TYPE_DATA_PROTECTION: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_DATA_PROTECTION +#ifndef DLMS_IGNORE_ACCOUNT + case DLMS_OBJECT_TYPE_ACCOUNT: + ret = cosem_setAccount((gxAccount*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_ACCOUNT +#ifndef DLMS_IGNORE_CREDIT + case DLMS_OBJECT_TYPE_CREDIT: + ret = cosem_setCredit((gxCredit*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_CREDIT +#ifndef DLMS_IGNORE_CHARGE + case DLMS_OBJECT_TYPE_CHARGE: + ret = cosem_setCharge(settings, (gxCharge*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_CHARGE +#ifndef DLMS_IGNORE_TOKEN_GATEWAY + case DLMS_OBJECT_TYPE_TOKEN_GATEWAY: + ret = cosem_setTokenGateway((gxTokenGateway*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_TOKEN_GATEWAY +#ifndef DLMS_IGNORE_GSM_DIAGNOSTIC + case DLMS_OBJECT_TYPE_GSM_DIAGNOSTIC: + ret = cosem_setGsmDiagnostic((gxGsmDiagnostic*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_GSM_DIAGNOSTIC + +#ifndef DLMS_IGNORE_COMPACT_DATA + case DLMS_OBJECT_TYPE_COMPACT_DATA: + ret = cosem_setCompactData(settings, (gxCompactData*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_COMPACT_DATA +#ifndef DLMS_IGNORE_PARAMETER_MONITOR + case DLMS_OBJECT_TYPE_PARAMETER_MONITOR: + ret = cosem_setParameterMonitor(settings, (gxParameterMonitor*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_PARAMETER_MONITOR +#ifndef DLMS_IGNORE_LLC_SSCS_SETUP + case DLMS_OBJECT_TYPE_LLC_SSCS_SETUP: + ret = cosem_setLlcSscsSetup(settings, (gxLlcSscsSetup*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_LLC_SSCS_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS: + ret = cosem_setPrimeNbOfdmPlcPhysicalLayerCounters(settings, (gxPrimeNbOfdmPlcPhysicalLayerCounters*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_SETUP: + ret = cosem_setPrimeNbOfdmPlcMacSetup(settings, (gxPrimeNbOfdmPlcMacSetup*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS: + ret = cosem_setPrimeNbOfdmPlcMacFunctionalParameters(settings, (gxPrimeNbOfdmPlcMacFunctionalParameters*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_COUNTERS: + ret = cosem_setPrimeNbOfdmPlcMacCounters(settings, (gxPrimeNbOfdmPlcMacCounters*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA: + ret = cosem_setPrimeNbOfdmPlcMacNetworkAdministrationData(settings, (gxPrimeNbOfdmPlcMacNetworkAdministrationData*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION: + ret = cosem_setPrimeNbOfdmPlcApplicationsIdentification(settings, (gxPrimeNbOfdmPlcApplicationsIdentification*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION +#ifndef DLMS_IGNORE_ARBITRATOR + case DLMS_OBJECT_TYPE_ARBITRATOR: + ret = cosem_setArbitrator(settings, (gxArbitrator*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_ARBITRATOR +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE1_SETUP: + ret = cosem_setIec8802LlcType1Setup(settings, (gxIec8802LlcType1Setup*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE2_SETUP: + ret = cosem_setIec8802LlcType2Setup(settings, (gxIec8802LlcType2Setup*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE3_SETUP: + ret = cosem_setIec8802LlcType3Setup(settings, (gxIec8802LlcType3Setup*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP +#ifndef DLMS_IGNORE_SFSK_ACTIVE_INITIATOR + case DLMS_OBJECT_TYPE_SFSK_ACTIVE_INITIATOR: + ret = cosem_setSFSKActiveInitiator(settings, (gxSFSKActiveInitiator*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_SFSK_ACTIVE_INITIATOR +#ifndef DLMS_IGNORE_SFSK_MAC_COUNTERS + case DLMS_OBJECT_TYPE_SFSK_MAC_COUNTERS: + ret = cosem_setFSKMacCounters(settings, (gxFSKMacCounters*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_SFSK_MAC_COUNTERS +#ifndef DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS + case DLMS_OBJECT_TYPE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS: + ret = cosem_setSFSKMacSynchronizationTimeouts(settings, (gxSFSKMacSynchronizationTimeouts*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS +#ifndef DLMS_IGNORE_SFSK_PHY_MAC_SETUP + case DLMS_OBJECT_TYPE_SFSK_PHY_MAC_SETUP: + ret = cosem_setSFSKPhyMacSetUp(settings, (gxSFSKPhyMacSetUp*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_SFSK_PHY_MAC_SETUP +#ifndef DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST + case DLMS_OBJECT_TYPE_SFSK_REPORTING_SYSTEM_LIST: + ret = cosem_setSFSKReportingSystemList(settings, (gxSFSKReportingSystemList*)e->target, e->index, &e->value); + break; +#endif //DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST +#ifdef DLMS_ITALIAN_STANDARD + case DLMS_OBJECT_TYPE_TARIFF_PLAN: + ret = cosem_setTariffPlan((gxTariffPlan*)e->target, e->index, &e->value); + break; +#endif //DLMS_ITALIAN_STANDARD + default: + //Unknown type. + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} diff --git a/components/xt211/gxset.h b/components/xt211/gxset.h new file mode 100644 index 0000000..46cb653 --- /dev/null +++ b/components/xt211/gxset.h @@ -0,0 +1,57 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef COSEM_SET_H +#define COSEM_SET_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) +#include "gxsetignoremalloc.h" +#else +#include "gxsetmalloc.h" +#endif //DLMS_IGNORE_MALLOC +#include "gxobjects.h" +#include "dlmssettings.h" + int cosem_setValue(dlmsSettings* settings, gxValueEventArg *e); + + ///////////////////////////////////////////////////////////////////////// + // The season profile is sorted according to start date + // (in increasing order). + int cosem_orderSeasonProfile(gxArray* profile); +#ifdef __cplusplus +} +#endif + +#endif//COSEM_SET_H diff --git a/components/xt211/gxsetmalloc.c b/components/xt211/gxsetmalloc.c new file mode 100644 index 0000000..533cd01 --- /dev/null +++ b/components/xt211/gxsetmalloc.c @@ -0,0 +1,8477 @@ +// +// -------------------------------------------------------------------------- +// 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(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) +#include +#endif + +#include "gxmem.h" +#if _MSC_VER > 1400 +#include +#endif +#include +#include + +#include "gxset.h" +#include "dlms.h" +#include "gxkey.h" +#include "cosem.h" +#include "gxget.h" +#include "server.h" + +#ifndef DLMS_IGNORE_DATA +int cosem_setData(gxValueEventArg* e) +{ + int ret; + if (e->index == 2) + { + ret = var_copy(&((gxData*)e->target)->value, &e->value); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_DATA + +#ifndef DLMS_IGNORE_REGISTER +int cosem_setRegister(gxRegister* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = 0; + if (index == 2) + { + ret = var_copy(&object->value, value); + } + else if (index == 3) + { + dlmsVARIANT* tmp; + if (value->vt != DLMS_DATA_TYPE_STRUCTURE) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + ret = va_getByIndex(value->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->scaler = (char)var_toInteger(tmp); + ret = va_getByIndex(value->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->unit = (unsigned char)var_toInteger(tmp); + object->unitRead = 1; + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_REGISTER + +#ifndef DLMS_IGNORE_REGISTER_TABLE +int cosem_setRegistertable(gxRegisterTable* object, unsigned char index, dlmsVARIANT* value) +{ + int pos, ret = 0; + dlmsVARIANT_PTR tmp; + if (index == 2) + { + if (value->Arr != NULL) + { + dlmsVARIANT* tmp2; + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + tmp2 = (dlmsVARIANT*)gxmalloc(sizeof(dlmsVARIANT)); + var_init(tmp2); + ret = var_copy(tmp2, tmp); + if (ret != 0) + { + break; + } + va_push(&object->tableCellValues, tmp2); + } + } + } + else if (index == 4) + { + if (value->vt != DLMS_DATA_TYPE_STRUCTURE) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + ret = va_getByIndex(value->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->scaler = (char)var_toInteger(tmp); + ret = va_getByIndex(value->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->unit = (unsigned char)var_toInteger(tmp); + object->unitRead = 1; + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_REGISTER_TABLE + +#ifndef DLMS_IGNORE_CLOCK +int cosem_setClock(dlmsSettings* settings, gxClock* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = DLMS_ERROR_CODE_OK; + dlmsVARIANT tmp; + if (index == 2) + { + //Some meters are returning empty octet string here. + if (value->vt == DLMS_DATA_TYPE_OCTET_STRING && value->byteArr != NULL) + { + var_init(&tmp); + ret = dlms_changeType2(value, DLMS_DATA_TYPE_DATETIME, &tmp); + if (ret != 0) + { + return ret; + } + time_copy(&object->time, tmp.dateTime); + //If user set's new time transform it to the same time zone as the server is. +#ifndef DLMS_IGNORE_SERVER + if (settings->server) + { + //Convert time to UCT if time zone is given. + time_toUTC(&object->time); + clock_updateDST(object, &object->time); + } +#endif// DLMS_IGNORE_SERVER + var_clear(&tmp); + } + else + { + time_clear(&object->time); + } + } + else if (index == 3) + { + object->timeZone = (short)var_toInteger(value); + } + else if (index == 4) + { + object->status = (DLMS_CLOCK_STATUS)var_toInteger(value); + } + else if (index == 5) + { + //Some meters are returning empty octet string here. + if (value->vt == DLMS_DATA_TYPE_OCTET_STRING && value->byteArr != NULL) + { + var_init(&tmp); + ret = dlms_changeType2(value, DLMS_DATA_TYPE_DATETIME, &tmp); + if (ret != 0) + { + return ret; + } + time_copy(&object->begin, tmp.dateTime); + var_clear(&tmp); + } + else + { + time_clear(&object->begin); + } + } + else if (index == 6) + { + //Some meters are returning empty octet string here. + if (value->vt == DLMS_DATA_TYPE_OCTET_STRING && value->byteArr != NULL) + { + var_init(&tmp); + ret = dlms_changeType2(value, DLMS_DATA_TYPE_DATETIME, &tmp); + if (ret != 0) + { + return ret; + } + time_copy(&object->end, tmp.dateTime); + var_clear(&tmp); + } + else + { + time_clear(&object->end); + } + } + else if (index == 7) + { + object->deviation = (char)var_toInteger(value); +#ifndef DLMS_IGNORE_SERVER + if (settings->server) + { + clock_updateDST(object, &object->time); + } +#endif// DLMS_IGNORE_SERVER + } + else if (index == 8) + { + object->enabled = (unsigned char)var_toInteger(value); +#ifndef DLMS_IGNORE_SERVER + if (settings->server) + { + clock_updateDST(object, &object->time); + } +#endif //DLMS_IGNORE_SERVER + } + else if (index == 9) + { + object->clockBase = (DLMS_CLOCK_BASE)var_toInteger(value); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} + +#endif //DLMS_IGNORE_CLOCK + +#ifndef DLMS_IGNORE_ACTIVITY_CALENDAR + + +// The season profiles list is sorted according to season_start (in increasing order). +int cosem_orderSeasonProfile(gxArray* profile) +{ + int ret = 0; + uint16_t pos, pos2, minPos = 0; + gxSeasonProfile* sp, * sp2; + uint32_t tmp, next1, next2; + for (pos = 0; pos < profile->size - 1; ++pos) + { + if ((ret = arr_getByIndex(profile, pos, (void**)&sp)) != 0) + { + break; + } + next1 = time_toUnixTime2(&sp->start); + next2 = 0xFFFFFFFF; + for (pos2 = pos + 1; pos2 < profile->size; ++pos2) + { + if ((ret = arr_getByIndex(profile, pos2, (void**)&sp2)) != 0) + { + break; + } + tmp = time_toUnixTime2(&sp2->start); + if (tmp < next2) + { + next2 = tmp; + minPos = pos2; + } + } + if (ret != 0) + { + break; + } + if (next2 < next1) + { + if ((ret = arr_swap(profile, pos, minPos)) != 0) + { + break; + } + } + } + return ret; +} + +int updateSeasonProfile(gxArray* profile, dlmsVARIANT* data) +{ + int ret = DLMS_ERROR_CODE_OK, pos; + gxSeasonProfile* sp = NULL; + obj_clearSeasonProfile(profile); + dlmsVARIANT tm; + dlmsVARIANT* tmp, * it; + var_init(&tm); + for (pos = 0; pos != data->Arr->size; ++pos) + { + sp = (gxSeasonProfile*)gxmalloc(sizeof(gxSeasonProfile)); + if (sp == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + ret = va_getByIndex(data->Arr, pos, &it); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = va_getByIndex(it->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + BYTE_BUFFER_INIT(&sp->name); + bb_set2(&sp->name, tmp->byteArr, 0, bb_size(tmp->byteArr)); + + ret = va_getByIndex(it->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = dlms_changeType2(tmp, DLMS_DATA_TYPE_DATETIME, &tm); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + time_copy(&sp->start, tm.dateTime); + var_clear(&tm); + ret = va_getByIndex(it->Arr, 2, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + BYTE_BUFFER_INIT(&sp->weekName); + bb_set2(&sp->weekName, tmp->byteArr, 0, bb_size(tmp->byteArr)); + arr_push(profile, sp); + } + if (ret != 0 && sp != NULL) + { + gxfree(sp); + } + return ret; +} + +int updateWeekProfileTable(gxArray* profile, dlmsVARIANT* data) +{ + int ret = DLMS_ERROR_CODE_OK, pos; + gxWeekProfile* wp = NULL; + obj_clearWeekProfileTable(profile); + dlmsVARIANT* tmp, * it; + for (pos = 0; pos != data->Arr->size; ++pos) + { + wp = (gxWeekProfile*)gxmalloc(sizeof(gxWeekProfile)); + if (wp == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + ret = va_getByIndex(data->Arr, pos, &it); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = va_getByIndex(it->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + BYTE_BUFFER_INIT(&wp->name); + bb_set2(&wp->name, tmp->byteArr, 0, bb_size(tmp->byteArr)); + ret = va_getByIndex(it->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + wp->monday = (unsigned char)var_toInteger(tmp); + + ret = va_getByIndex(it->Arr, 2, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + wp->tuesday = (unsigned char)var_toInteger(tmp); + + ret = va_getByIndex(it->Arr, 3, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + wp->wednesday = (unsigned char)var_toInteger(tmp); + + ret = va_getByIndex(it->Arr, 4, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + wp->thursday = (unsigned char)var_toInteger(tmp); + + ret = va_getByIndex(it->Arr, 5, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + wp->friday = (unsigned char)var_toInteger(tmp); + + ret = va_getByIndex(it->Arr, 6, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + wp->saturday = (unsigned char)var_toInteger(tmp); + + ret = va_getByIndex(it->Arr, 7, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + wp->sunday = (unsigned char)var_toInteger(tmp); + arr_push(profile, wp); + } + if (ret != 0 && wp != NULL) + { + gxfree(wp); + } + return ret; +} + +int updateDayProfileTable(dlmsSettings* settings, gxArray* profile, dlmsVARIANT* data) +{ + int ret = DLMS_ERROR_CODE_OK, pos, pos2; + gxDayProfile* dp = NULL; + gxDayProfileAction* ac = NULL; + obj_clearDayProfileTable(profile); + dlmsVARIANT* tmp, * tmp2, * it, * it2; + dlmsVARIANT tm; + for (pos = 0; pos != data->Arr->size; ++pos) + { + dp = (gxDayProfile*)gxmalloc(sizeof(gxDayProfile)); + if (dp == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + arr_init(&dp->daySchedules); + ret = va_getByIndex(data->Arr, pos, &it); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = va_getByIndex(it->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + dp->dayId = (unsigned char)var_toInteger(tmp); + ret = va_getByIndex(it->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + for (pos2 = 0; pos2 != tmp->Arr->size; ++pos2) + { + ac = (gxDayProfileAction*)gxmalloc(sizeof(gxDayProfileAction)); + if (ac == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + ret = va_getByIndex(tmp->Arr, pos2, &it2); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + //Get start time. + ret = va_getByIndex(it2->Arr, 0, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + var_init(&tm); + ret = dlms_changeType2(tmp2, DLMS_DATA_TYPE_TIME, &tm); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + time_copy(&ac->startTime, tm.dateTime); + var_clear(&tm); + //Get script logical name. + ret = va_getByIndex(it2->Arr, 1, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + if (tmp2->vt == DLMS_DATA_TYPE_OCTET_STRING && tmp2->byteArr != NULL) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = oa_findByLN(&settings->objects, DLMS_OBJECT_TYPE_SCRIPT_TABLE, tmp2->byteArr->data, &ac->script)) != 0) + { + break; + } + if (ac->script == NULL) + { + if ((ret = cosem_createObject(DLMS_OBJECT_TYPE_SCRIPT_TABLE, &ac->script)) != 0) + { + return ret; + } + memcpy(ac->script->logicalName, tmp2->byteArr->data, tmp2->byteArr->size); + //Add object to released objects list. + ret = oa_push(&settings->releasedObjects, ac->script); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + } +#else + memcpy(ac->scriptLogicalName, tmp2->byteArr->data, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + ret = va_getByIndex(it2->Arr, 2, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ac->scriptSelector = (uint16_t)var_toInteger(tmp2); + arr_push(&dp->daySchedules, ac); + } + if (ret != 0) + { + break; + } + arr_push(profile, dp); + } + if (ret != 0) + { + if (dp) + { + gxfree(dp); + } + if (ac) + { + gxfree(ac); + } + } + return ret; +} + +int cosem_setActivityCalendar(dlmsSettings* settings, gxActivityCalendar* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = DLMS_ERROR_CODE_OK; + dlmsVARIANT tm; + if (index == 2) + { + bb_clear(&object->calendarNameActive); + ret = bb_set2(&object->calendarNameActive, value->byteArr, 0, bb_size(value->byteArr)); + } + else if (index == 3) + { + ret = updateSeasonProfile(&object->seasonProfileActive, value); + } + else if (index == 4) + { + ret = updateWeekProfileTable(&object->weekProfileTableActive, value); + } + else if (index == 5) + { + ret = updateDayProfileTable(settings, &object->dayProfileTableActive, value); + } + else if (index == 6) + { + bb_clear(&object->calendarNamePassive); + ret = bb_set2(&object->calendarNamePassive, value->byteArr, 0, bb_size(value->byteArr)); + } + else if (index == 7) + { + ret = updateSeasonProfile(&object->seasonProfilePassive, value); + } + else if (index == 8) + { + ret = updateWeekProfileTable(&object->weekProfileTablePassive, value); + } + else if (index == 9) + { + ret = updateDayProfileTable(settings, &object->dayProfileTablePassive, value); + } + else if (index == 10) + { + //Some meters are returning empty octet string here. + if (value->vt == DLMS_DATA_TYPE_OCTET_STRING && value->byteArr != NULL) + { + var_init(&tm); + ret = dlms_changeType2(value, DLMS_DATA_TYPE_DATETIME, &tm); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + time_copy(&object->time, tm.dateTime); + var_clear(&tm); + } + else + { + time_clear(&object->time); + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif // DLMS_IGNORE_ACTIVITY_CALENDAR + +#ifndef DLMS_IGNORE_ACTION_SCHEDULE +int cosem_setActionSchedule( + dlmsSettings* settings, + gxActionSchedule* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret = 0, pos; + dlmsVARIANT* tmp; + gxtime* tm; + if (index == 2) + { + ret = va_getByIndex(value->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if (ret == 0) + { + if ((ret = oa_findByLN(&settings->objects, DLMS_OBJECT_TYPE_SCRIPT_TABLE, tmp->byteArr->data, (gxObject**)&object->executedScript)) != 0) + { + //Error code is returned at the end of the function. + } + if (object->executedScript == NULL) + { + //create object. + ret = cosem_createObject(DLMS_OBJECT_TYPE_SCRIPT_TABLE, (gxObject**)&object->executedScript); + if (ret == DLMS_ERROR_CODE_OK) + { + ret = cosem_setLogicalName((gxObject*)object->executedScript, tmp->byteArr->data); + if (ret == DLMS_ERROR_CODE_OK) + { + //Add object to released objects list. + ret = oa_push(&settings->releasedObjects, (gxObject*)object->executedScript); + } + } + } + } +#else + memcpy(object->executedScriptLogicalName, tmp->byteArr->data, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + ret = va_getByIndex(value->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->executedScriptSelector = (uint16_t)var_toInteger(tmp); + } + else if (index == 3) + { + object->type = (DLMS_SINGLE_ACTION_SCHEDULE_TYPE)var_toInteger(value); + } + else if (index == 4) + { + arr_clear(&object->executionTime); + dlmsVARIANT time, date; + dlmsVARIANT* tmp2; + var_init(&time); + var_init(&date); + if (value->Arr != NULL) + { + arr_capacity(&object->executionTime, value->Arr->size); + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + + ret = dlms_changeType2(tmp2, DLMS_DATA_TYPE_TIME, &time); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = va_getByIndex(tmp->Arr, 1, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = dlms_changeType2(tmp2, DLMS_DATA_TYPE_DATE, &date); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } +#ifdef DLMS_USE_EPOCH_TIME + time_addHours(date.dateTime, time_getHours(time.dateTime)); + time_addMinutes(date.dateTime, time_getMinutes(time.dateTime)); + time_addSeconds(date.dateTime, time_getSeconds(time.dateTime)); + date.dateTime->skip = (DATETIME_SKIPS)(date.dateTime->skip & time.dateTime->skip); +#else + date.dateTime->value.tm_hour = time.dateTime->value.tm_hour; + date.dateTime->value.tm_min = time.dateTime->value.tm_min; + date.dateTime->value.tm_sec = time.dateTime->value.tm_sec; + date.dateTime->skip &= ~(DATETIME_SKIPS_HOUR | DATETIME_SKIPS_MINUTE | DATETIME_SKIPS_SECOND | DATETIME_SKIPS_MS); + date.dateTime->skip |= time.dateTime->skip & (DATETIME_SKIPS_HOUR | DATETIME_SKIPS_MINUTE | DATETIME_SKIPS_SECOND | DATETIME_SKIPS_MS); +#endif // DLMS_USE_EPOCH_TIME + date.dateTime->deviation = (short)0x8000; + date.dateTime->skip |= DATETIME_SKIPS_DEVITATION; + tm = (gxtime*)gxmalloc(sizeof(gxtime)); + if (tm == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + time_copy(tm, date.dateTime); + arr_push(&object->executionTime, tm); + var_clear(&time); + var_clear(&date); + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_ACTION_SCHEDULE + +int cosem_updateAttributeAccessModes(gxObject* object, variantArray* arr) +{ + unsigned char id; + int ret; + uint16_t pos, cnt; + dlmsVARIANT* tmp, * it, * value; + //If accessmodes are not returned. Some meters do not return them. + if (arr->size != 2) + { + return 0; + } + ret = va_getByIndex(arr, 0, &tmp); + if (ret != 0) + { + return ret; + } + //If access modes are not retrieved yet. + if (object->access == NULL || object->access->attributeAccessModes.size == 0) + { + if (object->access == NULL) + { + object->access = (gxAccess*)gxcalloc(1, sizeof(gxAccess)); + } + cnt = obj_attributeCount(object); + bb_capacity(&object->access->attributeAccessModes, cnt); + object->access->attributeAccessModes.size = object->access->attributeAccessModes.capacity; + + cnt = obj_methodCount(object); + bb_capacity(&object->access->methodAccessModes, cnt); + object->access->methodAccessModes.size = object->access->methodAccessModes.capacity; + } + for (pos = 0; pos != tmp->Arr->size; ++pos) + { + ret = va_getByIndex(tmp->Arr, pos, &it); + if (ret != 0) + { + return ret; + } + if (it->vt != DLMS_DATA_TYPE_STRUCTURE || + it->Arr->size != 3) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + + //Get ID. + ret = va_getByIndex(it->Arr, 0, &value); + if (ret != 0) + { + return ret; + } + + id = (unsigned char)var_toInteger(value); + if (!(id > object->access->attributeAccessModes.size)) + { + ret = va_getByIndex(it->Arr, 1, &value); + if (ret != 0) + { + return ret; + } + //DLMS_ACCESS_MODE + object->access->attributeAccessModes.data[id - 1] = (unsigned char)var_toInteger(value); + } + } + + //Get method access modes. + ret = va_getByIndex(arr, 1, &tmp); + if (ret != 0) + { + return ret; + } + for (pos = 0; pos != tmp->Arr->size; ++pos) + { + ret = va_getByIndex(tmp->Arr, pos, &it); + if (ret != 0) + { + return ret; + } + if (it->vt != DLMS_DATA_TYPE_STRUCTURE || + it->Arr->size != 2) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + + //Get ID. + ret = va_getByIndex(it->Arr, 0, &value); + if (ret != 0) + { + return ret; + } + + id = (unsigned char)var_toInteger(value); + if (!(id > object->access->methodAccessModes.size)) + { + ret = va_getByIndex(it->Arr, 1, &value); + if (ret != 0) + { + return ret; + } + //DLMS_METHOD_ACCESS_MODE + object->access->methodAccessModes.data[id - 1] = (unsigned char)var_toInteger(value); + } + } + return ret; +} + +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + +int cosem_parseLNObjects(dlmsSettings* settings, gxByteBuffer* data, objectArray* objects) +{ + gxObject* object; + int ret; + uint16_t pos, count; + unsigned char size; + oa_clear(&settings->objects, 1); + unsigned char version; + gxDataInfo info; + DLMS_OBJECT_TYPE class_id = 0; + dlmsVARIANT value; + dlmsVARIANT* it1 = NULL, * it2 = NULL, * it3 = NULL, * ln = NULL; + var_init(&value); + //Get array tag. + ret = bb_getUInt8(data, &size); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + //Check that data is in the array + if (size != DLMS_DATA_TYPE_ARRAY) + { + return DLMS_ERROR_CODE_INVALID_RESPONSE; + } + //get object count + if (hlp_getObjectCount2(data, &count) != 0) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + oa_capacity(objects, (uint16_t)count); + for (pos = 0; pos != count; ++pos) + { + var_clear(&value); + object = NULL; + di_init(&info); + if ((ret = dlms_getData(data, &info, &value)) != 0) + { + //This fixs Iskraemeco (MT-880) bug. + if (ret == DLMS_ERROR_CODE_OUTOFMEMORY) + { + ret = 0; + } + break; + } + if (value.vt != DLMS_DATA_TYPE_STRUCTURE || value.Arr->size != 4) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + if ((ret = va_getByIndex(value.Arr, 0, &it1)) != 0 || + (ret = va_getByIndex(value.Arr, 1, &it2)) != 0 || + (ret = va_getByIndex(value.Arr, 2, &ln)) != 0 || + (ret = va_getByIndex(value.Arr, 3, &it3)) != 0) + { + break; + } + if (it1->vt != DLMS_DATA_TYPE_UINT16 || + it2->vt != DLMS_DATA_TYPE_UINT8 || + ln->vt != DLMS_DATA_TYPE_OCTET_STRING || + it3->vt != DLMS_DATA_TYPE_STRUCTURE || + it3->Arr->size != 2) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + class_id = (DLMS_OBJECT_TYPE)var_toInteger(it1); + version = (unsigned char)var_toInteger(it2); + ret = cosem_createObject(class_id, &object); + //If known object. + if (ret == 0) + { + object->version = version; + ret = cosem_updateAttributeAccessModes(object, it3->Arr); + if (ret != 0) + { + break; + } + cosem_setLogicalName(object, ln->byteArr->data); + oa_push(&settings->objects, object); + oa_push(&settings->releasedObjects, object); + } + else + { + if (ret != DLMS_ERROR_CODE_UNAVAILABLE_OBJECT) + { + break; + } + ret = 0; + } + } + var_clear(&value); + return ret; +} + +int cosem_setAssociationLogicalName( + dlmsSettings* settings, + gxAssociationLogicalName* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret = 0, pos = 0; + dlmsVARIANT* tmp, * tmp2; + unsigned char ch; + if (index == 2) + { + gxObject* obj = NULL; + unsigned char version; + DLMS_OBJECT_TYPE type; + oa_empty(&object->objectList); + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + + ret = va_getByIndex(tmp->Arr, 0, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + type = (DLMS_OBJECT_TYPE)var_toInteger(tmp2); + ret = va_getByIndex(tmp->Arr, 1, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + version = (unsigned char)var_toInteger(tmp2); + + //Get Logical name. + ret = va_getByIndex(tmp->Arr, 2, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = oa_findByLN(&settings->objects, type, tmp2->byteArr->data, &obj); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + if (obj == NULL) + { + ret = cosem_createObject(type, &obj); + if (ret != DLMS_ERROR_CODE_OK) + { + //If unknown object. + if (ret == DLMS_ERROR_CODE_UNAVAILABLE_OBJECT || + ret == DLMS_ERROR_CODE_INVALID_PARAMETER) + { + continue; + } + return ret; + } + ret = cosem_setLogicalName(obj, tmp2->byteArr->data); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + obj->version = (unsigned char)version; + //Add object to released objects list. + ret = oa_push(&settings->releasedObjects, obj); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + } + ret = va_getByIndex(tmp->Arr, 3, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + + ret = cosem_updateAttributeAccessModes(obj, tmp2->Arr); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + oa_push(&object->objectList, obj); + } + } + } + else if (index == 3) + { + ret = va_getByIndex(value->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->clientSAP = (unsigned char)var_toInteger(tmp); + ret = va_getByIndex(value->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->serverSAP = (uint16_t)var_toInteger(tmp); + } + else if (index == 4) + { + //Value of the object identifier encoded in BER + if (value->vt == DLMS_DATA_TYPE_OCTET_STRING) + { + if (value->byteArr->data[0] == 0x60) + { + object->applicationContextName.jointIsoCtt = 0; + object->applicationContextName.country = 0; + object->applicationContextName.countryName = 0; + ret = bb_getUInt8ByIndex(value->byteArr, 3, &object->applicationContextName.identifiedOrganization); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = bb_getUInt8ByIndex(value->byteArr, 4, &object->applicationContextName.dlmsUA); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = bb_getUInt8ByIndex(value->byteArr, 5, &object->applicationContextName.applicationContext); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = bb_getUInt8ByIndex(value->byteArr, 6, &object->applicationContextName.contextId); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + } + else + { + //Get Tag. + ret = bb_getUInt8(value->byteArr, &ch); + if (ret != DLMS_ERROR_CODE_OK || ch != 2) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + //Get Len. + ret = bb_getUInt8(value->byteArr, &ch); + if (ret != DLMS_ERROR_CODE_OK || ch != 7) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + + //Get tag + ret = bb_getUInt8(value->byteArr, &ch); + if (ret != DLMS_ERROR_CODE_OK || ch != 0x11) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + + ret = bb_getUInt8(value->byteArr, &object->applicationContextName.jointIsoCtt); + if (ret != DLMS_ERROR_CODE_OK) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + //Get tag + ret = bb_getUInt8(value->byteArr, &ch); + if (ret != DLMS_ERROR_CODE_OK || ch != 0x11) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + ret = bb_getUInt8(value->byteArr, &object->applicationContextName.country); + if (ret != DLMS_ERROR_CODE_OK) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + + //Get tag + ret = bb_getUInt8(value->byteArr, &ch); + if (ret != DLMS_ERROR_CODE_OK || ch != 0x12) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + ret = bb_getUInt16(value->byteArr, &object->applicationContextName.countryName); + if (ret != DLMS_ERROR_CODE_OK || ch != 0x12) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + + //Get tag + ret = bb_getUInt8(value->byteArr, &ch); + if (ret != DLMS_ERROR_CODE_OK || ch != 0x11) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + ret = bb_getUInt8(value->byteArr, &object->applicationContextName.identifiedOrganization); + if (ret != DLMS_ERROR_CODE_OK) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + + //Get tag + ret = bb_getUInt8(value->byteArr, &ch); + if (ret != DLMS_ERROR_CODE_OK || ch != 0x11) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + ret = bb_getUInt8(value->byteArr, &object->applicationContextName.dlmsUA); + if (ret != DLMS_ERROR_CODE_OK) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + //Get tag + ret = bb_getUInt8(value->byteArr, &ch); + if (ret != DLMS_ERROR_CODE_OK || ch != 0x11) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + ret = bb_getUInt8(value->byteArr, &object->applicationContextName.applicationContext); + if (ret != DLMS_ERROR_CODE_OK) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + //Get tag + ret = bb_getUInt8(value->byteArr, &ch); + if (ret != DLMS_ERROR_CODE_OK || ch != 0x11) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + ret = bb_getUInt8(value->byteArr, &object->applicationContextName.contextId); + if (ret != DLMS_ERROR_CODE_OK) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + } + } + else if (value->vt == DLMS_DATA_TYPE_STRUCTURE) + { + ret = va_getByIndex(value->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->applicationContextName.jointIsoCtt = (unsigned char)var_toInteger(tmp); + ret = va_getByIndex(value->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->applicationContextName.country = (unsigned char)var_toInteger(tmp); + ret = va_getByIndex(value->Arr, 2, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->applicationContextName.countryName = (uint16_t)var_toInteger(tmp); + ret = va_getByIndex(value->Arr, 3, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->applicationContextName.identifiedOrganization = (unsigned char)var_toInteger(tmp); + ret = va_getByIndex(value->Arr, 4, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->applicationContextName.dlmsUA = (unsigned char)var_toInteger(tmp); + ret = va_getByIndex(value->Arr, 5, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->applicationContextName.applicationContext = (unsigned char)var_toInteger(tmp); + ret = va_getByIndex(value->Arr, 6, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->applicationContextName.contextId = (unsigned char)var_toInteger(tmp); + } + } + else if (index == 5) + { + ret = va_getByIndex(value->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->xDLMSContextInfo.conformance = (DLMS_CONFORMANCE)var_toInteger(tmp); + ret = va_getByIndex(value->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->xDLMSContextInfo.maxReceivePduSize = (uint16_t)var_toInteger(tmp); + + ret = va_getByIndex(value->Arr, 2, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->xDLMSContextInfo.maxSendPduSize = (uint16_t)var_toInteger(tmp); + + ret = va_getByIndex(value->Arr, 3, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->xDLMSContextInfo.dlmsVersionNumber = (unsigned char)var_toInteger(tmp); + + ret = va_getByIndex(value->Arr, 4, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->xDLMSContextInfo.qualityOfService = (unsigned char)var_toInteger(tmp); + + ret = va_getByIndex(value->Arr, 5, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + bb_clear(&object->xDLMSContextInfo.cypheringInfo); + if (tmp->byteArr != NULL) + { + bb_set2(&object->xDLMSContextInfo.cypheringInfo, tmp->byteArr, 0, tmp->byteArr->size); + } + } + else if (index == 6) + { + //Value of the object identifier encoded in BER + if (value->vt == DLMS_DATA_TYPE_OCTET_STRING) + { + if (value->byteArr->data[0] == 0x60) + { + object->authenticationMechanismName.jointIsoCtt = 0; + object->authenticationMechanismName.country = 0; + object->authenticationMechanismName.countryName = 0; + pos += 2; + object->authenticationMechanismName.identifiedOrganization = value->byteArr->data[++pos]; + object->authenticationMechanismName.dlmsUA = value->byteArr->data[++pos]; + object->authenticationMechanismName.authenticationMechanismName = value->byteArr->data[++pos]; + object->authenticationMechanismName.mechanismId = (DLMS_AUTHENTICATION)value->byteArr->data[++pos]; + } + else + { + if ((ret = cosem_checkStructure(value->byteArr, 7)) == 0 && + (ret = cosem_getUInt8(value->byteArr, &object->authenticationMechanismName.jointIsoCtt)) == 0 && + (ret = cosem_getUInt8(value->byteArr, &object->authenticationMechanismName.country)) == 0 && + (ret = cosem_getUInt16(value->byteArr, &object->authenticationMechanismName.countryName)) == 0 && + (ret = cosem_getUInt8(value->byteArr, &object->authenticationMechanismName.identifiedOrganization)) == 0 && + (ret = cosem_getUInt8(value->byteArr, &object->authenticationMechanismName.dlmsUA)) == 0 && + (ret = cosem_getUInt8(value->byteArr, &object->authenticationMechanismName.authenticationMechanismName)) == 0 && + (ret = cosem_getUInt8(value->byteArr, &ch)) == 0) + { + object->authenticationMechanismName.mechanismId = (DLMS_AUTHENTICATION)ch; + } + } + } + else if (value->vt == DLMS_DATA_TYPE_STRUCTURE) + { + ret = va_getByIndex(value->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->authenticationMechanismName.jointIsoCtt = (unsigned char)var_toInteger(tmp); + ret = va_getByIndex(value->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->authenticationMechanismName.country = (unsigned char)var_toInteger(tmp); + ret = va_getByIndex(value->Arr, 2, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->authenticationMechanismName.countryName = (uint16_t)var_toInteger(tmp); + ret = va_getByIndex(value->Arr, 3, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->authenticationMechanismName.identifiedOrganization = (unsigned char)var_toInteger(tmp); + ret = va_getByIndex(value->Arr, 4, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->authenticationMechanismName.dlmsUA = (unsigned char)var_toInteger(tmp); + ret = va_getByIndex(value->Arr, 5, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->authenticationMechanismName.authenticationMechanismName = (unsigned char)var_toInteger(tmp); + ret = va_getByIndex(value->Arr, 6, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->authenticationMechanismName.mechanismId = (DLMS_AUTHENTICATION)var_toInteger(tmp); + } + } + else if (index == 7) + { + bb_clear(&object->secret); + if (value->byteArr != NULL) + { + ret = bb_set2(&object->secret, value->byteArr, 0, bb_size(value->byteArr)); + } + } + else if (index == 8) + { + object->associationStatus = (DLMS_ASSOCIATION_STATUS)var_toInteger(value); + } + else if (index == 9) + { + if (bb_size(value->byteArr) != 6) + { + return DLMS_ERROR_CODE_UNMATCH_TYPE; + } +#if !(defined(DLMS_IGNORE_OBJECT_POINTERS) || defined(DLMS_IGNORE_SECURITY_SETUP)) + ret = oa_findByLN(&settings->objects, DLMS_OBJECT_TYPE_SECURITY_SETUP, value->byteArr->data, (gxObject**)&object->securitySetup); +#else + memcpy(object->securitySetupReference, value->byteArr->data, 6); +#endif //!(defined(DLMS_IGNORE_OBJECT_POINTERS) || defined(DLMS_IGNORE_SECURITY_SETUP)) + } + else if (index == 10) + { + obj_clearUserList(&object->userList); + if (value->Arr != NULL) + { + gxKey2* it; + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + it = (gxKey2*)gxmalloc(sizeof(gxKey2)); + if (it == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + it->key = (unsigned char)var_toInteger(tmp2); + ret = va_getByIndex(tmp->Arr, 1, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + it->value = (char*)gxmalloc(tmp->strVal->size + 1); + if (it->value == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + ((char*)it->value)[tmp->strVal->size] = 0; + memcpy(it->value, tmp->strVal->data, tmp->strVal->size); + arr_push(&object->userList, it); + } + } + } + else if (index == 11) + { + if (object->currentUser.value != NULL) + { + gxfree(object->currentUser.value); + } + if (value->Arr->size == 2) + { + ret = va_getByIndex(value->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->currentUser.key = (unsigned char)var_toInteger(tmp); + ret = va_getByIndex(value->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + if (tmp->strVal != NULL && tmp->strVal->size != 0) + { + object->currentUser.value = gxmalloc(tmp->strVal->size + 1); + if (object->currentUser.value == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + memcpy(object->currentUser.value, tmp->strVal, tmp->strVal->size); + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME +int updateSNAccessRights( + objectArray* objectList, + variantArray* data) +{ + uint16_t sn; + int pos, ret; + dlmsVARIANT* it, * tmp; + gxObject* obj = NULL; + for (pos = 0; pos != data->size; ++pos) + { + ret = va_getByIndex(data, pos, &it); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = va_getByIndex(it->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + sn = (uint16_t)var_toInteger(tmp); + + ret = oa_findBySN(objectList, sn, &obj); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + if (obj != NULL) + { + ret = cosem_updateAttributeAccessModes(obj, it->Arr); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + /* + ret = va_getByIndex(it->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + //Update attribute Access + for(pos2 = 0; pos2 != tmp->Arr.size; ++pos2) + { + ret = va_getByIndex(tmp->Arr, pos, &access); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + //Get attribute ID. + ret = va_getByIndex(&access->Arr, 0, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + //TODO: id = var_toInteger(tmp2); + //Get access mode. + ret = va_getByIndex(&access->Arr, 1, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + //TODO: obj->SetAccess(id, (DLMS_ACCESS_MODE) var_toInteger(tmp2)); + } + + //Update method Access + ret = va_getByIndex(it->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + for(pos2 = 0; pos2 != tmp->Arr.size; ++pos2) + { + ret = va_getByIndex(tmp->Arr, pos, &access); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + //Get attribute ID. + ret = va_getByIndex(&access->Arr, 0, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + //TODO: id = var_toInteger(tmp2); + //Get access mode. + ret = va_getByIndex(&access->Arr, 1, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + //TODO: obj->SetMethodAccess(id, (DLMS_ACCESS_MODE) var_toInteger(tmp2)); + } + */ + } + } + return DLMS_ERROR_CODE_OK; +} + +int cosem_parseSNObjects(dlmsSettings* settings, gxByteBuffer* data, objectArray* objects) +{ + gxDataInfo info; + short sn; + DLMS_OBJECT_TYPE class_id; + dlmsVARIANT value; + dlmsVARIANT* it1 = NULL, * it2 = NULL, * it3 = NULL, * ln = NULL; + gxObject* object; + int ret; + uint16_t count, pos; + unsigned char size, version; + var_init(&value); + //Get array tag. + if ((ret = bb_getUInt8(data, &size)) != DLMS_ERROR_CODE_OK) + { + return 0; + } + //Check that data is in the array + if (size != 0x01) + { + return DLMS_ERROR_CODE_INVALID_RESPONSE; + } + //get object count + if ((ret = hlp_getObjectCount2(data, &count)) != 0) + { + return ret; + } + oa_capacity(objects, (uint16_t)count); + for (pos = 0; pos != count; ++pos) + { + var_clear(&value); + object = NULL; + di_init(&info); + if ((ret = dlms_getData(data, &info, &value)) != 0) + { + break; + } + if (value.vt != DLMS_DATA_TYPE_STRUCTURE || value.Arr->size != 4) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + if ((ret = va_getByIndex(value.Arr, 0, &it1)) != 0 || + (ret = va_getByIndex(value.Arr, 1, &it2)) != 0 || + (ret = va_getByIndex(value.Arr, 2, &it3)) != 0 || + (ret = va_getByIndex(value.Arr, 3, &ln)) != 0) + { + break; + } + if (it1->vt != DLMS_DATA_TYPE_INT16 || + it2->vt != DLMS_DATA_TYPE_UINT16 || + it3->vt != DLMS_DATA_TYPE_UINT8 || + ln->vt != DLMS_DATA_TYPE_OCTET_STRING) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + sn = (short)var_toInteger(it1); + class_id = (DLMS_OBJECT_TYPE)var_toInteger(it2); + version = (unsigned char)var_toInteger(it3); + ret = cosem_createObject(class_id, &object); + //If known object. + if (ret == 0) + { + object->shortName = sn; + object->version = version; + cosem_setLogicalName(object, ln->byteArr->data); + oa_push(objects, object); + oa_push(&settings->releasedObjects, object); + } + else + { + if (ret != DLMS_ERROR_CODE_UNAVAILABLE_OBJECT) + { + break; + } + ret = 0; + } + } + var_clear(&value); + return ret; +} + +int cosem_setAssociationShortName( + dlmsSettings* settings, + gxAssociationShortName* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret; + int pos; + if (index == 2) + { + dlmsVARIANT* it, * it1 = NULL, * it2 = NULL, * it3 = NULL, * ln = NULL; + unsigned char version; + short sn; + DLMS_OBJECT_TYPE class_id; + gxObject* obj; + oa_empty(&object->objectList); + if ((ret = oa_capacity(&object->objectList, value->Arr->size)) == 0) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + obj = NULL; + if ((ret = va_getByIndex(value->Arr, 0, &it)) != 0 || + (ret = va_getByIndex(it->Arr, 0, &it1)) != 0 || + (ret = va_getByIndex(it->Arr, 1, &it2)) != 0 || + (ret = va_getByIndex(it->Arr, 2, &it3)) != 0 || + (ret = va_getByIndex(it->Arr, 3, &ln)) != 0) + { + break; + } + if (it1->vt != DLMS_DATA_TYPE_INT16 || + it2->vt != DLMS_DATA_TYPE_UINT16 || + it3->vt != DLMS_DATA_TYPE_UINT8 || + ln->vt != DLMS_DATA_TYPE_OCTET_STRING) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + sn = (short)var_toInteger(it1); + class_id = (DLMS_OBJECT_TYPE)var_toInteger(it2); + version = (unsigned char)var_toInteger(it3); + ret = cosem_createObject(class_id, &obj); + //If known object. + if (ret == 0) + { + obj->shortName = sn; + obj->version = version; + cosem_setLogicalName(obj, ln->byteArr->data); + oa_push(&object->objectList, obj); + oa_push(&settings->releasedObjects, obj); + } + else + { + if (ret != DLMS_ERROR_CODE_UNAVAILABLE_OBJECT) + { + break; + } + ret = 0; + } + } + } + } + else if (index == 3) + { + ret = updateSNAccessRights(&object->objectList, value->Arr); + } + else if (index == 4) + { + if (bb_size(value->byteArr) != 6) + { + ret = DLMS_ERROR_CODE_UNMATCH_TYPE; + } + else + { +#ifndef DLMS_IGNORE_SECURITY_SETUP +#ifndef DLMS_IGNORE_OBJECT_POINTERS + ret = oa_findByLN(&settings->objects, DLMS_OBJECT_TYPE_SECURITY_SETUP, value->byteArr->data, (gxObject**)&object->securitySetup); +#else + memcpy(object->securitySetupReference, value->byteArr->data, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS +#endif // DLMS_IGNORE_SECURITY_SETUP + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + +#ifndef DLMS_IGNORE_AUTO_ANSWER +int cosem_setAutoAnswer(gxAutoAnswer* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = 0, pos; + dlmsVARIANT* tmp; + if (index == 2) + { + object->mode = (DLMS_AUTO_ANSWER_MODE)var_toInteger(value); + } + else if (index == 3) + { + arr_clearKeyValuePair(&object->listeningWindow); + dlmsVARIANT* tmp3; + dlmsVARIANT start, end; + gxtime* s, * e; + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + var_init(&start); + var_init(&end); + ret = dlms_changeType2(tmp3, DLMS_DATA_TYPE_DATETIME, &start); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = va_getByIndex(tmp->Arr, 1, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = dlms_changeType2(tmp3, DLMS_DATA_TYPE_DATETIME, &end); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + s = (gxtime*)gxmalloc(sizeof(gxtime)); + e = (gxtime*)gxmalloc(sizeof(gxtime)); + time_copy(s, start.dateTime); + time_copy(e, end.dateTime); + arr_push(&object->listeningWindow, key_init(s, e)); + var_clear(&start); + var_clear(&end); + } + } + } + else if (index == 4) + { + object->status = (DLMS_AUTO_ANSWER_STATUS)var_toInteger(value); + } + else if (index == 5) + { + object->numberOfCalls = (unsigned char)var_toInteger(value); + } + else if (index == 6) + { + ret = va_getByIndex(value->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->numberOfRingsInListeningWindow = (unsigned char)var_toInteger(tmp); + ret = va_getByIndex(value->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->numberOfRingsOutListeningWindow = (unsigned char)var_toInteger(tmp); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_AUTO_ANSWER + +#ifndef DLMS_IGNORE_AUTO_CONNECT +int cosem_setAutoConnect(gxAutoConnect* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = 0, pos; + if (index == 2) + { + object->mode = (DLMS_AUTO_CONNECT_MODE)var_toInteger(value); + } + else if (index == 3) + { + object->repetitions = (unsigned char)var_toInteger(value); + } + else if (index == 4) + { + object->repetitionDelay = (uint16_t)var_toInteger(value); + } + else if (index == 5) + { + dlmsVARIANT* tmp, * tmp3; + dlmsVARIANT start, end; + arr_clearKeyValuePair(&object->callingWindow); + if (value->Arr != NULL) + { + if ((ret = arr_capacity(&object->callingWindow, value->Arr->size)) == 0) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + gxtime* s, * e; + var_init(&start); + var_init(&end); + ret = dlms_changeType2(tmp3, DLMS_DATA_TYPE_DATETIME, &start); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = va_getByIndex(tmp->Arr, 1, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = dlms_changeType2(tmp3, DLMS_DATA_TYPE_DATETIME, &end); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + s = (gxtime*)gxmalloc(sizeof(gxtime)); + e = (gxtime*)gxmalloc(sizeof(gxtime)); + arr_push(&object->callingWindow, key_init(s, e)); + time_copy(s, start.dateTime); + time_copy(e, end.dateTime); + var_clear(&start); + var_clear(&end); + } + } + } + } + else if (index == 6) + { + dlmsVARIANT* tmp; + gxByteBuffer* str; + arr_clearStrings(&object->destinations); + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + str = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + BYTE_BUFFER_INIT(str); + bb_set2(str, tmp->byteArr, 0, bb_size(tmp->byteArr)); + arr_push(&object->destinations, str); + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_AUTO_CONNECT + +#ifndef DLMS_IGNORE_DEMAND_REGISTER +int cosem_setDemandRegister(gxDemandRegister* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = DLMS_ERROR_CODE_OK; + dlmsVARIANT* tmp; + dlmsVARIANT tmp2; + if (index == 2) + { + ret = var_copy(&object->currentAverageValue, value); + } + else if (index == 3) + { + ret = var_copy(&object->lastAverageValue, value); + } + else if (index == 4) + { + if (value->vt != DLMS_DATA_TYPE_STRUCTURE) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + ret = va_getByIndex(value->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->scaler = (char)var_toInteger(tmp); + ret = va_getByIndex(value->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->unit = (unsigned char)var_toInteger(tmp); + object->unitRead = 1; + } + else if (index == 5) + { + ret = var_copy(&object->status, value); + } + else if (index == 6) + { + //Some meters are returning empty octet string here. + if (value->vt == DLMS_DATA_TYPE_OCTET_STRING && value->byteArr != NULL) + { + ret = var_init(&tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = dlms_changeType2(value, DLMS_DATA_TYPE_DATETIME, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + time_copy(&object->captureTime, tmp2.dateTime); + var_clear(&tmp2); + } + else + { + time_clear(&object->captureTime); + } + } + else if (index == 7) + { + //Some meters are returning empty octet string here. + if (value->vt == DLMS_DATA_TYPE_OCTET_STRING && value->byteArr != NULL) + { + ret = var_init(&tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = dlms_changeType2(value, DLMS_DATA_TYPE_DATETIME, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + time_copy(&object->startTimeCurrent, tmp2.dateTime); + var_clear(&tmp2); + } + else + { + time_clear(&object->startTimeCurrent); + } + } + else if (index == 8) + { + object->period = var_toInteger(value); + } + else if (index == 9) + { + object->numberOfPeriods = (uint16_t)var_toInteger(value); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_DEMAND_REGISTER + +#ifndef DLMS_IGNORE_MAC_ADDRESS_SETUP +int cosem_setMacAddressSetup(gxMacAddressSetup* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = DLMS_ERROR_CODE_OK; + if (index == 2) + { + bb_clear(&object->macAddress); + ret = bb_set2(&object->macAddress, value->byteArr, 0, bb_size(value->byteArr)); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_MAC_ADDRESS_SETUP + +#ifndef DLMS_IGNORE_EXTENDED_REGISTER +int cosem_setExtendedRegister(gxExtendedRegister* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = DLMS_ERROR_CODE_OK; + dlmsVARIANT* tmp; + dlmsVARIANT tmp2; + if (index == 2) + { + ret = var_copy(&object->value, value); + } + else if (index == 3) + { + if (value->vt != DLMS_DATA_TYPE_STRUCTURE) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + ret = va_getByIndex(value->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->scaler = (char)var_toInteger(tmp); + ret = va_getByIndex(value->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->unit = (unsigned char)var_toInteger(tmp); + } + else if (index == 4) + { + ret = var_copy(&object->status, value); + } + else if (index == 5) + { + if (value->vt == DLMS_DATA_TYPE_OCTET_STRING) + { + ret = var_init(&tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = dlms_changeType2(value, DLMS_DATA_TYPE_DATETIME, &tmp2); + if (ret == 0) + { + time_copy(&object->captureTime, tmp2.dateTime); + var_clear(&tmp2); + } + } + else + { + time_copy(&object->captureTime, value->dateTime); + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_EXTENDED_REGISTER + +#ifndef DLMS_IGNORE_GPRS_SETUP +int cosem_setGprsSetup(gxGPRSSetup* object, unsigned char index, dlmsVARIANT* value) +{ + int ret; + if (index == 2) + { + bb_clear(&object->apn); + if (value->vt == DLMS_DATA_TYPE_STRING) + { + bb_set(&object->apn, (unsigned char*)value->strVal->data, value->strVal->size); + } + else + { + bb_set2(&object->apn, value->byteArr, 0, bb_size(value->byteArr)); + } + } + else if (index == 3) + { + object->pinCode = value->uiVal; + } + else if (index == 4) + { + dlmsVARIANT* tmp; + dlmsVARIANT* tmp3; + ret = va_getByIndex(value->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->defaultQualityOfService.precedence = (unsigned char)var_toInteger(tmp3); + ret = va_getByIndex(tmp->Arr, 1, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->defaultQualityOfService.delay = (unsigned char)var_toInteger(tmp3); + ret = va_getByIndex(tmp->Arr, 2, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->defaultQualityOfService.reliability = (unsigned char)var_toInteger(tmp3); + ret = va_getByIndex(tmp->Arr, 3, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->defaultQualityOfService.peakThroughput = (unsigned char)var_toInteger(tmp3); + ret = va_getByIndex(tmp->Arr, 4, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->defaultQualityOfService.meanThroughput = (unsigned char)var_toInteger(tmp3); + + ret = va_getByIndex(value->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->requestedQualityOfService.precedence = (unsigned char)var_toInteger(tmp3); + ret = va_getByIndex(tmp->Arr, 1, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->requestedQualityOfService.delay = (unsigned char)var_toInteger(tmp3); + ret = va_getByIndex(tmp->Arr, 2, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->requestedQualityOfService.reliability = (unsigned char)var_toInteger(tmp3); + ret = va_getByIndex(tmp->Arr, 3, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->requestedQualityOfService.peakThroughput = (unsigned char)var_toInteger(tmp3); + ret = va_getByIndex(tmp->Arr, 4, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->requestedQualityOfService.meanThroughput = (unsigned char)var_toInteger(tmp3); + } + else + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return DLMS_ERROR_CODE_OK; +} +#endif //DLMS_IGNORE_GPRS_SETUP + +#ifndef DLMS_IGNORE_SECURITY_SETUP +int cosem_setSecuritySetup(dlmsSettings* settings, gxSecuritySetup* object, unsigned char index, dlmsVARIANT* value) +{ + int pos, ret = 0; + gxCertificateInfo* it = NULL; + dlmsVARIANT* tmp, * tmp3; + switch (index) + { + case 2: + object->securityPolicy = (DLMS_SECURITY_POLICY)var_toInteger(value); + break; + case 3: + object->securitySuite = (DLMS_SECURITY_SUITE)var_toInteger(value); + break; + case 4: + if ((ret = bb_clear(&object->clientSystemTitle)) == 0) + { + if (!(value->byteArr == NULL || bb_available(value->byteArr) != 8)) + { + ret = bb_set2(&object->clientSystemTitle, value->byteArr, value->byteArr->position, 8); + } + } + break; + case 5: + if ((ret = bb_clear(&object->serverSystemTitle)) == 0) + { + if (!(value->byteArr == NULL || bb_available(value->byteArr) != 8)) + { + ret = bb_set2(&object->serverSystemTitle, value->byteArr, value->byteArr->position, 8); + } + } + break; + case 6: + obj_clearCertificateInfo(&object->certificates); + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + if ((ret = va_getByIndex(value->Arr, pos, &tmp)) != DLMS_ERROR_CODE_OK) + { + break; + } + it = (gxCertificateInfo*)gxmalloc(sizeof(gxCertificateInfo)); + if (it == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + //entity + if ((ret = va_getByIndex(tmp->Arr, 0, &tmp3)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->entity = (DLMS_CERTIFICATE_ENTITY)var_toInteger(tmp3); + //type + if ((ret = va_getByIndex(tmp->Arr, 1, &tmp3)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->type = (DLMS_CERTIFICATE_TYPE)var_toInteger(tmp3); + //serialNumber + if ((ret = va_getByIndex(tmp->Arr, 2, &tmp3)) != DLMS_ERROR_CODE_OK) + { + break; + } + if (tmp3->byteArr != NULL && tmp3->byteArr->size != 0) + { + it->serialNumber = gxmalloc(tmp3->byteArr->size + 1); + if (it->serialNumber == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + } + memcpy(it->serialNumber, tmp3->byteArr->data, tmp3->byteArr->size); + it->serialNumber[tmp3->byteArr->size] = 0; + } + else + { + it->serialNumber = NULL; + } + //issuer + if ((ret = va_getByIndex(tmp->Arr, 3, &tmp3)) != DLMS_ERROR_CODE_OK) + { + break; + } + if (tmp3->byteArr != NULL && tmp3->byteArr->size != 0) + { + it->issuer = gxmalloc(tmp3->byteArr->size + 1); + if (it->issuer == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + memcpy(it->issuer, tmp3->byteArr->data, tmp3->byteArr->size); + it->issuer[tmp3->byteArr->size] = 0; + } + else + { + it->issuer = NULL; + } + //subject + if ((ret = va_getByIndex(tmp->Arr, 4, &tmp3)) != DLMS_ERROR_CODE_OK) + { + break; + } + if (tmp3->byteArr != NULL && tmp3->byteArr->size != 0) + { + it->subject = gxmalloc(tmp3->byteArr->size + 1); + if (it->subject == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + memcpy(it->subject, tmp3->byteArr->data, tmp3->byteArr->size); + it->subject[tmp3->byteArr->size] = 0; + } + else + { + it->subject = NULL; + } + //subjectAltName. + if ((ret = va_getByIndex(tmp->Arr, 5, &tmp3)) != DLMS_ERROR_CODE_OK) + { + break; + } + if (tmp3->byteArr != NULL && tmp3->byteArr->size != 0) + { + it->subjectAltName = gxmalloc(tmp3->byteArr->size + 1); + if (it->subjectAltName == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + memcpy(it->subjectAltName, tmp3->byteArr->data, tmp3->byteArr->size); + it->subjectAltName[tmp3->byteArr->size] = 0; + } + else + { + it->subjectAltName = NULL; + } + arr_push(&object->certificates, it); + } + if (ret != 0 && it != NULL) + { + if (it->serialNumber != NULL) + { + gxfree(it->serialNumber); + } + if (it->subject != NULL) + { + gxfree(it->subject); + } + if (it->issuer != NULL) + { + gxfree(it->issuer); + } + gxfree(it); + } + } + break; + default: + ret = DLMS_ERROR_CODE_READ_WRITE_DENIED; + } + return ret; +} +#endif //DLMS_IGNORE_SECURITY_SETUP + +#ifndef DLMS_IGNORE_IEC_HDLC_SETUP +int cosem_setIecHdlcSetup(gxIecHdlcSetup* object, unsigned char index, dlmsVARIANT* value) +{ + if (index == 2) + { + object->communicationSpeed = (DLMS_BAUD_RATE)var_toInteger(value); + } + else if (index == 3) + { + object->windowSizeTransmit = (unsigned char)var_toInteger(value); + } + else if (index == 4) + { + object->windowSizeReceive = (unsigned char)var_toInteger(value); + } + else if (index == 5) + { + object->maximumInfoLengthTransmit = (uint16_t)var_toInteger(value); + } + else if (index == 6) + { + object->maximumInfoLengthReceive = (uint16_t)var_toInteger(value); + } + else if (index == 7) + { + object->interCharachterTimeout = (uint16_t)var_toInteger(value); + } + else if (index == 8) + { + object->inactivityTimeout = (uint16_t)var_toInteger(value); + } + else if (index == 9) + { + object->deviceAddress = (uint16_t)var_toInteger(value); + } + else + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return DLMS_ERROR_CODE_OK; +} +#endif //DLMS_IGNORE_IEC_HDLC_SETUP +#ifndef DLMS_IGNORE_IEC_LOCAL_PORT_SETUP +int cosem_setIecLocalPortSetup(gxLocalPortSetup* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = 0; + if (index == 2) + { + object->defaultMode = (DLMS_OPTICAL_PROTOCOL_MODE)var_toInteger(value); + } + else if (index == 3) + { + object->defaultBaudrate = (DLMS_BAUD_RATE)var_toInteger(value); + } + else if (index == 4) + { + object->proposedBaudrate = (DLMS_BAUD_RATE)var_toInteger(value); + } + else if (index == 5) + { + object->responseTime = (DLMS_LOCAL_PORT_RESPONSE_TIME)var_toInteger(value); + } + else if (index == 6) + { + bb_clear(&object->deviceAddress); + ret = bb_set2(&object->deviceAddress, value->byteArr, 0, bb_size(value->byteArr)); + } + else if (index == 7) + { + bb_clear(&object->password1); + ret = bb_set2(&object->password1, value->byteArr, 0, bb_size(value->byteArr)); + } + else if (index == 8) + { + bb_clear(&object->password2); + ret = bb_set2(&object->password2, value->byteArr, 0, bb_size(value->byteArr)); + } + else if (index == 9) + { + bb_clear(&object->password5); + ret = bb_set2(&object->password5, value->byteArr, 0, bb_size(value->byteArr)); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_IEC_LOCAL_PORT_SETUP +#ifndef DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP +int cosem_setIecTwistedPairSetup(gxIecTwistedPairSetup* object, unsigned char index, dlmsVARIANT* value) +{ + int pos, ret = 0; + dlmsVARIANT* tmp; + if (index == 2) + { + object->mode = var_toInteger(value); + } + else if (index == 3) + { + object->speed = var_toInteger(value); + } + else if (index == 4) + { + bb_clear(&object->primaryAddresses); + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + if ((ret = va_getByIndex(value->Arr, pos, &tmp)) != DLMS_ERROR_CODE_OK || + (ret = bb_setUInt8(&object->primaryAddresses, tmp->bVal)) != DLMS_ERROR_CODE_OK) + { + break; + } + } + } + } + else if (index == 5) + { + bb_clear(&object->tabis); + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + if ((ret = va_getByIndex(value->Arr, pos, &tmp)) != DLMS_ERROR_CODE_OK || + (ret = bb_setUInt8(&object->tabis, tmp->bVal)) != DLMS_ERROR_CODE_OK) + { + break; + } + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP + +#ifndef DLMS_IGNORE_IP4_SETUP +int cosem_setIP4Setup(dlmsSettings* settings, gxIp4Setup* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = 0, pos; + dlmsVARIANT* tmp, * tmp3; + gxip4SetupIpOption* ipItem = NULL; + if (index == 2) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = oa_findByLN(&settings->objects, DLMS_OBJECT_TYPE_NONE, value->byteArr->data, &object->dataLinkLayer)) != 0) + { + return ret; + } +#else + ret = bb_get(value->byteArr, object->dataLinkLayerReference, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + else if (index == 3) + { + object->ipAddress = var_toInteger(value); + } + else if (index == 4) + { + va_clear(&object->multicastIPAddress); + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + if ((ret = va_getByIndex(value->Arr, pos, &tmp)) != DLMS_ERROR_CODE_OK) + { + break; + } + tmp3 = (dlmsVARIANT*)gxmalloc(sizeof(dlmsVARIANT)); + + if ((ret = var_init(tmp3)) != 0 || + (ret = var_copy(tmp, tmp3)) != 0 || + (ret = va_push(&object->multicastIPAddress, tmp3)) != 0) + { + break; + } + } + } + } + else if (index == 5) + { + arr_clear(&object->ipOptions); + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ipItem = NULL; + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ipItem = (gxip4SetupIpOption*)gxmalloc(sizeof(gxip4SetupIpOption)); + if (ipItem == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + BYTE_BUFFER_INIT(&ipItem->data); + ipItem->type = (DLMS_IP_OPTION_TYPE)var_toInteger(tmp3); + ret = va_getByIndex(tmp->Arr, 1, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ipItem->length = (unsigned char)var_toInteger(tmp3); + ret = va_getByIndex(tmp->Arr, 2, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + bb_set(&ipItem->data, tmp3->byteArr->data, tmp3->byteArr->size); + arr_push(&object->ipOptions, ipItem); + } + if (ret != DLMS_ERROR_CODE_OK && ipItem != NULL) + { + gxfree(ipItem); + } + } + } + else if (index == 6) + { + object->subnetMask = var_toInteger(value); + } + else if (index == 7) + { + object->gatewayIPAddress = var_toInteger(value); + } + else if (index == 8) + { + object->useDHCP = value->boolVal; + } + else if (index == 9) + { + object->primaryDNSAddress = var_toInteger(value); + } + else if (index == 10) + { + object->secondaryDNSAddress = var_toInteger(value); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_IP4_SETUP + +#ifndef DLMS_IGNORE_IP6_SETUP +int cosem_setIP6Setup(dlmsSettings* settings, gxIp6Setup* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = 0, pos; + dlmsVARIANT* tmp, * tmp3; + IN6_ADDR* ip; + gxNeighborDiscoverySetup* it; + if (index == 2) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = oa_findByLN(&settings->objects, DLMS_OBJECT_TYPE_NONE, value->byteArr->data, &object->dataLinkLayer)) != 0) + { + return ret; + } +#else + ret = bb_get(value->byteArr, object->dataLinkLayerReference, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + else if (index == 3) + { + object->addressConfigMode = var_toInteger(value); + } + else if (index == 4) + { + arr_clear(&object->unicastIPAddress); + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + if ((ret = va_getByIndex(value->Arr, pos, &tmp)) != DLMS_ERROR_CODE_OK) + { + break; + } + if (tmp->byteArr->size != 16) + { + ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + break; + } + ip = (IN6_ADDR*)gxmalloc(sizeof(IN6_ADDR)); + memcpy(ip, tmp->byteArr->data, tmp->byteArr->size); + if ((ret = arr_push(&object->unicastIPAddress, ip)) != 0) + { + break; + } + } + } + } + else if (index == 5) + { + arr_clear(&object->multicastIPAddress); + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + if ((ret = va_getByIndex(value->Arr, pos, &tmp)) != DLMS_ERROR_CODE_OK) + { + break; + } + if (tmp->byteArr->size != 16) + { + ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + break; + } + ip = (IN6_ADDR*)gxmalloc(sizeof(IN6_ADDR)); + memcpy(ip, tmp->byteArr->data, tmp->byteArr->size); + if ((ret = arr_push(&object->multicastIPAddress, ip)) != 0) + { + break; + } + } + } + } + else if (index == 6) + { + arr_clear(&object->gatewayIPAddress); + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + if ((ret = va_getByIndex(value->Arr, pos, &tmp)) != DLMS_ERROR_CODE_OK) + { + break; + } + if (tmp->byteArr->size != 16) + { + ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + break; + } + ip = (IN6_ADDR*)gxmalloc(sizeof(IN6_ADDR)); + memcpy(ip, tmp->byteArr->data, tmp->byteArr->size); + if ((ret = arr_push(&object->gatewayIPAddress, ip)) != 0) + { + break; + } + } + } + } + else if (index == 7) + { + if (bb_size(value->byteArr) == 0) + { + memset(&object->primaryDNSAddress, 0, sizeof(IN6_ADDR)); + } + else if (bb_size(value->byteArr) != 16) + { + ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } + else + { + memcpy(&object->primaryDNSAddress, value->byteArr->data, value->byteArr->size); + } + } + else if (index == 8) + { + if (bb_size(value->byteArr) == 0) + { + memset(&object->secondaryDNSAddress, 0, sizeof(IN6_ADDR)); + } + else if (bb_size(value->byteArr) != 16) + { + ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } + else + { + memcpy(&object->secondaryDNSAddress, value->byteArr->data, value->byteArr->size); + } + } + else if (index == 9) + { + object->trafficClass = (DLMS_IP6_ADDRESS_CONFIG_MODE)var_toInteger(value); + } + else if (index == 10) + { + arr_clear(&object->neighborDiscoverySetup); + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + if ((ret = va_getByIndex(value->Arr, pos, &tmp)) != DLMS_ERROR_CODE_OK) + { + break; + } + it = (gxNeighborDiscoverySetup*)gxmalloc(sizeof(gxNeighborDiscoverySetup)); + if (it == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + if ((ret = va_getByIndex(tmp->Arr, 0, &tmp3)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->maxRetry = (unsigned char)var_toInteger(tmp3); + if ((ret = va_getByIndex(tmp->Arr, 1, &tmp3)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->retryWaitTime = (uint16_t)var_toInteger(tmp3); + if ((ret = va_getByIndex(tmp->Arr, 2, &tmp3)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->sendPeriod = var_toInteger(tmp3); + if ((ret = arr_push(&object->neighborDiscoverySetup, it)) != 0) + { + break; + } + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_IP6_SETUP +#ifndef DLMS_IGNORE_UTILITY_TABLES +int cosem_setUtilityTables(gxUtilityTables* object, unsigned char index, dlmsVARIANT* value) +{ + if (index == 2) + { + object->tableId = (uint16_t)var_toInteger(value); + } + else if (index == 3) + { + //Skip length. + } + else if (index == 4) + { + bb_clear(&object->buffer); + bb_set2(&object->buffer, value->byteArr, 0, bb_size(value->byteArr)); + } + else + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return DLMS_ERROR_CODE_OK; +} +#endif //DLMS_IGNORE_UTILITY_TABLES + +#ifndef DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP +int cosem_setMbusSlavePortSetup(gxMbusSlavePortSetup* object, unsigned char index, dlmsVARIANT* value) +{ + if (index == 2) + { + object->defaultBaud = (DLMS_BAUD_RATE)var_toInteger(value); + } + else if (index == 3) + { + object->availableBaud = (DLMS_BAUD_RATE)var_toInteger(value); + } + else if (index == 4) + { + object->addressState = (DLMS_ADDRESS_STATE)var_toInteger(value); + } + else if (index == 5) + { + object->busAddress = (unsigned char)var_toInteger(value); + } + else + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return DLMS_ERROR_CODE_OK; +} +#endif //DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP +#ifndef DLMS_IGNORE_DISCONNECT_CONTROL +int cosem_setDisconnectControl(gxDisconnectControl* object, unsigned char index, dlmsVARIANT* value) +{ + if (index == 2) + { + object->outputState = value->boolVal; + } + else if (index == 3) + { + object->controlState = (DLMS_CONTROL_STATE)var_toInteger(value); + } + else if (index == 4) + { + object->controlMode = (DLMS_CONTROL_MODE)var_toInteger(value); + } + else + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return DLMS_ERROR_CODE_OK; +} +#endif //DLMS_IGNORE_DISCONNECT_CONTROL +#ifndef DLMS_IGNORE_LIMITER +int cosem_setLimiter(dlmsSettings* settings, gxLimiter* object, unsigned char index, dlmsVARIANT* value) +{ + DLMS_OBJECT_TYPE ot; + int ret = DLMS_ERROR_CODE_OK, pos; + dlmsVARIANT* tmp, * tmp3; + dlmsVARIANT tmp2; + if (index == 2) + { + if (value->vt != DLMS_DATA_TYPE_STRUCTURE) + { +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + ret = va_getByIndex(value->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ot = (DLMS_OBJECT_TYPE)var_toInteger(tmp); + //Get LN. + ret = va_getByIndex(value->Arr, 1, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + //Get attribute index. + ret = va_getByIndex(value->Arr, 2, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->selectedAttributeIndex = (unsigned char)var_toInteger(tmp); + if (ot != 0) + { + if ((ret = oa_findByLN(&settings->objects, ot, tmp3->byteArr->data, &object->monitoredValue)) == 0 && + object->monitoredValue == NULL) + { + if ((ret = cosem_createObject(ot, &object->monitoredValue)) != 0) + { + return ret; + } + memcpy(object->monitoredValue->logicalName, tmp3->byteArr->data, tmp3->byteArr->size); + //Add object to released objects list. + ret = oa_push(&settings->releasedObjects, object->monitoredValue); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + } + } + else + { + object->monitoredValue = NULL; + } + } + else if (index == 3) + { + ret = var_copy(&object->thresholdActive, value); + } + else if (index == 4) + { + ret = var_copy(&object->thresholdNormal, value); + } + else if (index == 5) + { + ret = var_copy(&object->thresholdEmergency, value); + } + else if (index == 6) + { + object->minOverThresholdDuration = var_toInteger(value); + } + else if (index == 7) + { + object->minUnderThresholdDuration = var_toInteger(value); + } + else if (index == 8) + { + ret = va_getByIndex(value->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->emergencyProfile.id = (uint16_t)var_toInteger(tmp); + ret = va_getByIndex(value->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = var_init(&tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = dlms_changeType2(tmp, DLMS_DATA_TYPE_DATETIME, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + time_copy(&object->emergencyProfile.activationTime, tmp2.dateTime); + var_clear(&tmp2); + ret = va_getByIndex(value->Arr, 2, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->emergencyProfile.duration = var_toInteger(tmp); + } + else if (index == 9) + { + va_clear(&object->emergencyProfileGroupIDs); + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + tmp3 = (dlmsVARIANT*)gxmalloc(sizeof(dlmsVARIANT)); + var_init(tmp3); + ret = var_copy(tmp3, tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + va_push(&object->emergencyProfileGroupIDs, tmp3); + } + } + } + else if (index == 10) + { + object->emergencyProfileActive = value->boolVal; + } + else if (index == 11) + { + ret = va_getByIndex(value->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = oa_findByLN(&settings->objects, DLMS_OBJECT_TYPE_SCRIPT_TABLE, tmp3->byteArr->data, (gxObject**)&object->actionOverThreshold.script)) != 0) + { + return ret; + } + if (object->actionOverThreshold.script == NULL) + { + if ((ret = cosem_createObject(DLMS_OBJECT_TYPE_SCRIPT_TABLE, (gxObject**)&object->actionOverThreshold.script)) != 0) + { + return ret; + } + memcpy(object->actionOverThreshold.script->base.logicalName, tmp3->byteArr->data, tmp3->byteArr->size); + //Add object to released objects list. + ret = oa_push(&settings->releasedObjects, (gxObject*)object->actionOverThreshold.script); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + } +#else + memcpy(object->actionOverThreshold.logicalName, tmp3->byteArr->data, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + ret = va_getByIndex(tmp->Arr, 1, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->actionOverThreshold.scriptSelector = (uint16_t)var_toInteger(tmp3); + + ret = va_getByIndex(value->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = oa_findByLN(&settings->objects, DLMS_OBJECT_TYPE_SCRIPT_TABLE, tmp3->byteArr->data, (gxObject**)&object->actionUnderThreshold.script)) != 0) + { + return ret; + } + if (object->actionUnderThreshold.script == NULL) + { + if ((ret = cosem_createObject(DLMS_OBJECT_TYPE_SCRIPT_TABLE, (gxObject**)&object->actionUnderThreshold.script)) != 0) + { + return ret; + } + memcpy(object->actionUnderThreshold.script->base.logicalName, tmp3->byteArr->data, tmp3->byteArr->size); + //Add object to released objects list. + ret = oa_push(&settings->releasedObjects, (gxObject*)object->actionUnderThreshold.script); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + } +#else + memcpy(object->actionUnderThreshold.logicalName, tmp3->byteArr->data, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + ret = va_getByIndex(tmp->Arr, 1, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->actionUnderThreshold.scriptSelector = (uint16_t)var_toInteger(tmp3); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_LIMITER +#ifndef DLMS_IGNORE_MBUS_CLIENT +int cosem_setmMbusClient(dlmsSettings* settings, gxMBusClient* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = DLMS_ERROR_CODE_OK, pos; + if (index == 2) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = oa_findByLN(&settings->objects, DLMS_OBJECT_TYPE_MBUS_MASTER_PORT_SETUP, value->byteArr->data, &object->mBusPort)) != 0) + { + return ret; + } + if (object->mBusPort == NULL) + { + if ((ret = cosem_createObject(DLMS_OBJECT_TYPE_MBUS_MASTER_PORT_SETUP, &object->mBusPort)) != 0) + { + return ret; + } + memcpy(object->mBusPort->logicalName, value->byteArr->data, value->byteArr->size); + //Add object to released objects list. + ret = oa_push(&settings->releasedObjects, object->mBusPort); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + } +#else + ret = bb_get(value->byteArr, object->mBusPortReference, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + else if (index == 3) + { + arr_clearKeyValuePair(&object->captureDefinition); + dlmsVARIANT* tmp, * tmp3; + gxByteBuffer* start, * end; + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + start = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + end = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + BYTE_BUFFER_INIT(start); + BYTE_BUFFER_INIT(end); + bb_set(start, tmp3->byteArr->data, tmp3->byteArr->size); + ret = va_getByIndex(tmp->Arr, 1, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + gxfree(start); + gxfree(end); + break; + } + bb_set(end, tmp3->byteArr->data, tmp3->byteArr->size); + arr_push(&object->captureDefinition, key_init(start, end)); + } + } + } + else if (index == 4) + { + object->capturePeriod = var_toInteger(value); + } + else if (index == 5) + { + object->primaryAddress = (unsigned char)var_toInteger(value); + } + else if (index == 6) + { + object->identificationNumber = var_toInteger(value); + } + else if (index == 7) + { + object->manufacturerID = (uint16_t)var_toInteger(value); + } + else if (index == 8) + { + object->dataHeaderVersion = (unsigned char)var_toInteger(value); + } + else if (index == 9) + { + object->deviceType = (unsigned char)var_toInteger(value); + } + else if (index == 10) + { + object->accessNumber = (unsigned char)var_toInteger(value); + } + else if (index == 11) + { + object->status = (unsigned char)var_toInteger(value); + } + else if (index == 12) + { + object->alarm = (unsigned char)var_toInteger(value); + } + else if (index == 13 && object->base.version != 0) + { + object->configuration = (uint16_t)var_toInteger(value); + } + else if (index == 14 && object->base.version != 0) + { + object->encryptionKeyStatus = (DLMS_MBUS_ENCRYPTION_KEY_STATUS)var_toInteger(value); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} + +#endif //DLMS_IGNORE_MBUS_CLIENT +#ifndef DLMS_IGNORE_MODEM_CONFIGURATION +int cosem_setModemConfiguration(gxModemConfiguration* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = 0, pos; + gxModemInitialisation* modemInit; + dlmsVARIANT* tmp, * tmp3; + gxByteBuffer* str; + if (index == 2) + { + object->communicationSpeed = (DLMS_BAUD_RATE)var_toInteger(value); + } + else if (index == 3) + { + obj_clearModemConfigurationInitialisationStrings(&object->initialisationStrings); + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + modemInit = (gxModemInitialisation*)gxmalloc(sizeof(gxModemInitialisation)); + if (modemInit == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + BYTE_BUFFER_INIT(&modemInit->request); + BYTE_BUFFER_INIT(&modemInit->response); + bb_set(&modemInit->request, tmp3->byteArr->data, tmp3->byteArr->size); + ret = va_getByIndex(tmp->Arr, 1, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + bb_set(&modemInit->response, tmp3->byteArr->data, tmp3->byteArr->size); + if (tmp->Arr->size > 2) + { + ret = va_getByIndex(tmp->Arr, 2, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + modemInit->delay = tmp3->uiVal; + } + arr_push(&object->initialisationStrings, modemInit); + } + } + } + else if (index == 4) + { + arr_clearStrings(&object->modemProfile); + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + str = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + BYTE_BUFFER_INIT(str); + bb_set2(str, tmp->byteArr, 0, bb_size(tmp->byteArr)); + arr_push(&object->modemProfile, str); + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_MODEM_CONFIGURATION +#ifndef DLMS_IGNORE_PPP_SETUP +int cosem_setPppSetup(dlmsSettings* settings, gxPppSetup* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = DLMS_ERROR_CODE_OK, pos; + gxpppSetupLcpOption* lcpItem = NULL; + gxpppSetupIPCPOption* ipcpItem = NULL; + dlmsVARIANT* tmp; + dlmsVARIANT* tmp3; + if (index == 2) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = oa_findByLN(&settings->objects, DLMS_OBJECT_TYPE_NONE, value->byteArr->data, &object->phy)) != 0) + { + return ret; + } + if (object->phy == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + } +#else + ret = bb_get(value->byteArr, object->PHYReference, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + else if (index == 3) + { + arr_clear(&object->lcpOptions); + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + lcpItem = NULL; + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + lcpItem = (gxpppSetupLcpOption*)gxmalloc(sizeof(gxpppSetupLcpOption)); + if (lcpItem == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + var_init(&lcpItem->data); + lcpItem->type = (DLMS_PPP_SETUP_LCP_OPTION_TYPE)var_toInteger(tmp3); + ret = va_getByIndex(tmp->Arr, 1, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + lcpItem->length = (unsigned char)var_toInteger(tmp3); + ret = va_getByIndex(tmp->Arr, 2, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = var_copy(&lcpItem->data, tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + arr_push(&object->lcpOptions, lcpItem); + } + if (ret != 0 && lcpItem != NULL) + { + gxfree(lcpItem); + } + } + } + else if (index == 4) + { + arr_clear(&object->ipcpOptions); + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ipcpItem = (gxpppSetupIPCPOption*)gxmalloc(sizeof(gxpppSetupIPCPOption)); + if (ipcpItem == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + var_init(&ipcpItem->data); + ipcpItem->type = (DLMS_PPP_SETUP_IPCP_OPTION_TYPE)var_toInteger(tmp3); + ret = va_getByIndex(tmp->Arr, 1, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ipcpItem->length = (unsigned char)var_toInteger(tmp3); + ret = va_getByIndex(tmp->Arr, 2, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = var_copy(&ipcpItem->data, tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + arr_push(&object->ipcpOptions, ipcpItem); + } + if (ret != 0 && ipcpItem != NULL) + { + gxfree(ipcpItem); + } + } + } + else if (index == 5) + { + if (value->Arr == NULL || value->Arr->size == 0) + { + bb_clear(&object->userName); + bb_clear(&object->password); + } + else if (value->Arr->size == 2) + { + //Get user name. + ret = va_getByIndex(value->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + bb_clear(&object->userName); + bb_set2(&object->userName, tmp->byteArr, 0, bb_size(tmp->byteArr)); + //Get password. + ret = va_getByIndex(value->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + bb_clear(&object->password); + bb_set2(&object->password, tmp->byteArr, 0, bb_size(tmp->byteArr)); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_PPP_SETUP +#ifndef DLMS_IGNORE_REGISTER_ACTIVATION +int cosem_setRegisterActivation(dlmsSettings* settings, + gxValueEventArg* e) +{ + int ret = 0, pos; + gxRegisterActivation* object = (gxRegisterActivation*)e->target; + unsigned char index = e->index; + dlmsVARIANT* value = &e->value; +#ifdef DLMS_IGNORE_OBJECT_POINTERS + gxObjectDefinition* objectDefinition; +#else + gxObject* objectDefinition; +#endif //DLMS_IGNORE_OBJECT_POINTERS + if (index == 2) + { + obj_clearRegisterActivationAssignment(&object->registerAssignment); + dlmsVARIANT* tmp, * tmp3; + if (value->Arr != NULL) + { + short type; + for (pos = 0; pos != value->Arr->size; ++pos) + { + objectDefinition = NULL; + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + type = (short)var_toInteger(tmp3); + ret = va_getByIndex(tmp->Arr, 1, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + unsigned char* ln = tmp3->byteArr->data; +#ifdef DLMS_IGNORE_OBJECT_POINTERS + objectDefinition = (gxObjectDefinition*)gxmalloc(sizeof(gxObjectDefinition)); + objectDefinition->objectType = (DLMS_OBJECT_TYPE)type; + memcpy(objectDefinition->logicalName, ln, 6); + arr_push(&object->registerAssignment, objectDefinition); +#else + if (type != 0) + { + if ((ret = cosem_findObjectByLN(settings, type, ln, &objectDefinition)) != 0) + { + break; + } + oa_push(&object->registerAssignment, objectDefinition); + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + } +#ifdef DLMS_IGNORE_OBJECT_POINTERS + if (ret != 0 && objectDefinition != NULL) + { + gxfree(objectDefinition); + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + } + else if (index == 3) + { + obj_clearRegisterActivationMaskList(&object->maskList); + int pos2; + gxByteBuffer* start = NULL, * end = NULL; + dlmsVARIANT* tmp, * tmp3; + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + if ((ret = va_getByIndex(value->Arr, pos, &tmp)) != DLMS_ERROR_CODE_OK) + { + break; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + start = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + BYTE_BUFFER_INIT(start); + end = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + BYTE_BUFFER_INIT(end); + bb_set(start, tmp3->byteArr->data, tmp3->byteArr->size); + ret = va_getByIndex(tmp->Arr, 1, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + for (pos2 = 0; pos2 != tmp3->Arr->size; ++pos2) + { + if ((ret = va_getByIndex(tmp3->Arr, pos2, &tmp)) != 0 || + (ret = bb_setUInt8(end, (unsigned char)var_toInteger(tmp))) != 0) + { + break; + } + } + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + arr_push(&object->maskList, key_init(start, end)); + } + if (ret != 0) + { + if (start != NULL) + { + gxfree(start); + } + if (end != NULL) + { + gxfree(end); + } + } + } + } + else if (index == 4) + { + bb_clear(&object->activeMask); + ret = bb_set2(&object->activeMask, value->byteArr, 0, bb_size(value->byteArr)); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_REGISTER_ACTIVATION +#ifndef DLMS_IGNORE_REGISTER_MONITOR +int cosem_setRegisterMonitor(dlmsSettings* settings, gxRegisterMonitor* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = 0, pos; + gxActionSet* actionSet = NULL; + dlmsVARIANT* tmp; + dlmsVARIANT* tmp3, * tmp4; + if (index == 2) + { + va_clear(&object->thresholds); + if (value->Arr != NULL) + { + va_capacity(&object->thresholds, value->Arr->size); + for (pos = 0; pos != value->Arr->size; ++pos) + { + tmp3 = NULL; + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + tmp3 = (dlmsVARIANT*)gxmalloc(sizeof(dlmsVARIANT)); + if (tmp3 == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + var_init(tmp3); + ret = var_copy(tmp3, tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + va_push(&object->thresholds, tmp3); + } + } + } + else if (index == 3) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + signed short type; +#endif //DLMS_IGNORE_OBJECT_POINTERS + ret = va_getByIndex(value->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + type = (short)var_toInteger(tmp); +#else + object->monitoredValue.objectType = (DLMS_OBJECT_TYPE)var_toInteger(tmp); +#endif //DLMS_IGNORE_OBJECT_POINTERS + + ret = va_getByIndex(value->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = oa_findByLN(&settings->objects, type, tmp->byteArr->data, &object->monitoredValue.target)) != 0) + { + return ret; + } + if (object->monitoredValue.target == NULL) + { + ret = cosem_createObject(type, &object->monitoredValue.target); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = cosem_setLogicalName(object->monitoredValue.target, tmp->byteArr->data); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + //Add object to released objects list. + ret = oa_push(&settings->releasedObjects, object->monitoredValue.target); + } +#else + memcpy(object->monitoredValue.logicalName, tmp->byteArr->data, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + ret = va_getByIndex(value->Arr, 2, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->monitoredValue.attributeIndex = (unsigned char)var_toInteger(tmp); + } + else if (index == 4) + { + obj_clearRegisterMonitorActions(&object->actions); + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + actionSet = NULL; + ret = va_getByIndex(value->Arr, pos, &tmp4); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + actionSet = (gxActionSet*)gxmalloc(sizeof(gxActionSet)); + //Update action up. + ret = va_getByIndex(tmp4->Arr, 0, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = va_getByIndex(tmp3->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + actionSet->actionUp.script = NULL; + if ((ret = oa_findByLN(&settings->objects, DLMS_OBJECT_TYPE_SCRIPT_TABLE, tmp->byteArr->data, (gxObject**)&actionSet->actionUp.script)) != 0) + { + return ret; + } + if (actionSet->actionUp.script == NULL) + { + ret = cosem_createObject(DLMS_OBJECT_TYPE_SCRIPT_TABLE, (gxObject**)&actionSet->actionUp.script); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = cosem_setLogicalName((gxObject*)actionSet->actionUp.script, tmp->byteArr->data); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + //Add object to released objects list. + ret = oa_push(&settings->releasedObjects, (gxObject*)actionSet->actionUp.script); + } +#else + memcpy(actionSet->actionUp.logicalName, tmp->byteArr->data, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + ret = va_getByIndex(tmp3->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + actionSet->actionUp.scriptSelector = (uint16_t)var_toInteger(tmp); + //Update action down. + ret = va_getByIndex(tmp4->Arr, 1, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = va_getByIndex(tmp3->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + actionSet->actionDown.script = NULL; + if ((ret = oa_findByLN(&settings->objects, DLMS_OBJECT_TYPE_SCRIPT_TABLE, tmp->byteArr->data, (gxObject**)&actionSet->actionDown.script)) != 0) + { + return ret; + } + if (actionSet->actionDown.script == NULL) + { + ret = cosem_createObject(DLMS_OBJECT_TYPE_SCRIPT_TABLE, (gxObject**)&actionSet->actionDown.script); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = cosem_setLogicalName((gxObject*)actionSet->actionDown.script, tmp->byteArr->data); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + //Add object to released objects list. + ret = oa_push(&settings->releasedObjects, (gxObject*)actionSet->actionDown.script); + } +#else + memcpy(actionSet->actionDown.logicalName, tmp->byteArr->data, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + ret = va_getByIndex(tmp3->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + actionSet->actionDown.scriptSelector = (uint16_t)var_toInteger(tmp); + arr_push(&object->actions, actionSet); + } + if (ret != 0 && actionSet != NULL) + { + gxfree(actionSet); + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} + +#endif //DLMS_IGNORE_REGISTER_MONITOR +#ifndef DLMS_IGNORE_SAP_ASSIGNMENT +int cosem_setSapAssignment(gxSapAssignment* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = DLMS_ERROR_CODE_OK, pos; + gxSapItem* it = NULL; + if (index == 2) + { + obj_clearSapList(&object->sapAssignmentList); + dlmsVARIANT* tmp, * tmp2; + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + it = NULL; + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + it = (gxSapItem*)gxmalloc(sizeof(gxSapItem)); + if (it == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + BYTE_BUFFER_INIT(&it->name); + it->id = (uint16_t)var_toInteger(tmp2); + ret = va_getByIndex(tmp->Arr, 1, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + bb_set(&it->name, tmp2->byteArr->data, tmp2->byteArr->size); + arr_push(&object->sapAssignmentList, it); + } + if (ret != 0 && it != NULL) + { + gxfree(it); + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SAP_ASSIGNMENT +#ifndef DLMS_IGNORE_SCHEDULE +int cosem_setSchedule(dlmsSettings* settings, gxSchedule* object, unsigned char index, dlmsVARIANT* value) +{ + gxScheduleEntry* se; + int ret = 0, pos; + if (index == 2) + { + obj_clearScheduleEntries(&object->entries); + dlmsVARIANT* tmp, * it; + dlmsVARIANT tmp3; + var_init(&tmp3); + if (value->Arr != NULL) + { + se = NULL; + for (pos = 0; pos != value->Arr->size; ++pos) + { + se = NULL; + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + se = (gxScheduleEntry*)gxmalloc(sizeof(gxScheduleEntry)); + if (se == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + se->execWeekdays = 0; + ba_init(&se->execSpecDays); + ret = va_getByIndex(tmp->Arr, 0, &it); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + se->index = (uint16_t)var_toInteger(it); + ret = va_getByIndex(tmp->Arr, 1, &it); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + se->enable = (unsigned char)var_toInteger(it); + + ret = va_getByIndex(tmp->Arr, 2, &it); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = oa_findByLN(&settings->objects, DLMS_OBJECT_TYPE_SCRIPT_TABLE, it->byteArr->data, (gxObject**)&se->scriptTable)) != 0) + { + break; + } + if (se->scriptTable == NULL) + { + ret = cosem_createObject(DLMS_OBJECT_TYPE_SCRIPT_TABLE, (gxObject**)&se->scriptTable); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = cosem_setLogicalName((gxObject*)se->scriptTable, tmp->byteArr->data); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + //Add object to released objects list. + ret = oa_push(&settings->releasedObjects, (gxObject*)se->scriptTable); + } +#else + memcpy(se->logicalName, it->byteArr->data, bb_size(it->byteArr)); +#endif //DLMS_IGNORE_OBJECT_POINTERS + ret = va_getByIndex(tmp->Arr, 3, &it); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + se->scriptSelector = (uint16_t)var_toInteger(it); + ret = va_getByIndex(tmp->Arr, 4, &it); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = dlms_changeType2(it, DLMS_DATA_TYPE_TIME, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + time_copy(&se->switchTime, tmp3.dateTime); + ret = va_getByIndex(tmp->Arr, 5, &it); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + se->validityWindow = (uint16_t)var_toInteger(it); + + ret = va_getByIndex(tmp->Arr, 6, &it); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + if (it->bitArr != NULL) + { + uint32_t val; + if ((ret = ba_toInteger(it->bitArr, &val)) == 0) + { + se->execWeekdays = val; + } + } + ret = va_getByIndex(tmp->Arr, 7, &it); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + if (it->bitArr != NULL) + { + ba_copy(&se->execSpecDays, it->bitArr->data, (uint16_t)it->bitArr->size); + } + ret = va_getByIndex(tmp->Arr, 8, &it); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = dlms_changeType2(it, DLMS_DATA_TYPE_DATE, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + time_copy(&se->beginDate, tmp3.dateTime); + var_clear(&tmp3); + ret = va_getByIndex(tmp->Arr, 9, &it); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = dlms_changeType2(it, DLMS_DATA_TYPE_DATE, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + time_copy(&se->endDate, tmp3.dateTime); + arr_push(&object->entries, se); + var_clear(&tmp3); + } + if (ret != 0 && se != NULL) + { + gxfree(se); + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SCHEDULE + +#ifndef DLMS_IGNORE_SCRIPT_TABLE +int cosem_setScriptTable(dlmsSettings* settings, gxScriptTable* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = 0, pos, pos2; + gxScriptAction* scriptAction; + gxScript* script; + if (index == 2) + { + obj_clearScriptTable(&object->scripts); +#ifndef DLMS_IGNORE_OBJECT_POINTERS + uint16_t type; +#endif //DLMS_IGNORE_OBJECT_POINTERS + dlmsVARIANT* tmp, * tmp2, * tmp3; + if (value->Arr->size != 0) + { + script = NULL; + ret = va_getByIndex(value->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + //Fix Xemex bug here. + //Xemex meters do not return array as they should be according standard. + if (value->vt == DLMS_DATA_TYPE_ARRAY) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + script = NULL; + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + script = (gxScript*)gxmalloc(sizeof(gxScript)); + if (script == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + arr_init(&script->actions); + script->id = (uint16_t)var_toInteger(tmp3); + arr_push(&object->scripts, script); + ret = va_getByIndex(tmp->Arr, 1, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + scriptAction = NULL; + for (pos2 = 0; pos2 != tmp3->Arr->size; ++pos2) + { + scriptAction = NULL; + ret = va_getByIndex(tmp3->Arr, pos2, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = va_getByIndex(tmp2->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + scriptAction = (gxScriptAction*)gxmalloc(sizeof(gxScriptAction)); + if (scriptAction == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + var_init(&scriptAction->parameter); + scriptAction->type = (DLMS_SCRIPT_ACTION_TYPE)var_toInteger(tmp); + ret = va_getByIndex(tmp2->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } +#ifdef DLMS_IGNORE_OBJECT_POINTERS + scriptAction->objectType = (DLMS_OBJECT_TYPE)var_toInteger(tmp); +#else + type = (DLMS_OBJECT_TYPE)var_toInteger(tmp); +#endif //DLMS_IGNORE_OBJECT_POINTERS + ret = va_getByIndex(tmp2->Arr, 2, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } +#ifdef DLMS_IGNORE_OBJECT_POINTERS + if (bb_size(tmp->byteArr) == 6) + { + memcpy(scriptAction->logicalName, tmp->byteArr->data, 6); + } +#else + if ((ret = oa_findByLN(&settings->objects, type, tmp->byteArr->data, &scriptAction->target)) != 0) + { + break; + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + ret = va_getByIndex(tmp2->Arr, 3, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + scriptAction->index = (char)var_toInteger(tmp); + ret = va_getByIndex(tmp2->Arr, 4, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + var_copy(&scriptAction->parameter, tmp); + arr_push(&script->actions, scriptAction); + } + if (ret != DLMS_ERROR_CODE_OK) + { + if (scriptAction != NULL) + { + gxfree(scriptAction); + } + break; + } + } + if (ret != 0 && script != NULL) + { + gxfree(script); + } + } + else //Read Xemex meter here. + { + ret = va_getByIndex(value->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = va_getByIndex(tmp->Arr, 1, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = va_getByIndex(tmp2->Arr, 2, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + script = (gxScript*)gxmalloc(sizeof(gxScript)); + if (script == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + arr_init(&script->actions); + script->id = (uint16_t)var_toInteger(tmp3); + arr_push(&object->scripts, script); + ret = va_getByIndex(tmp->Arr, 3, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + scriptAction = (gxScriptAction*)gxmalloc(sizeof(gxScriptAction)); + if (scriptAction == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + var_init(&scriptAction->parameter); + scriptAction->type = (DLMS_SCRIPT_ACTION_TYPE)var_toInteger(tmp3); + ret = va_getByIndex(tmp2->Arr, 4, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + +#ifdef DLMS_IGNORE_OBJECT_POINTERS + scriptAction->objectType = (DLMS_OBJECT_TYPE)var_toInteger(tmp3); +#else + type = (uint16_t)var_toInteger(tmp3); +#endif //DLMS_IGNORE_OBJECT_POINTERS + ret = va_getByIndex(tmp2->Arr, 5, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } +#ifdef DLMS_IGNORE_OBJECT_POINTERS + memcpy(scriptAction->logicalName, tmp3->byteArr->data, 6); +#else + if ((ret = oa_findByLN(&settings->objects, type, tmp3->byteArr->data, &scriptAction->target)) != 0) + { + return ret; + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + ret = va_getByIndex(tmp2->Arr, 6, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + scriptAction->index = (char)var_toInteger(tmp3); + ret = va_getByIndex(tmp2->Arr, 7, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + var_copy(&scriptAction->parameter, tmp); + arr_push(&script->actions, scriptAction); + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SCRIPT_TABLE +#ifndef DLMS_IGNORE_SPECIAL_DAYS_TABLE +int cosem_setSpecialDaysTable(gxSpecialDaysTable* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = 0, pos; + gxSpecialDay* specialDay; + if (index == 2) + { + arr_clear(&object->entries); + dlmsVARIANT* tmp, * tmp3; + dlmsVARIANT tmp2; + if (value->Arr != NULL) + { + specialDay = NULL; + for (pos = 0; pos != value->Arr->size; ++pos) + { + specialDay = NULL; + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + specialDay = (gxSpecialDay*)gxmalloc(sizeof(gxSpecialDay)); + if (specialDay == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + specialDay->index = (uint16_t)var_toInteger(tmp3); + ret = va_getByIndex(tmp->Arr, 1, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + var_init(&tmp2); + ret = dlms_changeType2(tmp3, DLMS_DATA_TYPE_DATE, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + time_copy(&specialDay->date, tmp2.dateTime); + var_clear(&tmp2); + ret = va_getByIndex(tmp->Arr, 2, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + specialDay->dayId = (unsigned char)var_toInteger(tmp3); + arr_push(&object->entries, specialDay); + } + if (ret != 0 && specialDay != NULL) + { + gxfree(specialDay); + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SPECIAL_DAYS_TABLE +#ifndef DLMS_IGNORE_TCP_UDP_SETUP +int cosem_setTcpUdpSetup(dlmsSettings* settings, gxTcpUdpSetup* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = 0; + if (index == 2) + { + object->port = (uint16_t)var_toInteger(value); + } + else if (index == 3) + { + if (value->vt == DLMS_DATA_TYPE_NONE) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + object->ipSetup = NULL; +#else + memset(object->ipReference, 0, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + else + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; + if ((ret = bb_get(value->byteArr, ln, 6)) != 0 || + (ret = oa_findByLN(&settings->objects, DLMS_OBJECT_TYPE_IP4_SETUP, ln, &object->ipSetup)) != 0) + { + + } +#else + ret = bb_get(value->byteArr, object->ipReference, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + } + else if (index == 4) + { + object->maximumSegmentSize = (uint16_t)var_toInteger(value); + } + else if (index == 5) + { + object->maximumSimultaneousConnections = (unsigned char)var_toInteger(value); + } + else if (index == 6) + { + object->inactivityTimeout = (uint16_t)var_toInteger(value); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_TCP_UDP_SETUP + +#ifndef DLMS_IGNORE_MBUS_DIAGNOSTIC +int cosem_setMbusDiagnostic(gxMbusDiagnostic* object, unsigned char index, dlmsVARIANT* value) +{ + int pos, ret = 0; + dlmsVARIANT* tmp, * tmp3; + gxBroadcastFrameCounter* item; + if (index == 2) + { + object->receivedSignalStrength = (unsigned char)var_toInteger(value); + } + else if (index == 3) + { + object->channelId = (unsigned char)var_toInteger(value); + } + else if (index == 4) + { + object->linkStatus = (DLMS_MBUS_LINK_STATUS)var_toInteger(value); + } + else if (index == 5) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + item = NULL; + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + item = (gxBroadcastFrameCounter*)gxmalloc(sizeof(gxBroadcastFrameCounter)); + if (item == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + gxfree(item); + break; + } + item->clientId = (unsigned char)var_toInteger(tmp3); + ret = va_getByIndex(tmp->Arr, 1, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + gxfree(item); + break; + } + item->counter = tmp3->ulVal; + ret = va_getByIndex(tmp->Arr, 2, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + gxfree(item); + break; + } + item->timeStamp = *tmp3->dateTime; + arr_push(&object->broadcastFrames, item); + } + } + else if (index == 6) + { + object->transmissions = value->ulVal; + } + else if (index == 7) + { + object->receivedFrames = value->ulVal; + } + else if (index == 8) + { + object->failedReceivedFrames = value->ulVal; + } + else if (index == 9) + { + if ((ret = va_getByIndex(value->Arr, 0, &tmp)) == DLMS_ERROR_CODE_OK) + { + object->captureTime.attributeId = tmp->bVal; + if ((ret = va_getByIndex(value->Arr, 1, &tmp)) == DLMS_ERROR_CODE_OK) + { + object->captureTime.timeStamp = *tmp->dateTime; + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_MBUS_DIAGNOSTIC + + +#ifndef DLMS_IGNORE_MBUS_PORT_SETUP +int cosem_setMbusPortSetup(gxMBusPortSetup* object, unsigned char index, dlmsVARIANT* value) +{ + int pos, ret = 0; + dlmsVARIANT* tmp, * tmp3; + if (index == 2) + { + memcpy(object->profileSelection, value->byteArr->data, value->byteArr->size); + } + else if (index == 3) + { + object->portCommunicationStatus = (DLMS_MBUS_PORT_COMMUNICATION_STATE)var_toInteger(value); + } + else if (index == 4) + { + object->dataHeaderType = (DLMS_MBUS_DATA_HEADER_TYPE)var_toInteger(value); + } + else if (index == 5) + { + object->primaryAddress = (unsigned char)var_toInteger(value); + } + else if (index == 6) + { + object->identificationNumber = (uint32_t)var_toInteger(value); + } + else if (index == 7) + { + object->manufacturerId = (uint16_t)var_toInteger(value); + } + else if (index == 8) + { + object->mBusVersion = (unsigned char)var_toInteger(value); + } + else if (index == 9) + { + object->deviceType = (DLMS_MBUS_METER_TYPE)var_toInteger(value); + } + else if (index == 10) + { + object->maxPduSize = (uint16_t)var_toInteger(value); + } + else if (index == 11) + { + arr_clearKeyValuePair(&object->listeningWindow); + dlmsVARIANT start, end; + gxtime* s, * e; + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + var_init(&start); + var_init(&end); + ret = dlms_changeType2(tmp3, DLMS_DATA_TYPE_DATETIME, &start); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = va_getByIndex(tmp->Arr, 1, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = dlms_changeType2(tmp3, DLMS_DATA_TYPE_DATETIME, &end); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + s = (gxtime*)gxmalloc(sizeof(gxtime)); + e = (gxtime*)gxmalloc(sizeof(gxtime)); + time_copy(s, start.dateTime); + time_copy(e, end.dateTime); + arr_push(&object->listeningWindow, key_init(s, e)); + var_clear(&start); + var_clear(&end); + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_MBUS_PORT_SETUP + +#ifndef DLMS_IGNORE_MBUS_MASTER_PORT_SETUP +int cosem_setMbusMasterPortSetup(gxMBusMasterPortSetup* object, unsigned char index, dlmsVARIANT* value) +{ + if (index == 2) + { + object->commSpeed = (DLMS_BAUD_RATE)var_toInteger(value); + } + else + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return DLMS_ERROR_CODE_OK; +} +#endif //DLMS_IGNORE_MBUS_MASTER_PORT_SETUP + +#ifndef DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS +int cosem_setG3PlcMacLayerCounters(gxG3PlcMacLayerCounters* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = 0; + if (index == 2) + { + object->txDataPacketCount = value->ulVal; + } + else if (index == 3) + { + object->rxDataPacketCount = value->ulVal; + } + else if (index == 4) + { + object->txCmdPacketCount = value->ulVal; + } + else if (index == 5) + { + object->rxCmdPacketCount = value->ulVal; + } + else if (index == 6) + { + object->cSMAFailCount = value->ulVal; + } + else if (index == 7) + { + object->cSMANoAckCount = value->ulVal; + } + else if (index == 8) + { + object->badCrcCount = value->ulVal; + } + else if (index == 9) + { + object->txDataBroadcastCount = value->ulVal; + } + else if (index == 10) + { + object->rxDataBroadcastCount = value->ulVal; + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS + +#ifndef DLMS_IGNORE_G3_PLC_MAC_SETUP +int cosem_setG3PlcMacSetup(gxG3PlcMacSetup* object, unsigned char index, dlmsVARIANT* value) +{ + int pos, ret = 0; + if (index == 2) + { + object->shortAddress = value->uiVal; + } + else if (index == 3) + { + object->rcCoord = value->uiVal; + } + else if (index == 4) + { + object->panId = value->uiVal; + } + else if (index == 5) + { + arr_clear(&object->keyTable); + gxG3MacKeyTable* it; + dlmsVARIANT* tmp, * tmp2; + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + it = (gxG3MacKeyTable*)gxmalloc(sizeof(gxG3MacKeyTable)); + if (it == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + if ((ret = va_getByIndex(tmp->Arr, 0, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->id = tmp2->bVal; + if ((ret = va_getByIndex(tmp->Arr, 1, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + memcpy(it->key, tmp2->byteArr->data, bb_size(tmp2->byteArr)); + arr_push(&object->keyTable, it); + } + } + } + else if (index == 6) + { + object->frameCounter = value->ulVal; + } + else if (index == 7) + { + ba_clear(&object->toneMask); + if (value->bitArr != NULL) + { + ba_copy(&object->toneMask, value->bitArr->data, ba_size(value->bitArr)); + } + } + else if (index == 8) + { + object->tmrTtl = value->bVal; + } + else if (index == 9) + { + object->maxFrameRetries = value->bVal; + } + else if (index == 10) + { + object->neighbourTableEntryTtl = value->bVal; + } + else if (index == 11) + { + gxNeighbourTable* it; + obj_clearNeighbourTable(&object->neighbourTable); + dlmsVARIANT* tmp, * tmp2; + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + it = (gxNeighbourTable*)gxmalloc(sizeof(gxNeighbourTable)); + if (it == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + ba_init(&it->txCoeff); + ba_init(&it->toneMap); + if ((ret = va_getByIndex(tmp->Arr, 0, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->shortAddress = tmp2->uiVal; + if ((ret = va_getByIndex(tmp->Arr, 1, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->payloadModulationScheme = tmp2->bVal; + if ((ret = va_getByIndex(tmp->Arr, 2, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + if (tmp2->bitArr != NULL) + { + ba_copy(&it->toneMap, tmp2->bitArr->data, ba_size(tmp2->bitArr)); + } + if ((ret = va_getByIndex(tmp->Arr, 3, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->modulation = tmp2->bVal; + if ((ret = va_getByIndex(tmp->Arr, 4, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->txGain = tmp2->cVal; + if ((ret = va_getByIndex(tmp->Arr, 5, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->txRes = tmp2->bVal; + if ((ret = va_getByIndex(tmp->Arr, 6, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + if (tmp2->bitArr != NULL) + { + ba_copy(&it->txCoeff, tmp2->bitArr->data, ba_size(tmp2->bitArr)); + } + if ((ret = va_getByIndex(tmp->Arr, 7, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->lqi = tmp2->bVal; + if ((ret = va_getByIndex(tmp->Arr, 8, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->phaseDifferential = tmp2->cVal; + if ((ret = va_getByIndex(tmp->Arr, 9, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->tmrValidTime = tmp2->bVal; + if ((ret = va_getByIndex(tmp->Arr, 10, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + arr_push(&object->neighbourTable, it); + } + } + } + else if (index == 12) + { + object->highPriorityWindowSize = value->bVal; + } + else if (index == 13) + { + object->cscmFairnessLimit = value->bVal; + } + else if (index == 14) + { + object->beaconRandomizationWindowLength = value->bVal; + } + else if (index == 15) + { + object->macA = value->bVal; + } + else if (index == 16) + { + object->macK = value->bVal; + } + else if (index == 17) + { + object->minCwAttempts = value->bVal; + } + else if (index == 18) + { + object->cenelecLegacyMode = value->bVal; + } + else if (index == 19) + { + object->fccLegacyMode = value->bVal; + } + else if (index == 20) + { + object->maxBe = value->bVal; + } + else if (index == 21) + { + object->maxCsmaBackoffs = value->bVal; + } + else if (index == 22) + { + object->minBe = value->bVal; + } + else if (index == 23) + { + object->macBroadcastMaxCwEnabled = value->bVal; + } + else if (index == 24) + { + object->macTransmitAtten = value->bVal; + } + else if (index == 25) + { + arr_clear(&object->macPosTable); + gxMacPosTable* it; + dlmsVARIANT* tmp, * tmp2; + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + it = (gxMacPosTable*)gxmalloc(sizeof(gxMacPosTable)); + if (it == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + if ((ret = va_getByIndex(tmp->Arr, 0, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->shortAddress = tmp2->uiVal; + if ((ret = va_getByIndex(tmp->Arr, 1, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->lqi = tmp2->cVal; + if ((ret = va_getByIndex(tmp->Arr, 2, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->validTime = tmp2->cVal; + arr_push(&object->macPosTable, it); + } + } + } + else if (object->base.version > 2 && index == 26) + { + object->macDuplicateDetectionTTL = value->bVal; + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_G3_PLC_MAC_SETUP + +#ifndef DLMS_IGNORE_G3_PLC_6LO_WPAN + +int cosem_getUint16Array(variantArray* arr, dlmsVARIANT* value) +{ + int pos, ret = 0; + dlmsVARIANT* it; + va_clear(arr); + dlmsVARIANT* tmp; + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + it = (dlmsVARIANT*)gxmalloc(sizeof(dlmsVARIANT)); + if (it == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + var_init(it); + ret = var_copy(it, tmp); + if (ret != 0) + { + break; + } + va_push(arr, it); + } + } + return ret; +} + +int cosem_setG3Plc6LoWPAN(gxG3Plc6LoWPAN* object, unsigned char index, dlmsVARIANT* value) +{ + int pos, ret = 0; + if (index == 2) + { + object->maxHops = value->bVal; + } + else if (index == 3) + { + object->weakLqiValue = value->bVal; + } + else if (index == 4) + { + object->securityLevel = value->bVal; + } + else if (index == 5) + { + bb_clear(&object->prefixTable); + dlmsVARIANT* tmp; + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + if ((ret = va_getByIndex(value->Arr, pos, &tmp)) != DLMS_ERROR_CODE_OK) + { + break; + } + if ((ret = bb_setUInt8(&object->prefixTable, tmp->bVal)) != 0) + { + break; + } + } + } + } + else if (index == 6) + { + arr_clear(&object->routingConfiguration); + gxRoutingConfiguration* it; + dlmsVARIANT* tmp, * tmp2; + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + it = (gxRoutingConfiguration*)gxmalloc(sizeof(gxRoutingConfiguration)); + if (it == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + if ((ret = va_getByIndex(tmp->Arr, 0, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->netTraversalTime = tmp2->bVal; + if ((ret = va_getByIndex(tmp->Arr, 1, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->routingTableEntryTtl = tmp2->uiVal; + if ((ret = va_getByIndex(tmp->Arr, 2, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->kr = tmp2->cVal; + + if ((ret = va_getByIndex(tmp->Arr, 3, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->km = tmp2->cVal; + if ((ret = va_getByIndex(tmp->Arr, 4, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->kc = tmp2->cVal; + if ((ret = va_getByIndex(tmp->Arr, 5, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->kq = tmp2->cVal; + if ((ret = va_getByIndex(tmp->Arr, 6, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->kh = tmp2->cVal; + if ((ret = va_getByIndex(tmp->Arr, 7, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->krt = tmp2->cVal; + if ((ret = va_getByIndex(tmp->Arr, 8, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->rReqRetries = tmp2->cVal; + if ((ret = va_getByIndex(tmp->Arr, 9, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->rReqReqWait = tmp2->cVal; + if ((ret = va_getByIndex(tmp->Arr, 10, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->blacklistTableEntryTtl = tmp2->uiVal; + if ((ret = va_getByIndex(tmp->Arr, 11, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->unicastRreqGenEnable = tmp2->cVal; + if ((ret = va_getByIndex(tmp->Arr, 12, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->rlcEnabled = tmp2->cVal; + if ((ret = va_getByIndex(tmp->Arr, 13, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->addRevLinkCost = tmp2->cVal; + arr_push(&object->routingConfiguration, it); + } + } + } + else if (index == 7) + { + object->broadcastLogTableEntryTtl = value->uiVal; + } + else if (index == 8) + { + arr_clear(&object->routingTable); + gxRoutingTable* it; + dlmsVARIANT* tmp, * tmp2; + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + it = (gxRoutingTable*)gxmalloc(sizeof(gxRoutingTable)); + if (it == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + if ((ret = va_getByIndex(tmp->Arr, 0, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->destinationAddress = tmp2->uiVal; + if ((ret = va_getByIndex(tmp->Arr, 1, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->nextHopAddress = tmp2->uiVal; + if ((ret = va_getByIndex(tmp->Arr, 2, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->routeCost = tmp2->uiVal; + if ((ret = va_getByIndex(tmp->Arr, 3, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->hopCount = tmp2->bVal; + if ((ret = va_getByIndex(tmp->Arr, 4, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->weakLinkCount = tmp2->bVal; + if ((ret = va_getByIndex(tmp->Arr, 5, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->validTime = tmp2->uiVal; + arr_push(&object->routingTable, it); + } + } + } + else if (index == 9) + { + arr_clear(&object->contextInformationTable); + gxContextInformationTable* it; + uint32_t v; + dlmsVARIANT* tmp, * tmp2; + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + it = (gxContextInformationTable*)gxmalloc(sizeof(gxContextInformationTable)); + if (it == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + if ((ret = va_getByIndex(tmp->Arr, 0, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + if ((ret = ba_toInteger(tmp2->bitArr, &v)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->cid = (unsigned char)v; + if ((ret = va_getByIndex(tmp->Arr, 1, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->contextLength = tmp2->bVal; + if ((ret = va_getByIndex(tmp->Arr, 2, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + if (tmp2->byteArr != NULL) + { + int size = bb_size(tmp2->byteArr); + if (size > 16) + { + size = 16; + } + memcpy(it->context, tmp2->byteArr->data, size); + } + if ((ret = va_getByIndex(tmp->Arr, 3, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->compression = tmp2->bVal; + if ((ret = va_getByIndex(tmp->Arr, 4, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->validLifetime = tmp2->uiVal; + arr_push(&object->contextInformationTable, it); + } + } + } + else if (index == 10) + { + arr_clear(&object->blacklistTable); + gxBlacklistTable* it; + dlmsVARIANT* tmp, * tmp2; + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + it = (gxBlacklistTable*)gxmalloc(sizeof(gxBlacklistTable)); + if (it == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + if ((ret = va_getByIndex(tmp->Arr, 0, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->neighbourAddress = tmp2->uiVal; + if ((ret = va_getByIndex(tmp->Arr, 1, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->validTime = tmp2->uiVal; + arr_push(&object->blacklistTable, it); + } + } + } + else if (index == 11) + { + gxBroadcastLogTable* it; + arr_clear(&object->broadcastLogTable); + dlmsVARIANT* tmp, * tmp2; + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + it = (gxBroadcastLogTable*)gxmalloc(sizeof(gxBroadcastLogTable)); + if (it == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + if ((ret = va_getByIndex(tmp->Arr, 0, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->sourceAddress = tmp2->uiVal; + if ((ret = va_getByIndex(tmp->Arr, 1, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->sequenceNumber = tmp2->bVal; + if ((ret = va_getByIndex(tmp->Arr, 2, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->validTime = tmp2->uiVal; + if ((ret = va_getByIndex(tmp->Arr, 4, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + arr_push(&object->broadcastLogTable, it); + } + } + } + else if (index == 12) + { + ret = cosem_getUint16Array(&object->groupTable, value); + } + else if (index == 13) + { + object->maxJoinWaitTime = value->uiVal; + } + else if (index == 14) + { + object->pathDiscoveryTime = value->bVal; + } + else if (index == 15) + { + object->activeKeyIndex = value->bVal; + } + else if (index == 16) + { + object->metricType = value->bVal; + } + else if (index == 17) + { + object->coordShortAddress = value->uiVal; + } + else if (index == 18) + { + object->disableDefaultRouting = value->bVal; + } + else if (index == 19) + { + object->deviceType = (DLMS_PAN_DEVICE_TYPE)value->bVal; + } + else if (index == 20) + { + object->defaultCoordRouteEnabled = value->bVal; + } + else if (index == 21) + { + ret = cosem_getUint16Array(&object->destinationAddress, value); + } + else if (index == 22) + { + object->lowLQI = value->bVal; + } + else if (index == 23) + { + object->highLQI = value->bVal; + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_G3_PLC_6LO_WPAN + +#ifndef DLMS_IGNORE_FUNCTION_CONTROL +int cosem_setFunctionControl( + dlmsSettings* settings, + gxFunctionControl* object, + unsigned char index, + dlmsVARIANT* value) +{ + int pos, pos2, ret = 0; + if (index == 2) + { + functionStatus* it; + obj_clearActivationStatus(&object->activationStatus); + dlmsVARIANT* tmp, * tmp2; + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + it = (functionStatus*)gxmalloc(sizeof(functionStatus)); + if (it == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + if ((ret = va_getByIndex(tmp->Arr, 0, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + bb_init(&it->name); + bb_set2(&it->name, tmp2->byteArr, 0, bb_size(tmp2->byteArr)); + if ((ret = va_getByIndex(tmp->Arr, 1, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->status = tmp2->bVal; + arr_push(&object->activationStatus, it); + } + } + } + else if (index == 3) + { + functionalBlock* it; + gxObject* target; + obj_clearFunctionList(&object->functions); + dlmsVARIANT* tmp, * tmp2, * tmp3, * tmp4; + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + it = (functionalBlock*)gxmalloc(sizeof(functionalBlock)); + if (it == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + oa_init(&it->functionSpecifications); + if ((ret = va_getByIndex(tmp->Arr, 0, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + bb_init(&it->name); + bb_set2(&it->name, tmp2->byteArr, 0, bb_size(tmp2->byteArr)); + if ((ret = va_getByIndex(tmp->Arr, 1, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + for (pos2 = 0; pos2 != tmp2->Arr->size; ++pos2) + { + if ((ret = va_getByIndex(tmp2->Arr, pos, &tmp3)) != DLMS_ERROR_CODE_OK) + { + break; + } + if ((ret = va_getByIndex(tmp3->Arr, 0, &tmp4)) != DLMS_ERROR_CODE_OK) + { + break; + } + uint16_t ot = tmp4->uiVal; + //Get LN. + if ((ret = va_getByIndex(tmp3->Arr, 1, &tmp4)) != DLMS_ERROR_CODE_OK) + { + break; + } + if ((ret = oa_findByLN(&settings->objects, ot, tmp4->byteArr->data, &target)) != 0) + { + return ret; + } + if (target == NULL) + { + if ((ret = cosem_createObject(ot, &target)) != 0) + { + return ret; + } + oa_push(&settings->releasedObjects, target); + memcpy(target->logicalName, tmp4->byteArr->data, bb_size(tmp4->byteArr)); + } + oa_push(&it->functionSpecifications, target); + } + arr_push(&object->functions, it); + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} + +#endif //DLMS_IGNORE_FUNCTION_CONTROL + +#ifndef DLMS_IGNORE_ARRAY_MANAGER + +int cosem_setArrayManager( + dlmsSettings* settings, + gxArrayManager* object, + unsigned char index, + dlmsVARIANT* value) +{ + int pos, ret = 0; + if (index == 2) + { + arr_clear(&object->elements); + gxArrayManagerItem* it; + dlmsVARIANT* tmp, * tmp2, * tmp3; + uint16_t ot; + + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + it = (gxArrayManagerItem*)gxmalloc(sizeof(gxArrayManagerItem)); + if (it == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + if ((ret = va_getByIndex(tmp->Arr, 0, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->id = tmp2->bVal; + if ((ret = va_getByIndex(tmp->Arr, 1, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + if ((ret = va_getByIndex(tmp2->Arr, 0, &tmp3)) != DLMS_ERROR_CODE_OK) + { + break; + } + ot = tmp3->uiVal; + if ((ret = va_getByIndex(tmp2->Arr, 2, &tmp3)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->element.attributeIndex = tmp3->bVal; + //Get LN. + if ((ret = va_getByIndex(tmp2->Arr, 1, &tmp3)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->element.target = NULL; + if ((ret = oa_findByLN(&settings->objects, ot, tmp3->byteArr->data, &it->element.target)) != 0) + { + return ret; + } + if (it->element.target == NULL) + { + if ((ret = cosem_createObject(ot, &it->element.target)) != 0) + { + return ret; + } + oa_push(&settings->releasedObjects, it->element.target); + memcpy(it->element.target->logicalName, tmp3->byteArr->data, tmp3->byteArr->size); + } + arr_push(&object->elements, it); + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_ARRAY_MANAGER + +#ifndef DLMS_IGNORE_PUSH_SETUP +int cosem_setPushSetup(dlmsSettings* settings, gxPushSetup* object, unsigned char index, dlmsVARIANT* value) +{ + int ret, pos; + gxTarget* it; + gxObject* obj; + dlmsVARIANT* tmp, * tmp3; + gxtime* s, * e; + if (index == 2) + { + DLMS_OBJECT_TYPE type = DLMS_OBJECT_TYPE_NONE; + obj_clearPushObjectList(&object->pushObjectList); + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + type = (DLMS_OBJECT_TYPE)var_toInteger(tmp3); + //Get LN. + + ret = va_getByIndex(tmp->Arr, 1, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + obj = NULL; + if ((ret = oa_findByLN(&settings->objects, type, tmp3->byteArr->data, &obj)) != 0) + { + return ret; + } + if (obj == NULL) + { + if ((ret = cosem_createObject(type, &obj)) != 0) + { + return ret; + } + oa_push(&settings->releasedObjects, obj); + memcpy(obj->logicalName, tmp3->byteArr->data, tmp3->byteArr->size); + } + it = (gxTarget*)gxmalloc(sizeof(gxTarget)); + if (it == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + ret = va_getByIndex(tmp->Arr, 2, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + it->attributeIndex = (unsigned char)var_toInteger(tmp3); + ret = va_getByIndex(tmp->Arr, 3, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + it->dataIndex = (unsigned char)var_toInteger(tmp3); + arr_push(&object->pushObjectList, key_init(obj, it)); + } + } + } + else if (index == 3) + { + bb_clear(&object->destination); + //Get service. + ret = va_getByIndex(value->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->service = (DLMS_SERVICE_TYPE)var_toInteger(tmp); + //Destination. + ret = va_getByIndex(value->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + if (tmp->byteArr != NULL && tmp->byteArr->size != 0) + { + bb_clear(&object->destination); + bb_set(&object->destination, tmp->byteArr->data, tmp->byteArr->size); + } + //Message. + ret = va_getByIndex(value->Arr, 2, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->message = (DLMS_MESSAGE_TYPE)var_toInteger(tmp); + } + else if (index == 4) + { + arr_clearKeyValuePair(&object->communicationWindow); + if (value->Arr != NULL) + { + dlmsVARIANT start, end; + var_init(&start); + var_init(&end); + for (pos = 0; pos != value->Arr->size; ++pos) + { + if ((ret = va_getByIndex(value->Arr, pos, &tmp)) != 0 || + (ret = va_getByIndex(tmp->Arr, 0, &tmp3)) != 0 || + (ret = dlms_changeType2(tmp3, DLMS_DATA_TYPE_DATETIME, &start)) != 0 || + (ret = va_getByIndex(tmp->Arr, 1, &tmp3)) != 0 || + (ret = dlms_changeType2(tmp3, DLMS_DATA_TYPE_DATETIME, &end)) != 0) + { + break; + } + s = (gxtime*)gxmalloc(sizeof(gxtime)); + e = (gxtime*)gxmalloc(sizeof(gxtime)); + time_copy(s, start.dateTime); + time_copy(e, end.dateTime); + arr_push(&object->communicationWindow, key_init(s, e)); + } + var_clear(&start); + var_clear(&end); + } + } + else if (index == 5) + { + object->randomisationStartInterval = (uint16_t)var_toInteger(value); + } + else if (index == 6) + { + object->numberOfRetries = (unsigned char)var_toInteger(value); + } + else if (index == 7) + { + object->repetitionDelay = (uint16_t)var_toInteger(value); + } + else + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return DLMS_ERROR_CODE_OK; +} +#endif //DLMS_IGNORE_PUSH_SETUP + +#ifndef DLMS_IGNORE_CHARGE +int setUnitCharge(dlmsSettings* settings, gxUnitCharge* target, dlmsVARIANT* value) +{ + gxChargeTable* ct; + int ret, pos; + ret = obj_clearChargeTables(&target->chargeTables); + if (ret != 0) + { + return ret; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + signed short type; +#endif //DLMS_IGNORE_OBJECT_POINTERS + dlmsVARIANT* it, * it2, * tmp; + //charge per unit scaling + ret = va_getByIndex(value->Arr, 0, &it); + if (ret != 0) + { + return ret; + } + //commodity scale + ret = va_getByIndex(it->Arr, 0, &it2); + if (ret != 0) + { + return ret; + } + target->chargePerUnitScaling.commodityScale = (char)var_toInteger(it2); + //price scale + ret = va_getByIndex(it->Arr, 1, &it2); + if (ret != 0) + { + return ret; + } + target->chargePerUnitScaling.priceScale = (char)var_toInteger(it2); + //commodity + ret = va_getByIndex(value->Arr, 1, &it); + if (ret != 0) + { + return ret; + } + //type + ret = va_getByIndex(it->Arr, 0, &it2); + if (ret != 0) + { + return ret; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + type = (DLMS_OBJECT_TYPE)var_toInteger(it2); +#else + target->commodity.type = (DLMS_OBJECT_TYPE)var_toInteger(it2); +#endif //DLMS_IGNORE_OBJECT_POINTERS + //LN + ret = va_getByIndex(it->Arr, 1, &it2); + if (ret != 0) + { + return ret; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if (bb_size(it2->byteArr) == 6) + { + if ((ret = oa_findByLN(&settings->objects, type, it2->byteArr->data, &target->commodity.target)) != 0) + { + return ret; + } + } + else + { + target->commodity.target = NULL; + } +#else + memset(target->commodity.logicalName, 0, 6); + if (it2->byteArr != NULL && it2->byteArr->size == 6) + { + memcpy(target->commodity.logicalName, it2->byteArr->data, 6); + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + //attribute index + ret = va_getByIndex(it->Arr, 2, &it2); + if (ret != 0) + { + return ret; + } + target->commodity.attributeIndex = (unsigned char)var_toInteger(it2); + //chargeTables + obj_clearChargeTables(&target->chargeTables); + ret = va_getByIndex(value->Arr, 2, &it); + if (ret != 0) + { + return ret; + } + for (pos = 0; pos != it->Arr->size; ++pos) + { + ret = va_getByIndex(it->Arr, pos, &it2); + if (ret != 0) + { + break; + } + ct = (gxChargeTable*)gxmalloc(sizeof(gxChargeTable)); + if (ct == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + arr_push(&target->chargeTables, ct); + BYTE_BUFFER_INIT(&ct->index); + //index + ret = va_getByIndex(it2->Arr, 0, &tmp); + if (ret != 0) + { + break; + } + bb_set2(&ct->index, tmp->byteArr, 0, bb_size(tmp->byteArr)); + //chargePerUnit + ret = va_getByIndex(it2->Arr, 1, &tmp); + if (ret != 0) + { + break; + } + ct->chargePerUnit = (short)var_toInteger(tmp); + } + return ret; +} + +int cosem_setCharge(dlmsSettings* settings, gxCharge* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = 0; + dlmsVARIANT tmp; + if (index == 2) + { + object->totalAmountPaid = (short)var_toInteger(value); + } + else if (index == 3) + { + object->chargeType = (unsigned char)var_toInteger(value); + } + else if (index == 4) + { + object->priority = (unsigned char)var_toInteger(value); + } + else if (index == 5) + { + ret = setUnitCharge(settings, &object->unitChargeActive, value); + } + else if (index == 6) + { + ret = setUnitCharge(settings, &object->unitChargePassive, value); + } + else if (index == 7) + { + //Some meters are returning empty octet string here. + if (value->vt == DLMS_DATA_TYPE_OCTET_STRING && value->byteArr != NULL) + { + var_init(&tmp); + if ((ret = dlms_changeType2(value, DLMS_DATA_TYPE_DATETIME, &tmp)) != 0) + { + var_clear(&tmp); + return ret; + } + time_copy(&object->unitChargeActivationTime, tmp.dateTime); + var_clear(&tmp); + } + else + { + time_clear(&object->unitChargeActivationTime); + } + } + else if (index == 8) + { + object->period = var_toInteger(value); + } + else if (index == 9) + { + object->chargeConfiguration = var_toInteger(value); + } + else if (index == 10) + { + if (value->vt == DLMS_DATA_TYPE_DATETIME) + { + object->lastCollectionTime = *value->dateTime; + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + } + else if (index == 11) + { + object->lastCollectionAmount = var_toInteger(value); + } + else if (index == 12) + { + object->totalAmountRemaining = var_toInteger(value); + } + else if (index == 13) + { + object->proportion = (uint16_t)var_toInteger(value); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_CHARGE +#ifndef DLMS_IGNORE_CREDIT +int cosem_setCredit(gxCredit* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = 0; + dlmsVARIANT tmp; + if (index == 2) + { + object->currentCreditAmount = var_toInteger(value); + } + else if (index == 3) + { + object->type = (unsigned char)var_toInteger(value); + } + else if (index == 4) + { + object->priority = (unsigned char)var_toInteger(value); + } + else if (index == 5) + { + object->warningThreshold = var_toInteger(value); + } + else if (index == 6) + { + object->limit = var_toInteger(value); + } + else if (index == 7) + { + object->creditConfiguration = var_toInteger(value); + } + else if (index == 8) + { + object->status = (unsigned char)var_toInteger(value); + } + else if (index == 9) + { + object->presetCreditAmount = var_toInteger(value); + } + else if (index == 10) + { + object->creditAvailableThreshold = var_toInteger(value); + } + else if (index == 11) + { + var_init(&tmp); + ret = dlms_changeType(value->byteArr, DLMS_DATA_TYPE_DATETIME, &tmp); + if (ret == 0) + { + time_copy(&object->period, tmp.dateTime); + } + var_clear(&tmp); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_CREDIT +#ifndef DLMS_IGNORE_ACCOUNT +int cosem_setAccount(gxAccount* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = 0, pos; + unsigned char* ba; + dlmsVARIANT* it; + dlmsVARIANT tmp; + dlmsVARIANT* tmp2; + gxCreditChargeConfiguration* ccc; + gxTokenGatewayConfiguration* gwc; + if (index == 2) + { + //payment mode + ret = va_getByIndex(value->Arr, 0, &it); + if (ret != 0) + { + return ret; + } + object->paymentMode = (DLMS_ACCOUNT_PAYMENT_MODE)var_toInteger(it); + //account status + ret = va_getByIndex(value->Arr, 1, &it); + if (ret != 0) + { + return ret; + } + object->accountStatus = (DLMS_ACCOUNT_STATUS)var_toInteger(it); + } + else if (index == 3) + { + object->currentCreditInUse = (unsigned char)var_toInteger(value); + } + else if (index == 4) + { + if (value->bitArr == NULL || value->bitArr->size == 0) + { + return DLMS_ERROR_CODE_READ_WRITE_DENIED; + } + else + { + object->currentCreditStatus = (DLMS_ACCOUNT_CREDIT_STATUS)var_toInteger(value); + } + } + else if (index == 5) + { + object->availableCredit = var_toInteger(value); + } + else if (index == 6) + { + object->amountToClear = var_toInteger(value); + } + else if (index == 7) + { + object->clearanceThreshold = var_toInteger(value); + } + else if (index == 8) + { + object->aggregatedDebt = var_toInteger(value); + } + else if (index == 9) + { + arr_clear(&object->creditReferences); + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &it); + if (ret != 0) + { + return ret; + } + if (it->byteArr == NULL || it->byteArr->size != 6) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + ba = (unsigned char*)gxmalloc(6); + memcpy(ba, it->byteArr->data, 6); + arr_push(&object->creditReferences, ba); + } + } + else if (index == 10) + { + arr_clear(&object->chargeReferences); + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &it); + if (ret != 0) + { + return ret; + } + if (it->byteArr == NULL || it->byteArr->size != 6) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + ba = (unsigned char*)gxmalloc(6); + memcpy(ba, it->byteArr->data, 6); + arr_push(&object->chargeReferences, ba); + } + } + else if (index == 11) + { + ccc = NULL; + obj_clearCreditChargeConfigurations(&object->creditChargeConfigurations); + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &it); + if (ret != 0) + { + break; + } + ccc = (gxCreditChargeConfiguration*)gxmalloc(sizeof(gxCreditChargeConfiguration)); + if (ccc == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + //credit reference + ret = va_getByIndex(it->Arr, 0, &tmp2); + if (ret != 0) + { + break; + } + memcpy(ccc->creditReference, tmp2->byteArr->data, tmp2->byteArr->size); + //charge reference + ret = va_getByIndex(it->Arr, 1, &tmp2); + if (ret != 0) + { + break; + } + memcpy(ccc->chargeReference, tmp2->byteArr->data, tmp2->byteArr->size); + //collection configuration + ret = va_getByIndex(it->Arr, 2, &tmp2); + if (ret != 0) + { + break; + } + ccc->collectionConfiguration = (DLMS_CREDIT_COLLECTION_CONFIGURATION)var_toInteger(tmp2); + arr_push(&object->creditChargeConfigurations, ccc); + } + if (ret != 0 && ccc != NULL) + { + gxfree(ccc); + } + } + else if (index == 12) + { + obj_clearTokenGatewayConfigurations(&object->tokenGatewayConfigurations); + gwc = NULL; + for (pos = 0; pos != value->Arr->size; ++pos) + { + gwc = NULL; + if ((ret = va_getByIndex(value->Arr, pos, &it)) != 0) + { + break; + } + gwc = (gxTokenGatewayConfiguration*)gxmalloc(sizeof(gxTokenGatewayConfiguration)); + if (gwc == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + memset(gwc->creditReference, 0, 6); + //credit reference + if ((ret = va_getByIndex(it->Arr, 0, &tmp2)) != 0) + { + return ret; + } + if (tmp2->byteArr->size == 6) + { + memcpy(gwc->creditReference, tmp2->byteArr->data, tmp2->byteArr->size); + } + //token proportion + if ((ret = va_getByIndex(it->Arr, 1, &tmp2)) != 0) + { + break; + } + gwc->tokenProportion = (unsigned char)var_toInteger(tmp2); + arr_push(&object->tokenGatewayConfigurations, gwc); + } + if (ret != 0 && gwc != NULL) + { + gxfree(gwc); + } + } + else if (index == 13) + { + var_init(&tmp); + ret = dlms_changeType(value->byteArr, DLMS_DATA_TYPE_DATETIME, &tmp); + if (ret == 0) + { + time_copy(&object->accountActivationTime, tmp.dateTime); + } + var_clear(&tmp); + } + else if (index == 14) + { + var_init(&tmp); + ret = dlms_changeType(value->byteArr, DLMS_DATA_TYPE_DATETIME, &tmp); + if (ret == 0) + { + time_copy(&object->accountClosureTime, tmp.dateTime); + } + var_clear(&tmp); + } + else if (index == 15) + { + bb_clear(&object->currency.name); + //Name + ret = va_getByIndex(value->Arr, 0, &it); + if (ret != 0) + { + return ret; + } + if (it->strVal != NULL && it->strVal->size != 0) + { + bb_set2(&object->currency.name, it->strVal, 0, bb_size(it->strVal)); + } + //scale + ret = va_getByIndex(value->Arr, 1, &it); + if (ret != 0) + { + return ret; + } + object->currency.scale = (char)var_toInteger(it); + //unit + ret = va_getByIndex(value->Arr, 2, &it); + if (ret != 0) + { + return ret; + } + object->currency.unit = (DLMS_CURRENCY)var_toInteger(it); + } + else if (index == 16) + { + object->lowCreditThreshold = var_toInteger(value); + } + else if (index == 17) + { + object->nextCreditAvailableThreshold = var_toInteger(value); + } + else if (index == 18) + { + object->maxProvision = (uint16_t)var_toInteger(value); + } + else if (index == 19) + { + object->maxProvisionPeriod = var_toInteger(value); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_ACCOUNT +#ifndef DLMS_IGNORE_IMAGE_TRANSFER +int cosem_setImageTransfer(gxImageTransfer* object, unsigned char index, dlmsVARIANT* value) +{ + int pos, ret = 0; + gxImageActivateInfo* item; + dlmsVARIANT* it, * tmp; + if (index == 2) + { + object->imageBlockSize = var_toInteger(value); + } + else if (index == 3) + { + ba_clear(&object->imageTransferredBlocksStatus); + if (value->bitArr != NULL) + { + ba_copy(&object->imageTransferredBlocksStatus, value->bitArr->data, (uint16_t)value->bitArr->size); + } + } + else if (index == 4) + { + object->imageFirstNotTransferredBlockNumber = var_toInteger(value); + } + else if (index == 5) + { + object->imageTransferEnabled = var_toInteger(value) == 0 ? 0 : 1; + } + else if (index == 6) + { + object->imageTransferStatus = (DLMS_IMAGE_TRANSFER_STATUS)var_toInteger(value); + } + else if (index == 7) + { + arr_clear(&object->imageActivateInfo); + item = NULL; + if (value->Arr != NULL) + { + item = NULL; + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &it); + if (ret != 0) + { + break; + } + item = (gxImageActivateInfo*)gxmalloc(sizeof(gxImageActivateInfo)); + if (item == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + BYTE_BUFFER_INIT(&item->identification); + BYTE_BUFFER_INIT(&item->signature); + ret = va_getByIndex(it->Arr, 0, &tmp); + if (ret != 0) + { + break; + } + item->size = var_toInteger(tmp); + ret = va_getByIndex(it->Arr, 1, &tmp); + if (ret != 0) + { + break; + } + bb_set2(&item->identification, tmp->byteArr, 0, bb_size(tmp->byteArr)); + ret = va_getByIndex(it->Arr, 2, &tmp); + if (ret != 0) + { + break; + } + bb_set2(&item->signature, tmp->byteArr, 0, bb_size(tmp->byteArr)); + arr_push(&object->imageActivateInfo, item); + } + if (ret != 0 && item != NULL) + { + gxfree(item); + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_IMAGE_TRANSFER + +#if !(defined(DLMS_IGNORE_PROFILE_GENERIC) && defined(DLMS_IGNORE_COMPACT_DATA)) +int setCaptureObjects( + dlmsSettings* settings, + gxArray* objects, + dlmsVARIANT* value) +{ + gxObject* obj; + DLMS_OBJECT_TYPE type; + dlmsVARIANT* tmp, * tmp2; + gxTarget* co; + int pos, ret; + if ((ret = obj_clearProfileGenericCaptureObjects(objects)) != DLMS_ERROR_CODE_OK) + { + return ret; + } + arr_capacity(objects, value->Arr->size); + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + if (tmp->Arr->size != 4) + { + //Invalid structure format. + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + type = (DLMS_OBJECT_TYPE)var_toInteger(tmp2); + //Get LN. + ret = va_getByIndex(tmp->Arr, 1, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = oa_findByLN(&settings->objects, type, tmp2->byteArr->data, &obj); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + if (obj == NULL) + { + ret = cosem_createObject(type, &obj); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = cosem_setLogicalName(obj, tmp2->byteArr->data); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + //Add object to released objects list. + ret = oa_push(&settings->releasedObjects, obj); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + } + co = (gxTarget*)gxmalloc(sizeof(gxTarget)); + if (co == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + ret = va_getByIndex(tmp->Arr, 2, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + co->attributeIndex = (unsigned char)var_toInteger(tmp2); + ret = va_getByIndex(tmp->Arr, 3, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + co->dataIndex = (unsigned char)var_toInteger(tmp2); + arr_push(objects, key_init(obj, co)); + } + } + //Trim array. + arr_capacity(objects, objects->size); + return ret; +} +#endif //!(defined(DLMS_IGNORE_PROFILE_GENERIC) && defined(DLMS_IGNORE_CONPACT_DATA)) + +#ifndef DLMS_IGNORE_PROFILE_GENERIC +int cosem_setProfileGeneric( + dlmsSettings* settings, + gxProfileGeneric* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret = 0; + uint16_t pos, pos2; + DLMS_OBJECT_TYPE type; + dlmsVARIANT* tmp, * row, * data; + variantArray* va; + if (index == 2) + { + static unsigned char UNIX_TIME[6] = { 0, 0, 1, 1, 0, 255 }; + if (object->captureObjects.size == 0) + { + //Read capture objects first. + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if ((ret = obj_clearProfileGenericBuffer(&object->buffer)) == 0) + { + if (value->vt == DLMS_DATA_TYPE_OCTET_STRING) + { + uint16_t rIndex, rCount = arr_getCapacity(&object->buffer); + dlmsVARIANT* row; + if ((ret = cosem_checkArray(value->byteArr, &rCount)) == 0) + { + object->buffer.size = rCount; + if (rCount != 0 && (ret = arr_getByIndex(&object->buffer, 0, (void**)&row)) == 0) + { + uint16_t cCount = row->Arr->size; + if (cCount > object->captureObjects.size) + { + //Number of columns do not match. + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + for (rIndex = 0; rIndex != rCount; ++rIndex) + { + if ((ret = arr_getByIndex(&object->buffer, rIndex, (void**)&row)) != 0 || + (ret = cosem_checkStructure(value->byteArr, (unsigned char)cCount)) != 0) + { + break; + } + } + } + } + } + } + if (value->vt == DLMS_DATA_TYPE_ARRAY) + { + gxtime lastDate; + time_initUnix(&lastDate, 0); + //Allocate array. + arr_capacity(&object->buffer, value->Arr->size); + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &row); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + + if (row->Arr->size != object->captureObjects.size) + { + //Number of columns do not match. + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + for (pos2 = 0; pos2 < row->Arr->size; ++pos2) + { + ret = va_getByIndex(row->Arr, pos2, &data); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + if (data->vt == DLMS_DATA_TYPE_NONE || data->vt == DLMS_DATA_TYPE_OCTET_STRING || data->vt == DLMS_DATA_TYPE_UINT32) + { + gxObject* obj; + gxTarget* t; + gxKey* k; + if ((ret = arr_getByIndex(&object->captureObjects, pos2, (void**)&k)) != 0) + { + return ret; + } + obj = (gxObject*)k->key; + t = (gxTarget*)k->value; + if (obj->objectType == DLMS_OBJECT_TYPE_CLOCK && t->attributeIndex == 2) + { + if (data->vt == DLMS_DATA_TYPE_OCTET_STRING) + { + dlmsVARIANT tmp3; + var_init(&tmp3); + var_attach(&tmp3, data->byteArr); + ret = dlms_changeType(tmp3.byteArr, DLMS_DATA_TYPE_DATETIME, data); + var_clear(&tmp3); + if (ret != 0) + { + return ret; + } + lastDate = *data->dateTime; + } + //Some meters returns NULL date time to save bytes. + else if (data->vt == DLMS_DATA_TYPE_NONE) + { + if (object->sortMethod == DLMS_SORT_METHOD_FIFO || object->sortMethod == DLMS_SORT_METHOD_SMALLEST) + { + time_addSeconds(&lastDate, object->capturePeriod); + } + else + { + int tm = object->capturePeriod; + time_addSeconds(&lastDate, -tm); + } + var_setDateTime(data, &lastDate); + } + } + else if (data->vt == DLMS_DATA_TYPE_UINT32 && obj->objectType == DLMS_OBJECT_TYPE_DATA && t->attributeIndex == 2 && + memcmp(obj->logicalName, UNIX_TIME, 6) == 0) + { + gxtime tmp4; + time_initUnix(&tmp4, data->ulVal); + var_setDateTime(data, &tmp4); + lastDate = *data->dateTime; + } + } + } + //Attach rows from parser. + va = (variantArray*)gxmalloc(sizeof(variantArray)); + va_init(va); + va_attach2(va, row->Arr); + arr_push(&object->buffer, va); + } + } + if (settings->server) + { + object->entriesInUse = object->buffer.size; + } + //Trim array. + arr_capacity(&object->buffer, object->buffer.size); + } + else if (index == 3) + { + object->entriesInUse = 0; + ret = obj_clearProfileGenericBuffer(&object->buffer); + if (ret == DLMS_ERROR_CODE_OK) + { + ret = setCaptureObjects(settings, &object->captureObjects, value); + } + } + else if (index == 4) + { + object->capturePeriod = var_toInteger(value); + } + else if (index == 5) + { + object->sortMethod = (DLMS_SORT_METHOD)var_toInteger(value); + } + else if (index == 6) + { + if (value->vt == DLMS_DATA_TYPE_NONE) + { + object->sortObject = NULL; + } + else + { + if (value->Arr == NULL || value->Arr->size != 4) + { + //Invalid structure format. + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + ret = va_getByIndex(value->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + type = (DLMS_OBJECT_TYPE)var_toInteger(tmp); + + ret = va_getByIndex(value->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + + object->sortObject = NULL; + ret = oa_findByLN(&settings->objects, type, tmp->byteArr->data, &object->sortObject); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + if (object->sortObject == NULL) + { + ret = cosem_createObject(type, &object->sortObject); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = cosem_setLogicalName(object->sortObject, tmp->byteArr->data); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + //Add object to released objects list. + ret = oa_push(&settings->releasedObjects, object->sortObject); + } + ret = va_getByIndex(value->Arr, 2, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->sortObjectAttributeIndex = (char)var_toInteger(tmp); + ret = va_getByIndex(value->Arr, 3, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + object->sortObjectDataIndex = (uint16_t)var_toInteger(tmp); + } + } + else if (index == 7) + { + object->entriesInUse = var_toInteger(value); + } + else if (index == 8) + { + object->profileEntries = var_toInteger(value); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_PROFILE_GENERIC +#ifndef DLMS_IGNORE_GSM_DIAGNOSTIC +int cosem_setGsmDiagnostic(gxGsmDiagnostic* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = 0, pos; + dlmsVARIANT tmp2; + dlmsVARIANT* tmp, * it; + gxAdjacentCell* ac; + switch (index) + { + case 2: + if (value->vt == DLMS_DATA_TYPE_OCTET_STRING) + { + if (object->operatorName != NULL) + { + gxfree(object->operatorName); + object->operatorName = NULL; + } + + if (value->byteArr != NULL && bb_size(value->byteArr) != 0) + { + object->operatorName = (char*)gxmalloc(value->byteArr->size + 1); + if (object->operatorName == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + memcpy(object->operatorName, value->strVal->data, value->byteArr->size); + object->operatorName[value->byteArr->size] = '\0'; + } + } + else if (value->vt == DLMS_DATA_TYPE_STRING) + { + if (object->operatorName != NULL) + { + gxfree(object->operatorName); + object->operatorName = NULL; + } + object->operatorName = NULL; + if (value->strVal != NULL && bb_size(value->strVal) != 0) + { + object->operatorName = (char*)gxmalloc(value->strVal->size + 1); + if (object->operatorName == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + memcpy(object->operatorName, value->strVal->data, value->strVal->size); + object->operatorName[value->strVal->size] = '\0'; + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + break; + case 3: + object->status = (DLMS_GSM_STATUS)var_toInteger(value); + break; + case 4: + object->circuitSwitchStatus = (DLMS_GSM_CIRCUIT_SWITCH_STATUS)var_toInteger(value); + break; + case 5: + object->packetSwitchStatus = (DLMS_GSM_PACKET_SWITCH_STATUS)var_toInteger(value); + break; + case 6: + if (value != NULL && value->vt == DLMS_DATA_TYPE_STRUCTURE) + { + if ((ret = va_getByIndex(value->Arr, 0, &tmp)) != 0) + { + return ret; + } + object->cellInfo.cellId = (uint32_t)var_toInteger(tmp); + if ((ret = va_getByIndex(value->Arr, 1, &tmp)) != 0) + { + return ret; + } + object->cellInfo.locationId = (uint16_t)var_toInteger(tmp); + if ((ret = va_getByIndex(value->Arr, 2, &tmp)) != 0) + { + return ret; + } + object->cellInfo.signalQuality = (unsigned char)var_toInteger(tmp); + if ((ret = va_getByIndex(value->Arr, 3, &tmp)) != 0) + { + return ret; + } + object->cellInfo.ber = (unsigned char)var_toInteger(tmp); + if (object->base.version != 0) + { + if ((ret = va_getByIndex(value->Arr, 4, &tmp)) != 0) + { + return ret; + } + object->cellInfo.mobileCountryCode = (uint16_t)var_toInteger(tmp); + + if ((ret = va_getByIndex(value->Arr, 5, &tmp)) != 0) + { + return ret; + } + object->cellInfo.mobileNetworkCode = (uint16_t)var_toInteger(tmp); + + if ((ret = va_getByIndex(value->Arr, 6, &tmp)) != 0) + { + return ret; + } + object->cellInfo.channelNumber = tmp->ulVal; + } + } + break; + case 7: + arr_clear(&object->adjacentCells); + if (value != NULL && value->vt == DLMS_DATA_TYPE_ARRAY) + { + ac = NULL; + for (pos = 0; pos != value->Arr->size; ++pos) + { + ac = NULL; + ret = va_getByIndex(value->Arr, pos, &it); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ret = va_getByIndex(it->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ac = (gxAdjacentCell*)gxmalloc(sizeof(gxAdjacentCell)); + if (ac == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + ac->cellId = var_toInteger(tmp); + ret = va_getByIndex(it->Arr, 1, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ac->signalQuality = (unsigned char)var_toInteger(tmp); + arr_push(&object->adjacentCells, ac); + } + if (ret != 0 && ac != NULL) + { + gxfree(ac); + } + } + break; + case 8: + //Some meters are returning empty octet string here. + if (value->vt == DLMS_DATA_TYPE_OCTET_STRING && value->byteArr != NULL) + { + var_init(&tmp2); + ret = dlms_changeType2(value, DLMS_DATA_TYPE_DATETIME, &tmp2); + if (ret != 0) + { + return ret; + } + time_copy(&object->captureTime, tmp2.dateTime); + var_clear(&tmp2); + } + else if (value->vt == DLMS_DATA_TYPE_DATETIME) + { + time_copy(&object->captureTime, value->dateTime); + } + else + { + time_clear(&object->captureTime); + } + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_GSM_DIAGNOSTIC +#ifndef DLMS_IGNORE_TOKEN_GATEWAY +int cosem_setTokenGateway(gxTokenGateway* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = DLMS_ERROR_CODE_OK, pos; + dlmsVARIANT* tmp; + dlmsVARIANT tmp2; + dlmsVARIANT* it; + switch (index) + { + case 2: + bb_clear(&object->token); + ret = bb_set2(&object->token, value->byteArr, 0, bb_size(value->byteArr)); + break; + case 3: + time_clear(&object->time); + if (value->byteArr == NULL) + { + time_clear(&object->time); + } + else + { + var_init(&tmp2); + ret = dlms_changeType2(value, DLMS_DATA_TYPE_DATETIME, &tmp2); + if (ret != 0) + { + return ret; + } + time_copy(&object->time, tmp2.dateTime); + var_clear(&tmp2); + } + break; + case 4: + obj_clearByteBufferList(&object->descriptions); + if (value != NULL) + { + gxByteBuffer* d; + for (pos = 0; pos != value->Arr->size; ++pos) + { + if ((ret = va_getByIndex(value->Arr, pos, &it)) != 0) + { + return ret; + } + d = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + if (d == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + BYTE_BUFFER_INIT(d); + bb_set2(d, it->strVal, 0, it->strVal->size); + arr_push(&object->descriptions, d); + } + } + break; + case 5: + object->deliveryMethod = (DLMS_TOKEN_DELIVERY)var_toInteger(value); + break; + case 6: + if ((ret = va_getByIndex(value->Arr, 0, &tmp)) != 0) + { + return ret; + } + object->status = (DLMS_TOKEN_STATUS_CODE)var_toInteger(tmp); + if ((ret = va_getByIndex(value->Arr, 1, &tmp)) != 0) + { + return ret; + } + ba_clear(&object->dataValue); + if (tmp->strVal != NULL && tmp->strVal->size != 0) + { + ba_copy(&object->dataValue, tmp->bitArr->data, tmp->bitArr->size); + } + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_TOKEN_GATEWAY + +#ifndef DLMS_IGNORE_COMPACT_DATA + +int compactData_updateTemplateDescription( + dlmsSettings* settings, + gxCompactData* object) +{ + int ret; + uint16_t pos; + gxByteBuffer tmp; + gxValueEventCollection args; + gxValueEventArg e; + ve_init(&e); + gxKey* kv; + bb_clear(&object->buffer); + bb_clear(&object->templateDescription); + e.action = 1; + e.target = &object->base; + e.index = 2; + vec_init(&args); + BYTE_BUFFER_INIT(&tmp); + vec_push(&args, &e); + if (!e.handled) + { + if ((ret = bb_setUInt8(&object->templateDescription, DLMS_DATA_TYPE_STRUCTURE)) != DLMS_ERROR_CODE_OK) + { + bb_clear(&object->buffer); + return ret; + } + hlp_setObjectCount(object->captureObjects.size, &object->templateDescription); + for (pos = 0; pos != object->captureObjects.size; ++pos) + { + ret = arr_getByIndex(&object->captureObjects, pos, (void**)&kv); + if (ret != DLMS_ERROR_CODE_OK) + { + bb_clear(&object->buffer); + return ret; + } + e.target = (gxObject*)kv->key; + e.index = ((gxTarget*)kv->value)->attributeIndex; + if ((ret = cosem_getValue(settings, &e)) != 0) + { + var_clear(&e.value); + bb_clear(&object->buffer); + return ret; + } + if (e.byteArray) + { + if (bb_size(e.value.byteArr) == 0) + { + bb_setUInt8(&object->templateDescription, 0); + } + else + { + if (e.value.byteArr->data[0] == DLMS_DATA_TYPE_ARRAY || + e.value.byteArr->data[0] == DLMS_DATA_TYPE_STRUCTURE) + { + gxDataInfo info; + dlmsVARIANT value; + uint16_t count; + di_init(&info); + var_init(&value); + e.value.byteArr->position = 1; + if ((ret = hlp_getObjectCount2(e.value.byteArr, &count)) != 0 || + ((gxTarget*)kv->value)->dataIndex > count) + { + var_clear(&e.value); + bb_clear(&object->buffer); + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + //If all data is captured. + if (((gxTarget*)kv->value)->dataIndex == 0) + { + bb_setUInt8(&object->templateDescription, e.value.byteArr->data[0]); + if (e.value.byteArr->data[0] == DLMS_DATA_TYPE_ARRAY) + { + bb_setUInt16(&object->templateDescription, e.value.byteArr->data[1]); + } + else + { + bb_setUInt8(&object->templateDescription, e.value.byteArr->data[1]); + } + for (unsigned char pos = 0; pos < count; ++pos) + { + di_init(&info); + var_clear(&value); + if ((ret = dlms_getData(e.value.byteArr, &info, &value)) != 0) + { + var_clear(&value); + var_clear(&e.value); + bb_clear(&object->buffer); + return ret; + } + if (info.type == DLMS_DATA_TYPE_STRUCTURE || info.type == DLMS_DATA_TYPE_ARRAY) + { + dlmsVARIANT* value2; + bb_setUInt8(&object->templateDescription, info.type); + bb_setUInt8(&object->templateDescription, (unsigned char)value.Arr->size); + for (uint16_t pos = 0; pos < value.Arr->size; ++pos) + { + if ((ret = va_getByIndex(value.Arr, pos, &value2)) != 0) + { + var_clear(&value); + var_clear(&e.value); + bb_clear(&object->buffer); + return ret; + } + bb_setUInt8(&object->templateDescription, value2->vt); + } + } + else + { + bb_setUInt8(&object->templateDescription, info.type); + } + if (e.value.byteArr->data[0] == DLMS_DATA_TYPE_ARRAY) + { + break; + } + } + } + else + { + for (unsigned char pos = 0; pos < ((gxTarget*)kv->value)->dataIndex; ++pos) + { + var_clear(&value); + di_init(&info); + if ((ret = dlms_getData(e.value.byteArr, &info, &value)) != 0) + { + var_clear(&value); + var_clear(&e.value); + bb_clear(&object->buffer); + return ret; + } + if (!info.complete) + { + return DLMS_ERROR_CODE_READ_WRITE_DENIED; + } + } + if (info.type == DLMS_DATA_TYPE_STRUCTURE) + { + dlmsVARIANT* value2; + bb_setUInt8(&object->templateDescription, DLMS_DATA_TYPE_STRUCTURE); + bb_setUInt8(&object->templateDescription, (unsigned char)value.Arr->size); + for (uint16_t pos = 0; pos < value.Arr->size; ++pos) + { + if ((ret = va_getByIndex(value.Arr, pos, &value2)) != 0) + { + var_clear(&value); + var_clear(&e.value); + bb_clear(&object->buffer); + return ret; + } + bb_setUInt8(&object->templateDescription, value2->vt); + } + } + else + { + bb_setUInt8(&object->templateDescription, info.type); + } + } + var_clear(&value); + } + else + { + bb_setUInt8(&object->templateDescription, e.value.byteArr->data[0]); + } + } + } + else + { + if ((ret = dlms_setData(&tmp, e.value.vt, &e.value)) != 0) + { + var_clear(&e.value); + bb_clear(&tmp); + bb_clear(&object->buffer); + return ret; + } + bb_setUInt8(&object->templateDescription, tmp.data[0]); + bb_clear(&tmp); + } + var_clear(&e.value); + ve_clear(&e); + } + } + bb_clear(&tmp); + //svr_postGet(settings, &args); + vec_empty(&args); + return 0; +} + +int cosem_setCompactData( + dlmsSettings* settings, + gxCompactData* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret = DLMS_ERROR_CODE_OK; + switch (index) + { + case 2: + bb_clear(&object->buffer); + if (value->byteArr != NULL) + { + ret = bb_set(&object->buffer, value->byteArr->data, value->byteArr->size); + } + break; + case 3: + ret = setCaptureObjects(settings, &object->captureObjects, value); + if (ret == 0 && settings->server) + { + ret = compactData_updateTemplateDescription(settings, object); + } + break; + case 4: + object->templateId = (unsigned char)var_toInteger(value); + break; + case 5: + bb_clear(&object->templateDescription); + if (value->byteArr != NULL) + { + ret = bb_set(&object->templateDescription, value->byteArr->data, value->byteArr->size); + } + break; + case 6: + object->captureMethod = (DLMS_CAPTURE_METHOD)var_toInteger(value); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_COMPACT_DATA + +#ifndef DLMS_IGNORE_PARAMETER_MONITOR +int cosem_setParameterMonitor( + dlmsSettings* settings, + gxParameterMonitor* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret = 0, pos; + dlmsVARIANT* tmp, * tmp3; + dlmsVARIANT tmp2; + DLMS_OBJECT_TYPE type; + switch (index) + { + case 2: + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + object->changedParameter.target = NULL; +#else + object->changedParameter.type = DLMS_OBJECT_TYPE_NONE; + memset(object->changedParameter.logicalName, 0, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + if (value->Arr != NULL) + { + if ((ret = va_getByIndex(value->Arr, 0, &tmp3)) == DLMS_ERROR_CODE_OK) + { + type = (DLMS_OBJECT_TYPE)var_toInteger(tmp3); + //Get LN. + if ((ret = va_getByIndex(value->Arr, 1, &tmp3)) == DLMS_ERROR_CODE_OK) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = oa_findByLN(&settings->objects, type, tmp3->byteArr->data, &object->changedParameter.target)) != 0) + { + return ret; + } + if (object->changedParameter.target == NULL) + { + if ((ret = cosem_createObject(type, &object->changedParameter.target)) != 0) + { + return ret; + } + oa_push(&settings->releasedObjects, object->changedParameter.target); + memcpy(object->changedParameter.target->logicalName, tmp3->byteArr->data, tmp3->byteArr->size); + } + if ((ret = va_getByIndex(value->Arr, 2, &tmp3)) == DLMS_ERROR_CODE_OK) + { + object->changedParameter.attributeIndex = (unsigned char)var_toInteger(tmp3); + if ((ret = va_getByIndex(value->Arr, 3, &tmp3)) == DLMS_ERROR_CODE_OK) + { + ret = var_copy(&object->changedParameter.value, tmp3); + } + } +#else + object->changedParameter.type = type; + memcpy(object->changedParameter.logicalName, tmp3->byteArr->data, 6); + if ((ret = va_getByIndex(value->Arr, 2, &tmp3)) == DLMS_ERROR_CODE_OK) + { + object->changedParameter.attributeIndex = (unsigned char)var_toInteger(tmp3); + if ((ret = va_getByIndex(value->Arr, 3, &tmp3)) == DLMS_ERROR_CODE_OK) + { + ret = var_copy(&object->changedParameter.value, tmp3); + } + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + + } + } + } + break; + } + case 3: + { + //Some meters are returning empty octet string here. + if (value->vt == DLMS_DATA_TYPE_OCTET_STRING && value->byteArr != NULL) + { + ret = var_init(&tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = dlms_changeType2(value, DLMS_DATA_TYPE_DATETIME, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + time_copy(&object->captureTime, tmp2.dateTime); + var_clear(&tmp2); + } + else + { + time_clear(&object->captureTime); + } + } + break; + case 4: + { + obj_clearParametersList(&object->parameters); + if (value->Arr != NULL) + { + gxTarget* it; + gxObject* obj; + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + type = (DLMS_OBJECT_TYPE)var_toInteger(tmp3); + //Get LN. + + ret = va_getByIndex(tmp->Arr, 1, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + obj = NULL; + if ((ret = oa_findByLN(&settings->objects, type, tmp3->byteArr->data, &obj)) != 0) + { + return ret; + } + if (obj == NULL) + { + if ((ret = cosem_createObject(type, &obj)) != 0) + { + return ret; + } + oa_push(&settings->releasedObjects, obj); + memcpy(obj->logicalName, tmp3->byteArr->data, tmp3->byteArr->size); + } + it = (gxTarget*)gxmalloc(sizeof(gxTarget)); + if (it == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + ret = va_getByIndex(tmp->Arr, 2, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + it->attributeIndex = (unsigned char)var_toInteger(tmp3); + arr_push(&object->parameters, key_init(obj, it)); + } + } + break; + } + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_PARAMETER_MONITOR + +#ifndef DLMS_IGNORE_LLC_SSCS_SETUP +int cosem_setLlcSscsSetup( + dlmsSettings* settings, + gxLlcSscsSetup* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret = 0; + switch (index) + { + case 2: + object->serviceNodeAddress = (uint16_t)var_toInteger(value); + break; + case 3: + object->baseNodeAddress = (uint16_t)var_toInteger(value); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_LLC_SSCS_SETUP + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +int cosem_setPrimeNbOfdmPlcPhysicalLayerCounters( + dlmsSettings* settings, + gxPrimeNbOfdmPlcPhysicalLayerCounters* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret = 0; + switch (index) + { + case 2: + object->crcIncorrectCount = (uint16_t)var_toInteger(value); + break; + case 3: + object->crcFailedCount = (uint16_t)var_toInteger(value); + break; + case 4: + object->txDropCount = (uint16_t)var_toInteger(value); + break; + case 5: + object->rxDropCount = (uint16_t)var_toInteger(value); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} + +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +int cosem_setPrimeNbOfdmPlcMacSetup( + dlmsSettings* settings, + gxPrimeNbOfdmPlcMacSetup* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret = 0; + switch (index) + { + case 2: + object->macMinSwitchSearchTime = (unsigned char)var_toInteger(value); + break; + case 3: + object->macMaxPromotionPdu = (unsigned char)var_toInteger(value); + break; + case 4: + object->macPromotionPduTxPeriod = (unsigned char)var_toInteger(value); + break; + case 5: + object->macBeaconsPerFrame = (unsigned char)var_toInteger(value); + break; + case 6: + object->macScpMaxTxAttempts = (unsigned char)var_toInteger(value); + break; + case 7: + object->macCtlReTxTimer = (unsigned char)var_toInteger(value); + break; + case 8: + object->macMaxCtlReTx = (unsigned char)var_toInteger(value); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} + +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +int cosem_setPrimeNbOfdmPlcMacFunctionalParameters( + dlmsSettings* settings, + gxPrimeNbOfdmPlcMacFunctionalParameters* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret = 0; + switch (index) + { + case 2: + object->lnId = (short)var_toInteger(value); + break; + case 3: + object->lsId = (unsigned char)var_toInteger(value); + break; + case 4: + object->sId = (unsigned char)var_toInteger(value); + break; + case 5: + object->sna.size = 0; + ret = bb_set2(&object->sna, value->byteArr, 0, bb_size(value->byteArr)); + break; + case 6: + object->state = (DLMS_MAC_STATE)var_toInteger(value); + break; + case 7: + object->scpLength = (short)var_toInteger(value); + break; + case 8: + object->nodeHierarchyLevel = (unsigned char)var_toInteger(value); + break; + case 9: + object->beaconSlotCount = (unsigned char)var_toInteger(value); + break; + case 10: + object->beaconRxSlot = (unsigned char)var_toInteger(value); + break; + case 11: + object->beaconTxSlot = (unsigned char)var_toInteger(value); + break; + case 12: + object->beaconRxFrequency = (unsigned char)var_toInteger(value); + break; + case 13: + object->beaconTxFrequency = (unsigned char)var_toInteger(value); + break; + case 14: + object->capabilities = (DLMS_MAC_CAPABILITIES)var_toInteger(value); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +int cosem_setPrimeNbOfdmPlcMacCounters( + dlmsSettings* settings, + gxPrimeNbOfdmPlcMacCounters* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret = 0; + switch (index) + { + case 2: + object->txDataPktCount = var_toInteger(value); + break; + case 3: + object->rxDataPktCount = var_toInteger(value); + break; + case 4: + object->txCtrlPktCount = var_toInteger(value); + break; + case 5: + object->rxCtrlPktCount = var_toInteger(value); + break; + case 6: + object->csmaFailCount = var_toInteger(value); + break; + case 7: + object->csmaChBusyCount = var_toInteger(value); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + +int cosem_setMulticastEntries(gxPrimeNbOfdmPlcMacNetworkAdministrationData* object, dlmsVARIANT* value) +{ + int ret = 0; + int pos; + gxMacMulticastEntry* it; + arr_clear(&object->multicastEntries); + if (value->Arr != NULL) + { + dlmsVARIANT* tmp; + dlmsVARIANT* tmp2; + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + it = (gxMacMulticastEntry*)gxmalloc(sizeof(gxMacMulticastEntry)); + if ((ret = va_getByIndex(tmp->Arr, 0, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->id = (signed char)var_toInteger(tmp2); + if ((ret = va_getByIndex(tmp->Arr, 1, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->members = (short)var_toInteger(tmp2); + arr_push(&object->multicastEntries, it); + } + } + return 0; +} + + +int cosem_setSwitchTable(gxPrimeNbOfdmPlcMacNetworkAdministrationData* object, dlmsVARIANT* value) +{ + int ret = 0; + int pos; + arr_empty(&object->switchTable); + if (value->Arr != NULL) + { + dlmsVARIANT* it; + for (pos = 0; pos != value->Arr->size; ++pos) + { + if ((ret = va_getByIndex(value->Arr, pos, &it)) != DLMS_ERROR_CODE_OK) + { + break; + } + uint16_t* tmp = (uint16_t*)gxmalloc(sizeof(uint16_t)); + *tmp = (uint16_t)var_toInteger(it); + arr_push(&object->switchTable, tmp); + } + } + return 0; +} + +int cosem_setDirectTable(gxPrimeNbOfdmPlcMacNetworkAdministrationData* object, dlmsVARIANT* value) +{ + int ret = 0; + int pos; + gxMacDirectTable* it; + arr_clear(&object->directTable); + if (value->Arr != NULL) + { + dlmsVARIANT* tmp; + dlmsVARIANT* tmp2; + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + it = (gxMacDirectTable*)gxmalloc(sizeof(gxMacDirectTable)); + if ((ret = va_getByIndex(tmp->Arr, 0, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->sourceSId = (short)var_toInteger(tmp2); + if ((ret = va_getByIndex(tmp->Arr, 1, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->sourceLnId = (short)var_toInteger(tmp2); + if ((ret = va_getByIndex(tmp->Arr, 2, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->sourceLcId = (short)var_toInteger(tmp2); + if ((ret = va_getByIndex(tmp->Arr, 3, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->destinationSId = (short)var_toInteger(tmp2); + if ((ret = va_getByIndex(tmp->Arr, 4, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->destinationLnId = (short)var_toInteger(tmp2); + if ((ret = va_getByIndex(tmp->Arr, 5, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->destinationLcId = (short)var_toInteger(tmp2); + if ((ret = va_getByIndex(tmp->Arr, 6, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + if ((ret = bb_get(tmp2->byteArr, it->did, sizeof(it->did))) != DLMS_ERROR_CODE_OK) + { + break; + } + arr_push(&object->directTable, it); + } + } + return 0; +} + +int cosem_setAvailableSwitches(gxPrimeNbOfdmPlcMacNetworkAdministrationData* object, dlmsVARIANT* value) +{ + int ret = 0; + int pos; + gxMacAvailableSwitch* it; + obj_clearAvailableSwitches(&object->availableSwitches); + if (value->Arr != NULL) + { + dlmsVARIANT* tmp; + dlmsVARIANT* tmp2; + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + if ((ret = va_getByIndex(tmp->Arr, 0, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it = (gxMacAvailableSwitch*)gxmalloc(sizeof(gxMacAvailableSwitch)); + BYTE_BUFFER_INIT(&it->sna); + bb_capacity(&it->sna, tmp2->byteArr->size); + if ((ret = bb_set(&it->sna, tmp2->byteArr->data, tmp2->byteArr->size)) != DLMS_ERROR_CODE_OK) + { + gxfree(it); + break; + } + if ((ret = va_getByIndex(tmp->Arr, 1, &tmp2)) != DLMS_ERROR_CODE_OK) + { + gxfree(it); + break; + } + it->lsId = (short)var_toInteger(tmp2); + if ((ret = va_getByIndex(tmp->Arr, 2, &tmp2)) != DLMS_ERROR_CODE_OK) + { + gxfree(it); + break; + } + it->level = (signed char)var_toInteger(tmp2); + if ((ret = va_getByIndex(tmp->Arr, 3, &tmp2)) != DLMS_ERROR_CODE_OK) + { + gxfree(it); + break; + } + it->rxLevel = (signed char)var_toInteger(tmp2); + if ((ret = va_getByIndex(tmp->Arr, 4, &tmp2)) != DLMS_ERROR_CODE_OK) + { + gxfree(it); + break; + } + it->rxSnr = (signed char)var_toInteger(tmp2); + arr_push(&object->availableSwitches, it); + } + } + return 0; +} + +int cosem_setCommunications(gxPrimeNbOfdmPlcMacNetworkAdministrationData* object, dlmsVARIANT* value) +{ + int ret = 0; + int pos; + gxMacPhyCommunication* it; + arr_clear(&object->communications); + if (value->Arr != NULL) + { + dlmsVARIANT* tmp; + dlmsVARIANT* tmp2; + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + it = (gxMacPhyCommunication*)gxmalloc(sizeof(gxMacPhyCommunication)); + if ((ret = va_getByIndex(tmp->Arr, 0, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + if ((ret = bb_get(tmp2->byteArr, it->eui, sizeof(it->eui))) != DLMS_ERROR_CODE_OK) + { + break; + } + if ((ret = va_getByIndex(tmp->Arr, 1, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->txPower = (signed char)var_toInteger(tmp2); + if ((ret = va_getByIndex(tmp->Arr, 2, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->txCoding = (signed char)var_toInteger(tmp2); + if ((ret = va_getByIndex(tmp->Arr, 3, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->rxCoding = (signed char)var_toInteger(tmp2); + if ((ret = va_getByIndex(tmp->Arr, 4, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->rxLvl = (signed char)var_toInteger(tmp2); + if ((ret = va_getByIndex(tmp->Arr, 5, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->snr = (signed char)var_toInteger(tmp2); + if ((ret = va_getByIndex(tmp->Arr, 6, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->txPowerModified = (signed char)var_toInteger(tmp2); + if ((ret = va_getByIndex(tmp->Arr, 7, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->txCodingModified = (signed char)var_toInteger(tmp2); + if ((ret = va_getByIndex(tmp->Arr, 8, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->rxCodingModified = (signed char)var_toInteger(tmp2); + arr_push(&object->communications, it); + } + } + return 0; +} + +int cosem_setPrimeNbOfdmPlcMacNetworkAdministrationData( + dlmsSettings* settings, + gxPrimeNbOfdmPlcMacNetworkAdministrationData* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret = 0; + switch (index) + { + case 2: + ret = cosem_setMulticastEntries(object, value); + break; + case 3: + ret = cosem_setSwitchTable(object, value); + break; + case 4: + ret = cosem_setDirectTable(object, value); + break; + case 5: + ret = cosem_setAvailableSwitches(object, value); + break; + case 6: + ret = cosem_setCommunications(object, value); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} + +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION +int cosem_setPrimeNbOfdmPlcApplicationsIdentification( + dlmsSettings* settings, + gxPrimeNbOfdmPlcApplicationsIdentification* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret = 0; + switch (index) + { + case 2: + { + bb_clear(&object->firmwareVersion); + bb_set2(&object->firmwareVersion, value->byteArr, 0, bb_size(value->byteArr)); + } + break; + case 3: + object->vendorId = (uint16_t)var_toInteger(value); + break; + case 4: + object->productId = (uint16_t)var_toInteger(value); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION + +#ifndef DLMS_IGNORE_ARBITRATOR +int cosem_setArbitrator( + dlmsSettings* settings, + gxArbitrator* object, + unsigned char index, + dlmsVARIANT* value) +{ + int pos, ret = 0; + gxActionItem* it; + bitArray* ba; + dlmsVARIANT* tmp, * tmp2; + switch (index) + { + case 2: + { + arr_clear(&object->actions); + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + it = (gxActionItem*)gxmalloc(sizeof(gxActionItem)); + it->script = NULL; + if ((ret = va_getByIndex(value->Arr, pos, &tmp)) != DLMS_ERROR_CODE_OK) + { + break; + } + if ((ret = va_getByIndex(tmp->Arr, 0, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = oa_findByLN(&settings->objects, DLMS_OBJECT_TYPE_SCRIPT_TABLE, tmp2->byteArr->data, (gxObject**)&it->script)) != 0) + { + break; + } + if (it->script == NULL) + { + if ((ret = cosem_createObject(DLMS_OBJECT_TYPE_SCRIPT_TABLE, (gxObject**)&it->script)) != 0) + { + return ret; + } + memcpy(it->script->base.logicalName, tmp2->byteArr->data, tmp2->byteArr->size); + //Add object to released objects list. + ret = oa_push(&settings->releasedObjects, &it->script->base); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + } +#else + memcpy(it->scriptLogicalName, tmp2->byteArr->data, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + if ((ret = va_getByIndex(tmp->Arr, 1, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->scriptSelector = (uint16_t)var_toInteger(tmp2); + arr_push(&object->actions, it); + } + } + } + break; + case 3: + { + obj_clearBitArrayList(&object->permissionsTable); + if (value->Arr != NULL) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + ba = (bitArray*)gxmalloc(sizeof(bitArray)); + ba_init(ba); + if ((ba_copy(ba, tmp->bitArr->data, tmp->bitArr->size)) != 0) + { + break; + } + arr_push(&object->permissionsTable, ba); + } + } + } + break; + case 4: + { + arr_clear(&object->weightingsTable); + if (value->Arr != NULL) + { + dlmsVARIANT* tmp2; + for (pos = 0; pos != value->Arr->size; ++pos) + { + ret = va_getByIndex(value->Arr, pos, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + break; + } + tmp2 = (dlmsVARIANT*)gxmalloc(sizeof(dlmsVARIANT)); + var_init(tmp2); + ret = var_copy(tmp2, tmp); + if (ret != 0) + { + break; + } + arr_push(&object->weightingsTable, tmp2); + } + } + } + break; + case 5: + { + obj_clearBitArrayList(&object->mostRecentRequestsTable); + if (value->Arr != NULL) + { + bitArray* it; + for (pos = 0; pos != value->Arr->size; ++pos) + { + if ((ret = va_getByIndex(value->Arr, pos, &tmp)) != DLMS_ERROR_CODE_OK) + { + break; + } + it = (bitArray*)gxmalloc(sizeof(bitArray)); + ba_init(it); + if ((ba_copy(it, tmp->bitArr->data, tmp->bitArr->size)) != 0) + { + break; + } + arr_push(&object->mostRecentRequestsTable, it); + } + } + } + break; + case 6: + object->lastOutcome = (unsigned char)var_toInteger(value); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_ARBITRATOR +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +int cosem_setIec8802LlcType1Setup( + dlmsSettings* settings, + gxIec8802LlcType1Setup* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret = DLMS_ERROR_CODE_OK; + switch (index) + { + case 2: + object->maximumOctetsUiPdu = (uint16_t)var_toInteger(value); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP +int cosem_setIec8802LlcType2Setup( + dlmsSettings* settings, + gxIec8802LlcType2Setup* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret = DLMS_ERROR_CODE_OK; + switch (index) + { + case 2: + object->transmitWindowSizeK = (unsigned char)var_toInteger(value); + break; + case 3: + object->transmitWindowSizeRW = (unsigned char)var_toInteger(value); + break; + case 4: + object->maximumOctetsPdu = (uint16_t)var_toInteger(value); + break; + case 5: + object->maximumNumberTransmissions = (unsigned char)var_toInteger(value); + break; + case 6: + object->acknowledgementTimer = (uint16_t)var_toInteger(value); + break; + case 7: + object->bitTimer = (uint16_t)var_toInteger(value); + break; + case 8: + object->rejectTimer = (uint16_t)var_toInteger(value); + break; + case 9: + object->busyStateTimer = (uint16_t)var_toInteger(value); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP +int cosem_setIec8802LlcType3Setup( + dlmsSettings* settings, + gxIec8802LlcType3Setup* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret = DLMS_ERROR_CODE_OK; + switch (index) + { + case 2: + object->maximumOctetsACnPdu = (uint16_t)var_toInteger(value); + break; + case 3: + object->maximumTransmissions = (unsigned char)var_toInteger(value); + break; + case 4: + object->acknowledgementTime = (uint16_t)var_toInteger(value); + break; + case 5: + object->receiveLifetime = (uint16_t)var_toInteger(value); + break; + case 6: + object->transmitLifetime = (uint16_t)var_toInteger(value); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP +#ifndef DLMS_IGNORE_SFSK_ACTIVE_INITIATOR +int cosem_setSFSKActiveInitiator( + dlmsSettings* settings, + gxSFSKActiveInitiator* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret = 0; + dlmsVARIANT* tmp; + switch (index) + { + case 2: + if (value->vt == DLMS_DATA_TYPE_STRUCTURE) + { + bb_clear(&object->systemTitle); + if ((ret = va_getByIndex(value->Arr, 0, &tmp)) != DLMS_ERROR_CODE_OK) + { + break; + } + if (tmp->byteArr != NULL) + { + if ((ret = bb_set(&object->systemTitle, tmp->byteArr->data, bb_size(tmp->byteArr))) != 0) + { + break; + } + } + if ((ret = va_getByIndex(value->Arr, 1, &tmp)) != DLMS_ERROR_CODE_OK) + { + break; + } + object->macAddress = (uint16_t)var_toInteger(tmp); + if ((ret = va_getByIndex(value->Arr, 2, &tmp)) != DLMS_ERROR_CODE_OK) + { + break; + } + object->lSapSelector = (unsigned char)var_toInteger(tmp); + } + else + { + bb_clear(&object->systemTitle); + object->macAddress = 0; + object->lSapSelector = 0; + } + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SFSK_ACTIVE_INITIATOR +#ifndef DLMS_IGNORE_SFSK_MAC_COUNTERS +int cosem_setFSKMacCounters( + dlmsSettings* settings, + gxFSKMacCounters* object, + unsigned char index, + dlmsVARIANT* value) +{ + int pos, ret = DLMS_ERROR_CODE_OK; + gxUint16PairUint32* it; + dlmsVARIANT* tmp, * tmp2; + switch (index) + { + case 2: + { + arr_clear(&object->synchronizationRegister); + if (value->vt == DLMS_DATA_TYPE_ARRAY) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + if ((ret = va_getByIndex(value->Arr, pos, &tmp)) != DLMS_ERROR_CODE_OK) + { + break; + } + it = (gxUint16PairUint32*)gxmalloc(sizeof(gxUint16PairUint32)); + if (it == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + if ((ret = va_getByIndex(tmp->Arr, 0, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->first = (uint16_t)var_toInteger(tmp2); + if ((ret = va_getByIndex(tmp->Arr, 1, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->second = var_toInteger(tmp2); + arr_push(&object->synchronizationRegister, it); + } + } + } + break; + case 3: + { + if (value->vt == DLMS_DATA_TYPE_STRUCTURE) + { + if ((ret = va_getByIndex(value->Arr, 0, &tmp)) == DLMS_ERROR_CODE_OK) + { + object->physicalLayerDesynchronization = var_toInteger(tmp); + if ((ret = va_getByIndex(value->Arr, 1, &tmp)) == DLMS_ERROR_CODE_OK) + { + object->timeOutNotAddressedDesynchronization = var_toInteger(tmp); + if ((ret = va_getByIndex(value->Arr, 2, &tmp)) == DLMS_ERROR_CODE_OK) + { + object->timeOutFrameNotOkDesynchronization = var_toInteger(tmp); + if ((ret = va_getByIndex(value->Arr, 3, &tmp)) == DLMS_ERROR_CODE_OK) + { + object->writeRequestDesynchronization = var_toInteger(tmp); + if ((ret = va_getByIndex(value->Arr, 4, &tmp)) == DLMS_ERROR_CODE_OK) + { + object->wrongInitiatorDesynchronization = var_toInteger(tmp); + } + } + } + } + } + } + else + { + object->physicalLayerDesynchronization = 0; + object->timeOutNotAddressedDesynchronization = 0; + object->timeOutFrameNotOkDesynchronization = 0; + object->writeRequestDesynchronization = 0; + object->wrongInitiatorDesynchronization = 0; + } + } + break; + case 4: + { + arr_clear(&object->broadcastFramesCounter); + if (value->vt == DLMS_DATA_TYPE_ARRAY) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + if ((ret = va_getByIndex(value->Arr, pos, &tmp)) != DLMS_ERROR_CODE_OK) + { + break; + } + it = (gxUint16PairUint32*)gxmalloc(sizeof(gxUint16PairUint32)); + if (it == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + if ((ret = va_getByIndex(tmp->Arr, 0, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->first = (uint16_t)var_toInteger(tmp2); + if ((ret = va_getByIndex(tmp->Arr, 1, &tmp2)) != DLMS_ERROR_CODE_OK) + { + break; + } + it->second = var_toInteger(tmp2); + arr_push(&object->broadcastFramesCounter, it); + } + } + } + break; + case 5: + object->repetitionsCounter = var_toInteger(value); + break; + case 6: + object->transmissionsCounter = var_toInteger(value); + break; + case 7: + object->crcOkFramesCounter = var_toInteger(value); + break; + case 8: + object->crcNOkFramesCounter = var_toInteger(value); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_SFSK_MAC_COUNTERS +#ifndef DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS +int cosem_setSFSKMacSynchronizationTimeouts( + dlmsSettings* settings, + gxSFSKMacSynchronizationTimeouts* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret = 0; + switch (index) + { + case 2: + object->searchInitiatorTimeout = (uint16_t)var_toInteger(value); + break; + case 3: + object->synchronizationConfirmationTimeout = (uint16_t)var_toInteger(value); + break; + case 4: + object->timeOutNotAddressed = (uint16_t)var_toInteger(value); + break; + case 5: + object->timeOutFrameNotOK = (uint16_t)var_toInteger(value); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS +#ifndef DLMS_IGNORE_SFSK_PHY_MAC_SETUP +int cosem_setSFSKPhyMacSetUp( + dlmsSettings* settings, + gxSFSKPhyMacSetUp* object, + unsigned char index, + dlmsVARIANT* value) +{ + int pos, ret = 0; + dlmsVARIANT* it; + switch (index) + { + case 2: + object->initiatorElectricalPhase = (DLMS_INITIATOR_ELECTRICAL_PHASE)var_toInteger(value); + break; + case 3: + object->deltaElectricalPhase = (DLMS_DELTA_ELECTRICAL_PHASE)var_toInteger(value); + break; + case 4: + object->maxReceivingGain = (unsigned char)var_toInteger(value); + break; + case 5: + object->maxTransmittingGain = (unsigned char)var_toInteger(value); + break; + case 6: + object->searchInitiatorThreshold = (unsigned char)var_toInteger(value); + break; + case 7: + { + if (value->vt == DLMS_DATA_TYPE_STRUCTURE) + { + if ((ret = va_getByIndex(value->Arr, 0, &it)) == DLMS_ERROR_CODE_OK) + { + object->markFrequency = var_toInteger(it); + if ((ret = va_getByIndex(value->Arr, 1, &it)) == DLMS_ERROR_CODE_OK) + { + object->spaceFrequency = var_toInteger(it); + } + } + } + else + { + object->markFrequency = 0; + object->spaceFrequency = 0; + } + break; + } + case 8: + object->macAddress = (uint16_t)var_toInteger(value); + break; + case 9: + { + arr_clear(&object->macGroupAddresses); + if (value->vt == DLMS_DATA_TYPE_ARRAY) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + if ((ret = va_getByIndex(value->Arr, pos, &it)) != DLMS_ERROR_CODE_OK) + { + break; + } + uint16_t* v = gxmalloc(sizeof(uint16_t)); + *v = (uint16_t)var_toInteger(it); + arr_push(&object->macGroupAddresses, v); + } + } + break; + } + case 10: + object->repeater = (DLMS_REPEATER)var_toInteger(value); + break; + case 11: + object->repeaterStatus = value->boolVal; + break; + case 12: + object->minDeltaCredit = (unsigned char)var_toInteger(value); + break; + case 13: + object->initiatorMacAddress = (uint16_t)var_toInteger(value); + break; + case 14: + object->synchronizationLocked = (unsigned char)var_toInteger(value); + break; + case 15: + object->transmissionSpeed = (DLMS_BAUD_RATE)var_toInteger(value); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_SFSK_PHY_MAC_SETUP + +#ifndef DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST +int cosem_setSFSKReportingSystemList( + dlmsSettings* settings, + gxSFSKReportingSystemList* object, + unsigned char index, + dlmsVARIANT* value) +{ + int pos, ret = 0; + dlmsVARIANT* tmp; + gxByteBuffer* it; + if (index == 2) + { + obj_clearByteBufferList(&object->reportingSystemList); + if (value->vt == DLMS_DATA_TYPE_ARRAY) + { + if (value->vt == DLMS_DATA_TYPE_ARRAY) + { + for (pos = 0; pos != value->Arr->size; ++pos) + { + if ((ret = va_getByIndex(value->Arr, pos, &tmp)) != DLMS_ERROR_CODE_OK) + { + break; + } + it = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + BYTE_BUFFER_INIT(it); + bb_set(it, tmp->byteArr->data, tmp->byteArr->size); + if (it == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + arr_push(&object->reportingSystemList, it); + } + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST + +#ifdef DLMS_ITALIAN_STANDARD +int updateIntervals(gxInterval* interval, gxByteBuffer* value) +{ + int ret; + unsigned char b; + if ((ret = bb_getUInt8(value, &b)) != 0) + { + return ret; + } + interval[0].startHour = (unsigned char)(b >> 3); + interval[0].intervalTariff = (DLMS_DEFAULT_TARIFF_BAND)((b >> 1) & 0x3); + interval[0].useInterval = (b & 0x1) != 0; + if ((ret = bb_getUInt8(value, &b)) != 0) + { + return ret; + } + interval[1].startHour = (unsigned char)(b >> 3); + interval[1].intervalTariff = (DLMS_DEFAULT_TARIFF_BAND)((b >> 1) & 0x3); + interval[1].useInterval = (b & 0x1) != 0; + if ((ret = bb_getUInt8(value, &b)) != 0) + { + return ret; + } + interval[2].startHour = (unsigned char)(b >> 3); + interval[2].intervalTariff = (DLMS_DEFAULT_TARIFF_BAND)((b >> 1) & 0x3); + interval[2].useInterval = (b & 0x1) != 0; + if ((ret = bb_getUInt8(value, &b)) != 0) + { + return ret; + } + interval[3].startHour = (unsigned char)(b >> 3); + interval[3].intervalTariff = (DLMS_DEFAULT_TARIFF_BAND)((b >> 1) & 0x3); + interval[3].useInterval = (b & 0x1) != 0; + if ((ret = bb_getUInt8(value, &b)) != 0) + { + return ret; + } + interval[4].startHour = (unsigned char)(b >> 3); + interval[4].intervalTariff = (DLMS_DEFAULT_TARIFF_BAND)((b >> 1) & 0x3); + interval[4].useInterval = (b & 0x1) != 0; + return 0; +} + +int updateSeason(gxBandDescriptor* season, variantArray* value) +{ + int ret; + dlmsVARIANT* tmp; + if (value->size == 5) + { + if ((ret = va_getByIndex(value, 0, &tmp)) != 0) + { + return ret; + } + season->dayOfMonth = tmp->bVal; + if ((ret = va_getByIndex(value, 1, &tmp)) != 0) + { + return ret; + } + season->month = tmp->bVal; + if ((ret = va_getByIndex(value, 2, &tmp)) != 0 || + (ret = updateIntervals(season->workingDayIntervals, tmp->byteArr)) != 0 || + (ret = va_getByIndex(value, 3, &tmp)) != 0 || + (ret = updateIntervals(season->saturdayIntervals, tmp->byteArr)) != 0 || + (ret = va_getByIndex(value, 4, &tmp)) != 0 || + (ret = updateIntervals(season->holidayIntervals, tmp->byteArr)) != 0) + { + return ret; + } + } + else + { + ret = DLMS_ERROR_CODE_UNMATCH_TYPE; + } + return ret; +} + +int cosem_setTariffPlan(gxTariffPlan* object, unsigned char index, dlmsVARIANT* value) +{ + dlmsVARIANT tmp3; + dlmsVARIANT* tmp, * tmp2; + int ret, pos, h, m, s; + switch (index) + { + case 2: + if (value->vt == DLMS_DATA_TYPE_OCTET_STRING) + { + object->calendarName = (char*)gxmalloc(value->byteArr->size); + memcpy(object->calendarName, value->byteArr->data, value->byteArr->size); + object->calendarName[value->byteArr->size] = 0; + } + else + { + object->calendarName = (char*)gxmalloc(value->strVal->size + 1); + memcpy(object->calendarName, value->strVal->data, value->strVal->size); + object->calendarName[value->strVal->size] = 0; + } + break; + case 3: + object->enabled = value->boolVal; + break; + case 4: + { + if (value->Arr->size == 4) + { + if ((ret = va_getByIndex(value->Arr, 0, &tmp)) != 0) + { + return ret; + } + object->plan.defaultTariffBand = tmp->bVal; + if ((ret = va_getByIndex(value->Arr, 1, &tmp)) != 0) + { + return ret; + } + if ((ret = va_getByIndex(tmp->Arr, 0, &tmp2)) != 0 || + (ret = updateSeason(&object->plan.winterSeason, tmp2->Arr)) != 0 || + (ret = va_getByIndex(tmp->Arr, 1, &tmp2)) != 0 || + (ret = updateSeason(&object->plan.summerSeason, tmp2->Arr)) != 0) + { + return ret; + } + ba_clear(&object->plan.weeklyActivation); + if ((ret = va_getByIndex(value->Arr, 2, &tmp)) != 0 || + (ret = ba_copy(&object->plan.weeklyActivation, tmp->bitArr->data, tmp->bitArr->size)) != 0) + { + return ret; + } + if ((ret = va_getByIndex(value->Arr, 3, &tmp)) != 0) + { + return ret; + } + arr_clear(&object->plan.specialDays); + arr_capacity(&object->plan.specialDays, tmp->Arr->size); + for (pos = 0; pos != tmp->Arr->size; ++pos) + { + if ((ret = va_getByIndex(tmp->Arr, pos, &tmp2)) != 0) + { + return ret; + } + arr_push(&object->plan.specialDays, (void*)tmp2->ulVal); + } + } + break; + } + case 5: + { + if ((ret = va_getByIndex(value->Arr, 0, &tmp)) != 0) + { + return ret; + } + var_init(&tmp3); + if ((ret = dlms_changeType2(tmp, DLMS_DATA_TYPE_TIME, &tmp3)) != 0) + { + return ret; + } + if ((tmp3.dateTime->skip & DATETIME_SKIPS_HOUR) == 0) + { + h = time_getHours(tmp3.dateTime); + } + else + { + h = 0; + } + if ((tmp3.dateTime->skip & DATETIME_SKIPS_MINUTE) == 0) + { + m = time_getMinutes(tmp3.dateTime); + } + else + { + m = 0; + } + if ((tmp3.dateTime->skip & DATETIME_SKIPS_SECOND) == 0) + { + s = time_getSeconds(tmp3.dateTime); + } + else + { + s = 0; + } + if ((ret = va_getByIndex(value->Arr, 1, &tmp2)) != 0) + { + return ret; + } + var_clear(&tmp3); + if ((ret = dlms_changeType2(tmp2, DLMS_DATA_TYPE_DATE, &tmp3)) != 0) + { + return ret; + } + time_copy(&object->activationTime, tmp3.dateTime); + object->activationTime.skip &= ~(DATETIME_SKIPS_HOUR | DATETIME_SKIPS_MINUTE | DATETIME_SKIPS_SECOND | DATETIME_SKIPS_MS); + time_addHours(&object->activationTime, h); + time_addMinutes(&object->activationTime, m); + time_addSeconds(&object->activationTime, s); + } + break; + default: + return DLMS_ERROR_CODE_READ_WRITE_DENIED; + } + return DLMS_ERROR_CODE_OK; +} +#endif //DLMS_ITALIAN_STANDARD + +#endif //!defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) diff --git a/components/xt211/gxsetmalloc.h b/components/xt211/gxsetmalloc.h new file mode 100644 index 0000000..b7638c9 --- /dev/null +++ b/components/xt211/gxsetmalloc.h @@ -0,0 +1,396 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef COSEM_SET_MALLOC_H +#define COSEM_SET_MALLOC_H + +#include "gxignore.h" +#if !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + +#ifdef __cplusplus +extern "C" { +#endif + +#include "gxobjects.h" +#include "dlmssettings.h" + +#ifndef DLMS_IGNORE_DATA + int cosem_setData(gxValueEventArg* e); +#endif //DLMS_IGNORE_DATA + +#ifndef DLMS_IGNORE_REGISTER + int cosem_setRegister(gxRegister* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_REGISTER + +#ifndef DLMS_IGNORE_CLOCK + int cosem_setClock(dlmsSettings* settings, gxClock* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_CLOCK + +#ifndef DLMS_IGNORE_ACTION_SCHEDULE + int cosem_setActionSchedule(dlmsSettings* settings, gxActionSchedule* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_ACTION_SCHEDULE + +#ifndef DLMS_IGNORE_ACTIVITY_CALENDAR + int cosem_setActivityCalendar(dlmsSettings* settings, gxActivityCalendar* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_ACTIVITY_CALENDAR + +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + int cosem_parseLNObjects(dlmsSettings* settings, gxByteBuffer* data, objectArray* objects); + int cosem_setAssociationLogicalName(dlmsSettings* settings, gxAssociationLogicalName* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + int cosem_parseSNObjects(dlmsSettings* settings, gxByteBuffer* data, objectArray* objects); + int cosem_setAssociationShortName(dlmsSettings* settings, gxAssociationShortName* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + +#ifndef DLMS_IGNORE_AUTO_ANSWER + int cosem_setAutoAnswer(gxAutoAnswer* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_AUTO_ANSWER + +#ifndef DLMS_IGNORE_AUTO_CONNECT + int cosem_setAutoConnect(gxAutoConnect* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_AUTO_CONNECT + +#ifndef DLMS_IGNORE_DEMAND_REGISTER + int cosem_setDemandRegister(gxDemandRegister* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_DEMAND_REGISTER + +#ifndef DLMS_IGNORE_MAC_ADDRESS_SETUP + int cosem_setMacAddressSetup(gxMacAddressSetup* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_MAC_ADDRESS_SETUP + +#ifndef DLMS_IGNORE_EXTENDED_REGISTER + int cosem_setExtendedRegister(gxExtendedRegister* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_EXTENDED_REGISTER + +#ifndef DLMS_IGNORE_GPRS_SETUP + int cosem_setGprsSetup(gxGPRSSetup* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_GPRS_SETUP + +#ifndef DLMS_IGNORE_SECURITY_SETUP + int cosem_setSecuritySetup(dlmsSettings* settings, gxSecuritySetup* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_SECURITY_SETUP + +#ifndef DLMS_IGNORE_IEC_HDLC_SETUP + int cosem_setIecHdlcSetup(gxIecHdlcSetup* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_IEC_HDLC_SETUP + +#ifndef DLMS_IGNORE_IEC_LOCAL_PORT_SETUP + int cosem_setIecLocalPortSetup(gxLocalPortSetup* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_IEC_LOCAL_PORT_SETUP + +#ifndef DLMS_IGNORE_IP4_SETUP + int cosem_setIP4Setup(dlmsSettings* settings, gxIp4Setup* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_IP4_SETUP + +#ifndef DLMS_IGNORE_PROFILE_GENERIC + int cosem_setProfileGeneric(dlmsSettings* settings, gxProfileGeneric* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_PROFILE_GENERIC + +#ifndef DLMS_IGNORE_UTILITY_TABLES + int cosem_setUtilityTables(gxUtilityTables* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_UTILITY_TABLES + +#ifndef DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP + int cosem_setMbusSlavePortSetup(gxMbusSlavePortSetup* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP + +#ifndef DLMS_IGNORE_DISCONNECT_CONTROL + int cosem_setDisconnectControl(gxDisconnectControl* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_DISCONNECT_CONTROL + +#ifndef DLMS_IGNORE_LIMITER + int cosem_setLimiter(dlmsSettings* settings, gxLimiter* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_LIMITER + +#ifndef DLMS_IGNORE_MBUS_CLIENT + int cosem_setmMbusClient(dlmsSettings* settings, gxMBusClient* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_MBUS_CLIENT + +#ifndef DLMS_IGNORE_MODEM_CONFIGURATION + int cosem_setModemConfiguration(gxModemConfiguration* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_MODEM_CONFIGURATION + +#ifndef DLMS_IGNORE_PPP_SETUP + int cosem_setPppSetup(dlmsSettings* settings, gxPppSetup* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_PPP_SETUP + +#ifndef DLMS_IGNORE_REGISTER_ACTIVATION + int cosem_setRegisterActivation(dlmsSettings* settings, gxValueEventArg* e); +#endif //DLMS_IGNORE_REGISTER_ACTIVATION + +#ifndef DLMS_IGNORE_REGISTER_MONITOR + int cosem_setRegisterMonitor(dlmsSettings* settings, gxRegisterMonitor* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_REGISTER_MONITOR + +#ifndef DLMS_IGNORE_SAP_ASSIGNMENT + int cosem_setSapAssignment(gxSapAssignment* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_SAP_ASSIGNMENT + +#ifndef DLMS_IGNORE_SCHEDULE + int cosem_setSchedule(dlmsSettings* settings, gxSchedule* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_SCHEDULE + +#ifndef DLMS_IGNORE_SCRIPT_TABLE + int cosem_setScriptTable(dlmsSettings* settings, gxScriptTable* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_SCRIPT_TABLE + +#ifndef DLMS_IGNORE_SPECIAL_DAYS_TABLE + int cosem_setSpecialDaysTable(gxSpecialDaysTable* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_SPECIAL_DAYS_TABLE + +#ifndef DLMS_IGNORE_TCP_UDP_SETUP + int cosem_setTcpUdpSetup(dlmsSettings* settings, gxTcpUdpSetup* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_TCP_UDP_SETUP +#ifndef DLMS_IGNORE_MBUS_DIAGNOSTIC + int cosem_setMbusDiagnostic(gxMbusDiagnostic* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_MBUS_DIAGNOSTIC +#ifndef DLMS_IGNORE_MBUS_PORT_SETUP + int cosem_setMbusPortSetup(gxMBusPortSetup* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_MBUS_PORT_SETUP +#ifndef DLMS_IGNORE_MBUS_MASTER_PORT_SETUP + int cosem_setMbusMasterPortSetup(gxMBusMasterPortSetup* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_MBUS_MASTER_PORT_SETUP + +#ifndef DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS + int cosem_setG3PlcMacLayerCounters(gxG3PlcMacLayerCounters* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS +#ifndef DLMS_IGNORE_G3_PLC_MAC_SETUP + int cosem_setG3PlcMacSetup(gxG3PlcMacSetup* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_G3_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_G3_PLC_6LO_WPAN + int cosem_setG3Plc6LoWPAN(gxG3Plc6LoWPAN* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_G3_PLC_6LO_WPAN +#ifndef DLMS_IGNORE_FUNCTION_CONTROL + int cosem_setFunctionControl( + dlmsSettings* settings, + gxFunctionControl* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_FUNCTION_CONTROL +#ifndef DLMS_IGNORE_ARRAY_MANAGER + int cosem_setArrayManager(dlmsSettings* settings, gxArrayManager* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_ARRAY_MANAGER + +#ifndef DLMS_IGNORE_PUSH_SETUP + int cosem_setPushSetup(dlmsSettings* settings, gxPushSetup* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_PUSH_SETUP + +#ifndef DLMS_IGNORE_GSM_DIAGNOSTIC + int cosem_setGsmDiagnostic(gxGsmDiagnostic* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_GSM_DIAGNOSTIC + +#ifndef DLMS_IGNORE_COMPACT_DATA + int compactData_updateTemplateDescription( + dlmsSettings* settings, + gxCompactData* object); +#endif //DLMS_IGNORE_COMPACT_DATA + +#ifndef DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP + int cosem_setIecTwistedPairSetup(gxIecTwistedPairSetup* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP + +#ifndef DLMS_IGNORE_IP6_SETUP + int cosem_setIP6Setup(dlmsSettings* settings, gxIp6Setup* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_IP6_SETUP + +#ifndef DLMS_IGNORE_IMAGE_TRANSFER + int cosem_setImageTransfer(gxImageTransfer* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_IMAGE_TRANSFER + +#ifndef DLMS_IGNORE_REGISTER_TABLE + int cosem_setRegistertable(gxRegisterTable* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_REGISTER_TABLE + +#ifndef DLMS_IGNORE_ACCOUNT + int cosem_setAccount(gxAccount* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_ACCOUNT + +#ifndef DLMS_IGNORE_CREDIT + int cosem_setCredit(gxCredit* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_CREDIT +#ifndef DLMS_IGNORE_CHARGE + int cosem_setCharge(dlmsSettings* settings, gxCharge* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_CHARGE +#ifndef DLMS_IGNORE_TOKEN_GATEWAY + int cosem_setTokenGateway(gxTokenGateway* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_TOKEN_GATEWAY + +#ifndef DLMS_IGNORE_COMPACT_DATA + int cosem_setCompactData( + dlmsSettings* settings, + gxCompactData* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_COMPACT_DATA + +#ifndef DLMS_IGNORE_PARAMETER_MONITOR + int cosem_setParameterMonitor( + dlmsSettings* settings, + gxParameterMonitor* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_PARAMETER_MONITOR + +#ifndef DLMS_IGNORE_LLC_SSCS_SETUP + int cosem_setLlcSscsSetup( + dlmsSettings* settings, + gxLlcSscsSetup* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_LLC_SSCS_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS + int cosem_setPrimeNbOfdmPlcPhysicalLayerCounters( + dlmsSettings* settings, + gxPrimeNbOfdmPlcPhysicalLayerCounters* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP + int cosem_setPrimeNbOfdmPlcMacSetup( + dlmsSettings* settings, + gxPrimeNbOfdmPlcMacSetup* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS + int cosem_setPrimeNbOfdmPlcMacFunctionalParameters( + dlmsSettings* settings, + gxPrimeNbOfdmPlcMacFunctionalParameters* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS + int cosem_setPrimeNbOfdmPlcMacCounters( + dlmsSettings* settings, + gxPrimeNbOfdmPlcMacCounters* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + int cosem_setPrimeNbOfdmPlcMacNetworkAdministrationData( + dlmsSettings* settings, + gxPrimeNbOfdmPlcMacNetworkAdministrationData* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION + int cosem_setPrimeNbOfdmPlcApplicationsIdentification( + dlmsSettings* settings, + gxPrimeNbOfdmPlcApplicationsIdentification* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION + +#ifndef DLMS_IGNORE_ARBITRATOR + int cosem_setArbitrator( + dlmsSettings* settings, + gxArbitrator* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_ARBITRATOR + +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP + int cosem_setIec8802LlcType1Setup( + dlmsSettings* settings, + gxIec8802LlcType1Setup* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP + +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP + int cosem_setIec8802LlcType2Setup( + dlmsSettings* settings, + gxIec8802LlcType2Setup* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP + +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP + int cosem_setIec8802LlcType3Setup( + dlmsSettings* settings, + gxIec8802LlcType3Setup* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP + +#ifndef DLMS_IGNORE_SFSK_ACTIVE_INITIATOR + int cosem_setSFSKActiveInitiator( + dlmsSettings* settings, + gxSFSKActiveInitiator* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_SFSK_ACTIVE_INITIATOR + +#ifndef DLMS_IGNORE_SFSK_MAC_COUNTERS + int cosem_setFSKMacCounters( + dlmsSettings* settings, + gxFSKMacCounters* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_SFSK_MAC_COUNTERS + +#ifndef DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS + int cosem_setSFSKMacSynchronizationTimeouts( + dlmsSettings* settings, + gxSFSKMacSynchronizationTimeouts* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS + +#ifndef DLMS_IGNORE_SFSK_PHY_MAC_SETUP + int cosem_setSFSKPhyMacSetUp( + dlmsSettings* settings, + gxSFSKPhyMacSetUp* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_SFSK_PHY_MAC_SETUP + +#ifndef DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST + int cosem_setSFSKReportingSystemList( + dlmsSettings* settings, + gxSFSKReportingSystemList* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST + +#ifdef __cplusplus +} +#endif + +#endif //!defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) +#endif//COSEM_SET_MALLOC_H diff --git a/components/xt211/gxvalueeventargs.h b/components/xt211/gxvalueeventargs.h new file mode 100644 index 0000000..055921e --- /dev/null +++ b/components/xt211/gxvalueeventargs.h @@ -0,0 +1,178 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- +#ifndef VALUE_EVENT_ARG_H +#define VALUE_EVENT_ARG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "gxignore.h" +#include "gxobjects.h" +#include "errorcodes.h" + + typedef struct + { + /** + * CGXDLMSVariant value. + */ + dlmsVARIANT value; +#if !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + /** + * Data type of the value. + */ + DLMS_DATA_TYPE dataType; +#endif //!defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + /** + * Is request handled. + */ + unsigned char handled; + /** + * Target DLMS object + */ + gxObject* target; + + /** + * Attribute index. + */ + unsigned char index; + /** + * Optional selector. + */ + unsigned char selector; + /** + * Optional parameters. + */ + dlmsVARIANT parameters; + /** + * Occurred error. + */ + DLMS_ERROR_CODE error; + /** + * Is action. This is reserved for internal use. + */ + unsigned char action; + + /** + * Is value added as byte array. + */ + unsigned char byteArray; + + /** + * Is value max PDU size skipped. + */ + unsigned char skipMaxPduSize; + + /** + * Transaction begin index. + */ + uint32_t transactionStartIndex; + /** + * Transaction end index. + */ + uint32_t transactionEndIndex; + //It this transaction. + uint16_t transaction; + } gxValueEventArg; + + /** + * Initialize value event arg. + */ + void ve_init( + gxValueEventArg* ve); + + /** + * Clear value event arg. + */ + void ve_clear( + gxValueEventArg* ve); + + typedef struct + { +#ifdef DLMS_IGNORE_MALLOC + gxValueEventArg* data; +#else + gxValueEventArg** data; +#endif //DLMS_IGNORE_MALLOC + unsigned char capacity; + unsigned char size; + unsigned char position; + } gxValueEventCollection; + + + //Initialize value event collection. + void vec_init( + gxValueEventCollection* arr); + +#ifdef DLMS_IGNORE_MALLOC + //Attach value event collection. + void vec_attach( + gxValueEventCollection* arr, + gxValueEventArg* value, + unsigned char count, + unsigned char capacity); +#endif //DLMS_IGNORE_MALLOC + /* + * Is static buffer used. + */ + char vec_isAttached( + gxValueEventCollection* arr); + + //Bit array capacity. + unsigned char vec_getCapacity( + gxValueEventCollection* arr); + +#ifndef DLMS_IGNORE_MALLOC + //Push new data to the value event collection. + int vec_push( + gxValueEventCollection* arr, + gxValueEventArg* item); +#endif //DLMS_IGNORE_MALLOC + + //empty array, but items are not free. + void vec_empty( + gxValueEventCollection* arr); + + //Clear array. All items are automatically free. + void vec_clear( + gxValueEventCollection* arr); + + int vec_getByIndex( + gxValueEventCollection* arr, + int index, + gxValueEventArg** value); + +#ifdef __cplusplus +} +#endif + +#endif //VALUE_EVENT_ARG_H diff --git a/components/xt211/helpers.c b/components/xt211/helpers.c new file mode 100644 index 0000000..e799696 --- /dev/null +++ b/components/xt211/helpers.c @@ -0,0 +1,1187 @@ +// +// -------------------------------------------------------------------------- +// 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 +#include +#endif +#include +#include +#include "gxmem.h" + +#if defined(_WIN32) || defined(_WIN64) +#include +#endif //defined(_WIN32) || defined(_WIN64) + +#if !defined(DLMS_IGNORE_STRING_CONVERTER) && !defined(DLMS_IGNORE_MALLOC) +#include //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; +} \ No newline at end of file diff --git a/components/xt211/helpers.h b/components/xt211/helpers.h new file mode 100644 index 0000000..ea2b351 --- /dev/null +++ b/components/xt211/helpers.h @@ -0,0 +1,274 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef GXHELPERS_H +#define GXHELPERS_H + +#ifdef __cplusplus +extern "C" { +#endif +#include "gxignore.h" +#ifdef USE_AVR + //If AVR is used. +#include +#endif //USE_AVR + +#include "bytebuffer.h" +#include "variant.h" + +static const unsigned char EMPTY_SYSTEM_TITLE[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +static const unsigned char EMPTY_LN[6] = { 0, 0, 0, 0, 0, 0 }; +static const unsigned char DEFAULT_ASSOCIATION[6] = { 0, 0, 40, 0, 0, 255 }; +static const unsigned char EMPTY_KEY[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + +//Get error message directly from EEPROM to save RAM. +#if defined(ARDUINO) || defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) +//If AVR is used. + #ifdef IDF_VER//espressif is using the different folder. + #include + #else + #include + #endif//ESP_PLATFORM +#define GET_STR_FROM_EEPROM(x) PSTR(x) +#else +#define GET_STR_FROM_EEPROM(x) (const char*)x +#endif//defined(ARDUINO) || defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) + + +//Get UInt32. +#define GETU32(pt) (((uint32_t)(pt)[0] << 24) | \ + ((uint32_t)(pt)[1] << 16) | \ + ((uint32_t)(pt)[2] << 8) | \ + ((uint32_t)(pt)[3])) + +//Set Int32 as Big Endian value. +#define PUT32(ct, st) { \ + (ct)[0] = (unsigned char)((st) >> 24); \ + (ct)[1] = (unsigned char)((st) >> 16); \ + (ct)[2] = (unsigned char)((st) >> 8); \ + (ct)[3] = (unsigned char)(st); } + + //Check byte order. + unsigned char hlp_isBigEndian(void); + + //Convert ASCII value to numeric unsigned char value. + unsigned char hlp_getValue(char c); + + const char* hlp_getErrorMessage(int error); + + //Returns items count. Use hlp_getObjectCount22. + int hlp_getObjectCount(gxByteBuffer* buff); + + //Returns items count. + int hlp_getObjectCount2( + gxByteBuffer* buff, + uint16_t* count); + + //Get count size in bytes. + unsigned char hlp_getObjectCountSizeInBytes(uint32_t count); + + // Set count of items. + int hlp_setObjectCount( + uint32_t count, + gxByteBuffer* buff); + +#ifndef DLMS_IGNORE_MALLOC + /** + * Convert byte array to hex string. This method use malloc to allocate enough memory. + */ + char* hlp_bytesToHex(const unsigned char* pBytes, int count); +#endif //DLMS_IGNORE_MALLOC + + /** + * Convert byte array to hex string. + */ + int hlp_bytesToHex2(const unsigned char* bytes, uint16_t count, char* buff, uint16_t size); + +#ifndef DLMS_IGNORE_MALLOC + /** + * Convert hex string to byte array. This method use malloc to allocate enough memory. + */ + int hlp_hexToBytes( + const char* str, + unsigned char** arr, + uint16_t* count); +#endif //DLMS_IGNORE_MALLOC + + /** + * Convert hex string to byte array. + */ + int hlp_hexToBytes2( + const char* str, + unsigned char* arr, + uint16_t* count); + +#if !defined(DLMS_IGNORE_MALLOC) + //Set logical name from string. + int hlp_setLogicalName(unsigned char ln[6], const char* name); +#endif //!defined(DLMS_IGNORE_MALLOC) + +#if !defined(DLMS_IGNORE_STRING_CONVERTER) && !defined(DLMS_IGNORE_MALLOC) + void hlp_trace(unsigned char* data, int index, int count, unsigned char send); + //Get Logical Name from string. + int hlp_parseLogicalName(gxByteBuffer* value, unsigned char ln[6]); + + //Set logical name from string. + int hlp_setLogicalName2(dlmsVARIANT* ln, const char* name); + + int hlp_appendLogicalName(gxByteBuffer* bb, const unsigned char value[6]); + + //Print logical name to cout. + int hlp_printLogicalName( + //Format. + const char* format, + //Logical name. + const unsigned char value[6]); +#endif //!defined(DLMS_IGNORE_STRING_CONVERTER) && !defined(DLMS_IGNORE_MALLOC) + + int hlp_getLogicalNameToString(const unsigned char value[6], char* ln); + + void hlp_replace(gxByteBuffer* str, char oldCh, char newCh); + + double hlp_getScaler(int scaler); + + /** + * Get data type in bytes. + * + * @param type + * Data type. + * @return Size of data type in bytes. + */ + int hlp_getDataTypeSize(DLMS_DATA_TYPE type); + + /** + * Convert integer to string. + * + * @param str + * Parsed string. + * @param strsize + * String size. + * @param value + * Integer value. + * @param isSigned + * Is value signed number. + * @param digits + * number of digits in string. + * @return Length of the string or -1 if error has occurred. + */ + int hlp_intToString( + char* str, + int bufsize, + int32_t value, + unsigned char isSigned, + unsigned char digits); + + /** + * Convert integer to string. + * + * @param str + * Parsed string. + * @param strsize + * String size. + * @param value + * Integer value. + * @param digits + * number of digits in string. + * @return Length of the string or -1 if error has occurred. + */ + int hlp_uint64ToString( + char* str, + int bufsize, + uint64_t value, + unsigned char digits); + + /** + * Convert string to integer. + * + * @param str + * Parsed string. + * @return Value of string as integer. + */ + int32_t hlp_stringToInt( + const char* str); + /** + * Convert integer to string. + * + * @param str + * Parsed string. + * @param strsize + * String size. + * @param value + * Integer value. + * @param isSigned + * Is value signed number. + * @return Length of the string or -1 if error has occurred. + */ + int hlp_int64ToString( + char* str, + int bufsize, + int64_t value, + unsigned char isSigned); + + /** + * Convert string to integer64. + * + * @param str + * Parsed string. + * @return Value of string as integer. + */ + int64_t hlp_stringToInt64( + const char* str); + + /** + * Random generator using Linear-feedback shift register. + * https://en.wikipedia.org/wiki/Linear-feedback_shift_register + * + * @return Random number. + */ + unsigned char hlp_rand(void); + + //Add bits from byte array to bit array. + int hlp_add( + bitArray* arr, + gxByteBuffer* bytes, + uint16_t count); + + + //Swap bits. Reserved for internal use. + unsigned char hlp_swapBits(unsigned char value); + +#ifdef __cplusplus +} +#endif + +#endif //GXHELPERS_H diff --git a/components/xt211/lnparameters.h b/components/xt211/lnparameters.h new file mode 100644 index 0000000..11ff37e --- /dev/null +++ b/components/xt211/lnparameters.h @@ -0,0 +1,100 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef LN_PARAMETERS_H +#define LN_PARAMETERS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "dlmssettings.h" +#include "bytebuffer.h" +#include "enums.h" + +/** +* LN Parameters +*/ +typedef struct +{ + /** + * DLMS settings. + */ + dlmsSettings *settings; + /** + * DLMS command. + */ + DLMS_COMMAND command; + /** + * Request type. + */ + int requestType; + /** + * Attribute descriptor. + */ + gxByteBuffer attributeDescriptor; + /** + * Data. + */ + gxByteBuffer m_Data; + + /** + * Send date and time. This is used in Data notification messages. + */ +#ifdef DLMS_USE_EPOCH_TIME + uint32_t time; +#else + struct tm time; +#endif //DLMS_USE_EPOCH_TIME + /** + * Reply status. + */ + int status; + /** + * Are there more data to send or more data to receive. + */ + unsigned char multipleBlocks; + /** + * Is this last block in send. + */ + unsigned char lastBlock; + /** + * Block index. + */ + int blockIndex; +} lnParameters; + +#ifdef __cplusplus +} +#endif + +#endif //LN_PARAMETERS_H diff --git a/components/xt211/message.c b/components/xt211/message.c new file mode 100644 index 0000000..a3c0359 --- /dev/null +++ b/components/xt211/message.c @@ -0,0 +1,143 @@ +// +// -------------------------------------------------------------------------- +// 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" +#ifndef DLMS_IGNORE_MALLOC +#include "gxmem.h" +#endif //DLMS_IGNORE_MALLOC + +#if _MSC_VER > 1400 +#include +#endif +#include +#include "message.h" +#include "errorcodes.h" + +#ifndef DLMS_IGNORE_MALLOC +//Initialize gxByteBuffer. +void mes_init(message* mes) +{ + mes->capacity = MESSAGE_CAPACITY; + mes->data = (gxByteBuffer**)gxmalloc(mes->capacity * sizeof(gxByteBuffer*)); + mes->size = 0; + mes->attached = 0; +} +#endif //DLMS_IGNORE_MALLOC + +void mes_attach(message* mes, gxByteBuffer** data, unsigned char capacity) +{ + mes->capacity = capacity; + mes->data = data; + mes->size = 0; +#ifndef DLMS_IGNORE_MALLOC + mes->attached = 1; +#endif //DLMS_IGNORE_MALLOC +} + +#ifndef DLMS_IGNORE_MALLOC +//Push new message. +int mes_push(message* mes, gxByteBuffer* item) +{ + if (mes->size == mes->capacity) + { + if (mes->attached) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + mes->capacity += MESSAGE_CAPACITY; + if (mes->data == NULL) + { + mes->data = (gxByteBuffer**)gxmalloc(mes->capacity * sizeof(gxByteBuffer*)); + if (mes->data == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + } + else + { +#ifdef gxrealloc + //If compiler supports realloc. + mes->data = (gxByteBuffer**)gxrealloc(mes->data, mes->capacity * sizeof(gxByteBuffer*)); + if (mes->data == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } +#else + //If compiler doesn't support realloc. + gxByteBuffer** old = mes->data; + mes->data = (gxByteBuffer**)gxmalloc(mes->capacity * sizeof(gxByteBuffer*)); + //If not enought memory available. + if (mes->data == NULL) + { + mes->data = old; + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + memcpy(mes->data, old, sizeof(gxByteBuffer*) * mes->size); + gxfree(old); +#endif // gxrealloc + } + } + mes->data[mes->size] = item; + ++mes->size; + return 0; +} +#endif //DLMS_IGNORE_MALLOC + +void mes_clear(message* mes) +{ + int pos; +#ifdef DLMS_IGNORE_MALLOC + for (pos = 0; pos != mes->capacity; ++pos) + { + mes->data[pos]->size = mes->data[pos]->position = 0; + } +#else + if (!mes->attached) + { + if (mes->size != 0) + { + for (pos = 0; pos != mes->size; ++pos) + { + gxfree(mes->data[pos]->data); + gxfree(mes->data[pos]); + } + } + if (mes->data != NULL) + { + gxfree(mes->data); + mes->data = NULL; + } + mes->capacity = 0; + } +#endif //DLMS_IGNORE_MALLOC + mes->size = 0; +} diff --git a/components/xt211/message.h b/components/xt211/message.h new file mode 100644 index 0000000..e71eecc --- /dev/null +++ b/components/xt211/message.h @@ -0,0 +1,73 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef MESSAGE_H +#define MESSAGE_H + +#include "gxignore.h" +#include "bytebuffer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MESSAGE_CAPACITY 2 + +typedef struct +{ + gxByteBuffer** data; + unsigned char capacity; + unsigned char size; +#ifndef DLMS_IGNORE_MALLOC + unsigned char attached; +#endif //DLMS_IGNORE_MALLOC +} message; + +#ifndef DLMS_IGNORE_MALLOC +//Initialize gxByteBuffer. +void mes_init(message* mes); +//Push new message. +int mes_push( + message* mes, + gxByteBuffer* item); +#endif //DLMS_IGNORE_MALLOC + +void mes_attach(message* mes, gxByteBuffer** data, unsigned char capacity); + +//Clear message list. +void mes_clear( + message* mes); + +#ifdef __cplusplus +} +#endif +#endif //MESSAGE_H diff --git a/components/xt211/object_locker.cpp b/components/xt211/object_locker.cpp new file mode 100644 index 0000000..2710ac8 --- /dev/null +++ b/components/xt211/object_locker.cpp @@ -0,0 +1,12 @@ +#include "object_locker.h" + +namespace esphome { + namespace xt211 { + + std::vector AnyObjectLocker::locked_objects_(5); + Mutex AnyObjectLocker::lock_; + +// unlock() function removed + + }; // namespace xt211 +}; // namespace esphome \ No newline at end of file diff --git a/components/xt211/object_locker.h b/components/xt211/object_locker.h new file mode 100644 index 0000000..86be48a --- /dev/null +++ b/components/xt211/object_locker.h @@ -0,0 +1,32 @@ +#pragma once +#include "esphome/core/log.h" +#include "esphome/core/helpers.h" +#include +#include + +namespace esphome { + namespace xt211 { + + class AnyObjectLocker { + public: + static bool try_lock(void *obj) { + if (!lock_.try_lock()) { + return false; + } + bool result = false; + if (std::find(locked_objects_.begin(), locked_objects_.end(), obj) == locked_objects_.end()) { + locked_objects_.push_back(obj); + result = true; + } + lock_.unlock(); + return result; + } + + // unlock() function removed to enforce read-only/no-session-release + + private: + static std::vector locked_objects_; + static Mutex lock_; + }; + }; // namespace xt211 +}; // namespace esphome diff --git a/components/xt211/objectarray.c b/components/xt211/objectarray.c new file mode 100644 index 0000000..8dbd714 --- /dev/null +++ b/components/xt211/objectarray.c @@ -0,0 +1,446 @@ +// +// -------------------------------------------------------------------------- +// 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 _MSC_VER > 1400 +#include +#endif +#if defined(_WIN64) || defined(_WIN32) || defined(__linux__) +#include +#endif //defined(_WIN64) || defined(_WIN32) || defined(__linux__) +#include +#include "objectarray.h" +#include "helpers.h" + +#if defined(_WIN64) || defined(_WIN32) || defined(__linux__) +#include +#include "helpers.h" +#endif //defined(_WIN64) || defined(_WIN32) || defined(__linux__) + +//Initialize objectArray. +void oa_init(objectArray* arr) +{ + arr->capacity = 0; + arr->data = NULL; +#if !(defined(GX_DLMS_MICROCONTROLLER) || defined(DLMS_IGNORE_MALLOC)) + arr->position = 0; +#endif //!(defined(GX_DLMS_MICROCONTROLLER) || defined(DLMS_IGNORE_MALLOC)) + arr->size = 0; +} + +char oa_isAttached(objectArray* arr) +{ + return (arr->capacity & 0x8000) == 0x8000; +} + +uint16_t oa_getCapacity(objectArray* arr) +{ + return arr->capacity & 0x7FFF; +} + +//Allocate new size for the array in bytes. +int oa_capacity(objectArray* arr, const uint16_t capacity) +{ +#ifndef DLMS_IGNORE_MALLOC + if (!oa_isAttached(arr)) + { + arr->capacity = capacity; + if (arr->data == NULL) + { + arr->data = (gxObject**)gxmalloc(arr->capacity * sizeof(gxObject*)); + } + else + { +#ifdef gxrealloc + //If compiler supports realloc. + arr->data = (gxObject**)gxrealloc(arr->data, arr->capacity * sizeof(gxObject*)); + #else + //If compiler doesn't support realloc. + gxObject** old = arr->data; + arr->data = (gxObject**)gxmalloc(arr->capacity * sizeof(gxObject*)); + //If not enought memory available. + if (arr->data == NULL) + { + arr->data = old; + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + memcpy(arr->data, old, sizeof(gxObject*) * arr->size); + gxfree(old); + #endif // gxrealloc + } + } +#endif //DLMS_IGNORE_MALLOC + if (oa_getCapacity(arr) < capacity) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + return 0; +} + +//Attach object to objectArray. +void oa_attach(objectArray* arr, gxObject** item, uint16_t count) +{ + arr->capacity = 0x8000 + count; + arr->size = count; +#if !(defined(GX_DLMS_MICROCONTROLLER) || defined(DLMS_IGNORE_MALLOC)) + arr->position = 0; +#endif //!(defined(GX_DLMS_MICROCONTROLLER) || defined(DLMS_IGNORE_MALLOC)) + arr->data = item; +} + +int oa_verify(objectArray* arr) +{ + uint16_t pos; + int ret; + gxObject* it; + for (pos = 0; pos != arr->size; ++pos) + { + if ((ret = oa_getByIndex(arr, pos, &it)) != 0) + { + return ret; + } + if (it->objectType == 0) + { +#if defined(_WIN64) || defined(_WIN32) || defined(__linux__) + if (pos > 0) + { + char ln[25]; + if ((ret = oa_getByIndex(arr, pos - 1, &it)) != 0 || + (ret = hlp_getLogicalNameToString(it->logicalName, ln)) != 0) + { + return ret; + } + printf("Last initialized object:%s\n", ln); + } +#endif + //If init2 is not called. + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + } + return DLMS_ERROR_CODE_OK; +} + +#ifndef DLMS_IGNORE_MALLOC +//Push new data to the objectArray. +int oa_push(objectArray* arr, gxObject* item) +{ + if (!oa_isAttached(arr) && arr->size >= arr->capacity) + { + arr->capacity += OBJECT_ARRAY_CAPACITY; + if (arr->data == NULL) + { + arr->data = (gxObject**)gxmalloc(arr->capacity * sizeof(gxObject*)); + } + else + { +#ifdef gxrealloc + //If compiler supports realloc. + arr->data = (gxObject**)gxrealloc(arr->data, arr->capacity * sizeof(gxObject*)); + #else + //If compiler doesn't support realloc. + gxObject** old = arr->data; + arr->data = (gxObject**)gxmalloc(arr->capacity * sizeof(gxObject*)); + //If not enought memory available. + if (arr->data == NULL) + { + arr->data = old; + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + memcpy(arr->data, old, sizeof(gxObject*) * arr->size); + gxfree(old); + #endif // gxrealloc + } + } + if (oa_getCapacity(arr) <= arr->size) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + arr->data[arr->size] = item; + ++arr->size; + return DLMS_ERROR_CODE_OK; +} +#endif //DLMS_IGNORE_MALLOC + +void oa_copy(objectArray* target, objectArray* source) +{ + int pos; + oa_empty(target); + oa_capacity(target, source->size); + for (pos = 0; pos != source->size; ++pos) + { + target->data[pos] = source->data[pos]; + } + target->size = source->size; +} + +void oa_move(objectArray* target, objectArray* source) +{ + int pos; + oa_empty(target); + oa_capacity(target, source->size); + for (pos = 0; pos != source->size; ++pos) + { + target->data[pos] = source->data[pos]; + } + target->size = source->size; + source->size = 0; +#if !(defined(GX_DLMS_MICROCONTROLLER) || defined(DLMS_IGNORE_MALLOC)) + source->position = 0; +#endif //!(defined(GX_DLMS_MICROCONTROLLER) || defined(DLMS_IGNORE_MALLOC)) +} + +void oa_clear2( + objectArray* arr, + uint16_t index, + uint16_t count) +{ + uint16_t pos; + if (arr->data != NULL) + { + //Clear objects first. + for (pos = 0; pos != count; ++pos) + { + obj_clear(arr->data[index + pos]); + } +#ifndef DLMS_IGNORE_MALLOC + for (pos = 0; pos != count; ++pos) + { + gxfree(arr->data[index + pos]); + } +#endif //DLMS_IGNORE_MALLOC + } + arr->size = index; +#if !(defined(GX_DLMS_MICROCONTROLLER) || defined(DLMS_IGNORE_MALLOC)) + arr->position = 0; +#endif //!(defined(GX_DLMS_MICROCONTROLLER) || defined(DLMS_IGNORE_MALLOC)) +} + +void oa_clear(objectArray* arr, unsigned char releaseObjects) +{ +#ifndef DLMS_IGNORE_MALLOC + uint16_t pos; + if (arr->data != NULL) + { + //Clear objects first. + for (pos = 0; pos != arr->size; ++pos) + { + obj_clear(arr->data[pos]); + } + if (releaseObjects) + { + for (pos = 0; pos != arr->size; ++pos) + { + gxfree(arr->data[pos]); + } + } + if (!oa_isAttached(arr)) + { + gxfree(arr->data); + arr->data = NULL; + arr->capacity = 0; + } + } +#endif //DLMS_IGNORE_MALLOC + arr->size = 0; +#if !(defined(GX_DLMS_MICROCONTROLLER) || defined(DLMS_IGNORE_MALLOC)) + arr->position = 0; +#endif //!(defined(GX_DLMS_MICROCONTROLLER) || defined(DLMS_IGNORE_MALLOC)) +} + +void oa_empty(objectArray* arr) +{ +#ifndef DLMS_IGNORE_MALLOC + if (!oa_isAttached(arr)) + { + if (arr->data != NULL) + { + gxfree(arr->data); + arr->data = NULL; + } + arr->capacity = 0; + } +#endif //DLMS_IGNORE_MALLOC + arr->size = 0; +#if !(defined(GX_DLMS_MICROCONTROLLER) || defined(DLMS_IGNORE_MALLOC)) + arr->position = 0; +#endif //!(defined(GX_DLMS_MICROCONTROLLER) || defined(DLMS_IGNORE_MALLOC)) +} + +//Get item from object array by index. +int oa_getByIndex( + const objectArray* arr, + uint16_t index, + gxObject** item) +{ + if (index >= arr->size) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + *item = (gxObject*)arr->data[index]; + return DLMS_ERROR_CODE_OK; +} + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME +int oa_findBySN( + objectArray* objects, + uint16_t sn, + gxObject** object) +{ + uint16_t pos; + int ret = DLMS_ERROR_CODE_OK; + gxObject* obj = NULL; + *object = NULL; + for (pos = 0; pos != objects->size; ++pos) + { + ret = oa_getByIndex(objects, pos, &obj); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + if (obj->shortName == sn) + { + *object = obj; + return 0; + } + } + return ret; +} +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + +int oa_findByLN( + objectArray* objects, + DLMS_OBJECT_TYPE type, + const unsigned char* ln, + gxObject** object) +{ + uint16_t pos; + int ret = DLMS_ERROR_CODE_OK; + gxObject* obj = NULL; + *object = NULL; + if (ln == NULL) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + for (pos = 0; pos != objects->size; ++pos) + { + if ((ret = oa_getByIndex(objects, pos, &obj)) != DLMS_ERROR_CODE_OK) + { + break; + } + if ((obj->objectType == type || DLMS_OBJECT_TYPE_NONE == type) && memcmp(obj->logicalName, ln, 6) == 0) + { + *object = obj; + break; + } + } + return ret; +} + +int oa_getObjects(objectArray* src, DLMS_OBJECT_TYPE type, objectArray* objects) +{ + uint16_t pos; + int ret = DLMS_ERROR_CODE_OK; + gxObject* obj = NULL; + if (src == NULL || objects == NULL) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + for (pos = 0; pos != src->size; ++pos) + { + ret = oa_getByIndex(src, pos, &obj); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + if (obj->objectType == type || type == DLMS_OBJECT_TYPE_NONE) + { +#ifdef DLMS_IGNORE_MALLOC + if (objects->data == NULL || !(objects->size < oa_getCapacity(objects))) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + objects->data[objects->size] = obj; + ++objects->size; +#else + oa_push(objects, obj); +#endif //DLMS_IGNORE_MALLOC + } + } + //Trim array. + oa_capacity(objects, objects->size); + return ret; +} + +int oa_getObjects2( + objectArray* src, + DLMS_OBJECT_TYPE* types, + unsigned char typeCount, + objectArray* objects) +{ + uint16_t pos, pos2; + int ret = DLMS_ERROR_CODE_OK; + gxObject* obj = NULL; + oa_empty(objects); + if (src == NULL || objects == NULL || types == NULL) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + for (pos = 0; pos != src->size; ++pos) + { + ret = oa_getByIndex(src, pos, &obj); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + for (pos2 = 0; pos2 != typeCount; ++pos2) + { + if (types[pos2] == obj->objectType) + { +#ifdef DLMS_IGNORE_MALLOC + if (!(objects->size < oa_getCapacity(objects))) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + memcpy(&objects->data[objects->size], obj, sizeof(gxObject)); + ++objects->size; +#else + oa_push(objects, obj); +#endif //DLMS_IGNORE_MALLOC + break; + } + } + } + //Trim array. + oa_capacity(objects, objects->size); + return ret; +} diff --git a/components/xt211/objectarray.h b/components/xt211/objectarray.h new file mode 100644 index 0000000..0541432 --- /dev/null +++ b/components/xt211/objectarray.h @@ -0,0 +1,141 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef OBJECTARRAY_H +#define OBJECTARRAY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "gxignore.h" +#include "gxobjects.h" + +#define OBJECT_ARRAY_CAPACITY 10 + + //Initialize variantArray. + void oa_init( + objectArray* arr); + + //Attach objects to objectArray. + void oa_attach( + objectArray * arr, + gxObject** item, + uint16_t count); + + //Verify that all objects are called init2. This is used for developing purposes. + int oa_verify( + objectArray * arr); + + + + char oa_isAttached(objectArray* arr); + + uint16_t oa_getCapacity(objectArray* arr); + + //Allocate new size for the array in bytes. + int oa_capacity( + objectArray* arr, + const uint16_t capacity); + +#ifndef DLMS_IGNORE_MALLOC + //Push new data to the variantArray. + int oa_push( + objectArray * arr, + gxObject* item); +#endif //DLMS_IGNORE_MALLOC + + //Copy content of object array. + void oa_copy( + objectArray *target, + objectArray* source); + + //Move content of object array. + void oa_move( + objectArray* target, + objectArray* source); + + //Clear object array. Clear will free objects as well. + void oa_clear2( + objectArray* arr, + uint16_t index, + uint16_t count); + + //Clear object array. Clear will free objects as well. + void oa_clear( + objectArray* arr, + unsigned char releaseObjects); + + //Empty object array. Empty do not free objects. + void oa_empty( + objectArray* arr); + + //Get item from object array by index. + int oa_getByIndex( + const objectArray* arr, + uint16_t index, + gxObject** item); + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + //Find object using Short Name. + int oa_findBySN( + objectArray* objects, + uint16_t sn, + gxObject** object); +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + + //Find object using Logical Name. + int oa_findByLN( + objectArray* objects, + DLMS_OBJECT_TYPE type, + const unsigned char* ln, + gxObject** object); + + //Get object by object type. + int oa_getObjects( + objectArray* src, + DLMS_OBJECT_TYPE type, + objectArray* objects); + + //Get object by array of object type. + int oa_getObjects2( + objectArray* src, + DLMS_OBJECT_TYPE* types, + unsigned char typeCount, + objectArray* objects); + +#define OA_ATTACH(X, V) oa_attach(&X, (gxObject**) V, sizeof(V)/sizeof(V[0])) +#ifdef __cplusplus +} +#endif + +#endif //OBJECTARRAY_H diff --git a/components/xt211/parameters.c b/components/xt211/parameters.c new file mode 100644 index 0000000..3abf191 --- /dev/null +++ b/components/xt211/parameters.c @@ -0,0 +1,90 @@ +// +// -------------------------------------------------------------------------- +// 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 "parameters.h" +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + +void params_initSN( + gxSNParameters *target, + dlmsSettings *settings, + DLMS_COMMAND command, + int count, + unsigned char commandType, + gxByteBuffer* attributeDescriptor, + gxByteBuffer* data, + DLMS_COMMAND encryptedCommand) +{ + target->settings = settings; + target->blockIndex = (uint16_t)settings->blockIndex; + target->command = command; + target->encryptedCommand = encryptedCommand; + target->count = count; + target->requestType = commandType; + target->attributeDescriptor = attributeDescriptor; + target->data = data; + target->multipleBlocks = 0; + target->time = 0; + target->lastBlock = 1; +#ifdef DLMS_IGNORE_MALLOC + target->serializedPdu = settings->serializedPdu; +#endif //DLMS_IGNORE_MALLOC +} +#endif // DLMS_IGNORE_ASSOCIATION_SHORT_NAME + +void params_initLN( + gxLNParameters *target, + dlmsSettings* settings, + unsigned char invokeId, + DLMS_COMMAND command, + unsigned char commandType, + gxByteBuffer* attributeDescriptor, + gxByteBuffer* data, + unsigned char status, + DLMS_COMMAND encryptedCommand, + unsigned char multipleBlocks, + unsigned char lastBlock) +{ + target->invokeId = invokeId; + target->settings = settings; + target->blockIndex = settings->blockIndex; + target->command = command; + target->encryptedCommand = encryptedCommand; + target->requestType = commandType; + target->attributeDescriptor = attributeDescriptor; + target->data = data; + target->time = 0; + target->status = status; + target->multipleBlocks = multipleBlocks; + target->lastBlock = lastBlock; + //Serialize data to this PDU. + target->serializedPdu = settings->serializedPdu; +} diff --git a/components/xt211/parameters.h b/components/xt211/parameters.h new file mode 100644 index 0000000..f2a257c --- /dev/null +++ b/components/xt211/parameters.h @@ -0,0 +1,194 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef PARAMETERS_H +#define PARAMETERS_H + +#ifdef __cplusplus +extern "C" { +#endif +#include "gxignore.h" +#include "dlmssettings.h" + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + /** + * SN Parameters + */ + typedef struct + { + /** + * DLMS settings. + */ + dlmsSettings *settings; + /** + * DLMS command. + */ + DLMS_COMMAND command; + /** + * Encrypted DLMS command. + */ + DLMS_COMMAND encryptedCommand; + /** + * Request type. + */ + unsigned char requestType; + /** + * Attribute descriptor. + */ + gxByteBuffer* attributeDescriptor; + /** + * Data. + */ + gxByteBuffer* data; + /** + * Send date and time. This is used in Data notification messages. + */ +#ifdef DLMS_USE_EPOCH_TIME + uint32_t time; +#else + struct tm* time; +#endif //DLMS_USE_EPOCH_TIME + /** + * Item Count. + */ + int count; + + /** + * Are there more data to send or more data to receive. + */ + unsigned char multipleBlocks; + + /** + * Is this last block. + */ + unsigned char lastBlock; + /** + * Block index. + */ + uint16_t blockIndex; + //Serialize data to this PDU. +#ifdef DLMS_IGNORE_MALLOC + gxByteBuffer* serializedPdu; +#endif //DLMS_IGNORE_MALLOC + } gxSNParameters; + + void params_initSN( + gxSNParameters *target, + dlmsSettings *settings, + DLMS_COMMAND command, + int count, + unsigned char commandType, + gxByteBuffer* attributeDescriptor, + gxByteBuffer* data, + DLMS_COMMAND encryptedCommand); + +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + + /** + * LN Parameters + */ + typedef struct + { + /** + * DLMS settings. + */ + dlmsSettings *settings; + /** + * DLMS command. + */ + DLMS_COMMAND command; + /** + * Encrypted DLMS command. + */ + DLMS_COMMAND encryptedCommand; + /** + * Request type. + */ + unsigned char requestType; + /** + * Attribute descriptor. + */ + gxByteBuffer* attributeDescriptor; + /** + * Data. + */ + gxByteBuffer* data; + /** + * Send date and time. This is used in Data notification messages. + */ +#ifdef DLMS_USE_EPOCH_TIME + uint32_t time; +#else + struct tm* time; +#endif // DLMS_USE_EPOCH_TIME + /** + * Reply status. + */ + unsigned char status; + /** + * Are there more data to send or more data to receive. + */ + unsigned char multipleBlocks; + /** + * Is this last block in send. + */ + unsigned char lastBlock; + /** + * Block index. + */ + uint32_t blockIndex; + /** + * Received invoke ID. + */ + unsigned char invokeId; + //Serialize data to this PDU. + gxByteBuffer* serializedPdu; + } gxLNParameters; + + void params_initLN( + gxLNParameters *target, + dlmsSettings* settings, + unsigned char invokeId, + DLMS_COMMAND command, + unsigned char commandType, + gxByteBuffer* attributeDescriptor, + gxByteBuffer* data, + unsigned char status, + DLMS_COMMAND encryptedCommand, + unsigned char multipleBlocks, + unsigned char lastBlock); + +#ifdef __cplusplus +} +#endif + +#endif //PARAMETERS_H diff --git a/components/xt211/replydata.c b/components/xt211/replydata.c new file mode 100644 index 0000000..0a8b646 --- /dev/null +++ b/components/xt211/replydata.c @@ -0,0 +1,116 @@ +// +// -------------------------------------------------------------------------- +// 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 /* memset */ +#include "gxmem.h" +#if _MSC_VER > 1400 +#include +#endif +#include "replydata.h" + +/** +* @return Is more data available. +*/ +unsigned char reply_isMoreData(gxReplyData* reply) +{ + return reply->moreData != DLMS_DATA_REQUEST_TYPES_NONE; +} + +/** +* Initialize reply structure. +*/ +void reply_init(gxReplyData* reply) +{ + reply->invokeId = 0; + reply->commandType = 0; + reply->moreData = DLMS_DATA_REQUEST_TYPES_NONE; + reply->encryptedCommand = reply->command = DLMS_COMMAND_NONE; + BYTE_BUFFER_INIT(&reply->data); + reply->complete = 0; + var_init(&reply->dataValue); + reply->totalCount = 0; + reply->readPosition = 0; + reply->packetLength = 0; + reply->peek = 0; + reply->ignoreValue = 0; + reply->dataType = DLMS_DATA_TYPE_NONE; + reply->cipherIndex = 0; +#ifdef DLMS_USE_EPOCH_TIME + reply->time = 0; +#else + memset(&reply->time, 0, sizeof(struct tm)); +#endif // DLMS_USE_EPOCH_TIME + reply->preEstablished = 0; + reply->blockNumber = 0; + reply->blockNumberAck = 0; + reply->streaming = 0; + reply->windowSize = 0; + reply->serverAddress = 0; + reply->clientAddress = 0; +} + +void reply_clear2(gxReplyData* reply, unsigned char clearData) +{ + reply->invokeId = 0; + reply->moreData = DLMS_DATA_REQUEST_TYPES_NONE; + reply->encryptedCommand = reply->command = DLMS_COMMAND_NONE; + if (clearData) + { + bb_clear(&reply->data); + reply->preEstablished = 0; + } + reply->complete = 0; + var_clear(&reply->dataValue); + reply->totalCount = 0; + reply->readPosition = 0; + reply->packetLength = 0; + reply->peek = 0; + reply->ignoreValue = 0; + reply->dataType = DLMS_DATA_TYPE_NONE; + reply->cipherIndex = 0; +#ifdef DLMS_USE_EPOCH_TIME + reply->time = 0; +#else + memset(&reply->time, 0, sizeof(struct tm)); +#endif // DLMS_USE_EPOCH_TIME + reply->blockNumber = 0; + reply->blockNumberAck = 0; + reply->streaming = 0; + reply->windowSize = 0; + reply->serverAddress = 0; + reply->clientAddress = 0; +} + +void reply_clear(gxReplyData* reply) +{ + reply_clear2(reply, 1); +} diff --git a/components/xt211/replydata.h b/components/xt211/replydata.h new file mode 100644 index 0000000..5edbbad --- /dev/null +++ b/components/xt211/replydata.h @@ -0,0 +1,158 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef GXREPLYDATA_H +#define GXREPLYDATA_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "variant.h" + + typedef struct + { + /** + * Is more data available. + */ + DLMS_DATA_REQUEST_TYPES moreData; + /** + * Received command. + */ + DLMS_COMMAND command; + /** + * Encrypted command. + */ + DLMS_COMMAND encryptedCommand; + + unsigned char commandType; + + /** + * Received data. + */ + gxByteBuffer data; + + /** + * Is frame complete. + */ + unsigned char complete; + + /** + * Read value. + */ + dlmsVARIANT dataValue; + + /** + * Expected count of element in the array. + */ + uint16_t totalCount; + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + /** + * Last read position. This is used in peek to solve how far data is read. + */ + uint32_t readPosition; + /** + * Packet length. + */ + uint32_t packetLength; +#else + /** + * Last read position. This is used in peek to solve how far data is read. + */ + uint16_t readPosition; + /** + * Packet length. + */ + uint16_t packetLength; +#endif + /** + * Try Get value. + */ + unsigned char peek; + + /** + * Value is not try to parse. This is used in data collector. + */ + unsigned char ignoreValue; + + DLMS_DATA_TYPE dataType; + + /** + * Cipher index is position where data is decrypted. + */ + uint16_t cipherIndex; + + /** + * Data notification date time. + */ +#ifdef DLMS_USE_EPOCH_TIME + uint32_t time; +#else + struct tm time; +#endif // DLMS_USE_EPOCH_TIME + /** + * Pre-established connection. + */ + unsigned char preEstablished; + unsigned char invokeId; + + //GBT block number. + uint16_t blockNumber; + //GBT block number ACK. + uint16_t blockNumberAck; + //GBT is streaming used. + unsigned streaming; + //GBT window size + unsigned windowSize; + //Server address. + uint16_t serverAddress; + //Client address. + uint16_t clientAddress; + } gxReplyData; + + unsigned char reply_isMoreData(gxReplyData* reply); + + /** + * Initialize reply structure. + */ + void reply_init(gxReplyData* reply); + + void reply_clear(gxReplyData* reply); + + void reply_clear2(gxReplyData* reply, unsigned char clearData); + +#ifdef __cplusplus +} +#endif + +#endif //GXREPLYDATA_H diff --git a/components/xt211/sensor.py b/components/xt211/sensor.py new file mode 100644 index 0000000..b7ee10b --- /dev/null +++ b/components/xt211/sensor.py @@ -0,0 +1,41 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor +from . import ( + XT211, + xt211_ns, + obis_code, + CONF_XT211_ID, + CONF_OBIS_CODE, + CONF_DONT_PUBLISH, + CONF_CLASS, +) + +XT211Sensor = xt211_ns.class_("XT211Sensor", sensor.Sensor) + +CONF_MULTIPLIER = "multiplier" + +CONFIG_SCHEMA = cv.All( + sensor.sensor_schema( + XT211Sensor, + ).extend( + { + cv.GenerateID(CONF_XT211_ID): cv.use_id(XT211), + cv.Required(CONF_OBIS_CODE): obis_code, + cv.Optional(CONF_DONT_PUBLISH, default=False): cv.boolean, + cv.Optional(CONF_MULTIPLIER, default=1.0): cv.float_, + cv.Optional(CONF_CLASS, default=3): cv.int_, + } + ), + cv.has_exactly_one_key(CONF_OBIS_CODE), +) + + +async def to_code(config): + component = await cg.get_variable(config[CONF_XT211_ID]) + var = await sensor.new_sensor(config) + cg.add(var.set_obis_code(config[CONF_OBIS_CODE])) + cg.add(var.set_dont_publish(config.get(CONF_DONT_PUBLISH))) + cg.add(var.set_multiplier(config[CONF_MULTIPLIER])) + cg.add(var.set_obis_class(config[CONF_CLASS])) + cg.add(component.register_sensor(var)) \ No newline at end of file diff --git a/components/xt211/server.c b/components/xt211/server.c new file mode 100644 index 0000000..f17aefe --- /dev/null +++ b/components/xt211/server.c @@ -0,0 +1,5108 @@ +// +// -------------------------------------------------------------------------- +// Gurux Ltd +// +// -------------------------------------------------------------------------- +// 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" +#ifndef DLMS_IGNORE_SERVER + +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) +#include +#if _MSC_VER > 1400 +#include +#include +#endif +#endif +#include "gxmem.h" +#include "apdu.h" +#include "server.h" +#include "dlms.h" +#include "cosem.h" +#include "enums.h" +#include "gxset.h" +#include "gxget.h" +#include "gxinvoke.h" +#include "gxserializer.h" + +typedef struct +{ + /** + * Is attribute index or action index + */ + unsigned char action; + + /** + * Attribute index. + */ + unsigned char index; + + /** + * COSEM object. + */ + gxObject* item; +} gxSNInfo; + +//Is interface type HDLC or HDLC with mode E. +#define IS_HDLC(interfaceType) (interfaceType == DLMS_INTERFACE_TYPE_HDLC || interfaceType == DLMS_INTERFACE_TYPE_HDLC_WITH_MODE_E) + +#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) +/** + * Handle read request. + */ +int svr_handleReadRequest( + dlmsServerSettings* settings, + gxByteBuffer* data); + +/** +* Declare a prototype for a svr_handleWriteRequest. +*/ +int svr_handleWriteRequest( + dlmsServerSettings* settings, + gxByteBuffer* data); +#endif //!defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + +#if !defined(DLMS_IGNORE_MALLOC) +//Copy association view. +void svr_copyAssociationView(objectArray* target, objectArray* source) +{ + uint16_t cnt = 0, pos; + oa_empty(target); + oa_capacity(target, source->size); + for (pos = 0; pos != source->size; ++pos) + { + if (source->data[pos]->objectType != DLMS_OBJECT_TYPE_ASSOCIATION_SHORT_NAME && + source->data[pos]->objectType != DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME) + { + target->data[cnt] = source->data[pos]; + ++cnt; + } + } + target->size = cnt; +} +#endif //!defined(DLMS_IGNORE_MALLOC) + +int sr_initialize( + gxServerReply* sr, + unsigned char* data, + uint16_t dataSize, + gxByteBuffer* reply) +{ + /*Received data from the client.*/ + sr->data = data; + /*Data size.*/ + sr->dataSize = dataSize; + /*Server reply for the client.*/ + sr->reply = reply; + /*Is GBT streaming in progress.*/ + sr->moreData = DLMS_DATA_REQUEST_TYPES_NONE; + /*GBT Message count to send.*/ + sr->gbtCount = 0; + /*HDLC window count to send.*/ + sr->hdlcWindowCount = 0; + /*Received command.*/ + sr->command = DLMS_COMMAND_NONE; +#ifndef DLMS_IGNORE_IEC + /*Baudrate is changed when optical probe is used.*/ + sr->newBaudRate = 0; +#endif //DLMS_IGNORE_IEC + return 0; +} + +int svr_initialize( + dlmsServerSettings* settings) +{ + uint16_t pos; + int ret; + gxObject* associationObject = NULL, * it; + settings->initialized = 1; + if (settings->base.maxPduSize < 64) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + for (pos = 0; pos != settings->base.objects.size; ++pos) + { + if ((ret = oa_getByIndex(&settings->base.objects, pos, &it)) != 0) + { + return ret; + } + if (memcmp(it->logicalName, EMPTY_LN, sizeof(EMPTY_LN)) == 0) + { + //Invalid Logical Name. + return DLMS_ERROR_CODE_INVALID_LOGICAL_NAME; + } + if (it->objectType == DLMS_OBJECT_TYPE_ASSOCIATION_SHORT_NAME + && !settings->base.useLogicalNameReferencing) + { +#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + objectArray* list = &((gxAssociationShortName*)it)->objectList; + if (list->size == 0) + { + svr_copyAssociationView(list, &settings->base.objects); + } + associationObject = it; +#endif //!defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + } + else if (it->objectType == DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME + && settings->base.useLogicalNameReferencing) + { +#if !defined(DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME) && !defined(DLMS_IGNORE_MALLOC) + gxAssociationLogicalName* ln = (gxAssociationLogicalName*)it; + objectArray* list = &ln->objectList; + if (list->size == 0) + { + svr_copyAssociationView(list, &settings->base.objects); + } +#endif //!defined(DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME) && !defined(DLMS_IGNORE_MALLOC) + associationObject = it; + } + } + if (associationObject == NULL) + { +#ifndef DLMS_IGNORE_MALLOC + objectArray* list; + if (settings->base.useLogicalNameReferencing) + { +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + gxAssociationLogicalName* ln; + if ((ret = cosem_createObject(DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME, (gxObject**)&ln)) != 0) + { + return ret; + } + list = &((gxAssociationLogicalName*)ln)->objectList; + oa_push(&settings->base.objects, (gxObject*)ln); + //Add object to released objects list. + ret = oa_push(&settings->base.releasedObjects, (gxObject*)ln); + oa_copy(list, &settings->base.objects); +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + } + else + { +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + gxAssociationShortName* it2; + if ((ret = cosem_createObject(DLMS_OBJECT_TYPE_ASSOCIATION_SHORT_NAME, (gxObject**)&it2)) != 0) + { + return ret; + } + list = &((gxAssociationShortName*)it2)->objectList; + oa_push(&settings->base.objects, (gxObject*)it2); + oa_copy(list, &settings->base.objects); + //Add object to released objects list. + ret = oa_push(&settings->base.releasedObjects, (gxObject*)it2); +#endif // DLMS_IGNORE_ASSOCIATION_SHORT_NAME + } +#else + return DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif //DLMS_IGNORE_MALLOC + } +#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + // Arrange items by Short Name. + if (!settings->base.useLogicalNameReferencing) + { + return svr_updateShortNames(settings, 0); + } +#endif //!defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + return 0; +} + +#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) +int svr_updateShortNames( + dlmsServerSettings* settings, + unsigned char force) +{ + gxObject* it; + uint16_t sn = 0xA0; + uint16_t pos; + int ret; + unsigned char offset, count; + for (pos = 0; pos != settings->base.objects.size; ++pos) + { + if ((ret = oa_getByIndex(&settings->base.objects, pos, (gxObject**)&it)) != 0) + { + return ret; + } + if (it->objectType == DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME || + it->objectType == DLMS_OBJECT_TYPE_ASSOCIATION_SHORT_NAME) + { + continue; + } + // Generate Short Name if not given. + if (force != 0 || it->shortName == 0) + { + it->shortName = sn; + // Add method index addresses. + if ((ret = dlms_getActionInfo((DLMS_OBJECT_TYPE)it->objectType, &offset, &count)) != 0) + { + return ret; + } + if (count != 0) + { + sn += offset + (8 * count); + } + else + { + // If there are no methods. + // Add attribute index addresses. + sn += (uint16_t)(8 * obj_attributeCount(it)); + } + } + else + { + sn = (uint16_t)(it->shortName + (8 * obj_attributeCount(it))); + } + } + return 0; +} +#endif //!defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + +void svr_setInitialize(dlmsServerSettings* settings) +{ + settings->base.protocolVersion = 0; +#ifndef DLMS_IGNORE_HIGH_GMAC +#ifndef DLMS_IGNORE_MALLOC + if (settings->base.cipher.dedicatedKey != NULL) + { + bb_clear(settings->base.cipher.dedicatedKey); + gxfree(settings->base.cipher.dedicatedKey); + settings->base.cipher.dedicatedKey = NULL; + } +#else + memset(settings->base.cipher.dedicatedKey, 0, 16); +#endif //DLMS_IGNORE_MALLOC + memset(settings->base.sourceSystemTitle, 0, sizeof(settings->base.sourceSystemTitle)); +#endif //DLMS_IGNORE_HIGH_GMAC + trans_clear(&settings->transaction); + settings->base.blockIndex = 1; + settings->base.connected = DLMS_CONNECTION_STATE_NONE; + settings->base.authentication = DLMS_AUTHENTICATION_NONE; + settings->base.isAuthenticationRequired = 0; +#ifndef DLMS_IGNORE_HIGH_GMAC + settings->base.cipher.security = DLMS_SECURITY_NONE; +#endif //DLMS_IGNORE_HIGH_GMAC + bb_clear(&settings->base.ctoSChallenge); + bb_clear(&settings->base.stoCChallenge); +} + +void svr_reset( + dlmsServerSettings* settings) +{ + svr_setInitialize(settings); + resetFrameSequence(&settings->base); + reply_clear2(&settings->info, 1); + settings->base.serverAddress = 0; + settings->base.clientAddress = 0; + settings->dataReceived = 0; + settings->frameReceived = 0; +} + +int svr_generateExceptionResponse( + dlmsSettings* settings, + DLMS_EXCEPTION_STATE_ERROR state, + int error, + gxByteBuffer* data) +{ + int ret; + if ((ret = bb_setUInt8(data, DLMS_COMMAND_EXCEPTION_RESPONSE)) == 0 && + (ret = bb_setUInt8(data, state)) == 0) + { + if (error == DLMS_ERROR_CODE_INVOCATION_COUNTER_TOO_SMALL) + { + if ((ret = bb_setUInt8(data, DLMS_EXCEPTION_SERVICE_ERROR_INVOCATION_COUNTER_ERROR)) == 0) + { +#ifdef DLMS_COSEM_INVOCATION_COUNTER_SIZE64 + ret = bb_setUInt64(data, *settings->expectedInvocationCounter); +#else + ret = bb_setUInt32(data, (uint32_t)*settings->expectedInvocationCounter); +#endif //DLMS_COSEM_INVOCATION_COUNTER_SIZE64 + } + } + else if (error == DLMS_ERROR_CODE_INVALID_COMMAND) + { + ret = bb_setUInt8(data, DLMS_EXCEPTION_SERVICE_ERROR_SERVICE_NOT_SUPPORTED); + } + else + { + ret = bb_setUInt8(data, DLMS_EXCEPTION_SERVICE_ERROR_DECIPHERING_ERROR); + } + } +#ifndef DLMS_IGNORE_HIGH_GMAC + if (settings->cipher.security != DLMS_SECURITY_NONE) + { + unsigned char cmd = DLMS_COMMAND_GLO_CONFIRMED_SERVICE_ERROR; +#ifndef DLMS_IGNORE_MALLOC + gxByteBuffer* key; +#else + unsigned char* key; +#endif //DLMS_IGNORE_MALLOC + if (dlms_useDedicatedKey(settings) && (settings->connected & DLMS_CONNECTION_STATE_DLMS) != 0) + { +#ifndef DLMS_IGNORE_MALLOC + key = settings->cipher.dedicatedKey; +#else + key = settings->cipher.dedicatedKey; +#endif //DLMS_IGNORE_MALLOC + cmd = DLMS_COMMAND_DED_CONFIRMED_SERVICE_ERROR; + } + else + { +#ifndef DLMS_IGNORE_MALLOC + key = &settings->cipher.blockCipherKey; +#else + key = settings->cipher.blockCipherKey; +#endif //DLMS_IGNORE_MALLOC + } + ret = cip_encrypt( + &settings->cipher, + settings->cipher.security, + DLMS_COUNT_TYPE_PACKET, + settings->cipher.invocationCounter, + cmd, +#ifndef DLMS_IGNORE_MALLOC + settings->cipher.systemTitle.data, +#else + settings->cipher.systemTitle, +#endif //DLMS_IGNORE_MALLOC + key, + data); + } +#endif //DLMS_IGNORE_HIGH_GMAC +#ifndef DLMS_IGNORE_HDLC + if (ret == 0 && IS_HDLC(settings->interfaceType)) + { + ret = dlms_addLLCBytes(settings, data); + } +#endif //DLMS_IGNORE_HDLC + return ret; +} + +/** + * Parse AARQ request that client send and returns AARE request. + * + * @return Reply to the client. + */ +int svr_HandleAarqRequest( + dlmsServerSettings* settings, + gxByteBuffer* data) +{ + unsigned char command = 0; + int ret; + unsigned char ERROR_BUFF[4]; + gxByteBuffer error; + BB_ATTACH(error, ERROR_BUFF, 0); + DLMS_ASSOCIATION_RESULT result; + unsigned char diagnostic; + // Reset settings for wrapper and PDU. + if (settings->base.interfaceType == DLMS_INTERFACE_TYPE_WRAPPER || + settings->base.interfaceType == DLMS_INTERFACE_TYPE_PDU) + { + svr_setInitialize(settings); + } +#ifndef DLMS_IGNORE_HIGH_GMAC + else + { + settings->base.cipher.security = DLMS_SECURITY_NONE; + } +#endif + //If client is not called SNRM. +#ifndef DLMS_IGNORE_HDLC + if (IS_HDLC(settings->base.interfaceType) && (settings->base.connected & DLMS_CONNECTION_STATE_HDLC) == 0) + { + return DLMS_ERROR_CODE_REJECTED; + } +#endif //DLMS_IGNORE_HDLC + ret = apdu_parsePDU(&settings->base, data, &result, &diagnostic, &command); +#ifdef DLMS_DEBUG + svr_notifyTrace("parsePDU", ret); +#endif //DLMS_DEBUG + bb_clear(data); + if (ret == DLMS_ERROR_CODE_INVOCATION_COUNTER_TOO_SMALL || + ret == DLMS_ERROR_CODE_INVALID_DECIPHERING_ERROR || + ret == DLMS_ERROR_CODE_INVALID_SECURITY_SUITE) + { + return svr_generateExceptionResponse( + &settings->base, + DLMS_EXCEPTION_STATE_ERROR_SERVICE_UNKNOWN, + ret, + data); + } + else if (ret == 0 && result == DLMS_ASSOCIATION_RESULT_ACCEPTED) + { + if (settings->base.dlmsVersionNumber < 6) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("Invalid DLMS version number.", DLMS_INITIATE_DLMS_VERSION_TOO_LOW); +#endif //DLMS_DEBUG + result = DLMS_ASSOCIATION_RESULT_PERMANENT_REJECTED; + diagnostic = DLMS_SOURCE_DIAGNOSTIC_NO_REASON_GIVEN; + bb_setUInt8(&error, 0xE); + bb_setUInt8(&error, DLMS_CONFIRMED_SERVICE_ERROR_INITIATE_ERROR); + bb_setUInt8(&error, DLMS_SERVICE_ERROR_INITIATE); + bb_setUInt8(&error, DLMS_INITIATE_DLMS_VERSION_TOO_LOW); + settings->base.dlmsVersionNumber = 6; + } + else if (settings->base.maxPduSize < 64) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("Max PDU size is too short.", DLMS_INITIATE_PDU_SIZE_TOOSHORT); +#endif //DLMS_DEBUG + result = DLMS_ASSOCIATION_RESULT_PERMANENT_REJECTED; + diagnostic = DLMS_SOURCE_DIAGNOSTIC_NO_REASON_GIVEN; + bb_setUInt8(&error, 0xE); + bb_setUInt8(&error, DLMS_CONFIRMED_SERVICE_ERROR_INITIATE_ERROR); + bb_setUInt8(&error, DLMS_SERVICE_ERROR_INITIATE); + bb_setUInt8(&error, DLMS_INITIATE_PDU_SIZE_TOOSHORT); + settings->base.maxPduSize = 64; + } + else if (settings->base.negotiatedConformance == 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("Invalid negotiated conformance.", DLMS_INITIATE_INCOMPATIBLE_CONFORMANCE); +#endif //DLMS_DEBUG + result = DLMS_ASSOCIATION_RESULT_PERMANENT_REJECTED; + diagnostic = DLMS_SOURCE_DIAGNOSTIC_NO_REASON_GIVEN; + bb_setUInt8(&error, 0xE); + bb_setUInt8(&error, DLMS_CONFIRMED_SERVICE_ERROR_INITIATE_ERROR); + bb_setUInt8(&error, DLMS_SERVICE_ERROR_INITIATE); + bb_setUInt8(&error, DLMS_INITIATE_INCOMPATIBLE_CONFORMANCE); + } + else if (diagnostic != DLMS_SOURCE_DIAGNOSTIC_NONE) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("Connection rejected.", -1); +#endif //DLMS_DEBUG + result = DLMS_ASSOCIATION_RESULT_PERMANENT_REJECTED; + diagnostic = DLMS_SOURCE_DIAGNOSTIC_APPLICATION_CONTEXT_NAME_NOT_SUPPORTED; + } + else + { +#ifdef DLMS_DEBUG + svr_notifyTrace("svr_validateAuthentication.", 0); +#endif //DLMS_DEBUG + diagnostic = svr_validateAuthentication( + settings, + settings->base.authentication, + &settings->base.password); + if (diagnostic != DLMS_SOURCE_DIAGNOSTIC_NONE) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("Connection rejected.", -1); +#endif //DLMS_DEBUG + svr_invalidConnection(settings); + result = DLMS_ASSOCIATION_RESULT_PERMANENT_REJECTED; + } + else if (settings->base.authentication > DLMS_AUTHENTICATION_LOW) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("High authentication is used.", 0); +#endif //DLMS_DEBUG + // If High authentication is used. + result = DLMS_ASSOCIATION_RESULT_ACCEPTED; + diagnostic = DLMS_SOURCE_DIAGNOSTIC_AUTHENTICATION_REQUIRED; + } + } + // Generate AARE packet. + if (settings->base.authentication > DLMS_AUTHENTICATION_LOW && settings->base.customChallenges == 0) + { + // If High authentication is used. + if ((ret = dlms_generateChallenge(&settings->base.stoCChallenge)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("generateChallenge ", ret); +#endif //DLMS_DEBUG + bb_clear(&error); + return ret; + } + if (settings->base.useLogicalNameReferencing) + { +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + gxAssociationLogicalName* it; + unsigned char ln[] = { 0, 0, 40, 0, 0, 255 }; + if ((ret = oa_findByLN(&settings->base.objects, DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME, ln, (gxObject**)&it)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("oa_findByLN ", ret); +#endif //DLMS_DEBUG + return ret; + } + if (it == NULL) + { + gxValueEventArg e; + ve_init(&e); + svr_findObject(&settings->base, DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME, 0, ln, &e); + it = (gxAssociationLogicalName*)e.target; + } + if (it != NULL) + { +#ifndef DLMS_IGNORE_HIGH_GMAC + if (settings->base.cipher.security == DLMS_SECURITY_NONE) +#endif //DLMS_IGNORE_HIGH_GMAC + { + it->applicationContextName.contextId = DLMS_APPLICATION_CONTEXT_NAME_LOGICAL_NAME; + } +#ifndef DLMS_IGNORE_HIGH_GMAC + else + { + it->applicationContextName.contextId = DLMS_APPLICATION_CONTEXT_NAME_LOGICAL_NAME_WITH_CIPHERING; + } +#endif //DLMS_IGNORE_HIGH_GMAC + it->authenticationMechanismName.mechanismId = settings->base.authentication; + it->associationStatus = DLMS_ASSOCIATION_STATUS_ASSOCIATION_PENDING; + } + else + { +#ifdef DLMS_DEBUG + svr_notifyTrace("Association logical name not found. ", -1); +#endif //DLMS_DEBUG + } +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + } + } + else if (result == DLMS_ASSOCIATION_RESULT_ACCEPTED) + { + if (settings->base.useLogicalNameReferencing) + { +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + gxAssociationLogicalName* it; + unsigned char ln[] = { 0, 0, 40, 0, 0, 255 }; + if ((ret = oa_findByLN(&settings->base.objects, DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME, ln, (gxObject**)&it)) != 0) + { + return ret; + } + if (it == NULL) + { + gxValueEventArg e; + ve_init(&e); + svr_findObject(&settings->base, DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME, 0, ln, &e); + it = (gxAssociationLogicalName*)e.target; + } + if (it != NULL) + { +#ifndef DLMS_IGNORE_HIGH_GMAC + if (settings->base.cipher.security == DLMS_SECURITY_NONE) +#endif //DLMS_IGNORE_HIGH_GMAC + { + it->applicationContextName.contextId = DLMS_APPLICATION_CONTEXT_NAME_LOGICAL_NAME; + } +#ifndef DLMS_IGNORE_HIGH_GMAC + else + { + it->applicationContextName.contextId = DLMS_APPLICATION_CONTEXT_NAME_LOGICAL_NAME_WITH_CIPHERING; + } +#endif //DLMS_IGNORE_HIGH_GMAC + it->authenticationMechanismName.mechanismId = settings->base.authentication; + it->associationStatus = DLMS_ASSOCIATION_STATUS_ASSOCIATED; + } +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + } + } + } + else if (diagnostic == DLMS_SOURCE_DIAGNOSTIC_NONE) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("Permanent rejected.", -1); +#endif //DLMS_DEBUG + result = DLMS_ASSOCIATION_RESULT_PERMANENT_REJECTED; + diagnostic = DLMS_SOURCE_DIAGNOSTIC_NO_REASON_GIVEN; + bb_setUInt8(&error, 0xE); + bb_setUInt8(&error, DLMS_CONFIRMED_SERVICE_ERROR_INITIATE_ERROR); + bb_setUInt8(&error, DLMS_SERVICE_ERROR_INITIATE); + bb_setUInt8(&error, DLMS_INITIATE_OTHER); + } + +#ifndef DLMS_IGNORE_HDLC + if (IS_HDLC(settings->base.interfaceType)) + { + dlms_addLLCBytes(&settings->base, data); + } +#endif //DLMS_IGNORE_HDLC + ret = apdu_generateAARE(&settings->base, data, result, diagnostic, &error, NULL, command); +#ifdef DLMS_DEBUG + svr_notifyTrace("apdu_generateAARE.", ret); +#endif //DLMS_DEBUG + bb_clear(&error); + return ret; +} + +/** + * Parse SNRM Request. If server do not accept client empty byte array is + * returned. + * + * @return Returns returned UA packet. + */ +int svr_handleSnrmRequest( + dlmsServerSettings* settings, + gxByteBuffer* data) +{ + int ret; + unsigned char len; + uint16_t clientAddress; + uint32_t serverAddress; +#ifndef DLMS_IGNORE_HIGH_GMAC + DLMS_SECURITY security; +#endif + //Initialize default settings. + if (settings->hdlc != NULL) + { + settings->base.maxInfoRX = settings->hdlc->maximumInfoLengthReceive; + settings->base.maxInfoTX = settings->hdlc->maximumInfoLengthTransmit; + settings->base.windowSizeRX = settings->hdlc->windowSizeReceive; + settings->base.windowSizeTX = settings->hdlc->windowSizeTransmit; + } + else + { + settings->base.maxInfoRX = DEFAULT_MAX_INFO_RX; + settings->base.maxInfoTX = DEFAULT_MAX_INFO_TX; + settings->base.windowSizeRX = DEFAULT_MAX_WINDOW_SIZE_RX; + settings->base.windowSizeTX = DEFAULT_MAX_WINDOW_SIZE_TX; + + } + if ((ret = dlms_parseSnrmUaResponse(&settings->base, data)) != 0) + { + return ret; + } + bb_clear(data); +#ifndef DLMS_IGNORE_HIGH_GMAC + security = settings->base.cipher.security; +#endif + serverAddress = settings->base.serverAddress; + clientAddress = settings->base.clientAddress; + svr_reset(settings); +#ifndef DLMS_IGNORE_HIGH_GMAC + settings->base.cipher.security = security; +#endif + settings->base.serverAddress = serverAddress; + settings->base.clientAddress = clientAddress; + bb_setUInt8(data, 0x81); // FromatID + bb_setUInt8(data, 0x80); // GroupID + bb_setUInt8(data, 0); // Length + bb_setUInt8(data, HDLC_INFO_MAX_INFO_TX); + dlms_appendHdlcParameter(data, settings->base.maxInfoTX); + + bb_setUInt8(data, HDLC_INFO_MAX_INFO_RX); + dlms_appendHdlcParameter(data, settings->base.maxInfoRX); + + bb_setUInt8(data, HDLC_INFO_WINDOW_SIZE_TX); + bb_setUInt8(data, 4); + bb_setUInt32(data, settings->base.windowSizeTX); + + bb_setUInt8(data, HDLC_INFO_WINDOW_SIZE_RX); + bb_setUInt8(data, 4); + bb_setUInt32(data, settings->base.windowSizeRX); + + len = (unsigned char)(data->size - 3); + // Update length. + bb_setUInt8ByIndex(data, 2, len); + return 0; +} + +/** + * Generates disconnect request. + * + * @return Disconnect request. + */ +int svr_generateDisconnectRequest( + dlmsServerSettings* settings, + gxByteBuffer* data) +{ + int ret, len; + if (settings->base.interfaceType == DLMS_INTERFACE_TYPE_WRAPPER) + { + bb_setUInt8(data, 0x63); + ret = bb_setUInt8(data, 0x0); + } + else + { + bb_setUInt8(data, 0x81); // FromatID + bb_setUInt8(data, 0x80); // GroupID + bb_setUInt8(data, 0); // Length + + bb_setUInt8(data, HDLC_INFO_MAX_INFO_TX); + dlms_appendHdlcParameter(data, settings->base.maxInfoTX); + + bb_setUInt8(data, HDLC_INFO_MAX_INFO_RX); + dlms_appendHdlcParameter(data, settings->base.maxInfoRX); + + bb_setUInt8(data, HDLC_INFO_WINDOW_SIZE_TX); + bb_setUInt8(data, 4); + bb_setUInt32(data, settings->base.windowSizeTX); + + bb_setUInt8(data, HDLC_INFO_WINDOW_SIZE_RX); + bb_setUInt8(data, 4); + bb_setUInt32(data, settings->base.windowSizeRX); + + len = data->size - 3; + // Update length. + ret = bb_setUInt8ByIndex(data, 2, (unsigned char)len); + } + return ret; +} + +//Add PDU to frame. +int dlms_addFrame( + dlmsSettings* settings, + DLMS_COMMAND command, + gxByteBuffer* data, + gxByteBuffer* reply) +{ + int ret; + switch (settings->interfaceType) + { +#ifndef DLMS_IGNORE_HDLC + case DLMS_INTERFACE_TYPE_HDLC: + case DLMS_INTERFACE_TYPE_HDLC_WITH_MODE_E: + { + unsigned char frame = 0; + if (command == DLMS_COMMAND_UA) + { + frame = (unsigned char)DLMS_COMMAND_UA; + } + if ((ret = dlms_getHdlcFrame(settings, frame, data, reply)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("getHdlcFrame failed. ", ret); +#endif //DLMS_DEBUG + } + } + break; +#endif //DLMS_IGNORE_HDLC +#ifndef DLMS_IGNORE_WRAPPER + case DLMS_INTERFACE_TYPE_WRAPPER: + if ((ret = dlms_getWrapperFrame(settings, command, data, reply)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("dlms_getWrapperFrame failed. ", ret); +#endif //DLMS_DEBUG + } + break; +#endif //DLMS_IGNORE_WRAPPER +#ifndef DLMS_IGNORE_PLC + case DLMS_INTERFACE_TYPE_PLC: + case DLMS_INTERFACE_TYPE_PLC_HDLC: + ret = dlms_getMacFrame(settings, 0, 0, data, reply); + break; +#endif //DLMS_IGNORE_PLC + case DLMS_INTERFACE_TYPE_PDU: + ret = bb_set2(reply, data, 0, bb_size(data)); + break; + default: +#ifdef DLMS_DEBUG + svr_notifyTrace("Unknown frame type. ", -1); +#endif //DLMS_DEBUG + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} + +int svr_reportError( + dlmsServerSettings* settings, + DLMS_COMMAND command, + DLMS_ERROR_CODE error, + gxByteBuffer* reply) +{ + int ret; + DLMS_COMMAND cmd; + gxByteBuffer data; + switch (command) + { +#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + case DLMS_COMMAND_READ_REQUEST: + cmd = DLMS_COMMAND_READ_RESPONSE; + break; + case DLMS_COMMAND_WRITE_REQUEST: + cmd = DLMS_COMMAND_WRITE_RESPONSE; + break; +#endif //!defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + case DLMS_COMMAND_GET_REQUEST: + cmd = DLMS_COMMAND_GET_RESPONSE; + break; + case DLMS_COMMAND_SET_REQUEST: + cmd = DLMS_COMMAND_SET_RESPONSE; + break; + case DLMS_COMMAND_METHOD_REQUEST: + cmd = DLMS_COMMAND_METHOD_RESPONSE; + break; + default: + if (settings->info.encryptedCommand != 0) + { + //Do nothing if ciphered content is invalid. + return 0; + } + else + { + // Return HW error and close connection. + cmd = DLMS_COMMAND_NONE; + } + break; + } + BYTE_BUFFER_INIT(&data); + if (settings->base.useLogicalNameReferencing) + { + gxLNParameters p; + params_initLN(&p, &settings->base, 0, cmd, 1, + NULL, NULL, error, DLMS_COMMAND_NONE, 0, 0); + ret = dlms_getLNPdu(&p, &data); + if (ret != 0) + { + bb_clear(&data); + return ret; + } + } + else + { +#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + gxSNParameters p; + gxByteBuffer bb; + BYTE_BUFFER_INIT(&bb); + bb_setUInt8(&bb, error); + params_initSN(&p, &settings->base, cmd, 1, 1, NULL, &bb, settings->info.encryptedCommand); + p.lastBlock = 1; + ret = dlms_getSNPdu(&p, &data); + bb_clear(&bb); + if (ret != 0) + { + bb_clear(&data); + return ret; + } +#else + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif //!defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + } + ret = dlms_addFrame(&settings->base, command, &data, reply); + bb_clear(&data); + return ret; +} + +#ifndef DLMS_IGNORE_SET +int svr_handleSetRequest2( + dlmsServerSettings* settings, + gxByteBuffer* data, + unsigned char type, + gxLNParameters* p) +{ + gxValueEventArg* e; + gxValueEventCollection list; + int ret; + DLMS_OBJECT_TYPE ci; + unsigned char ch; + uint16_t tmp; + unsigned char* ln = NULL; +#ifdef DLMS_IGNORE_MALLOC + list = settings->transaction.targets; + e = &list.data[0]; + ve_clear(e); +#else + e = (gxValueEventArg*)gxmalloc(sizeof(gxValueEventArg)); + ve_init(e); + vec_init(&list); + vec_push(&list, e); +#endif //DLMS_IGNORE_MALLOC + + if ((ret = bb_getUInt16(data, &tmp)) != 0) + { + vec_clear(&list); + return ret; + } + ci = (DLMS_OBJECT_TYPE)tmp; + ln = data->data + data->position; + data->position += 6; + // Attribute index. + if ((ret = bb_getUInt8(data, &e->index)) != 0) + { + vec_clear(&list); + return ret; + } + // Get Access Selection. + if ((ret = bb_getUInt8(data, &ch)) != 0) + { + vec_clear(&list); + return ret; + } + if (type == DLMS_SET_COMMAND_TYPE_FIRST_DATABLOCK) + { + uint32_t blockNumber; + uint16_t size; + if ((ret = bb_getUInt8(data, &ch)) != 0) + { + vec_clear(&list); + return ret; + } + p->multipleBlocks = ch == 0; + ret = bb_getUInt32(data, &blockNumber); + if (ret != 0) + { + vec_clear(&list); + return ret; + } + if (blockNumber != settings->base.blockIndex) + { + vec_clear(&list); + return DLMS_ERROR_CODE_DATA_BLOCK_NUMBER_INVALID; + } + ++settings->base.blockIndex; + if (hlp_getObjectCount2(data, &size) != 0) + { + vec_clear(&list); + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + //If received date is not what expected. + if (size != data->size - data->position) + { + vec_clear(&list); + return DLMS_ERROR_CODE_DATA_BLOCK_UNAVAILABLE; + } + } +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + e->value.byteArr = data; + e->value.vt = DLMS_DATA_TYPE_OCTET_STRING | DLMS_DATA_TYPE_BYREF; +#else + if (!p->multipleBlocks) + { + gxDataInfo di; + di_init(&di); + resetBlockIndex(&settings->base); + ret = dlms_getData(data, &di, &e->value); + } +#endif //!defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + if (ret == 0) + { + if ((ret = oa_findByLN(&settings->base.objects, ci, ln, &e->target)) == 0) + { + if (e->target == NULL) + { + ret = svr_findObject(&settings->base, ci, 0, ln, e); + } +#ifndef DLMS_IGNORE_MALLOC + bb_clear(data); +#endif //DLMS_IGNORE_MALLOC + if (ret == 0) + { + // If target is unknown. + if (e->target == NULL) + { + // Device reports a undefined object. + ret = DLMS_ERROR_CODE_UNAVAILABLE_OBJECT; + } + else + { + DLMS_ACCESS_MODE am = svr_getAttributeAccess(&settings->base, e->target, e->index); + // If write is denied. + if (am != DLMS_ACCESS_MODE_WRITE && am != DLMS_ACCESS_MODE_READ_WRITE) + { + //Read Write denied. + ret = DLMS_ERROR_CODE_READ_WRITE_DENIED; + } + else + { + svr_preWrite(&settings->base, &list); + if (p->multipleBlocks) + { +#ifdef DLMS_IGNORE_MALLOC + settings->transaction.targets.size = 1; +#else + bb_clear(&settings->transaction.data); + vec_clear(&settings->transaction.targets); + settings->transaction.targets = list; + var_clear(&e->value); + vec_init(&list); + if (!bb_isAttached(data)) + { + ret = bb_set2(&settings->transaction.data, data, data->position, data->size - data->position); + } +#endif //DLMS_IGNORE_MALLOC + settings->transaction.command = DLMS_COMMAND_SET_REQUEST; + } + if (ret == 0) + { + if (e->error != 0) + { + ret = e->error; + } + else if (!e->handled && !p->multipleBlocks) + { + ret = cosem_setValue(&settings->base, e); + if (ret != 0 && e->error == 0) + { + e->error = ret; + } + svr_postWrite(&settings->base, &list); + if (e->error != 0) + { + ret = e->error; + } + } + } + } + } + } + } + if (type == DLMS_SET_COMMAND_TYPE_NORMAL) + { + bb_clear(data); + } + } +#ifndef DLMS_IGNORE_MALLOC + vec_clear(&list); +#endif //DLMS_IGNORE_MALLOC + return ret; +} + +int svr_getTarget( + dlmsServerSettings* settings, + gxByteBuffer* data, + gxByteBuffer* status, + gxValueEventArg* e, + unsigned char seek) +{ + int ret; + DLMS_OBJECT_TYPE ci; + unsigned char ch; + uint16_t tmp; + unsigned char* ln = NULL; + if ((ret = bb_getUInt16(data, &tmp)) != 0) + { + return ret; + } + ci = (DLMS_OBJECT_TYPE)tmp; + ln = data->data + data->position; + data->position += 6; + // Attribute index. + if ((ret = bb_getUInt8(data, &e->index)) == 0 && + // Get Access Selection. + (ret = bb_getUInt8(data, &ch)) == 0) + { + if ((ret = oa_findByLN(&settings->base.objects, ci, ln, &e->target)) == 0) + { + if (e->target == NULL) + { + ret = svr_findObject(&settings->base, ci, 0, ln, e); + } + if (!seek) + { + if (ret == 0) + { + // If target is unknown. + if (e->target == NULL) + { + // Device reports a undefined object. + bb_setUInt8(status, DLMS_ERROR_CODE_UNAVAILABLE_OBJECT); + } + else + { + DLMS_ACCESS_MODE am = svr_getAttributeAccess(&settings->base, e->target, e->index); + // If write is denied. + if (am != DLMS_ACCESS_MODE_WRITE && am != DLMS_ACCESS_MODE_READ_WRITE) + { + //Read Write denied. + bb_setUInt8(status, DLMS_ERROR_CODE_READ_WRITE_DENIED); + } + else + { + bb_setUInt8(status, DLMS_ERROR_CODE_OK); + } + } + } + else + { + bb_setUInt8(status, DLMS_ERROR_CODE_UNAVAILABLE_OBJECT); + } + } + } + } + return ret; +} + +int svr_handleSetRequestWithList( + dlmsServerSettings* settings, + gxByteBuffer* data, + gxLNParameters* p) +{ + gxValueEventArg* e; + gxValueEventCollection list; + int ret; + unsigned char ch; + uint16_t pos, count, targetPos, tmp; + gxByteBuffer status; + bb_init(&status); +#ifdef DLMS_IGNORE_MALLOC + unsigned char STATUS_BUFF[20]; + bb_attach(&status, STATUS_BUFF, 0, sizeof(STATUS_BUFF)); + list = settings->transaction.targets; + list.size = 1; + e = &list.data[0]; + ve_clear(e); +#else + bb_capacity(&status, 10); + vec_init(&list); + e = (gxValueEventArg*)gxmalloc(sizeof(gxValueEventArg)); + ve_init(e); + vec_push(&list, e); +#endif //DLMS_IGNORE_MALLOC + if ((ret = hlp_getObjectCount2(data, &count)) == 0) + { + targetPos = (uint16_t)data->position; + for (pos = 0; pos != count; ++pos) + { + if ((ret = svr_getTarget(settings, data, &status, e, 0)) != 0) + { + break; + } + } + if (ret == 0 && + (ret = hlp_getObjectCount2(data, &count)) == 0) + { + gxDataInfo di; + for (pos = 0; pos != count; ++pos) + { + di_init(&di); + resetBlockIndex(&settings->base); + tmp = (uint16_t)data->position; + //Target must seek from the byte buffer. + data->position = targetPos; + ret = svr_getTarget(settings, data, &status, e, 1); + targetPos = (uint16_t)data->position; + data->position = tmp; + if (ret != 0) + { + break; + } + if ((ret = dlms_getData(data, &di, &e->value)) != 0) + { + bb_setUInt8ByIndex(&status, pos, ret); + } + if (bb_getUInt8(&status, &ch) != 0 || + ch != 0) + { + continue; + } + //Objects are invoked one at the time when malloc is not used. + //This must be done because octet-strings cause problems. + svr_preWrite(&settings->base, &list); + if (p->multipleBlocks) + { +#ifdef DLMS_IGNORE_MALLOC + settings->transaction.targets.size = 1; +#else + bb_clear(&settings->transaction.data); + vec_clear(&settings->transaction.targets); + settings->transaction.targets = list; + var_clear(&e->value); + vec_init(&list); + if (!bb_isAttached(data)) + { + ret = bb_set2(&settings->transaction.data, data, data->position, data->size - data->position); + } +#endif //DLMS_IGNORE_MALLOC + settings->transaction.command = DLMS_COMMAND_SET_REQUEST; + } + if (ret == 0) + { + if (e->error != 0) + { + bb_setUInt8ByIndex(&status, pos, e->error); + } + else if (!e->handled && !p->multipleBlocks) + { + ret = cosem_setValue(&settings->base, e); + if (ret != 0 && e->error == 0) + { + bb_setUInt8ByIndex(&status, pos, ret); + } + svr_postWrite(&settings->base, &list); + if (e->error != 0) + { + bb_setUInt8ByIndex(&status, pos, e->error); + } + } + } +#ifndef DLMS_IGNORE_MALLOC + var_clear(&e->value); +#endif //DLMS_IGNORE_MALLOC + } + } + } +#ifndef DLMS_IGNORE_MALLOC + vec_clear(&list); +#endif //DLMS_IGNORE_MALLOC + bb_clear(data); + p->status = 0xFF; + hlp_setObjectCount(status.size, data); + for (pos = 0; pos != status.size; ++pos) + { + bb_setUInt8(data, status.data[pos]); + } + bb_clear(&status); + p->requestType = DLMS_SET_RESPONSE_TYPE_WITH_LIST; + return ret; +} +#endif //DLMS_IGNORE_SET + +#ifndef DLMS_IGNORE_MALLOC +int svr_hanleSetRequestWithDataBlock( + dlmsServerSettings* settings, + gxByteBuffer* data, + gxLNParameters* p) +{ + int ret; + uint32_t blockNumber; + uint16_t size; + unsigned char ch; + if ((ret = bb_getUInt8(data, &ch)) != 0) + { + return ret; + } + p->multipleBlocks = ch == 0; + if ((ret = bb_getUInt32(data, &blockNumber)) == 0) + { + if (blockNumber != settings->base.blockIndex) + { + ret = DLMS_ERROR_CODE_DATA_BLOCK_NUMBER_INVALID; + } + else + { + ++settings->base.blockIndex; + if (hlp_getObjectCount2(data, &size) != 0) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + else if (size != data->size - data->position) + { + ret = DLMS_ERROR_CODE_DATA_BLOCK_UNAVAILABLE; + } + if (ret == 0 && (ret = bb_set2(&settings->transaction.data, data, data->position, data->size - data->position)) == 0) + { + // If all data is received. + if (!p->multipleBlocks) + { + gxDataInfo di; + gxValueEventArg* e = settings->transaction.targets.data[0]; + di_init(&di); + if ((ret != dlms_getData(&settings->transaction.data, &di, &e->value)) != 0) + { + return ret; + } + svr_preWrite(&settings->base, &settings->transaction.targets); + if (!e->handled && !p->multipleBlocks) + { + if ((ret = cosem_setValue(&settings->base, e)) != 0) + { + return ret; + } + svr_postWrite(&settings->base, &settings->transaction.targets); + } + trans_clear(&settings->transaction); + resetBlockIndex(&settings->base); + } + } + } + } + p->multipleBlocks = 1; + return ret; +} +#endif //DLMS_IGNORE_MALLOC + +/** + * Generate confirmed service error. + * + * @param service + * Confirmed service error. + * @param type + * Service error. + * @param code + * code + * @return + */ +int svr_generateConfirmedServiceError( + dlmsServerSettings* settings, + DLMS_CONFIRMED_SERVICE_ERROR service, + DLMS_SERVICE_ERROR type, + unsigned char code, + gxByteBuffer* data) +{ + bb_clear(data); +#ifndef DLMS_IGNORE_HDLC + if (IS_HDLC(settings->base.interfaceType)) + { + dlms_addLLCBytes(&settings->base, data); + } +#endif //DLMS_IGNORE_HDLC + bb_setUInt8(data, DLMS_COMMAND_CONFIRMED_SERVICE_ERROR); + bb_setUInt8(data, service); + bb_setUInt8(data, type); + bb_setUInt8(data, code); + return 0; +} + +#ifndef DLMS_IGNORE_SET +int svr_handleSetRequest( + dlmsServerSettings* settings, + gxByteBuffer* data) +{ + gxLNParameters p; + unsigned char invokeId, type; + int ret; + // Get type. + if ((ret = bb_getUInt8(data, &type)) != 0) + { + return ret; + } + // Get invoke ID and priority. + if ((ret = bb_getUInt8(data, &invokeId)) != 0) + { + return ret; + } + updateInvokeId(settings, invokeId); + params_initLN(&p, &settings->base, invokeId, DLMS_COMMAND_SET_RESPONSE, type, NULL, data, 0, settings->info.encryptedCommand, 0, 0); + switch (type) + { + case DLMS_SET_COMMAND_TYPE_NORMAL: + case DLMS_SET_COMMAND_TYPE_FIRST_DATABLOCK: + ret = svr_handleSetRequest2(settings, data, type, &p); + break; + case DLMS_SET_COMMAND_TYPE_WITH_DATABLOCK: +#ifdef DLMS_IGNORE_MALLOC + //All data must fit to one PDU at the moment if malloc is not used. + ret = DLMS_ERROR_CODE_READ_WRITE_DENIED; +#else + // Set Request With Data Block + ret = svr_hanleSetRequestWithDataBlock(settings, data, &p); +#endif //DLMS_IGNORE_MALLOC + break; + case DLMS_SET_COMMAND_TYPE_WITH_LIST: + ret = svr_handleSetRequestWithList(settings, data, &p); + break; + default: + p.requestType = 1; + ret = DLMS_ERROR_CODE_READ_WRITE_DENIED; + break; + } + if (ret != 0) + { + // Access Error : Device reports Read-Write denied. + bb_clear(data); + resetBlockIndex(&settings->base); + //If error is DLMS error code. + if (ret > 0 && ret <= DLMS_ERROR_CODE_OTHER_REASON) + { + p.status = ret; + } + else + { + p.status = DLMS_ERROR_CODE_READ_WRITE_DENIED; + } + p.multipleBlocks = 0; + p.requestType = 1; + } + return dlms_getLNPdu(&p, data); +} + +#endif //DLMS_IGNORE_SET + +int svr_getRequestNormal( + dlmsServerSettings* settings, + gxByteBuffer* data, + unsigned char invokeId) +{ + gxValueEventCollection* arr; + uint16_t ci; + gxValueEventArg* e; + unsigned char index; + int ret; + unsigned char* ln; + DLMS_ERROR_CODE status = DLMS_ERROR_CODE_OK; + resetBlockIndex(&settings->base); + // CI + if ((ret = bb_getUInt16(data, &ci)) != 0) + { + return ret; + } + ln = data->data + data->position; + data->position += 6; + // Attribute Id + if ((ret = bb_getUInt8(data, &index)) != 0) + { + return ret; + } + if (index < 1) + { + //Attribute0 Supported With Get is not supported. + return DLMS_ERROR_CODE_INVALID_COMMAND; + } + +#ifdef DLMS_IGNORE_MALLOC + arr = &settings->transaction.targets; + if (arr->capacity == 0) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + e = &arr->data[0]; + ve_clear(e); + arr->size = 1; + e->value.byteArr = data; + e->value.vt = DLMS_DATA_TYPE_OCTET_STRING; +#else + gxValueEventCollection list; + e = (gxValueEventArg*)gxmalloc(sizeof(gxValueEventArg)); + ve_init(e); + e->value.byteArr = data; + e->value.vt = DLMS_DATA_TYPE_OCTET_STRING; + e->index = index; + vec_init(&list); + vec_push(&list, e); + arr = &list; +#endif //DLMS_IGNORE_MALLOC + e->index = index; + // Access selection + unsigned char selection; + if ((ret = bb_getUInt8(data, &selection)) != 0) + { +#ifdef DLMS_IGNORE_MALLOC + vec_clear(arr); +#endif //DLMS_IGNORE_MALLOC + return ret; + } + if (selection != 0) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = bb_getUInt8(data, &e->selector)) != 0) + { + vec_clear(arr); + return ret; + } + e->parameters.byteArr = data; + e->parameters.vt = DLMS_DATA_TYPE_OCTET_STRING; +#else + gxDataInfo di; + di_init(&di); + if ((ret = bb_getUInt8(data, &e->selector)) != 0 || + (ret = dlms_getData(data, &di, &e->parameters)) != 0) + { + vec_clear(arr); + return ret; + } + bb_clear(data); +#endif //DLMS_IGNORE_MALLOC + } + else + { + bb_clear(data); + } + ret = oa_findByLN(&settings->base.objects, (DLMS_OBJECT_TYPE)ci, ln, &e->target); + if (ret != 0) + { + bb_clear(data); +#ifdef DLMS_IGNORE_MALLOC + vec_clear(arr); +#endif //DLMS_IGNORE_MALLOC + return ret; + } + if (e->target == NULL) + { + ret = svr_findObject(&settings->base, (DLMS_OBJECT_TYPE)ci, 0, ln, e); + } + if (e->target == NULL) + { + // Access Error : Device reports a undefined object. + status = DLMS_ERROR_CODE_UNDEFINED_OBJECT; + } + else + { + DLMS_ACCESS_MODE mode = svr_getAttributeAccess(&settings->base, e->target, index); + if ((mode & DLMS_ACCESS_MODE_READ) == 0) + { + status = DLMS_ERROR_CODE_READ_WRITE_DENIED; + } + else + { + //Handle default Association LN read as a special case. + if (ci == DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME && index == 1 && memcmp(DEFAULT_ASSOCIATION, ln, 6) == 0) + { + e->byteArray = 1; + if ((ret = bb_setUInt8(data, DLMS_DATA_TYPE_OCTET_STRING)) != 0 || + (ret = bb_setUInt8(data, 6)) != 0 || + (ret = bb_set(data, DEFAULT_ASSOCIATION, 6)) != 0) + { +#ifdef DLMS_IGNORE_MALLOC + vec_clear(arr); +#endif //DLMS_IGNORE_MALLOC + return ret; + } + } + else + { + svr_preRead(&settings->base, arr); + if (!e->handled) + { + if ((ret = cosem_getValue(&settings->base, e)) != 0) + { + status = DLMS_ERROR_CODE_HARDWARE_FAULT; + } + svr_postRead(&settings->base, arr); + } + } + if (status == 0) + { + status = e->error; + } + if (status == 0) + { +#ifdef DLMS_IGNORE_MALLOC + if (e->value.vt != DLMS_DATA_TYPE_OCTET_STRING) + { + if ((ret = dlms_setData(data, e->value.vt, &e->value)) != 0) + { + status = DLMS_ERROR_CODE_HARDWARE_FAULT; + } + } +#else + if (!e->byteArray) + { + if ((ret = dlms_setData(data, e->value.vt, &e->value)) != 0) + { + status = DLMS_ERROR_CODE_HARDWARE_FAULT; + } + } + else if (!bb_isAttached(e->value.byteArr)) + { + if ((ret = bb_set2(data, e->value.byteArr, 0, e->value.byteArr->size)) != 0) + { + status = DLMS_ERROR_CODE_HARDWARE_FAULT; + } + var_clear(&e->value); + } +#endif //DLMS_IGNORE_MALLOC + } + else if (status != 0) + { + bb_clear(data); + } + } + } + //PDU is used for serialization. Set data type to none so size is not changed. + if (e->byteArray || (e->value.vt == DLMS_DATA_TYPE_OCTET_STRING && bb_isAttached(e->value.byteArr))) + { + e->value.vt = DLMS_DATA_TYPE_NONE; + } + unsigned char moreData = e->transactionStartIndex != e->transactionEndIndex; + gxLNParameters p; + params_initLN(&p, &settings->base, invokeId, DLMS_COMMAND_GET_RESPONSE, 1, NULL, data, status, settings->info.encryptedCommand, moreData, !moreData); + ret = dlms_getLNPdu(&p, data); + if (e->transactionStartIndex != e->transactionEndIndex || data->size > settings->base.maxPduSize +#ifdef DLMS_IGNORE_MALLOC + || ((settings->base.interfaceType == DLMS_INTERFACE_TYPE_HDLC || + settings->base.interfaceType == DLMS_INTERFACE_TYPE_HDLC_WITH_MODE_E) && data->size > settings->base.maxInfoTX) +#endif //DLMS_IGNORE_MALLOC + ) + { +#ifndef DLMS_IGNORE_MALLOC + trans_clear(&settings->transaction); + settings->transaction.targets = list; + vec_init(&list); + if (!bb_isAttached(data)) + { + ret = bb_set2(&settings->transaction.data, data, data->position, data->size - data->position); + } +#endif //DLMS_IGNORE_MALLOC + e->transaction = 1; + settings->transaction.command = DLMS_COMMAND_GET_REQUEST; + } +#ifndef DLMS_IGNORE_MALLOC + vec_clear(arr); +#endif //DLMS_IGNORE_MALLOC + return ret; +} + +int svr_getRequestNextDataBlock( + dlmsServerSettings* settings, + gxByteBuffer* data, + unsigned char invokeId) +{ + gxValueEventArg* e; + gxLNParameters p; + unsigned char moreData; + int ret; + uint32_t index, pos; + // Get block index. + if ((ret = bb_getUInt32(data, &index)) != 0) + { + return ret; + } + bb_clear(data); + if (index != settings->base.blockIndex) + { + params_initLN(&p, &settings->base, invokeId, DLMS_COMMAND_GET_RESPONSE, 2, + NULL, NULL, DLMS_ERROR_CODE_DATA_BLOCK_NUMBER_INVALID, settings->info.encryptedCommand, 0, 0); + return dlms_getLNPdu(&p, data); + } + else + { + ++settings->base.blockIndex; + params_initLN(&p, &settings->base, invokeId, DLMS_COMMAND_GET_RESPONSE, 2, NULL, data, DLMS_ERROR_CODE_OK, settings->info.encryptedCommand, 1, 1); + // If transaction is not in progress. + if (settings->transaction.command == DLMS_COMMAND_NONE) + { + p.status = DLMS_ERROR_CODE_NO_LONG_GET_OR_READ_IN_PROGRESS; + } + else + { +#ifndef DLMS_IGNORE_MALLOC + bb_set2(data, &settings->transaction.data, 0, settings->transaction.data.size); + bb_clear(&settings->transaction.data); +#endif //DLMS_IGNORE_MALLOC + moreData = 1; + // If there is multiple blocks on the buffer. + // This might happen when Max PDU size is very small. + if (data->size < settings->base.maxPduSize) + { + for (pos = 0; pos != settings->transaction.targets.size; ++pos) + { + if ((ret = vec_getByIndex(&settings->transaction.targets, pos, &e)) != 0) + { + break; + } + e->value.byteArr = data; + e->value.vt = DLMS_DATA_TYPE_OCTET_STRING; + svr_preRead(&settings->base, &settings->transaction.targets); + if (!e->handled) + { + if ((ret = cosem_getValue(&settings->base, e)) != 0) + { + p.status = DLMS_ERROR_CODE_HARDWARE_FAULT; + } + svr_postRead(&settings->base, &settings->transaction.targets); + } + // Add data. + if (e->byteArray) + { + e->value.vt = DLMS_DATA_TYPE_NONE; + } + else + { + if ((ret = dlms_setData(data, e->value.vt, &e->value)) != 0) + { + break; + } + var_clear(&e->value); + } + } + p.lastBlock = !(e->transactionStartIndex < e->transactionEndIndex); + } + ret = dlms_getLNPdu(&p, data); + if (moreData || data->size - data->position != 0) + { + //Append data to transaction data if buffer is not static. +#ifndef DLMS_IGNORE_MALLOC + if (!bb_isAttached(data)) + { + bb_set2(&settings->transaction.data, data, data->position, data->size - data->position); + } +#endif //DLMS_IGNORE_MALLOC + } + else + { + trans_clear(&settings->transaction); + resetBlockIndex(&settings->base); + } + } + } + return ret; +} + +int svr_getRequestWithList( + dlmsServerSettings* settings, + gxByteBuffer* data, + unsigned char invokeId) +{ + int ret = 0; + gxValueEventCollection* arr; + gxValueEventArg* e; + DLMS_OBJECT_TYPE ci; + gxLNParameters p; + unsigned char attributeIndex; + uint16_t id; + uint16_t pos, cnt; + unsigned char* ln; +#ifdef DLMS_IGNORE_MALLOC + if (hlp_getObjectCount2(data, &cnt) != 0 || cnt > settings->transaction.targets.capacity) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + arr = &settings->transaction.targets; + arr->size = (unsigned char)cnt; +#else + gxValueEventCollection list; + if (hlp_getObjectCount2(data, &cnt) != 0) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + vec_init(&list); + arr = &list; +#endif //DLMS_IGNORE_MALLOC + + for (pos = 0; pos != cnt; ++pos) + { + if ((ret = bb_getUInt16(data, &id)) != 0) + { + break; + } + ci = (DLMS_OBJECT_TYPE)id; + ln = data->data + data->position; + data->position += 6; + if ((ret = bb_getUInt8(data, &attributeIndex)) != 0) + { + break; + } +#ifdef DLMS_IGNORE_MALLOC + if ((ret = vec_getByIndex(arr, pos, &e)) != 0) + { + break; + } + ve_clear(e); +#else + e = (gxValueEventArg*)gxmalloc(sizeof(gxValueEventArg)); + ve_init(e); + vec_push(&list, e); +#endif //DLMS_IGNORE_MALLOC + + e->index = attributeIndex; + if ((ret = oa_findByLN(&settings->base.objects, ci, ln, &e->target)) != 0) + { + break; + } + if (e->target == NULL) + { + ret = svr_findObject(&settings->base, ci, 0, ln, e); + } + if (e->target == NULL) + { + // Access Error : Device reports a undefined object. + e->error = DLMS_ERROR_CODE_UNDEFINED_OBJECT; + } + else + { + if (svr_getAttributeAccess(&settings->base, e->target, attributeIndex) == DLMS_ACCESS_MODE_NONE) + { + // Read Write denied. + e->error = DLMS_ERROR_CODE_READ_WRITE_DENIED; + } + else + { + // AccessSelection + unsigned char selection; + if ((ret = bb_getUInt8(data, &selection)) != 0) + { + break; + } + if (selection != 0) + { + gxDataInfo di; + di_init(&di); + if ((ret = bb_getUInt8(data, &e->selector)) != 0) + { + break; + } + if ((ret = dlms_getData(data, &di, &e->parameters)) != 0) + { + break; + } + } + } + } + } + bb_clear(data); + svr_preRead(&settings->base, arr); + hlp_setObjectCount(cnt, data); + unsigned char moreData = 0; + for (pos = 0; pos != arr->size; ++pos) + { + if ((ret = vec_getByIndex(arr, pos, &e)) != 0) + { + break; + } +#ifdef DLMS_IGNORE_MALLOC + e->value.byteArr = data; + e->value.vt = DLMS_DATA_TYPE_OCTET_STRING; +#endif //DLMS_IGNORE_MALLOC + if (e->error == 0) + { +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + uint32_t pos2 = data->size; +#else + uint16_t pos2 = data->size; +#endif + bb_setUInt8(data, (unsigned char)e->error); + if (!e->handled) + { + if ((ret = cosem_getValue(&settings->base, e)) != 0) + { + e->error = DLMS_ERROR_CODE_HARDWARE_FAULT; + bb_setUInt8ByIndex(data, pos2, (unsigned char)e->error); + } + } + } + if (e->error == 0) + { + if (!e->byteArray) + { + if ((ret = dlms_setData(data, e->value.vt, &e->value)) != 0) + { + e->error = DLMS_ERROR_CODE_HARDWARE_FAULT; + } + } + else if (!bb_isAttached(e->value.byteArr)) + { + if ((ret = bb_set2(data, e->value.byteArr, 0, e->value.byteArr->size)) != 0) + { + e->error = DLMS_ERROR_CODE_HARDWARE_FAULT; + } + var_clear(&e->value); + } + } + else + { + bb_setUInt8(data, 1); + bb_setUInt8(data, (unsigned char)e->error); + } + //PDU is used for serialization. Set data type to none so size is not changed. + if (e->byteArray || (e->value.vt == DLMS_DATA_TYPE_OCTET_STRING && bb_isAttached(e->value.byteArr))) + { + e->value.vt = DLMS_DATA_TYPE_NONE; + } + if (e->transactionStartIndex != e->transactionEndIndex) + { + e->transaction = 1; + settings->transaction.command = DLMS_COMMAND_GET_REQUEST; + moreData = 1; +#ifndef DLMS_IGNORE_MALLOC + trans_clear(&settings->transaction); + settings->transaction.targets = list; + var_clear(&e->value); + vec_init(&list); + if (!bb_isAttached(data)) + { + bb_set2(&settings->transaction.data, data, data->position, data->size - data->position); + } +#endif //DLMS_IGNORE_MALLOC + } + } + svr_postRead(&settings->base, arr); + params_initLN(&p, &settings->base, invokeId, DLMS_COMMAND_GET_RESPONSE, 3, NULL, data, 0xFF, settings->info.encryptedCommand, moreData, !moreData); + ret = dlms_getLNPdu(&p, data); +#ifndef DLMS_IGNORE_MALLOC + vec_clear(&list); +#endif //DLMS_IGNORE_MALLOC + return ret; +} + +int svr_handleGetRequest( + dlmsServerSettings* settings, + gxByteBuffer* data) +{ + int ret; + DLMS_GET_COMMAND_TYPE type; + unsigned char invokeId, ch; + // Get type. + if ((ret = bb_getUInt8(data, &ch)) != 0) + { + return ret; + } + type = (DLMS_GET_COMMAND_TYPE)ch; + // Get invoke ID and priority. + if ((ret = bb_getUInt8(data, &invokeId)) != 0) + { + return ret; + } + updateInvokeId(settings, invokeId); + // GetRequest normal + if (type == DLMS_GET_COMMAND_TYPE_NORMAL) + { + ret = svr_getRequestNormal(settings, data, invokeId); + if (ret == DLMS_ERROR_CODE_INVALID_COMMAND) + { + return ret; + } + } + else if (type == DLMS_GET_COMMAND_TYPE_NEXT_DATA_BLOCK) + { + // Get request for next data block + ret = svr_getRequestNextDataBlock(settings, data, invokeId); + } + else if (type == DLMS_GET_COMMAND_TYPE_WITH_LIST) + { + if ((settings->base.negotiatedConformance & DLMS_CONFORMANCE_MULTIPLE_REFERENCES) == 0) + { + return DLMS_ERROR_CODE_INVALID_COMMAND; + } + // Get request with a list. + ret = svr_getRequestWithList(settings, data, invokeId); + } + else + { + ret = DLMS_ERROR_CODE_READ_WRITE_DENIED; + type = DLMS_GET_COMMAND_TYPE_NORMAL; + } + if (ret != 0) + { + //If error is not DLMS error code. + if (!(ret > 0 && ret <= DLMS_ERROR_CODE_OTHER_REASON)) + { + // Access Error : Device reports Read-Write denied. + ret = DLMS_ERROR_CODE_READ_WRITE_DENIED; + } + gxLNParameters p; + params_initLN(&p, &settings->base, invokeId, DLMS_COMMAND_GET_RESPONSE, type, NULL, data, ret, settings->info.encryptedCommand, 0, 0); + bb_clear(data); + ret = dlms_getLNPdu(&p, data); + } + return ret; +} + +#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) +/** + * Find Short Name object. + * + * @param sn + */ +int svr_findSNObject(dlmsServerSettings* settings, int sn, gxSNInfo* i) +{ + uint16_t pos; + int ret; + gxObject* it; + unsigned char offset, count; + i->action = 0; + i->item = NULL; + i->index = 0; + + for (pos = 0; pos != settings->base.objects.size; ++pos) + { + if ((ret = oa_getByIndex(&settings->base.objects, pos, &it)) != 0) + { + return ret; + } + if (sn >= it->shortName) + { + // If attribute is accessed. + if (sn < it->shortName + obj_attributeCount(it) * 8) + { + i->action = 0; + i->item = it; + i->index = (unsigned char)(((sn - it->shortName) / 8) + 1); + break; + } + else + { + // If method is accessed. + dlms_getActionInfo((DLMS_OBJECT_TYPE)it->objectType, &offset, &count); + if (sn < it->shortName + offset + (8 * count)) + { + i->item = it; + i->action = 1; + i->index = (unsigned char)((sn - it->shortName - offset) / 8 + 1); + break; + } + } + } + } + if (i->item == NULL) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return 0; +} + +int svr_handleRead( + dlmsServerSettings* settings, + DLMS_VARIABLE_ACCESS_SPECIFICATION type, + gxByteBuffer* data, + gxValueEventCollection* list) +{ + gxSNInfo info; + gxValueEventArg* e; + int ret; + gxDataInfo di; + uint16_t sn; + di_init(&di); + if ((ret = bb_getUInt16(data, &sn)) != 0) + { + return ret; + } + if ((ret = svr_findSNObject(settings, sn, &info)) != 0) + { + return ret; + } + +#ifdef DLMS_IGNORE_MALLOC + if (settings->transaction.targets.capacity < 1) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + list = &settings->transaction.targets; + list->size = 1; + e = &list->data[0]; + ve_clear(e); +#else + e = (gxValueEventArg*)gxmalloc(sizeof(gxValueEventArg)); + ve_init(e); + vec_push(list, e); +#endif //DLMS_IGNORE_MALLOC + e->target = info.item; + e->index = info.index; + e->action = info.action; + if (type == DLMS_VARIABLE_ACCESS_SPECIFICATION_PARAMETERISED_ACCESS) + { + if ((ret = bb_getUInt8(data, &e->selector)) != 0) + { + return ret; + } + if ((ret = dlms_getData(data, &di, &e->parameters)) != 0) + { + return ret; + } + } + if (svr_getAttributeAccess(&settings->base, info.item, info.index) == DLMS_ACCESS_MODE_NONE) + { + e->error = DLMS_ERROR_CODE_READ_WRITE_DENIED; + e->handled = 1; + } + return ret; +} +#endif //#ifdef !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + +/** +* Get data for Read command. +* +* @param settings +* DLMS settings. +* @param list +* received objects. +* @param data +* Data as byte array. +* @param type +* Response type. +*/ +int svr_getReadData( + dlmsServerSettings* settings, + gxValueEventCollection* list, + gxByteBuffer* data, + DLMS_SINGLE_READ_RESPONSE* type, + unsigned char* multipleBlocks) +{ + int ret; + gxValueEventArg* e; + uint32_t pos; +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + uint32_t statusindex; +#else + uint16_t statusindex; +#endif + unsigned char first = 1; + *type = DLMS_SINGLE_READ_RESPONSE_DATA; + bb_clear(data); + for (pos = 0; pos != list->size; ++pos) + { + if ((ret = vec_getByIndex(list, pos, &e)) != 0) + { + break; + } + statusindex = data->size; + if (!e->handled) + { + if (e->action) + { + if ((ret = cosem_invoke(settings, e)) != 0) + { + e->error = (DLMS_ERROR_CODE)ret; + } + } + else + { + if ((ret = cosem_getValue(&settings->base, e)) != 0) + { + e->error = (DLMS_ERROR_CODE)ret; + } + } + } + if (e->error == DLMS_ERROR_CODE_OK) + { + if (!first && list->size != 1) + { + bb_insertUInt8(data, statusindex, DLMS_SINGLE_READ_RESPONSE_DATA); + } + if (e->byteArray) + { + e->value.vt = DLMS_DATA_TYPE_NONE; + } + else + { + if ((ret = dlms_setData(data, e->value.vt, &e->value)) != 0) + { + var_clear(&e->value); + break; + } + } + } + else + { + if (!first && list->size != 1) + { + bb_insertUInt8(data, statusindex, DLMS_SINGLE_READ_RESPONSE_DATA_ACCESS_ERROR); + } + bb_insertUInt8(data, statusindex + 1, e->error); + *type = DLMS_SINGLE_READ_RESPONSE_DATA_ACCESS_ERROR; + } + var_clear(&e->value); + first = 0; + *multipleBlocks |= e->transactionEndIndex != e->transactionStartIndex; + e->transaction = *multipleBlocks; + } + return 0; +} +#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) +int svr_handleReadBlockNumberAccess( + dlmsServerSettings* settings, + gxByteBuffer* data) +{ + gxSNParameters p; + gxValueEventArg* e; + uint16_t pos, blockNumber; + unsigned char lastBlock = 1; + int ret; + unsigned char multipleBlocks; + if ((ret = bb_getUInt16(data, &blockNumber)) != 0) + { + return ret; + } + if (blockNumber != settings->base.blockIndex) + { + gxByteBuffer bb; + BYTE_BUFFER_INIT(&bb); + bb_setUInt8(&bb, DLMS_ERROR_CODE_DATA_BLOCK_NUMBER_INVALID); + params_initSN(&p, &settings->base, + DLMS_COMMAND_READ_RESPONSE, 1, + DLMS_SINGLE_READ_RESPONSE_DATA_ACCESS_ERROR, &bb, NULL, settings->info.encryptedCommand); + ret = dlms_getSNPdu(&p, data); + resetBlockIndex(&settings->base); + bb_clear(&bb); + return ret; + } + gxValueEventCollection reads; + gxValueEventCollection actions; + vec_init(&reads); + vec_init(&actions); + for (pos = 0; pos != settings->transaction.targets.size; ++pos) + { + if ((ret = vec_getByIndex(&settings->transaction.targets, pos, &e)) != 0) + { + break; + } + if (e->action) + { + vec_push(&actions, e); + } + else + { + vec_push(&reads, e); + } + } + if (ret == 0) + { + DLMS_SINGLE_READ_RESPONSE requestType; + if (reads.size != 0) + { + svr_preRead(&settings->base, &reads); + } + + if (actions.size != 0) + { + svr_preAction(&settings->base, &actions); + } + ret = svr_getReadData(settings, &settings->transaction.targets, + data, &requestType, &multipleBlocks); + if (reads.size != 0) + { + svr_postRead(&settings->base, &reads); + } + if (actions.size != 0) + { + svr_postAction(&settings->base, &actions); + } + if (lastBlock) + { + lastBlock = e->transactionStartIndex == e->transactionEndIndex; + } + } + vec_empty(&reads); + vec_empty(&actions); + if (ret == 0) + { + ++settings->base.blockIndex; + params_initSN(&p, &settings->base, DLMS_COMMAND_READ_RESPONSE, 1, + DLMS_SINGLE_READ_RESPONSE_DATA_BLOCK_RESULT, NULL, data, settings->info.encryptedCommand); + p.multipleBlocks = 1; + p.lastBlock = lastBlock; + ret = dlms_getSNPdu(&p, data); + // If all data is sent. + if (p.lastBlock && settings->transaction.data.size == settings->transaction.data.position) + { + trans_clear(&settings->transaction); + resetBlockIndex(&settings->base); + } + else + { + bb_trim(&settings->transaction.data); + } + } + return ret; +} + +int svr_handleReadDataBlockAccess( + dlmsServerSettings* settings, + DLMS_COMMAND command, + gxByteBuffer* data, + int cnt) +{ + gxSNParameters p; + int ret; + uint16_t size; + uint16_t blockNumber; + unsigned char isLast, ch; + unsigned char count = 1, type = DLMS_DATA_TYPE_OCTET_STRING; + if ((ret = bb_getUInt8(data, &ch)) != 0) + { + return ret; + } + isLast = ch != 0; + if ((ret = bb_getUInt16(data, &blockNumber)) != 0) + { + return ret; + } + if (blockNumber != settings->base.blockIndex) + { + gxByteBuffer bb; + BYTE_BUFFER_INIT(&bb); + bb_setUInt8(&bb, DLMS_ERROR_CODE_DATA_BLOCK_NUMBER_INVALID); + params_initSN(&p, &settings->base, command, 1, DLMS_SINGLE_READ_RESPONSE_DATA_ACCESS_ERROR, &bb, NULL, settings->info.encryptedCommand); + ret = dlms_getSNPdu(&p, data); + resetBlockIndex(&settings->base); + bb_clear(&bb); + return ret; + } + if (command == DLMS_COMMAND_WRITE_RESPONSE) + { + if ((ret = bb_getUInt8(data, &count)) != 0 || + (ret = bb_getUInt8(data, &type)) != 0) + { + return ret; + } + } + if (hlp_getObjectCount2(data, &size) != 0) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if (count != 1 || type != DLMS_DATA_TYPE_OCTET_STRING || + size != data->size - data->position) + { + gxByteBuffer bb; + BYTE_BUFFER_INIT(&bb); + bb_setUInt8(&bb, DLMS_ERROR_CODE_DATA_BLOCK_UNAVAILABLE); + params_initSN(&p, &settings->base, command, cnt, + DLMS_SINGLE_READ_RESPONSE_DATA_ACCESS_ERROR, &bb, NULL, settings->info.encryptedCommand); + ret = dlms_getSNPdu(&p, data); + bb_clear(&bb); + resetBlockIndex(&settings->base); + return ret; + } + settings->transaction.command = command; + bb_set2(&settings->transaction.data, data, data->position, data->size - data->position); + if (!isLast) + { + gxByteBuffer bb; + BYTE_BUFFER_INIT(&bb); + bb_setUInt16(&bb, blockNumber); + ++settings->base.blockIndex; + if (command == DLMS_COMMAND_READ_RESPONSE) + { + type = DLMS_SINGLE_READ_RESPONSE_BLOCK_NUMBER; + } + else + { + type = DLMS_SINGLE_WRITE_RESPONSE_BLOCK_NUMBER; + } + params_initSN(&p, &settings->base, command, cnt, type, NULL, &bb, settings->info.encryptedCommand); + ret = dlms_getSNPdu(&p, data); + bb_clear(&bb); + } + else + { + data->position = data->size = 0; + bb_set2(data, &settings->transaction.data, + settings->transaction.data.position, + settings->transaction.data.size - settings->transaction.data.position); + trans_clear(&settings->transaction); + if (command == DLMS_COMMAND_READ_RESPONSE) + { + ret = svr_handleReadRequest(settings, data); + } + else + { + ret = svr_handleWriteRequest(settings, data); + } + resetBlockIndex(&settings->base); + } + return ret; +} + +int svr_returnSNError( + dlmsServerSettings* settings, + DLMS_COMMAND cmd, + DLMS_ERROR_CODE error, + gxByteBuffer* data) +{ + int ret; + gxByteBuffer bb; + gxSNParameters p; + BYTE_BUFFER_INIT(&bb); + bb_setUInt8(&bb, error); + params_initSN(&p, &settings->base, cmd, 1, + DLMS_SINGLE_READ_RESPONSE_DATA_ACCESS_ERROR, &bb, NULL, settings->info.encryptedCommand); + ret = dlms_getSNPdu(&p, data); + resetBlockIndex(&settings->base); + return ret; +} + +/** + * Handle read request. + */ +int svr_handleReadRequest( + dlmsServerSettings* settings, + gxByteBuffer* data) +{ + DLMS_SINGLE_READ_RESPONSE requestType; + gxSNParameters p; + int ret = 0; + unsigned char ch, multipleBlocks = 0; + uint16_t pos, cnt = 0; + DLMS_VARIABLE_ACCESS_SPECIFICATION type; + gxValueEventCollection list; + // If get next frame. + if (data->size == 0) + { + if (settings->transaction.command != DLMS_COMMAND_NONE) + { + return 0; + } + list = settings->transaction.targets; + } + else + { + vec_init(&list); + if (hlp_getObjectCount2(data, &cnt) != 0) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + for (pos = 0; pos != cnt; ++pos) + { + if ((ret = bb_getUInt8(data, &ch)) != 0) + { + break; + } + type = (DLMS_VARIABLE_ACCESS_SPECIFICATION)ch; + switch (type) + { + case DLMS_VARIABLE_ACCESS_SPECIFICATION_VARIABLE_NAME: + case DLMS_VARIABLE_ACCESS_SPECIFICATION_PARAMETERISED_ACCESS: + ret = svr_handleRead(settings, type, data, &list); + break; + case DLMS_VARIABLE_ACCESS_SPECIFICATION_BLOCK_NUMBER_ACCESS: + vec_clear(&list); + return svr_handleReadBlockNumberAccess(settings, data); + case DLMS_VARIABLE_ACCESS_SPECIFICATION_READ_DATA_BLOCK_ACCESS: + vec_clear(&list); + return svr_handleReadDataBlockAccess(settings, DLMS_COMMAND_READ_RESPONSE, data, cnt); + default: + vec_clear(&list); + return svr_returnSNError(settings, DLMS_COMMAND_READ_RESPONSE, DLMS_ERROR_CODE_READ_WRITE_DENIED, data); + } + } + if (ret == 0) + { + if (list.size != 0) + { + svr_preRead(&settings->base, &list); + } + } + } + if (ret == 0) + { + ret = svr_getReadData(settings, &list, data, &requestType, &multipleBlocks); + if (ret == 0) + { + if (list.size != 0) + { + svr_postRead(&settings->base, &list); + } + params_initSN(&p, &settings->base, DLMS_COMMAND_READ_RESPONSE, cnt, + requestType, NULL, data, settings->info.encryptedCommand); + p.multipleBlocks = multipleBlocks; + p.lastBlock = list.data[0]->transactionStartIndex == list.data[0]->transactionEndIndex; + ret = dlms_getSNPdu(&p, data); + if (ret == 0) + { + if (list.data[0]->transactionStartIndex != list.data[0]->transactionEndIndex) + { + settings->transaction.targets = list; + vec_init(&list); + settings->transaction.command = DLMS_COMMAND_READ_REQUEST; + if (!bb_isAttached(data)) + { + bb_set2(&settings->transaction.data, data, data->position, data->size - data->position); + } + } + } + } + } + vec_clear(&list); + return ret; +} + +int svr_handleWriteRequest( + dlmsServerSettings* settings, + gxByteBuffer* data) +{ + gxSNParameters p; + int ret = 0; + gxValueEventArg* e; + unsigned char ch; + uint16_t sn; + uint16_t cnt, pos; + gxDataInfo di; + DLMS_ACCESS_MODE am; + gxSNInfo i; + gxValueEventCollection list; + gxValueEventCollection writes; + gxValueEventCollection actions; + DLMS_VARIABLE_ACCESS_SPECIFICATION type; + gxByteBuffer results; + // Get object count. + if (hlp_getObjectCount2(data, &cnt) != 0) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + BYTE_BUFFER_INIT(&results); + bb_capacity(&results, cnt); + vec_init(&list); + vec_init(&writes); + vec_init(&actions); + for (pos = 0; pos != cnt; ++pos) + { + if ((ret = bb_getUInt8(data, &ch)) != 0) + { + break; + } + type = (DLMS_VARIABLE_ACCESS_SPECIFICATION)ch; + switch (type) + { + case DLMS_VARIABLE_ACCESS_SPECIFICATION_VARIABLE_NAME: + if ((ret = bb_getUInt16(data, &sn)) != 0) + { + break; + } + if ((ret = svr_findSNObject(settings, sn, &i)) != 0) + { + break; + } + e = (gxValueEventArg*)gxmalloc(sizeof(gxValueEventArg)); + ve_init(e); + e->target = i.item; + e->index = i.index; + e->action = i.action; + vec_push(&list, e); + if (e->action) + { + vec_push(&actions, e); + } + else + { + vec_push(&writes, e); + } + // Return error if connection is not established. + if (!settings->info.preEstablished && (settings->base.connected & DLMS_CONNECTION_STATE_DLMS) == 0 + && (!e->action || e->target->shortName != 0xFA00 || e->index != 8)) + { + ret = svr_generateConfirmedServiceError( + settings, + DLMS_CONFIRMED_SERVICE_ERROR_INITIATE_ERROR, + DLMS_SERVICE_ERROR_SERVICE, + DLMS_SERVICE_UNSUPPORTED, data); + break; + } + // If target is unknown. + if (i.item == NULL) + { + // Device reports a undefined object. + bb_setUInt8(&results, DLMS_ERROR_CODE_UNDEFINED_OBJECT); + } + else + { + bb_setUInt8(&results, DLMS_ERROR_CODE_OK); + } + break; + case DLMS_VARIABLE_ACCESS_SPECIFICATION_WRITE_DATA_BLOCK_ACCESS: + // Return error if connection is not established. + if (!settings->info.preEstablished && (settings->base.connected & DLMS_CONNECTION_STATE_DLMS) == 0) + { + ret = svr_generateConfirmedServiceError( + settings, + DLMS_CONFIRMED_SERVICE_ERROR_INITIATE_ERROR, + DLMS_SERVICE_ERROR_SERVICE, + DLMS_SERVICE_UNSUPPORTED, data); + break; + } + bb_clear(&results); + return svr_handleReadDataBlockAccess(settings, DLMS_COMMAND_WRITE_RESPONSE, data, cnt); + default: + // Device reports a HW error. + ret = DLMS_ERROR_CODE_HARDWARE_FAULT; + } + } + // Get data count. + if (hlp_getObjectCount2(data, &cnt) != 0) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + cnt = 0; + } + di_init(&di); + for (pos = 0; pos != cnt; ++pos) + { + if ((ret = bb_getUInt8ByIndex(&results, pos, &ch)) != 0) + { + break; + } + if (ch == 0) + { + // If object has found. + if ((ret = vec_getByIndex(&list, pos, &e)) != 0) + { + break; + } + if (e->action) + { + if ((ret = dlms_getData(data, &di, &e->parameters)) != 0) + { + break; + } + } + else if ((ret = dlms_getData(data, &di, &e->value)) != 0) + { + break; + } + di_init(&di); + am = svr_getAttributeAccess(&settings->base, e->target, e->index); + // If write is denied. + if (am != DLMS_ACCESS_MODE_WRITE && am != DLMS_ACCESS_MODE_READ_WRITE) + { + bb_setUInt8ByIndex(&results, pos, DLMS_ERROR_CODE_READ_WRITE_DENIED); + } + else + { + if (writes.size != 0) + { + if (pos == 0) + { + svr_preWrite(&settings->base, &list); + } + if (e->error != 0) + { + bb_setUInt8ByIndex(&results, pos, e->error); + } + else if (!e->handled) + { + if ((ret = cosem_setValue(&settings->base, e)) != 0) + { + break; + } + //Call post write after all values are written. + if (pos == cnt - 1) + { + svr_postWrite(&settings->base, &list); + if (e->error != 0) + { + bb_setUInt8ByIndex(&results, pos, e->error); + } + } + } + } + if (actions.size != 0) + { + if (pos == 0) + { + svr_preAction(&settings->base, &actions); + } + ret = cosem_invoke(settings, e); + // If High level authentication fails. + if (e->target != NULL && e->target->objectType == DLMS_OBJECT_TYPE_ASSOCIATION_SHORT_NAME && e->index == 1) + { + if ((settings->base.connected & DLMS_CONNECTION_STATE_DLMS) != 0) + { + svr_connected(settings); + } + else + { + svr_invalidConnection(settings); + } + } + //Call post action after all values are invoked. + if (pos == cnt - 1) + { + svr_postAction(&settings->base, &actions); + } + if (ret != 0) + { + break; + } + } + } + } + } + if (ret != 0) + { + // Add parameters error code. + if (ret > 0 && ret < DLMS_ERROR_CODE_OTHER_REASON + 1) + { + bb_setUInt8ByIndex(&results, pos, ret); + } + else + { + bb_setUInt8ByIndex(&results, pos, DLMS_ERROR_CODE_READ_WRITE_DENIED); + } + } + gxByteBuffer bb; + BYTE_BUFFER_INIT(&bb); + bb_capacity(&bb, 2 * cnt); + for (pos = 0; pos != cnt; ++pos) + { + if ((ret = bb_getUInt8(&results, &ch)) != 0) + { + break; + } + // If meter returns error. + if (ch != 0) + { + bb_setUInt8(&bb, 1); + } + bb_setUInt8(&bb, ch); + } + params_initSN(&p, &settings->base, DLMS_COMMAND_WRITE_RESPONSE, cnt, 0xFF, &bb, NULL, settings->info.encryptedCommand); + p.lastBlock = e->transactionStartIndex == e->transactionEndIndex; + ret = dlms_getSNPdu(&p, data); + bb_clear(&bb); + // If all data is transfered. + bb_clear(&results); + vec_empty(&writes); + vec_empty(&actions); + vec_clear(&list); + return ret; +} +#endif //!defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + +#ifndef DLMS_IGNORE_ACTION +/** +* Handle action request. +* +* @param reply +* Received data from the client. +* @return Reply. +*/ +int svr_handleMethodRequest( + dlmsServerSettings* settings, + gxByteBuffer* data) +{ + DLMS_OBJECT_TYPE ci; + gxValueEventArg* e; + unsigned char* ln; + int error = DLMS_ERROR_CODE_OK; + int ret; + unsigned char invokeId, ch, id; + uint16_t tmp; + gxValueEventCollection* list; +#ifndef DLMS_IGNORE_MALLOC + gxValueEventCollection arr; +#endif //DLMS_IGNORE_MALLOC + // Get type. + if ((ret = bb_getUInt8(data, &ch)) != 0) + { + return ret; + } + // Get invoke ID and priority. + if ((ret = bb_getUInt8(data, &invokeId)) != 0) + { + return ret; + } + updateInvokeId(settings, invokeId); + // CI + if ((ret = bb_getUInt16(data, &tmp)) != 0) + { + return ret; + } + ci = (DLMS_OBJECT_TYPE)tmp; + ln = data->data + data->position; + data->position += 6; + // Attribute + if ((ret = bb_getUInt8(data, &id)) != 0) + { + return ret; + } + // Get parameters. + if ((ret = bb_getUInt8(data, &ch)) != 0) + { + return ret; + } +#ifdef DLMS_IGNORE_MALLOC + if (settings->transaction.targets.capacity < 1) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + list = &settings->transaction.targets; + list->size = 1; + e = &list->data[0]; + ve_clear(e); + e->value.byteArr = &settings->info.data; + e->value.vt = DLMS_DATA_TYPE_OCTET_STRING; +#else + list = &arr; + vec_init(list); + e = (gxValueEventArg*)gxmalloc(sizeof(gxValueEventArg)); + ve_init(e); + vec_push(list, e); +#endif //DLMS_IGNORE_MALLOC + e->index = id; + if (ch != 0) + { +#ifdef DLMS_IGNORE_MALLOC + e->parameters.byteArr = data; + e->parameters.vt = DLMS_DATA_TYPE_OCTET_STRING; +#endif //DLMS_IGNORE_MALLOC + gxDataInfo di; + di_init(&di); + if ((ret = dlms_getData(data, &di, &e->parameters)) != 0) + { +#ifndef DLMS_IGNORE_MALLOC + bb_clear(data); + vec_clear(&arr); +#endif //DLMS_IGNORE_MALLOC + return ret; + } + } + if (ci == DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME) + { + e->target = NULL; + } + else + { + if ((ret = oa_findByLN(&settings->base.objects, ci, ln, &e->target)) != 0) + { +#ifndef DLMS_IGNORE_MALLOC + bb_clear(data); + vec_clear(&arr); +#endif //DLMS_IGNORE_MALLOC + return ret; + } + } + if (e->target == NULL) + { + ret = svr_findObject(&settings->base, ci, 0, ln, e); + } +#ifndef DLMS_IGNORE_MALLOC + bb_clear(data); +#endif //DLMS_IGNORE_MALLOC + if (e->target == NULL) + { + error = DLMS_ERROR_CODE_UNDEFINED_OBJECT; + } + else + { +#if !defined(DLMS_ITALIAN_STANDARD) + //In Italian standard reply_to_HLS_authentication can be called without access rights. + if (!(ci == DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME && id == 1) && + svr_getMethodAccess(&settings->base, e->target, id) == DLMS_METHOD_ACCESS_MODE_NONE) +#else + if (svr_getMethodAccess(&settings->base, e->target, id) == DLMS_METHOD_ACCESS_MODE_NONE) +#endif //defined(DLMS_ITALIAN_STANDARD) + { + e->error = DLMS_ERROR_CODE_READ_WRITE_DENIED; + } + else + { + svr_preAction(&settings->base, list); + if (!e->handled) + { + if ((ret = cosem_invoke(settings, e)) != 0) + { + e->error = (DLMS_ERROR_CODE)ret; + ret = 0; + } + svr_postAction(&settings->base, list); + } + } +#ifdef DLMS_IGNORE_MALLOC + if (data->position == data->size) + { + bb_clear(data); + } +#endif //DLMS_IGNORE_MALLOC + + // Set default action reply if not given. + if (e->error == DLMS_ERROR_CODE_OK) + { + if (// Add return parameters + (ret = bb_insertUInt8(data, 0, 0)) != 0 || + //Add parameters error code. + (ret = bb_insertUInt8(data, 0, 1)) != 0) + { + error = DLMS_ERROR_CODE_HARDWARE_FAULT; + } + if (e->byteArray) + { + if (!bb_isAttached(e->value.byteArr) && e->value.vt == DLMS_DATA_TYPE_OCTET_STRING) + { + if ((ret = bb_set2(data, e->value.byteArr, 0, bb_size(e->value.byteArr))) != 0) + { + error = DLMS_ERROR_CODE_HARDWARE_FAULT; + } + var_clear(&e->value); + } + else + { + e->value.vt = DLMS_DATA_TYPE_NONE; + } + } + else + { + if ((ret = dlms_setData(data, e->value.vt, &e->value)) != 0) + { + error = DLMS_ERROR_CODE_HARDWARE_FAULT; + } + } + } + else + { + // Add parameters error code. + if (e->error > 0 && e->error < DLMS_ERROR_CODE_OTHER_REASON + 1) + { + error = e->error; + } + else + { + error = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } + bb_clear(data); + bb_setUInt8(data, 0); + } + } + if (ret == 0) + { + gxLNParameters p; + params_initLN(&p, &settings->base, invokeId, DLMS_COMMAND_METHOD_RESPONSE, 1, NULL, data, error, settings->info.encryptedCommand, 0, 0); + ret = dlms_getLNPdu(&p, data); + // If High level authentication fails. + if (e->target != NULL && e->target->objectType == DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME && id == 1) + { +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + if (((gxAssociationLogicalName*)e->target)->associationStatus == DLMS_ASSOCIATION_STATUS_ASSOCIATED) + { + settings->base.connected |= DLMS_CONNECTION_STATE_DLMS; + svr_connected(settings); + } + else + { + svr_invalidConnection(settings); + settings->base.connected &= ~DLMS_CONNECTION_STATE_DLMS; + } +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + } + } +#ifndef DLMS_IGNORE_MALLOC + vec_clear(&arr); +#endif //DLMS_IGNORE_MALLOC + return ret; +} +#endif //DLMS_IGNORE_ACTION + +/** +* Handles release request. +* +* @param settings +* DLMS settings. +* @param data +* Received data. +*/ +int svr_handleReleaseRequest( + dlmsServerSettings* settings, + gxByteBuffer* data) { + int ret; + unsigned char ch, len; + gxByteBuffer tmp; + //Get len. + if ((ret = bb_getUInt8(data, &len)) != 0 || + (ret = bb_getUInt8(data, &ch)) != 0 || + (ret = bb_getUInt8(data, &ch)) != 0 || + //Get reason. + (ret = bb_getUInt8(data, &ch)) != 0) + { + return ret; + } + unsigned char userInfo = len != 3; + bb_clear(data); +#ifdef DLMS_IGNORE_MALLOC + unsigned char offset = IS_HDLC(settings->base.interfaceType) ? 12 : 9; + bb_attach(&tmp, data->data + offset, 0, data->capacity - offset); +#else + BYTE_BUFFER_INIT(&tmp); +#endif //DLMS_IGNORE_MALLOC + if (!(userInfo && (ret = apdu_getUserInformation(&settings->base, &tmp, 0)) != 0)) + { +#ifndef DLMS_IGNORE_HDLC + if (IS_HDLC(settings->base.interfaceType)) + { + dlms_addLLCBytes(&settings->base, data); + } +#endif //DLMS_IGNORE_HDLC + if ((ret = bb_setUInt8(data, 0x63)) == 0 && + //Len. + (ret = bb_setUInt8(data, (unsigned char)(tmp.size + 3))) == 0 && + (ret = bb_setUInt8(data, 0x80)) == 0 && + (ret = bb_setUInt8(data, 0x01)) == 0 && + //Reason + (ret = bb_setUInt8(data, ch)) == 0) + { + if (tmp.size != 0) + { + if ((ret = bb_setUInt8(data, 0xBE)) == 0 && + (ret = bb_setUInt8(data, (unsigned char)(tmp.size + 1))) == 0 && + (ret = bb_setUInt8(data, 4)) == 0 && + (ret = bb_setUInt8(data, (unsigned char)tmp.size)) == 0) + { +#ifndef DLMS_IGNORE_MALLOC + ret = bb_set(data, tmp.data, tmp.size); +#endif //DLMS_IGNORE_MALLOC + } + } + } + } + return 0; +} + +#ifndef DLMS_IGNORE_PLC +int svr_registerRequest( + dlmsSettings* settings, + gxByteBuffer* initiatorSystemTitle, + gxByteBuffer* systemTitle, + gxByteBuffer* data) +{ + gxByteBuffer bb; + BYTE_BUFFER_INIT(&bb); + bb_setUInt8(&bb, DLMS_COMMAND_REGISTER_REQUEST); + bb_set(&bb, initiatorSystemTitle->data, initiatorSystemTitle->size); + // LEN + bb_setUInt8(&bb, 0x1); + bb_set(&bb, systemTitle->data, systemTitle->size); + // MAC address. + bb_setUInt16(&bb, settings->plcSettings.macSourceAddress); + int ret; + int val = settings->plcSettings.initialCredit << 5; + val |= settings->plcSettings.currentCredit << 2; + val |= settings->plcSettings.deltaCredit & 0x3; + int clientAddress = settings->clientAddress; + int serverAddress = settings->serverAddress; + int macSourceAddress = settings->plcSettings.macSourceAddress; + int macTargetAddress = settings->plcSettings.macDestinationAddress; + // 10.4.6.4 Source and destination APs and addresses of CI-PDUs + // Client address is No-station in discoverReport. + if (settings->interfaceType == DLMS_INTERFACE_TYPE_PLC_HDLC) + { + settings->plcSettings.initialCredit = 0; + settings->plcSettings.currentCredit = 0; + settings->plcSettings.macSourceAddress = 0xC01; + settings->plcSettings.macDestinationAddress = 0xFFF; + settings->clientAddress = 0x66; + // All-station + settings->serverAddress = 0x33FF; + } + else + { + settings->clientAddress = 1; + settings->serverAddress = 0; + settings->plcSettings.macSourceAddress = 0xC00; + settings->plcSettings.macDestinationAddress = 0xFFF; + } + ret = dlms_getMacFrame(settings, 0x13, val, &bb, data); + settings->clientAddress = clientAddress; + settings->serverAddress = serverAddress; + settings->plcSettings.macSourceAddress = macSourceAddress; + settings->plcSettings.macDestinationAddress = macTargetAddress; + return ret; +} + +int svr_parseRegisterRequest( + dlmsSettings* settings, + gxByteBuffer* value) +{ + int ret; + unsigned char pos, count; + // Get System title. + bb_get(value, settings->plcSettings.systemTitle.data, settings->plcSettings.systemTitle.size); + if ((ret = bb_getUInt8(value, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + // MAC address. + if ((ret = bb_get(value, settings->plcSettings.systemTitle.data, settings->plcSettings.systemTitle.size)) != 0 || + (ret = bb_getUInt16(value, &settings->plcSettings.macSourceAddress)) != 0) + { + break; + } + } + } + return ret; +} + +int svr_parseDiscoverRequest( + gxByteBuffer* value, + gxPlcRegister* reg) +{ + int ret; + if ((ret = bb_getUInt8(value, ®->responseProbability)) != 0 || + (ret = bb_getUInt16(value, ®->allowedTimeSlots)) != 0 || + (ret = bb_getUInt8(value, ®->discoverReportInitialCredit)) != 0 || + (ret = bb_getUInt8(value, ®->icEqualCredit)) != 0) + { + } + return 0; +} + +int dlms_pingRequest( + dlmsSettings* settings, + gxByteBuffer* systemTitle, + gxByteBuffer* data) +{ + int ret; + gxByteBuffer bb; + BYTE_BUFFER_INIT(&bb); + // Control byte. + if ((ret = bb_setUInt8(&bb, DLMS_COMMAND_PING_REQUEST)) != 0 || + (ret = bb_set(&bb, systemTitle->data, systemTitle->size)) != 0 || + (ret = dlms_getMacFrame(settings, 0x13, 0, &bb, data)) != 0) + { + bb_clear(&bb); + } + return ret; +} + +int dlm_parsePing(gxByteBuffer* data, gxByteBuffer* value) +{ + bb_clear(data); + return bb_set(value, data->data + data->position + 1, 6); +} + +int dlms_repeaterCallRequest( + dlmsSettings* settings, + gxByteBuffer* data) +{ + int ret; + gxByteBuffer bb; + BYTE_BUFFER_INIT(&bb); + // Control byte. + if ((ret = bb_setUInt8(&bb, DLMS_COMMAND_REPEAT_CALL_REQUEST)) != 0 || + // MaxAdrMac. + (ret = bb_setUInt16(&bb, 0x63)) != 0 || + // Nb_Tslot_For_New + (ret = bb_setUInt8(&bb, 0)) != 0 || + // Reception-Threshold default value + (ret = bb_setUInt8(&bb, 0)) != 0 || + (ret = dlms_getMacFrame(settings, 0x13, 0xFC, &bb, data)) != 0) + { + } + bb_clear(&bb); + return ret; +} + +int svr_discoverReport( + dlmsSettings* settings, + gxByteBuffer* systemTitle, + unsigned char newMeter, + gxByteBuffer* data) +{ + if (settings->interfaceType != DLMS_INTERFACE_TYPE_PLC && settings->interfaceType != DLMS_INTERFACE_TYPE_PLC_HDLC) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + gxByteBuffer bb; + BYTE_BUFFER_INIT(&bb); + int ret; + unsigned char alarmDescription; + if (settings->interfaceType == DLMS_INTERFACE_TYPE_PLC) + { + alarmDescription = (newMeter ? 1 : 0x82); + } + else + { + alarmDescription = 0; + } + if (settings->interfaceType == DLMS_INTERFACE_TYPE_PLC_HDLC) + { + ret = dlms_addLLCBytes(settings, &bb); + } + bb_setUInt8(&bb, DLMS_COMMAND_DISCOVER_REPORT); + bb_setUInt8(&bb, 1); + bb_set(&bb, settings->plcSettings.systemTitle.data, settings->plcSettings.systemTitle.size); + if (alarmDescription != 0) + { + bb_setUInt8(&bb, 1); + } + bb_setUInt8(&bb, alarmDescription); + int clientAddress = settings->clientAddress; + int serverAddress = settings->serverAddress; + int macSourceAddress = settings->plcSettings.macSourceAddress; + int macTargetAddress = settings->plcSettings.macDestinationAddress; + // 10.4.6.4 Source and destination APs and addresses of CI-PDUs + // Client address is No-station in discoverReport. + if (settings->interfaceType == DLMS_INTERFACE_TYPE_PLC_HDLC) + { + settings->plcSettings.macDestinationAddress = DLMS_PLC_HDLC_SOURCE_ADDRESS_INITIATOR; + } + else + { + settings->clientAddress = 0; + settings->serverAddress = 0xFD; + } + ret = dlms_getMacFrame(settings, 0x13, 0, &bb, data); + //Restore original values. + settings->clientAddress = clientAddress; + settings->serverAddress = serverAddress; + settings->plcSettings.macSourceAddress = macSourceAddress; + settings->plcSettings.macDestinationAddress = macTargetAddress; + return ret; +} + +#endif //DLMS_IGNORE_PLC + +int svr_handleCommand( + dlmsServerSettings* settings, + DLMS_COMMAND cmd, + gxByteBuffer* data, + gxByteBuffer* reply) +{ + int ret = 0; + unsigned char frame = 0; +#ifndef DLMS_IGNORE_MALLOC + if (dlms_useHdlc(settings->base.interfaceType) && bb_size(&settings->transaction.data) != 0) + { + //Get next frame. + frame = getNextSend(&settings->base, 0); + } +#else + if (dlms_useHdlc(settings->base.interfaceType) && bb_size(reply) != 0) + { + //Get next frame. + frame = getNextSend(&settings->base, 0); + } +#endif //DLMS_IGNORE_MALLOC + switch (cmd) + { +#ifndef DLMS_IGNORE_SET + case DLMS_COMMAND_SET_REQUEST: + //If connection is not established. + if ((!settings->info.preEstablished && (settings->base.connected & DLMS_CONNECTION_STATE_DLMS) == 0) || + //If service is not negotiated. + (settings->base.negotiatedConformance & DLMS_CONFORMANCE_SET) == 0) + { + ret = DLMS_ERROR_CODE_INVALID_COMMAND; + } + else + { + ret = svr_handleSetRequest(settings, data); + } + break; +#endif //DLMS_IGNORE_SET +#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + case DLMS_COMMAND_WRITE_REQUEST: + //Connection establised is checked inside of the function because of HLS. + if ((settings->base.negotiatedConformance & DLMS_CONFORMANCE_WRITE) == 0) + { + ret = DLMS_ERROR_CODE_INVALID_COMMAND; + } + else + { + ret = svr_handleWriteRequest(settings, data); + } + break; +#endif //!defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + case DLMS_COMMAND_GET_REQUEST: + //If connection is not established. + if ((!settings->info.preEstablished && (settings->base.connected & DLMS_CONNECTION_STATE_DLMS) == 0) || + //If service is not negotiated. + (settings->base.negotiatedConformance & DLMS_CONFORMANCE_GET) == 0) + { + ret = DLMS_ERROR_CODE_INVALID_COMMAND; + } + else + { + //Check is client reading frames. + if (settings->transaction.command != DLMS_COMMAND_NONE && + data->position == data->size) + { + data->position = 0; + } + else + { + ret = svr_handleGetRequest(settings, data); + } + } + break; +#if !defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) + case DLMS_COMMAND_READ_REQUEST: + //If connection is not established. + if ((!settings->info.preEstablished && (settings->base.connected & DLMS_CONNECTION_STATE_DLMS) == 0) || + //If service is not negotiated. + (settings->base.negotiatedConformance & DLMS_CONFORMANCE_READ) == 0) + { + ret = DLMS_ERROR_CODE_INVALID_COMMAND; + } + else + { + if (settings->transaction.command != DLMS_COMMAND_NONE && + data->position == data->size) + { + data->position = 0; + } + else + { + ret = svr_handleReadRequest(settings, data); + } + } + break; +#endif //!defined(DLMS_IGNORE_ASSOCIATION_SHORT_NAME) && !defined(DLMS_IGNORE_MALLOC) +#ifndef DLMS_IGNORE_ACTION + case DLMS_COMMAND_METHOD_REQUEST: + //Connection established is checked inside of the function because of HLS. + //If service is not negotiated. + if ((settings->base.negotiatedConformance & DLMS_CONFORMANCE_ACTION) == 0) + { + ret = DLMS_ERROR_CODE_INVALID_COMMAND; + } + else + { + ret = svr_handleMethodRequest(settings, data); + if (ret != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("handleMethodRequest failed. ", ret); +#endif //DLMS_DEBUG + } + } + break; +#endif //DLMS_IGNORE_ACTION +#ifndef DLMS_IGNORE_HDLC + case DLMS_COMMAND_SNRM: + if ((ret = svr_handleSnrmRequest(settings, data)) == 0) + { + settings->base.connected = DLMS_CONNECTION_STATE_HDLC; + frame = DLMS_COMMAND_UA; + } + else + { +#ifdef DLMS_DEBUG + svr_notifyTrace("handleSnrmRequest failed. ", ret); +#endif //DLMS_DEBUG + } + break; +#endif //DLMS_IGNORE_HDLC + case DLMS_COMMAND_AARQ: + ret = svr_HandleAarqRequest(settings, data); + if (ret == 0 && settings->base.authentication < DLMS_AUTHENTICATION_HIGH) + { + settings->base.connected |= DLMS_CONNECTION_STATE_DLMS; + svr_connected(settings); + } + else + { +#ifdef DLMS_DEBUG + svr_notifyTrace("HandleAarqRequest failed. ", ret); +#endif //DLMS_DEBUG + } + break; + case DLMS_COMMAND_RELEASE_REQUEST: + ret = svr_handleReleaseRequest(settings, data); + svr_disconnected(settings); + settings->base.connected &= ~DLMS_CONNECTION_STATE_DLMS; + break; +#ifndef DLMS_IGNORE_HDLC + case DLMS_COMMAND_DISC: + ret = svr_generateDisconnectRequest(settings, data); + if (settings->base.connected != DLMS_CONNECTION_STATE_NONE) + { + svr_disconnected(settings); + settings->base.connected = DLMS_CONNECTION_STATE_NONE; + } + frame = DLMS_COMMAND_UA; + break; +#endif //DLMS_IGNORE_HDLC +#ifndef DLMS_IGNORE_PLC + case DLMS_COMMAND_DISCOVER_REQUEST: + { + gxPlcRegister r; + svr_parseDiscoverRequest(data, &r); + unsigned char newMeter = settings->base.plcSettings.macSourceAddress == 0xFFE && settings->base.plcSettings.macDestinationAddress == 0xFFF; + return svr_discoverReport(&settings->base, &settings->base.plcSettings.systemTitle, newMeter, reply); + } + case DLMS_COMMAND_REGISTER_REQUEST: + svr_parseRegisterRequest(&settings->base, data); + return svr_discoverReport(&settings->base, &settings->base.plcSettings.systemTitle, 0, reply); + case DLMS_COMMAND_PING_REQUEST: + break; +#endif //DLMS_IGNORE_PLC + case DLMS_COMMAND_NONE: + //Get next frame. + data->position = 0; + frame = getNextSend(&settings->base, 0); + break; + default: + //Invalid command. +#ifdef DLMS_DEBUG + svr_notifyTrace("Unknown command. ", cmd); +#endif //DLMS_DEBUG + ret = DLMS_ERROR_CODE_INVALID_COMMAND; + } + if (ret == DLMS_ERROR_CODE_INVALID_COMMAND) + { + bb_clear(data); + if (settings->base.useLogicalNameReferencing) + { + ret = svr_generateExceptionResponse(&settings->base, + DLMS_EXCEPTION_STATE_ERROR_SERVICE_NOT_ALLOWED, + DLMS_ERROR_CODE_INVALID_COMMAND, + data); + } + else + { + ret = svr_generateConfirmedServiceError( + settings, + DLMS_CONFIRMED_SERVICE_ERROR_INITIATE_ERROR, + DLMS_SERVICE_ERROR_SERVICE, DLMS_SERVICE_UNSUPPORTED, + data); + } + } + if (ret != 0) + { + return ret; + } + if ((settings->base.interfaceType == DLMS_INTERFACE_TYPE_HDLC || + settings->base.interfaceType == DLMS_INTERFACE_TYPE_HDLC_WITH_MODE_E) && + bb_available(data) > settings->hdlc->maximumInfoLengthTransmit) + { + settings->info.moreData |= DLMS_DATA_REQUEST_TYPES_FRAME; + } + ret = dlms_addFrame(&settings->base, frame, data, reply); + if (cmd == DLMS_COMMAND_DISC || + (settings->base.interfaceType == DLMS_INTERFACE_TYPE_WRAPPER && cmd == DLMS_COMMAND_RELEASE_REQUEST)) + { + svr_reset(settings); + } +#ifdef DLMS_DEBUG + if (ret != 0) + { + svr_notifyTrace("svr_handleCommand", ret); + } +#endif //DLMS_DEBUG + return ret; +} + +int svr_handleRequest( + dlmsServerSettings* settings, + gxByteBuffer* data, + gxByteBuffer* reply) +{ + if (data == NULL || data->data == NULL) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return svr_handleRequest2(settings, data->data, (uint16_t)bb_available(data), reply); +} + +int svr_handleRequest3( + dlmsServerSettings* settings, + unsigned char data, + gxByteBuffer* reply) +{ + return svr_handleRequest2(settings, &data, 1, reply); +} + +int svr_handleRequest2( + dlmsServerSettings* settings, + unsigned char* buff, + uint16_t size, + gxByteBuffer* reply) +{ + gxServerReply sr; + sr.data = buff; + sr.dataSize = size; + sr.reply = reply; + return svr_handleRequest4(settings, &sr); +} + +/* Find IEC frame.Sometimes there are extra bytes or multiple packets on the data so they are removed.*/ +int svr_getIecPacket(dlmsServerSettings* settings) +{ + if (settings->receivedData.size < 5) + { + return DLMS_ERROR_CODE_FALSE; + } + int ret; + int pos; + unsigned char ch; + int eop = -1; + int bop = -1; + //Find EOP. + for (pos = settings->receivedData.size - 2; pos != 2; --pos) + { + if ((ret = bb_getUInt8ByIndex(&settings->receivedData, pos, &ch) == 0) && + ch == 0x0D && + (ret = bb_getUInt8ByIndex(&settings->receivedData, pos + 1, &ch) == 0) && + ch == 0x0A) + { + eop = pos; + break; + } + if (ret != 0) + { + break; + } + } + if (eop == -1) + { + return DLMS_ERROR_CODE_FALSE; + } + //Find BOP + for (pos = eop - 1; pos >= 0; --pos) + { + if ((ret = bb_getUInt8ByIndex(&settings->receivedData, pos, &ch) != 0)) + { + break; + } + if (ch == 6 || + (pos + 2 < (int)settings->receivedData.size && + ch == '/' && + (ret = bb_getUInt8ByIndex(&settings->receivedData, pos + 1, &ch)) == 0 && + ch == (unsigned char)'?' && + (ret = bb_getUInt8ByIndex(&settings->receivedData, pos + 2, &ch)) == 0 && + ch == (unsigned char)'!')) + { + bop = pos; + break; + } + } + if (bop == -1) + { + return DLMS_ERROR_CODE_FALSE; + } + settings->receivedData.position = bop; + return ret; +} + +int svr_handleRequest4( + dlmsServerSettings* settings, + gxServerReply* sr) +{ + if (sr == NULL) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + int ret; + unsigned char first; + bb_clear(sr->reply); + if (sr->data == NULL || sr->dataSize == 0) + { + return 0; + } + if (!settings->initialized) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("Server not Initialized.", -1); +#endif //DLMS_DEBUG + //Server not Initialized. + return DLMS_ERROR_CODE_NOT_INITIALIZED; + } + //Check frame using inter Charachter Timeout. +#if !defined(DLMS_IGNORE_HDLC) || !defined(DLMS_IGNORE_IEC_HDLC_SETUP) + if (IS_HDLC(settings->base.interfaceType) && settings->hdlc != NULL && settings->hdlc->inactivityTimeout != 0) + { + uint32_t now = time_elapsed(); + uint16_t elapsed = (uint16_t)(now - settings->frameReceived) / 1000; + //If frame shoud be fully received. + if (elapsed >= settings->hdlc->inactivityTimeout) + { + settings->receivedData.position = settings->receivedData.size = 0; + } + settings->frameReceived = now; + } +#endif //!defined(DLMS_IGNORE_HDLC) || !defined(DLMS_IGNORE_IEC_HDLC_SETUP) + if (bb_isAttached(&settings->receivedData) && + settings->receivedData.size + sr->dataSize > bb_getCapacity(&settings->receivedData)) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("svr_handleRequest2 bb_isAttached failed. ", -1); +#endif //DLMS_DEBUG +#ifndef DLMS_IGNORE_HDLC + //Send U-Frame Frame Reject if we have received more data that can fit to one HDLC frame. + if (IS_HDLC(settings->base.interfaceType)) + { + ret = dlms_getHdlcFrame(&settings->base, DLMS_COMMAND_REJECTED, NULL, sr->reply); + settings->receivedData.position = settings->receivedData.size = 0; + reply_clear2(&settings->info, 1); + } + else + { + ret = 0; + } +#else + ret = 0; +#endif //DLMS_IGNORE_HDLC + return ret; + } + if (bb_set(&settings->receivedData, sr->data, sr->dataSize) != 0) + { + //If client is sending junk data. + bb_clear(&settings->receivedData); + return 0; + } + first = settings->base.serverAddress == 0 + && settings->base.clientAddress == 0; +#if !defined(DLMS_IGNORE_IEC) && !defined(DLMS_IGNORE_IEC_LOCAL_PORT_SETUP) + //If using optical probe. + if (settings->base.interfaceType == DLMS_INTERFACE_TYPE_HDLC_WITH_MODE_E) + { + unsigned char ch; + if (settings->base.connected == DLMS_CONNECTION_STATE_NONE) + { + //If IEC packet not found or it's not fully received. + if (svr_getIecPacket(settings) != 0) + { + return 0; + } + if (bb_getUInt8ByIndex(&settings->receivedData, settings->receivedData.position, &ch) != 0) + { + return 0; + } + sr->newBaudRate = 0; + if (ch == 6) + { + //User changes the baud rate. + //Only Mode E is allowed. + if (bb_getUInt8ByIndex(&settings->receivedData, settings->receivedData.position + 1, &ch) != 0 || + ch != 0x32 || + bb_getUInt8ByIndex(&settings->receivedData, settings->receivedData.position + 3, &ch) != 0 || + ch != 0x32) + { + return 0; + } + if (bb_getUInt8ByIndex(&settings->receivedData, settings->receivedData.position + 2, &ch) != 0) + { + return 0; + } + DLMS_BAUD_RATE baudrate = (DLMS_BAUD_RATE)ch - '0'; + if (baudrate > settings->localPortSetup->proposedBaudrate) + { + baudrate = settings->localPortSetup->proposedBaudrate; + } + bb_clear(&settings->receivedData); + //Return used baud rate. + settings->base.connected = DLMS_CONNECTION_STATE_IEC; + //"2" //(HDLC protocol procedure) (Binary mode) + //Set mode E. + unsigned char tmp[] = { 0x06, + //"2" HDLC protocol procedure (Mode E) + (unsigned char)'2', + //Send Baud rate character + (unsigned char)('0' + baudrate), + //Mode control character + (unsigned char)'2', 13, 10 }; + if ((ret = bb_set(sr->reply, tmp, sizeof(tmp))) != 0) + { + return 0; + } + //Change the baud rate. + sr->newBaudRate = 300 << (uint16_t)baudrate; + } + else if (bb_getUInt8ByIndex(&settings->receivedData, settings->receivedData.position, &ch) == 0 && + ch == '/') + { + gxByteBuffer meterAddress; + bb_attach(&meterAddress, settings->receivedData.data, settings->receivedData.position + 3, bb_available(&settings->receivedData) - 5); + //If meter address is wrong. + if (bb_size(&meterAddress) != 0 && bb_compare(&settings->localPortSetup->deviceAddress, meterAddress.data, meterAddress.size) != 0) + { + bb_clear(&settings->receivedData); + return 0; + } + bb_clear(&settings->receivedData); + bb_clear(sr->reply); + if (bb_setUInt8(sr->reply, '/') != 0 || + //Add flag ID. + bb_set(sr->reply, settings->flagId, 3) != 0 || + //Add proposed baud rate. + bb_setUInt8(sr->reply, '0' + settings->localPortSetup->proposedBaudrate) != 0 || + //Add device address. + bb_set(sr->reply, settings->localPortSetup->deviceAddress.data, settings->localPortSetup->deviceAddress.size) != 0 || + bb_setUInt8(sr->reply, '\r') != 0 || + bb_setUInt8(sr->reply, '\n') != 0) + { + return 0; + } + } + return 0; + } + } +#endif// !defined(DLMS_IGNORE_IEC) && !defined(DLMS_IGNORE_IEC_LOCAL_PORT_SETUP) + if ((ret = dlms_getData2(&settings->base, &settings->receivedData, &settings->info, first)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("svr_handleRequest2 dlms_getData2 failed. ", ret); +#endif //DLMS_DEBUG + if (ret == DLMS_ERROR_CODE_INVOCATION_COUNTER_TOO_SMALL || + ret == DLMS_ERROR_CODE_INVALID_DECIPHERING_ERROR || + ret == DLMS_ERROR_CODE_INVALID_SECURITY_SUITE) + { + bb_clear(sr->reply); + gxByteBuffer data; + unsigned char tmp[10]; + bb_attach(&data, tmp, 0, sizeof(tmp)); + if ((ret = svr_generateConfirmedServiceError( + settings, + DLMS_CONFIRMED_SERVICE_ERROR_INITIATE_ERROR, + DLMS_SERVICE_ERROR_APPLICATION_REFERENCE, + DLMS_APPLICATION_REFERENCE_DECIPHERING_ERROR, + &data)) != 0) + { + settings->receivedData.position = settings->receivedData.size = 0; + return ret; + } + return dlms_addFrame(&settings->base, 0, &data, sr->reply); + } + else if (ret == DLMS_ERROR_CODE_INVALID_SERVER_ADDRESS) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("Invalid server address. ", -1); +#endif //DLMS_DEBUG + return 0; + } + else if (ret == DLMS_ERROR_CODE_INVALID_CLIENT_ADDRESS) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("Invalid client address. ", -1); +#endif //DLMS_DEBUG + if (settings->info.preEstablished) + { + svr_disconnected(settings); + svr_reset(settings); + first = 1; + settings->receivedData.position = 0; + if ((ret = dlms_getData2(&settings->base, &settings->receivedData, &settings->info, first)) != 0) + { + settings->receivedData.position = settings->receivedData.size = 0; + return ret; + } + } +#ifndef DLMS_IGNORE_HDLC + else if (IS_HDLC(settings->base.interfaceType) && + (settings->base.connected & DLMS_CONNECTION_STATE_HDLC) != 0) + { + ret = dlms_getHdlcFrame(&settings->base, DLMS_COMMAND_REJECTED, NULL, sr->reply); + settings->receivedData.position = settings->receivedData.size = 0; + return ret; + } +#endif //DLMS_IGNORE_HDLC + settings->receivedData.position = settings->receivedData.size = 0; + reply_clear2(&settings->info, 1); + return 0; + } + else if (ret == DLMS_ERROR_CODE_INVALID_FRAME_NUMBER) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("Invalid frame number. ", -1); +#endif //DLMS_DEBUG +#ifndef DLMS_IGNORE_HDLC + if ((settings->base.connected & DLMS_CONNECTION_STATE_HDLC) != 0) + { + settings->dataReceived = time_elapsed(); + ret = dlms_getHdlcFrame(&settings->base, DLMS_COMMAND_REJECTED, NULL, sr->reply); + settings->receivedData.position = settings->receivedData.size = 0; + return ret; + } +#endif //DLMS_IGNORE_HDLC + settings->receivedData.position = settings->receivedData.size = 0; + reply_clear2(&settings->info, 1); + return 0; + } + else + { +#ifndef DLMS_IGNORE_HDLC + if (ret != DLMS_ERROR_CODE_WRONG_CRC && IS_HDLC(settings->base.interfaceType) && + (settings->base.connected & DLMS_CONNECTION_STATE_HDLC) != 0) + { + ret = dlms_getHdlcFrame(&settings->base, DLMS_COMMAND_REJECTED, NULL, sr->reply); + settings->receivedData.position = settings->receivedData.size = 0; + return ret; + } +#endif //DLMS_IGNORE_HDLC + settings->receivedData.position = settings->receivedData.size = 0; + reply_clear2(&settings->info, 1); + return 0; + } + } + // If all data is not received yet. + if (!settings->info.complete) + { + return 0; + } + bb_clear(&settings->receivedData); + if (settings->info.command == DLMS_COMMAND_DISC && (settings->base.connected & DLMS_CONNECTION_STATE_HDLC) == 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("Disconnecting from the meter. ", -1); +#endif //DLMS_DEBUG +#ifndef DLMS_IGNORE_HDLC + ret = dlms_getHdlcFrame(&settings->base, DLMS_COMMAND_DISCONNECT_MODE, NULL, sr->reply); +#endif //DLMS_IGNORE_HDLC + reply_clear2(&settings->info, 1); + return ret; + } + + if ((first || settings->info.command == DLMS_COMMAND_SNRM || + (settings->base.interfaceType == DLMS_INTERFACE_TYPE_WRAPPER && settings->info.command == DLMS_COMMAND_AARQ)) && + settings->base.interfaceType != DLMS_INTERFACE_TYPE_PDU) + { +#ifndef DLMS_IGNORE_HDLC + if (IS_HDLC(settings->base.interfaceType) && settings->info.preEstablished) + { + svr_disconnected(settings); + } +#endif //DLMS_IGNORE_HDLC + // Check is data send to this server. + if (settings->base.interfaceType == DLMS_INTERFACE_TYPE_WRAPPER && settings->info.command == DLMS_COMMAND_AARQ) + { + if (!svr_isTarget(&settings->base, settings->base.serverAddress, settings->base.clientAddress)) + { + if ((settings->base.connected & DLMS_CONNECTION_STATE_DLMS) == 0) + { + settings->base.serverAddress = settings->base.clientAddress = 0; + } + reply_clear2(&settings->info, 1); + return 0; + } + } +#ifndef DLMS_IGNORE_HDLC + if (IS_HDLC(settings->base.interfaceType)) + { + settings->base.connected |= DLMS_CONNECTION_STATE_HDLC; + svr_connected(settings); + } +#endif //DLMS_IGNORE_HDLC + } + // If client want next frame. +#ifndef DLMS_IGNORE_HDLC + if ((settings->info.moreData & DLMS_DATA_REQUEST_TYPES_FRAME) == DLMS_DATA_REQUEST_TYPES_FRAME) + { + settings->dataReceived = time_elapsed(); + return dlms_getHdlcFrame(&settings->base, getReceiverReady(&settings->base), NULL, sr->reply); + } +#endif //DLMS_IGNORE_HDLC + // Update command if transaction and next frame is asked. + if (settings->info.command == DLMS_COMMAND_NONE) + { + if (settings->transaction.command != DLMS_COMMAND_NONE) + { + //If client wants next PDU. + if (settings->info.data.size == 0) + { + settings->info.command = settings->transaction.command; + } + else + { + settings->info.data.position = 0; +#ifndef DLMS_IGNORE_HDLC + //Return rest of frame. + return dlms_getHdlcFrame(&settings->base, getNextSend(&settings->base, 0), &settings->info.data, sr->reply); +#endif //DLMS_IGNORE_HDLC + } + } + else if (settings->info.data.size == 0) + { + settings->dataReceived = time_elapsed(); +#ifndef DLMS_IGNORE_HDLC + return dlms_getHdlcFrame(&settings->base, getKeepAlive(&settings->base), NULL, sr->reply); +#endif //DLMS_IGNORE_HDLC + } + } + //Check inactivity timeout. +#ifndef DLMS_IGNORE_HDLC +#ifndef DLMS_IGNORE_IEC_HDLC_SETUP + if (IS_HDLC(settings->base.interfaceType) && + settings->hdlc != NULL && settings->hdlc->inactivityTimeout != 0) + { + if (settings->info.command != DLMS_COMMAND_SNRM) + { + uint32_t elapsed = time_elapsed() - settings->dataReceived; + elapsed /= 1000; + //If inactivity time out is elapsed. + if (elapsed >= settings->hdlc->inactivityTimeout) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("Inactivity timeout. ", 0); +#endif //DLMS_DEBUG + if (!settings->info.preEstablished) + { + if (settings->info.command == DLMS_COMMAND_DISC) + { + dlms_getHdlcFrame(&settings->base, DLMS_COMMAND_DISCONNECT_MODE, NULL, sr->reply); + } + svr_disconnected(settings); + svr_reset(settings); + return 0; + } + if ((settings->base.connected & DLMS_CONNECTION_STATE_HDLC) != 0) + { + svr_disconnected(settings); + } + } + } + } +#endif // DLMS_IGNORE_IEC_HDLC_SETUP +#endif //DLMS_IGNORE_HDLC +#ifndef DLMS_IGNORE_WRAPPER +#ifndef DLMS_IGNORE_TCP_UDP_SETUP + if (settings->base.interfaceType == DLMS_INTERFACE_TYPE_WRAPPER && + settings->wrapper != NULL && settings->wrapper->inactivityTimeout != 0) + { + if (settings->info.command != DLMS_COMMAND_AARQ) + { + uint32_t elapsed = time_elapsed() - settings->dataReceived; + elapsed /= 1000; + //If inactivity time out is elapsed. + if (elapsed >= settings->wrapper->inactivityTimeout) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("Inactivity timeout. ", 0); +#endif //DLMS_DEBUG + if (!settings->info.preEstablished) + { + svr_disconnected(settings); + svr_reset(settings); + return 0; + } + if ((settings->base.connected & DLMS_CONNECTION_STATE_HDLC) != 0) + { + svr_disconnected(settings); + } + } + } + } +#endif // DLMS_IGNORE_TCP_UDP_SETUP +#endif //DLMS_IGNORE_WRAPPER + ret = svr_handleCommand(settings, settings->info.command, &settings->info.data, sr->reply); + if (ret != 0) + { + bb_clear(sr->reply); +#ifndef DLMS_IGNORE_HDLC + if (IS_HDLC(settings->base.interfaceType)) + { + if (ret == DLMS_ERROR_CODE_REJECTED) + { + ret = dlms_getHdlcFrame(&settings->base, DLMS_COMMAND_DISCONNECT_MODE, NULL, sr->reply); + } + else + { + ret = dlms_getHdlcFrame(&settings->base, DLMS_COMMAND_REJECTED, NULL, sr->reply); + } + settings->receivedData.position = settings->receivedData.size = 0; + } + else +#endif //DLMS_IGNORE_HDLC + { + ret = svr_reportError(settings, settings->info.command, DLMS_ERROR_CODE_OTHER_REASON, sr->reply); + } + } + DLMS_COMMAND cmd = settings->info.command; + DLMS_DATA_REQUEST_TYPES moreData = settings->info.moreData; + reply_clear2(&settings->info, 0); + // Save command if there is more data available. + // This is needed when Windows size is bigger than one. + if ((moreData & DLMS_DATA_REQUEST_TYPES_FRAME) != 0) + { + settings->transaction.command = cmd; + } + settings->dataReceived = time_elapsed(); + return ret; +} + +int svr_handleInactivityTimeout( + dlmsServerSettings* settings, + uint32_t time, + uint32_t* next) +{ + //If connection is established. + if (settings->info.preEstablished || (settings->base.connected & DLMS_CONNECTION_STATE_DLMS) != 0) + { + //Check inactivity timeout. + unsigned char inactivity = 0; + //Delay in seconds from last message. + uint32_t elapsed = (time_elapsed() - settings->dataReceived); + elapsed /= 1000; + uint32_t timeout = 0xFFFFFFFF; +#ifndef DLMS_IGNORE_HDLC +#ifndef DLMS_IGNORE_IEC_HDLC_SETUP + if (IS_HDLC(settings->base.interfaceType) && + settings->hdlc != NULL && settings->hdlc->inactivityTimeout != 0) + { + inactivity = !(elapsed < settings->hdlc->inactivityTimeout); + timeout = settings->hdlc->inactivityTimeout - elapsed; + } +#endif // DLMS_IGNORE_IEC_HDLC_SETUP +#endif //DLMS_IGNORE_HDLC +#ifndef DLMS_IGNORE_WRAPPER +#ifndef DLMS_IGNORE_TCP_UDP_SETUP + if (settings->base.interfaceType == DLMS_INTERFACE_TYPE_WRAPPER && + settings->wrapper != NULL && settings->wrapper->inactivityTimeout != 0) + { + inactivity = !(elapsed < settings->wrapper->inactivityTimeout); + timeout = settings->wrapper->inactivityTimeout - elapsed; + } +#endif // DLMS_IGNORE_TCP_UDP_SETUP +#endif //DLMS_IGNORE_WRAPPER + //If inactivity timeout is elapsed. + if (inactivity) + { + svr_disconnected(settings); + svr_reset(settings); + } + else if (timeout != 0xFFFFFFFF) + { + if (*next > time + timeout) + { + *next = time + timeout; + } + } + } + return 0; +} + +int svr_invoke( + dlmsServerSettings* settings, + unsigned char isAction, + gxObject* target, + unsigned char index, + dlmsVARIANT* value, + uint32_t time, + gxtime* start, + gxtime* end, + uint32_t* executed, + uint32_t* next) +{ + unsigned char exec = start == NULL; + int ret = 0; + if (!exec) + { + //Execute in exact time if end time is not given. + if (end == NULL) + { + //Ignore deviation and status for single action script. + exec = *executed < time && time_compareWithDiff(start, time, 0) == 0; + } + else if (*executed < time) + { + exec = time_compare2(start, time) != 1 && time_compare2(end, time) != -1; + } + } + if (exec) + { + *executed = time; + gxValueEventCollection args; + gxValueEventArg* e; +#ifdef DLMS_IGNORE_MALLOC + gxValueEventArg tmp[1]; + ve_init(&tmp[0]); + vec_attach(&args, tmp, 1, 1); + e = &tmp[0]; +#else + e = (gxValueEventArg*)gxmalloc(sizeof(gxValueEventArg)); + ve_init(e); + vec_init(&args); + vec_push(&args, e); +#endif //DLMS_IGNORE_MALLOC + e->target = target; + e->index = index; + if (value != NULL) + { + e->value = *value; + } + if (isAction) + { + svr_preAction(&settings->base, &args); + if (!e->handled) + { + ret = cosem_invoke(settings, e); + svr_postAction(&settings->base, &args); + } + } + else + { + svr_preWrite(&settings->base, &args); + if (!e->handled) + { + ret = cosem_setValue(&settings->base, e); + svr_postWrite(&settings->base, &args); + } + } +#ifndef DLMS_IGNORE_MALLOC + vec_clear(&args); +#endif //DLMS_IGNORE_MALLOC + //Increase time by one second so next scheduled date is retreaved. + ++time; + } + if (start != NULL) + { + uint32_t tmp = time_getNextScheduledDate(time, start); + if (tmp < *next) + { + *next = tmp; + } + } + return ret; +} + +#ifndef DLMS_IGNORE_PROFILE_GENERIC + +int svr_handleProfileGeneric( + dlmsServerSettings* settings, + gxProfileGeneric* object, + uint32_t time, + uint32_t* next) +{ + int ret = 0; + if (object->capturePeriod != 0) + { + //Get seconds. + uint32_t tm = time % 60L; + //Time where seconds part is zero. + uint32_t tm2 = time - tm; + tm = time % object->capturePeriod; + if (tm == 0) + { + if (*next == (uint32_t)-1 || *next > time + object->capturePeriod) + { + *next = time + object->capturePeriod; + } + ret = svr_invoke( + settings, + 1, + (gxObject*)object, + 2, + NULL, + time, + NULL, + NULL, + &object->executedTime, + next); + } + else if (tm2 + object->capturePeriod < *next) + { + tm = time - tm2; + tm %= object->capturePeriod; + uint32_t offset = object->capturePeriod - tm; + if (time + offset < *next) + { + *next = time + offset; + } + } + } + return ret; +} +#endif //DLMS_IGNORE_PROFILE_GENERIC + + +#if !defined(DLMS_IGNORE_ACTION_SCHEDULE) && !defined(DLMS_IGNORE_OBJECT_POINTERS) + +int svr_handleSingleActionSchedule( + dlmsServerSettings* settings, + gxActionSchedule* object, + uint32_t time, + uint32_t* next) +{ + //Execution time is saved in case there are multiple actions in one schedule. + //If it's not returned only the first action is executed. + uint32_t originalExecutedTime = object->executedTime; + gxtime* s; + int ret = 0; + int pos; + for (pos = 0; pos != object->executionTime.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->executionTime, pos, (void**)&s)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->executionTime, pos, (void**)&s, sizeof(gxtime))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if (object->executedScript != NULL) + { + gxScript* it; + gxScriptAction* a; + int posS; + if (settings->defaultClock != NULL) + { + s->deviation = settings->defaultClock->timeZone; + s->status = settings->defaultClock->status; + } + for (posS = 0; posS != object->executedScript->scripts.size; ++posS) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->executedScript->scripts, posS, (void**)&it, sizeof(gxScript))) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->executedScript->scripts, posS, (void**)&it)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if (it->id == object->executedScriptSelector) + { + int posA; + for (posA = 0; posA != it->actions.size; ++posA) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&it->actions, posA, (void**)&a, sizeof(gxScriptAction))) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&it->actions, posA, (void**)&a)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + //Execution time is returned in case there are multiple actions in one schedule. + object->executedTime = originalExecutedTime; + if ((ret = svr_invoke( + settings, + a->type == DLMS_SCRIPT_ACTION_TYPE_EXECUTE, + (gxObject*)a->target, + a->index, + &a->parameter, + time, + s, + NULL, + &object->executedTime, + next)) != 0) + { + break; + } + } + } + } + } + } + return ret; +} +#endif //!defined(DLMS_IGNORE_ACTION_SCHEDULE) && !defined(DLMS_IGNORE_OBJECT_POINTERS) + +#if !defined(DLMS_IGNORE_ACTIVITY_CALENDAR) && !defined(DLMS_IGNORE_OBJECT_POINTERS) + +unsigned char equal(gxByteBuffer* a, gxByteBuffer* b) +{ + if (a->size == b->size) + { + return memcmp(a->data, b->data, a->size) == 0; + } + return 0; +} + +int svr_invokeScript( + dlmsServerSettings* settings, + gxArray* dayProfiles, + uint16_t id, + uint32_t time, + uint32_t* next) +{ + uint16_t pos, pos2; + int ret = 0; + gxDayProfile* dp; + gxDayProfileAction* da; + gxValueEventCollection args; + gxValueEventArg* e; +#ifdef DLMS_IGNORE_MALLOC + gxValueEventArg tmp[1]; + ve_init(&tmp[0]); + vec_attach(&args, tmp, 1, 1); + e = &tmp[0]; +#else + e = (gxValueEventArg*)gxmalloc(sizeof(gxValueEventArg)); + ve_init(e); + vec_init(&args); + vec_push(&args, e); +#endif //DLMS_IGNORE_MALLOC + for (pos = 0; pos != dayProfiles->size; ++pos) + { + if ((ret = arr_getByIndex2(dayProfiles, pos, (void**)&dp, sizeof(gxDayProfile))) != 0) + { + break; + } + for (pos2 = 0; pos2 != dp->daySchedules.size; ++pos2) + { + if ((ret = arr_getByIndex2(&dp->daySchedules, pos2, (void**)&da, sizeof(gxDayProfileAction))) != 0) + { + break; + } + if (dp->dayId == id && time_compare2(&da->startTime, time) == 0) + { + e->target = da->script; + e->index = 1; + if ((ret = var_setInt8(&e->parameters, (unsigned char)da->scriptSelector)) != 0 || + (ret = invoke_ScriptTable(settings, e)) != 0) + { + break; + } + } + //Update next execution time. + uint32_t tmp = time_getNextScheduledDate(time, &da->startTime); + if (tmp < *next) + { + *next = tmp; + } + } + if (ret != 0) + { + break; + } + } +#ifndef DLMS_IGNORE_MALLOC + vec_clear(&args); +#endif //DLMS_IGNORE_MALLOC + return ret; +} + +int svr_handleActivityCalendar( + dlmsServerSettings* settings, + gxActivityCalendar* object, + uint32_t time, + uint32_t* next) +{ + gxSeasonProfile* sp; + gxWeekProfile* wp; + int pos, ret = 0; + uint16_t pos2; + gxtime tm; + gxObject* obj; + gxSpecialDay* sd; + //Check activate passive calendar time. + //The activate passive calendar time is never execute if all the values are ignored. + if ((object->time.skip & (DATETIME_SKIPS_YEAR | DATETIME_SKIPS_MONTH | DATETIME_SKIPS_DAY | DATETIME_SKIPS_HOUR | DATETIME_SKIPS_MINUTE | DATETIME_SKIPS_SECOND)) != + (DATETIME_SKIPS_YEAR | DATETIME_SKIPS_MONTH | DATETIME_SKIPS_DAY | DATETIME_SKIPS_HOUR | DATETIME_SKIPS_MINUTE | DATETIME_SKIPS_SECOND)) + { + if (time_compareWithDiff(&object->time, time, 0) == 0) + { + //Executed time is not needed. + uint32_t executed; + if ((ret = svr_invoke( + settings, + 1, + (gxObject*)object, + 1, + NULL, + time, + NULL, + NULL, + &executed, + next)) != 0) + { + //Save inforation that invoke failed. + } + } + } + + //Check that today is not a special day. + for (pos = 0; pos != settings->base.objects.size; ++pos) + { + if ((ret = oa_getByIndex(&settings->base.objects, pos, &obj)) != 0) + { + break; + } + if (obj->objectType == DLMS_OBJECT_TYPE_SPECIAL_DAYS_TABLE) + { + for (pos2 = 0; pos2 != ((gxSpecialDaysTable*)obj)->entries.size; ++pos2) + { + if ((ret = arr_getByIndex2(&((gxSpecialDaysTable*)obj)->entries, + pos2, (void**)&sd, sizeof(gxSpecialDay))) != 0) + { + break; + } + if (time_compare2(&sd->date, time) == 0) + { + //Invoke day profile + if ((ret = svr_invokeScript(settings, + &object->dayProfileTableActive, sd->dayId, time, next)) != 0) + { + break; + } + return ret; + } + } + } + } + if (object->seasonProfileActive.size != 0) + { + uint16_t activeSeason = object->seasonProfileActive.size - 1; + gxtime* start = NULL; + gxtime* end = NULL; + //Find active season. + for (pos = 0; pos != object->seasonProfileActive.size; ++pos) + { + if ((ret = arr_getByIndex2(&object->seasonProfileActive, + pos, (void**)&sp, sizeof(gxSeasonProfile))) != 0) + { + break; + } + //The season is never start if all the values are ignored. + if ((sp->start.skip & (DATETIME_SKIPS_YEAR | DATETIME_SKIPS_MONTH | DATETIME_SKIPS_DAY | DATETIME_SKIPS_HOUR | DATETIME_SKIPS_MINUTE | DATETIME_SKIPS_SECOND)) == + (DATETIME_SKIPS_YEAR | DATETIME_SKIPS_MONTH | DATETIME_SKIPS_DAY | DATETIME_SKIPS_HOUR | DATETIME_SKIPS_MINUTE | DATETIME_SKIPS_SECOND)) + { + continue; + } + //In season_start, wildcards are allowed. If all fields are wildcards, the season will never start. + tm = sp->start; + tm.deviation = 0x8000; + tm.skip |= DATETIME_SKIPS_SECOND | DATETIME_SKIPS_MINUTE | DATETIME_SKIPS_HOUR | DATETIME_SKIPS_MS; + if (time_compare2(&tm, time) != 1) + { + start = &sp->start; + //Reset end time. + end = NULL; + activeSeason = pos; + } + else if (start != NULL && end == NULL) + { + end = &sp->start; + } + } + if ((ret = arr_getByIndex2(&object->seasonProfileActive, + activeSeason, (void**)&sp, sizeof(gxSeasonProfile))) == 0) + { + for (pos2 = 0; pos2 != object->weekProfileTableActive.size; ++pos2) + { + if ((ret = arr_getByIndex2(&object->weekProfileTableActive, + pos2, (void**)&wp, sizeof(gxWeekProfile))) != 0) + { + break; + } + //If week name matches. +#ifdef DLMS_IGNORE_MALLOC + if (memcmp(&wp->name, &sp->weekName, sizeof(gxWeekProfileName)) == 0) +#else + if (equal(&wp->name, &sp->weekName)) +#endif //DLMS_IGNORE_MALLOC + { + unsigned char dayId; + switch (time_dayOfWeek(time_getYears2(time), time_getMonths2(time), time_getDays2(time))) + { + case 7: + dayId = wp->sunday; + break; + case 1: + dayId = wp->monday; + break; + case 2: + dayId = wp->tuesday; + break; + case 3: + dayId = wp->wednesday; + break; + case 4: + dayId = wp->thursday; + break; + case 5: + dayId = wp->friday; + break; + case 6: + dayId = wp->saturday; + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + if (ret != 0) + { + break; + } + ret = svr_invokeScript(settings, &object->dayProfileTableActive, + dayId, time, next); + //If week name matches. + break; + } + if (ret != 0) + { + break; + } + } + } + } + return ret; +} +#endif //!defined(DLMS_IGNORE_ACTIVITY_CALENDAR) && !defined(DLMS_IGNORE_OBJECT_POINTERS) + +#ifndef DLMS_IGNORE_PUSH_SETUP + +int svr_handlePushSetup( + dlmsServerSettings* settings, + gxPushSetup* object, + uint32_t time, + uint32_t* next) +{ + gxtime* s, * e; +#ifndef DLMS_IGNORE_MALLOC + gxKey* k; +#else + gxTimePair* k; +#endif //DLMS_IGNORE_MALLOC + int ret = 0; + int pos; + for (pos = 0; pos != object->communicationWindow.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->communicationWindow, pos, (void**)&k)) != 0) + { + break; + } + s = (gxtime*)k->key; + e = (gxtime*)k->value; +#else + if ((ret = arr_getByIndex(&object->communicationWindow, pos, (void**)&k, sizeof(gxTimePair))) != 0) + { + break; + } + s = &k->first; + e = &k->second; +#endif //DLMS_IGNORE_MALLOC + if ((ret = svr_invoke( + settings, + 1, + (gxObject*)object, + 1, + NULL, + time, + s, + e, + &object->executedTime, + next)) != 0) + { + //Save infor that invoke failed. + } + } + return ret; +} +#endif //DLMS_IGNORE_PUSH_SETUP + +#ifndef DLMS_IGNORE_AUTO_CONNECT +int svr_handleAutoConnect( + dlmsServerSettings* settings, + gxAutoConnect* object, + uint32_t time, + uint32_t* next) +{ + gxtime* s, * e; +#ifndef DLMS_IGNORE_MALLOC + gxKey* k; +#else + gxTimePair* k; +#endif //DLMS_IGNORE_MALLOC + int ret = 0; + int pos; + for (pos = 0; pos != object->callingWindow.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->callingWindow, pos, (void**)&k)) != 0) + { + break; + } + s = (gxtime*)k->key; + e = (gxtime*)k->value; +#else + if ((ret = arr_getByIndex(&object->callingWindow, pos, (void**)&k, sizeof(gxTimePair))) != 0) + { + break; + } + s = &k->first; + e = &k->second; +#endif //DLMS_IGNORE_MALLOC + if ((ret = svr_invoke( + settings, + 1, + (gxObject*)object, + 1, + NULL, + time, + s, + e, + &object->executedTime, + next)) != 0) + { + break; + } + } + return ret; +} +#endif //DLMS_IGNORE_AUTO_CONNECT + +int svr_run( + dlmsServerSettings* settings, + uint32_t time, + uint32_t* next) +{ + uint16_t pos; + int ret = 0; + gxObject* obj; + *next = (uint32_t)-1; +#ifndef DLMS_IGNORE_PROFILE_GENERIC + //profile Generic objects. + for (pos = 0; pos != settings->base.objects.size; ++pos) + { + if ((ret = oa_getByIndex(&settings->base.objects, pos, &obj)) != DLMS_ERROR_CODE_OK) + { + return ret; + } + if (obj->objectType == DLMS_OBJECT_TYPE_PROFILE_GENERIC) + { + svr_handleProfileGeneric(settings, (gxProfileGeneric*)obj, time, next); + } + } +#endif //DLMS_IGNORE_PROFILE_GENERIC + +#if !defined(DLMS_IGNORE_ACTION_SCHEDULE) && !defined(DLMS_IGNORE_OBJECT_POINTERS) + //Single action schedules. + for (pos = 0; pos != settings->base.objects.size; ++pos) + { + if ((ret = oa_getByIndex(&settings->base.objects, pos, &obj)) != DLMS_ERROR_CODE_OK) + { + return ret; + } + if (obj->objectType == DLMS_OBJECT_TYPE_ACTION_SCHEDULE) + { + svr_handleSingleActionSchedule(settings, (gxActionSchedule*)obj, time, next); + } + } +#endif //!defined(DLMS_IGNORE_ACTION_SCHEDULE) && !defined(DLMS_IGNORE_OBJECT_POINTERS) + +#if !defined(DLMS_IGNORE_ACTIVITY_CALENDAR) && !defined(DLMS_IGNORE_OBJECT_POINTERS) + //Single activity calendars. + for (pos = 0; pos != settings->base.objects.size; ++pos) + { + if ((ret = oa_getByIndex(&settings->base.objects, pos, &obj)) != DLMS_ERROR_CODE_OK) + { + return ret; + } + if (obj->objectType == DLMS_OBJECT_TYPE_ACTIVITY_CALENDAR) + { + svr_handleActivityCalendar(settings, (gxActivityCalendar*)obj, time, next); + } + } +#endif //!defined(DLMS_IGNORE_ACTIVITY_CALENDAR) && !defined(DLMS_IGNORE_OBJECT_POINTERS) + +#ifndef DLMS_IGNORE_PUSH_SETUP + //Push objects. + for (pos = 0; pos != settings->base.objects.size; ++pos) + { + if ((ret = oa_getByIndex(&settings->base.objects, pos, &obj)) != DLMS_ERROR_CODE_OK) + { + return ret; + } + if (obj->objectType == DLMS_OBJECT_TYPE_PUSH_SETUP) + { + svr_handlePushSetup(settings, (gxPushSetup*)obj, time, next); + } + } +#endif //DLMS_IGNORE_PUSH_SETUP +#ifndef DLMS_IGNORE_AUTO_CONNECT + //Get auto connect objects. + for (pos = 0; pos != settings->base.objects.size; ++pos) + { + if ((ret = oa_getByIndex(&settings->base.objects, pos, &obj)) != DLMS_ERROR_CODE_OK) + { + return ret; + } + if (obj->objectType == DLMS_OBJECT_TYPE_AUTO_CONNECT) + { + //Handle calling window execution times. Ignore errors. + svr_handleAutoConnect(settings, (gxAutoConnect*)obj, time, next); + } + } +#endif //DLMS_IGNORE_AUTO_CONNECT + return svr_handleInactivityTimeout(settings, time, next); +} + +uint32_t svr_isChangedWithAction(DLMS_OBJECT_TYPE objectType, unsigned char methodIndex) +{ + uint32_t ret = 0; + switch (objectType) + { + case DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME: + switch (methodIndex) + { + case 2: + //Secret. + ret = GET_ATTRIBUTE(7); + break; + case 3: + case 4: + //Object. + ret = GET_ATTRIBUTE(2); + break; + case 5: + case 6: + //User. + ret = GET_ATTRIBUTE(10); + break; + default: + break; + } + break; + case DLMS_OBJECT_TYPE_SECURITY_SETUP: + switch (methodIndex) + { + case 1: + //Activate Security policy. + ret = GET_ATTRIBUTE(2); + break; + case 2: + //Key transfer. TODO: Check this when SS 1 is released. + ret = GET_ATTRIBUTE(7); + break; + case 4: + //Generate key pair. TODO: Check this when SS 1 is released. + ret = GET_ATTRIBUTE(2); + break; + case 6: + case 8: + //Import or export certificate. + ret = GET_ATTRIBUTE(6); + break; + default: + break; + } + break; + //SAP assignment is added or removed. + case DLMS_OBJECT_TYPE_SAP_ASSIGNMENT: + ret = GET_ATTRIBUTE(2); + break; + //Connection state is changed. + case DLMS_OBJECT_TYPE_DISCONNECT_CONTROL: + //Register activation is changed. + ret = GET_ATTRIBUTE(2, 3); + break; + case DLMS_OBJECT_TYPE_REGISTER_ACTIVATION: + if (methodIndex == 1) + { + //Register is assigned. + ret = GET_ATTRIBUTE(2); + } + else + { + //Mask is added. + ret = GET_ATTRIBUTE(3); + } + break; + case DLMS_OBJECT_TYPE_SPECIAL_DAYS_TABLE: + ret = GET_ATTRIBUTE(2); + break; + default: + break; + } + return ret; +} + +#ifndef DLMS_IGNORE_REGISTER_MONITOR +int svr_monitor(dlmsServerSettings* settings, gxRegisterMonitor* object) +{ + int ret; + unsigned char pos; + gxValueEventCollection args; + gxValueEventArg* e; +#ifdef DLMS_IGNORE_MALLOC + gxValueEventArg tmp[1]; + ve_init(&tmp[0]); + vec_attach(&args, tmp, 1, 1); + e = &tmp[0]; +#else + e = (gxValueEventArg*)gxmalloc(sizeof(gxValueEventArg)); + ve_init(e); + vec_init(&args); + vec_push(&args, e); +#endif //DLMS_IGNORE_MALLOC + e->target = object->monitoredValue.target; + e->index = object->monitoredValue.attributeIndex; + e->action = 1; + svr_preRead(&settings->base, &args); + ret = e->error; + if (!e->handled && ret == 0) + { + if ((ret = cosem_getValue(&settings->base, e)) == 0) + { + svr_postRead(&settings->base, &args); + ret = e->error; + } + } + if (ret == 0) + { + //Save value. + dlmsVARIANT value = e->value; + dlmsVARIANT* threshold; + dlmsVARIANT* lastValue; + unsigned char buff[1]; + gxByteBuffer bb; + bb_attach(&bb, buff, 0, 1); + e->parameters.vt = DLMS_DATA_TYPE_OCTET_STRING; + e->parameters.byteArr = &bb; + gxActionSet* act; + e->index = 1; + unsigned char index = 0, cnt = (unsigned char)object->thresholds.size; + if (object->actions.size < cnt) + { + cnt = (unsigned char)object->actions.size; + } + double currentValue = var_toDouble(&e->value); + for (pos = 0; pos != cnt; ++pos) + { + e->target = NULL; + if ((ret = va_getByIndex(&object->thresholds, pos, &threshold)) != 0 || + (ret = va_getByIndex(&object->lastValues, pos, &lastValue)) != 0) + { + break; + } + double thresholdsValue = var_toDouble(threshold); + //If value is down. + if (currentValue < thresholdsValue) + { + if (lastValue->vt == DLMS_DATA_TYPE_NONE || var_toDouble(lastValue) > thresholdsValue) + { + if ((ret = arr_getByIndex2(&object->actions, pos, (void**)&act, sizeof(gxActionSet))) != 0) + { + break; + } + e->target = &act->actionDown.script->base; + index = (unsigned char)act->actionDown.scriptSelector; + ret = var_copy(lastValue, &value); + } + } + //If value is up. + else if (currentValue > thresholdsValue) + { + if (lastValue->vt == DLMS_DATA_TYPE_NONE || var_toDouble(lastValue) < thresholdsValue) + { + if ((ret = arr_getByIndex2(&object->actions, pos, (void**)&act, sizeof(gxActionSet))) != 0) + { + break; + } + e->target = &act->actionUp.script->base; + index = (unsigned char)act->actionUp.scriptSelector; + ret = var_copy(lastValue, &value); + } + } + if (e->target != NULL) + { + bb_clear(&bb); + if ((ret = var_setInt8(&e->parameters, index)) != 0 || + (ret = invoke_ScriptTable(settings, e)) != 0) + { + break; + } + } + } + } +#ifndef DLMS_IGNORE_MALLOC + vec_clear(&args); +#endif //DLMS_IGNORE_MALLOC + return ret; +} + +int svr_monitorAll(dlmsServerSettings* settings) +{ + int ret = 0, pos; + gxObject* obj; + //Single activity calendars. + for (pos = 0; pos != settings->base.objects.size; ++pos) + { + if ((ret = oa_getByIndex(&settings->base.objects, pos, &obj)) != DLMS_ERROR_CODE_OK) + { + break; + } + if (obj->objectType == DLMS_OBJECT_TYPE_REGISTER_MONITOR) + { + if ((ret = svr_monitor(settings, (gxRegisterMonitor*)obj)) != 0) + { + break; + } + } + } + return ret; +} +#endif //DLMS_IGNORE_REGISTER_MONITOR + + +#ifndef DLMS_IGNORE_LIMITER + +int svr_invokeLimiterAction( + dlmsServerSettings* settings, + gxValueEventArg* e, + gxActionItem* action) +{ + int pos, ret = 0; + gxObject* obj; + for (pos = 0; pos != settings->base.objects.size; ++pos) + { + if ((ret = oa_getByIndex(&settings->base.objects, pos, &obj)) != DLMS_ERROR_CODE_OK) + { + break; + } + if (obj->objectType == DLMS_OBJECT_TYPE_SCRIPT_TABLE && + memcmp(obj->logicalName, action->script->base.logicalName, 6) == 0) + { + e->target = (gxObject*)action->script; + e->index = 1; + if ((ret = var_setInt16(&e->parameters, action->scriptSelector)) != 0 || + (ret = invoke_ScriptTable(settings, e)) != 0) + { + break; + } + break; + } + } + return ret; +} + +int svr_limiter(dlmsServerSettings* settings, + gxLimiter* object, + uint32_t now) +{ + uint16_t pos; + int ret; + gxValueEventCollection args; + gxValueEventArg* e; +#ifdef DLMS_IGNORE_MALLOC + uint16_t* id; + gxValueEventArg tmp[1]; + ve_init(&tmp[0]); + vec_attach(&args, tmp, 1, 1); + e = &tmp[0]; +#else + dlmsVARIANT* id; + e = (gxValueEventArg*)gxmalloc(sizeof(gxValueEventArg)); + ve_init(e); + vec_init(&args); + vec_push(&args, e); +#endif //DLMS_IGNORE_MALLOC + e->target = object->monitoredValue; + e->index = object->selectedAttributeIndex; + e->action = 1; + svr_preRead(&settings->base, &args); + ret = e->error; + if (!e->handled && ret == 0) + { + if ((ret = cosem_getValue(&settings->base, e)) == 0) + { + svr_postRead(&settings->base, &args); + ret = e->error; + } + } + if (ret == 0) + { + //Save value. + double currentValue = var_toDouble(&e->value); + double activeValue; + double normalValue = var_toDouble(&object->thresholdNormal); + double emergencyValue = var_toDouble(&object->thresholdEmergency); + if (!object->emergencyProfileActive) + { + //Use normal threshold in normal mode. + activeValue = normalValue; + } + else + { + //Use emergency threshold in emergency mode. + activeValue = emergencyValue; + } + + if (currentValue < activeValue) + { + //If active value is under threshold or it changes from over to under. + if (object->activationTime == 0 || (object->overThreshold & 0x1) == 1) + { + if (object->activationTime == 0) + { + //Server is started and limiter is set to IDLE mode. + object->activationTime = now; + // Threshold is NOT invoked when server is started. + object->overThreshold = 0x80; + } + else + { + object->activationTime = now; + object->overThreshold = 0; + } + } + else if (now - object->activationTime >= object->minUnderThresholdDuration) + { + if ((object->actionUnderThreshold.script != NULL) && (0 == object->overThreshold)) + { + ret = svr_invokeLimiterAction(settings, e, &object->actionUnderThreshold); + // Threshold is invoked only once. + // The highest bit is set to indicate that the action has been completed. + object->overThreshold = 0x80; + } + } + } + else if (currentValue > activeValue) + { + //If active value is over threshold or it changes from under to over. + if (object->activationTime == 0 || (object->overThreshold & 0x1) == 0) + { + if (object->activationTime == 0) + { + //Server is started and limiter is set to IDLE mode. + object->activationTime = now; + // Threshold is NOT invoked when server is started. + object->overThreshold = 0x81; + } + else + { + object->activationTime = now; + object->overThreshold = 1; + } + } + else if (now - object->activationTime >= object->minOverThresholdDuration) + { + if ((object->actionOverThreshold.script != NULL) && (1 == object->overThreshold)) + { + ret = svr_invokeLimiterAction(settings, e, &object->actionOverThreshold); + //Threshold is invoked only once. + // The highest bit is set to indicate that the action has been completed. + object->overThreshold = 0x81; + } + } + } + if (ret == 0) + { + if (!object->emergencyProfileActive) + { + //Limiter is in normal mode. + if ((now >= time_toUnixTime2(&object->emergencyProfile.activationTime)) && + (now < (time_toUnixTime2(&object->emergencyProfile.activationTime) + (object->emergencyProfile.duration)))) + { + //Search emergency profile group ID and activate the emergency if it is found. + for (pos = 0; pos != object->emergencyProfileGroupIDs.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if (va_getByIndex(&object->emergencyProfileGroupIDs, pos, &id) != 0) + { + break; + } +#else + if (arr_getByIndex(&object->emergencyProfileGroupIDs, pos, (void**)&id, sizeof(uint16_t)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC +#ifndef DLMS_IGNORE_MALLOC + if (object->emergencyProfile.id == id->iVal) +#else + if (object->emergencyProfile.id == *id) +#endif //DLMS_IGNORE_MALLOC + { + //Activate emergency mode. + object->emergencyProfileActive = 1; + break; + } + } + } + } + else + { + //Limiter is in emergency mode. + if ((now - time_toUnixTime2(&object->emergencyProfile.activationTime)) > + (object->emergencyProfile.duration)) + { + //The emergency duration elapsed and emergency is over. + object->emergencyProfileActive = 0; + } + } + } + } +#ifndef DLMS_IGNORE_MALLOC + vec_clear(&args); +#endif //DLMS_IGNORE_MALLOC + return ret; +} + +int svr_limiterAll(dlmsServerSettings* settings, uint32_t now) +{ + int ret = 0, pos; + gxObject* obj; + for (pos = 0; pos != settings->base.objects.size; ++pos) + { + if ((ret = oa_getByIndex(&settings->base.objects, pos, &obj)) != DLMS_ERROR_CODE_OK) + { + break; + } + if (obj->objectType == DLMS_OBJECT_TYPE_LIMITER) + { + if ((ret = svr_limiter(settings, (gxLimiter*)obj, now)) != 0) + { + break; + } + } + } + return ret; +} +#endif //DLMS_IGNORE_LIMITER + +#endif //DLMS_IGNORE_SERVER diff --git a/components/xt211/server.h b/components/xt211/server.h new file mode 100644 index 0000000..45e99d9 --- /dev/null +++ b/components/xt211/server.h @@ -0,0 +1,157 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef SERVER_H +#define SERVER_H + +#include "gxignore.h" +#ifndef DLMS_IGNORE_SERVER + +#ifdef __cplusplus +extern "C" { +#endif + +#include "serverevents.h" +#include "dlms.h" + + typedef struct + { + /*Received data from the client.*/ + unsigned char* data; + /*Data size.*/ + uint16_t dataSize; + /*Server reply for the client.*/ + gxByteBuffer* reply; + /*Is GBT streaming in progress.*/ + DLMS_DATA_REQUEST_TYPES moreData; + /*GBT Message count to send.*/ + unsigned char gbtCount; + /*HDLC window count to send.*/ + unsigned char hdlcWindowCount; + /*Received command.*/ + DLMS_COMMAND command; +#ifndef DLMS_IGNORE_IEC + /*Baudrate is changed when optical probe is used.*/ + uint16_t newBaudRate; +#endif //DLMS_IGNORE_IEC + }gxServerReply; + + int sr_initialize( + gxServerReply* sr, + unsigned char* data, + uint16_t dataSize, + gxByteBuffer* reply); + + int svr_initialize( + dlmsServerSettings* settings); + + /*Server handles received bytes from the client.*/ + int svr_handleRequest( + dlmsServerSettings* settings, + gxByteBuffer* data, + gxByteBuffer* reply); + + /*Server handles received bytes from the client.*/ + int svr_handleRequest2( + dlmsServerSettings* settings, + unsigned char* buff, + uint16_t size, + gxByteBuffer* reply); + + /*Server handles received byte from the client.*/ + int svr_handleRequest3( + dlmsServerSettings* settings, + unsigned char data, + gxByteBuffer* reply); + + /*Server handles received bytes from the client.*/ + int svr_handleRequest4( + dlmsServerSettings* settings, + gxServerReply* sr); + + void svr_reset( + dlmsServerSettings* settings); + + /* + Run the background processes. + */ + int svr_run( + dlmsServerSettings* settings, + //Current EPOCH time. + uint32_t time, + //Next EPOCH execution time. + uint32_t* next); + +#ifndef DLMS_IGNORE_REGISTER_MONITOR + /* + The server verifies that value of monitored object don't cross the thresholds. + Selected script is invoked if value is passed. + */ + int svr_monitor(dlmsServerSettings* settings, gxRegisterMonitor* object); + /* + The server verifies that values of monitored objects don't cross the thresholds. + Selected script is invoked if value is passed. + */ + int svr_monitorAll(dlmsServerSettings* settings); +#endif //DLMS_IGNORE_REGISTER_MONITOR + +#ifndef DLMS_IGNORE_LIMITER + /* + The server verifies that value of monitored object don't cross the thresholds. + Selected script is invoked if value is passed. + */ + int svr_limiter(dlmsServerSettings* settings, gxLimiter* object, uint32_t now); + /* + The server verifies that values of monitored objects don't cross the thresholds. + Selected script is invoked if value is passed. + */ + int svr_limiterAll(dlmsServerSettings* settings, uint32_t now); +#endif //DLMS_IGNORE_LIMITER + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + /** + * Update short names. + */ + int svr_updateShortNames( + dlmsServerSettings* settings, + unsigned char force); +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + + //Check is client changing the settings with action. + //This can be used to check is meter data changed. + //Return value is saved atribute index or zero if nothing hasn't change. + uint32_t svr_isChangedWithAction(DLMS_OBJECT_TYPE objectType, unsigned char methodIndex); +#ifdef __cplusplus +} +#endif +#endif //DLMS_IGNORE_SERVER +#endif //SERVER_H diff --git a/components/xt211/serverevents.c b/components/xt211/serverevents.c new file mode 100644 index 0000000..6ab1144 --- /dev/null +++ b/components/xt211/serverevents.c @@ -0,0 +1,67 @@ +// +// -------------------------------------------------------------------------- +// 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 "serverevents.h" +#ifdef DLMS_DEBUG +#include +#endif //DLMS_DEBUG + +void svr_notifyTrace(const char* str, int err) +{ +#ifdef DLMS_DEBUG + if (err != 0) + { + char tmp[20]; + sprintf(tmp, " Error: %d", err); + svr_trace(str, tmp); + } + else + { + svr_trace(str, " succeeded."); + } +#endif// DLMS_DEBUG +} + +void svr_notifyTrace2(const char* str, const short ot, const unsigned char* ln, int err) +{ +#ifdef DLMS_DEBUG + if (err != 0) + { + char tmp[20]; + sprintf(tmp, " %d:%d.%d.%d.%d.%d.%d Error: %d", ot, ln[0], ln[1], ln[2], ln[3], ln[4], ln[5], err); + svr_trace(str, tmp); + } + else + { + svr_trace(str, " succeeded."); + } +#endif// DLMS_DEBUG +} diff --git a/components/xt211/serverevents.h b/components/xt211/serverevents.h new file mode 100644 index 0000000..c720156 --- /dev/null +++ b/components/xt211/serverevents.h @@ -0,0 +1,227 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef SERVER_EVENTS_H +#define SERVER_EVENTS_H + +#include "gxignore.h" +#if !defined(DLMS_IGNORE_SERVER) || defined(DLMS_DEBUG) +#include "dlmssettings.h" + +#ifdef __cplusplus +extern "C" { +#endif +#ifndef DLMS_IGNORE_SERVER + /** + * Check is data sent to this server. + * + * @param serverAddress + * Server address. + * @param clientAddress + * Client address. + * @return True, if data is sent to this server. + */ + extern unsigned char svr_isTarget( + dlmsSettings* settings, + uint32_t serverAddress, + uint32_t clientAddress); + + /** + * Get attribute access level. + */ + extern DLMS_ACCESS_MODE svr_getAttributeAccess( + dlmsSettings* settings, + gxObject* obj, + unsigned char index); + + /** + * Get method access level. + */ + extern DLMS_METHOD_ACCESS_MODE svr_getMethodAccess( + dlmsSettings* settings, + gxObject* obj, + unsigned char index); + + /** + * called when client makes connection to the server. + */ + extern int svr_connected( + dlmsServerSettings* settings); + + /** + * Client has try to made invalid connection. Password is incorrect. + * + * @param connectionInfo + * Connection information. + */ + extern int svr_invalidConnection( + dlmsServerSettings* settings); + + /** + * called when client clses connection to the server. + */ + extern int svr_disconnected( + dlmsServerSettings* settings); + + extern void svr_preGet( + dlmsSettings* settings, + gxValueEventCollection* args); + + extern void svr_postGet( + dlmsSettings* settings, + gxValueEventCollection* args); + + /** + * Read selected item(s). + * + * @param args + * Handled read requests. + */ + extern void svr_preRead( + dlmsSettings* settings, + gxValueEventCollection* args); + + /** + * Write selected item(s). + * + * @param args + * Handled write requests. + */ + extern void svr_preWrite( + dlmsSettings* settings, + gxValueEventCollection* args); + + /** + * Action is occurred. + * + * @param args + * Handled action requests. + */ + extern void svr_preAction( + dlmsSettings* settings, + gxValueEventCollection* args); + + /** + * Read selected item(s). + * + * @param args + * Handled read requests. + */ + extern void svr_postRead( + dlmsSettings* settings, + gxValueEventCollection* args); + + /** + * Write selected item(s). + * + * @param args + * Handled write requests. + */ + extern void svr_postWrite( + dlmsSettings* settings, + gxValueEventCollection* args); + + /** + * Action is occurred. + * + * @param args + * Handled action requests. + */ + extern void svr_postAction( + dlmsSettings* settings, + gxValueEventCollection* args); + + /** + * Check whether the authentication and password are correct. + * + * @param authentication + * Authentication level. + * @param password + * Password. + * @return Source diagnostic. + */ + extern DLMS_SOURCE_DIAGNOSTIC svr_validateAuthentication( + dlmsServerSettings* settings, + DLMS_AUTHENTICATION authentication, + gxByteBuffer* password); + + /** + * Find object. + * + * @param objectType + * Object type. + * @param sn + * Short Name. In Logical name referencing this is not used. + * @param ln + * Logical Name. In Short Name referencing this is not used. + * @return Found object or NULL if object is not found. + */ + extern int svr_findObject( + dlmsSettings* settings, + DLMS_OBJECT_TYPE objectType, + int sn, + unsigned char* ln, + gxValueEventArg* e); + + /** + * This is reserved for future use. + * + * @param args + * Handled data type requests. + */ + extern void svr_getDataType( + dlmsSettings* settings, + gxValueEventCollection* args); +#endif //DLMS_IGNORE_SERVER +#ifdef DLMS_DEBUG + /** + * Trace that can be used in debugging. + * + * str: Method info. + * Data: optional data. + */ + extern void svr_trace( + const char* str, + const char* data); +#endif //DLMS_DEBUG + + //Server uses notify trace if DLMS_DEBUG is defined. + void svr_notifyTrace(const char* str, int err); + + //Server uses notify trace if DLMS_DEBUG is defined. + void svr_notifyTrace2(const char* str, const short ot, const unsigned char* ln, int err); + +#ifdef __cplusplus +} +#endif +#endif //DLMS_IGNORE_SERVER +#endif //SERVER_EVENTS_H diff --git a/components/xt211/snparameters.h b/components/xt211/snparameters.h new file mode 100644 index 0000000..3cd942f --- /dev/null +++ b/components/xt211/snparameters.h @@ -0,0 +1,98 @@ +// +// -------------------------------------------------------------------------- +// 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" +#ifndef SN_PARAMETERS_H +#define SN_PARAMETERS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME +#include "dlmssettings.h" +#include "bytebuffer.h" +#include "enums.h" + +typedef struct +{ + /** + * DLMS settings. + */ + dlmsSettings *settings; + /** + * DLMS command. + */ + DLMS_COMMAND command; + /** + * Request type. + */ + int requestType; + /** + * Attribute descriptor. + */ + gxByteBuffer attributeDescriptor; + /** + * Data. + */ + gxByteBuffer data; + /** + * Send date and time. This is used in Data notification messages. + */ +#ifdef DLMS_USE_EPOCH_TIME + uint32_t time; +#else + struct tm time; +#endif // DLMS_USE_EPOCH_TIME + + /** + * Item Count. + */ + int count; + + /** + * Are there more data to send or more data to receive. + */ + unsigned char multipleBlocks; + + /** + * Block index. + */ + int blockIndex; +} snParameters; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + +#ifdef __cplusplus +} +#endif + +#endif //SN_PARAMETERS_H diff --git a/components/xt211/text_sensor.py b/components/xt211/text_sensor.py new file mode 100644 index 0000000..1b1e982 --- /dev/null +++ b/components/xt211/text_sensor.py @@ -0,0 +1,43 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import text_sensor +from . import ( + XT211, + xt211_ns, + obis_code, + CONF_XT211_ID, + CONF_OBIS_CODE, + CONF_DONT_PUBLISH, + CONF_CLASS, +) + +AUTO_LOAD = ["xt211"] + +XT211TextSensor = xt211_ns.class_( + "XT211TextSensor", text_sensor.TextSensor +) + + +CONFIG_SCHEMA = cv.All( + text_sensor.text_sensor_schema( + XT211TextSensor, + ).extend( + { + cv.GenerateID(CONF_XT211_ID): cv.use_id(XT211), + cv.Required(CONF_OBIS_CODE): obis_code, + cv.Optional(CONF_DONT_PUBLISH, default=False): cv.boolean, + cv.Optional(CONF_CLASS, default=1): cv.int_, + } + ), + cv.has_exactly_one_key(CONF_OBIS_CODE), +) + + +async def to_code(config): + component = await cg.get_variable(config[CONF_XT211_ID]) + var = await text_sensor.new_text_sensor(config) + cg.add(var.set_obis_code(config[CONF_OBIS_CODE])) + cg.add(var.set_dont_publish(config.get(CONF_DONT_PUBLISH))) + cg.add(var.set_obis_class(config[CONF_CLASS])) + + cg.add(component.register_sensor(var)) \ No newline at end of file diff --git a/components/xt211/unused/cipheringenums.h b/components/xt211/unused/cipheringenums.h new file mode 100644 index 0000000..2c5a34d --- /dev/null +++ b/components/xt211/unused/cipheringenums.h @@ -0,0 +1,48 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef CHIPPERINGENUMS_H +#define CHIPPERINGENUMS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DLMS_IGNORE_HIGH_GMAC + +#endif //DLMS_IGNORE_HIGH_GMAC + +#ifdef __cplusplus +} +#endif + +#endif //CHIPPERINGENUMS_H diff --git a/components/xt211/unused/gxinvoke.c b/components/xt211/unused/gxinvoke.c new file mode 100644 index 0000000..c4901ff --- /dev/null +++ b/components/xt211/unused/gxinvoke.c @@ -0,0 +1,3148 @@ +// +// -------------------------------------------------------------------------- +// 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" +#ifndef DLMS_IGNORE_SERVER + +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) +#include +#endif + +#include "gxmem.h" +#if _MSC_VER > 1400 +#include +#endif +#include + +#include "cosem.h" +#include "dlms.h" +#include "gxset.h" +#include "gxinvoke.h" +#include "helpers.h" +#include "objectarray.h" +#include "ciphering.h" +#include "gxget.h" +#include "gxkey.h" +#include "serverevents.h" + +#ifndef DLMS_IGNORE_CHARGE + +int invoke_Charge( + gxCharge* object, + unsigned char index, + dlmsVARIANT* value) +{ + gxChargeTable* ct, * it; + int ret = 0, pos; + //Update unit charge. + if (index == 1) + { + for (pos = 0; pos != object->unitChargePassive.chargeTables.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + ret = arr_getByIndex(&object->unitChargePassive.chargeTables, pos, (void**)&ct, sizeof(gxCharge)); +#else + ret = arr_getByIndex(&object->unitChargePassive.chargeTables, pos, (void**)&ct); +#endif //DLMS_IGNORE_MALLOC + if (ret != 0) + { + return ret; + } + ct->chargePerUnit = (short)var_toInteger(value); + } + } + //Activate passive unit charge. + else if (index == 2) + { + object->unitChargeActive.chargePerUnitScaling = object->unitChargePassive.chargePerUnitScaling; + object->unitChargeActive.commodity = object->unitChargePassive.commodity; + for (pos = 0; pos != object->unitChargePassive.chargeTables.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->unitChargePassive.chargeTables, pos, (void**)&ct, sizeof(gxChargeTable))) != 0 || + (ret = arr_getByIndex(&object->unitChargeActive.chargeTables, object->unitChargeActive.chargeTables.size, (void**)&it, sizeof(gxChargeTable))) != 0) + { + break; + } + ++object->unitChargeActive.chargeTables.size; +#else + if ((ret = arr_getByIndex(&object->unitChargePassive.chargeTables, pos, (void**)&ct)) != 0) + { + break; + } + it = (gxChargeTable*)gxmalloc(sizeof(gxChargeTable)); + arr_push(&object->unitChargeActive.chargeTables, it); +#endif //DLMS_IGNORE_MALLOC + it->chargePerUnit = ct->chargePerUnit; + it->index = ct->index; + } + } + //Update total amount remaining. + else if (index == 4) + { + object->totalAmountRemaining += var_toInteger(value); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_CHARGE +#ifndef DLMS_IGNORE_CREDIT +int invoke_Credit( + gxCredit* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret = 0; + //Update amount. + if (index == 1) + { + object->currentCreditAmount += var_toInteger(value); + } + //Set amount to value. + else if (index == 2) + { + object->currentCreditAmount = var_toInteger(value); + } + else if (index == 3) + { + // The mechanism for selecting the �Credit� is not in the scope of COSEM and + // shall be specified by the implementer (e.g. button push, meter process, script etc.). + object->status |= 4; + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_CREDIT +#ifndef DLMS_IGNORE_TOKEN_GATEWAY +int invoke_gxTokenGateway( + gxTokenGateway* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret = 0; + //Update token. + if (index == 1) + { + bb_clear(&object->token); + if (value->vt == DLMS_DATA_TYPE_OCTET_STRING) + { + bb_set(&object->token, value->byteArr->data, value->byteArr->size); + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_TOKEN_GATEWAY + +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME +int invoke_AssociationLogicalName( + dlmsServerSettings* settings, + gxValueEventArg* e) +{ + int ret = 0; + gxAssociationLogicalName* object = (gxAssociationLogicalName*)e->target; + // Check reply_to_HLS_authentication + if (e->index == 1) + { +#ifndef DLMS_IGNORE_HIGH_GMAC + unsigned char ch; + gxByteBuffer tmp; +#endif //DLMS_IGNORE_HIGH_GMAC + unsigned char tmp2[64]; + unsigned char equal; + uint32_t ic = 0; + gxByteBuffer bb; + gxByteBuffer* readSecret; + BYTE_BUFFER_INIT(&bb); +#ifdef DLMS_IGNORE_MALLOC + uint16_t count; + if ((ret = bb_getUInt8(e->parameters.byteArr, &ch)) != 0) + { + return ret; + } + if (ch != DLMS_DATA_TYPE_OCTET_STRING) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("High authentication failed. ", DLMS_ERROR_CODE_INVALID_PARAMETER); +#endif //DLMS_DEBUG + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if ((ret = hlp_getObjectCount2(e->parameters.byteArr, &count)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("High authentication failed. ", DLMS_ERROR_CODE_INVALID_PARAMETER); +#endif //DLMS_DEBUG + return ret; + } + if (count > bb_available(e->parameters.byteArr)) + { +#ifdef DLMS_DEBUG + svr_notifyTrace("High authentication failed. ", DLMS_ERROR_CODE_INVALID_PARAMETER); +#endif //DLMS_DEBUG + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } +#endif //DLMS_IGNORE_MALLOC + +#ifndef DLMS_IGNORE_HIGH_GMAC + if (settings->base.authentication == DLMS_AUTHENTICATION_HIGH_GMAC) + { + bb_attach(&tmp, settings->base.sourceSystemTitle, sizeof(settings->base.sourceSystemTitle), sizeof(settings->base.sourceSystemTitle)); + if ((ret = bb_getUInt8(e->parameters.byteArr, &ch)) != 0 || + (ret = bb_getUInt32(e->parameters.byteArr, &ic)) != 0) + { + return ret; + } + //IC is also compared. + e->parameters.byteArr->position -= 5; + readSecret = &tmp; + } + else +#endif //DLMS_IGNORE_MALLOC + { + readSecret = &object->secret; + } + + BYTE_BUFFER_INIT(&bb); + bb_attach(&bb, tmp2, 0, sizeof(tmp2)); + if ((ret = dlms_secure(&settings->base, + ic, + &settings->base.stoCChallenge, + readSecret, + &bb)) != 0) + { + return ret; + } + equal = bb_available(e->parameters.byteArr) != 0 && + bb_compare(&bb, + e->parameters.byteArr->data + e->parameters.byteArr->position, + bb_available(e->parameters.byteArr)); + bb_clear(&settings->info.data); + if (equal) + { +#ifndef DLMS_IGNORE_HIGH_GMAC + if (settings->base.authentication == DLMS_AUTHENTICATION_HIGH_GMAC) + { +#ifdef DLMS_IGNORE_MALLOC + bb_attach(&tmp, settings->base.cipher.systemTitle, sizeof(settings->base.cipher.systemTitle), sizeof(settings->base.cipher.systemTitle)); + readSecret = &tmp; +#else + readSecret = &settings->base.cipher.systemTitle; +#endif //DLMS_IGNORE_MALLOC + ic = settings->base.cipher.invocationCounter; + } +#endif //DLMS_IGNORE_HIGH_GMAC + e->byteArray = 1; + if ((ret = dlms_secure(&settings->base, + ic, + &settings->base.ctoSChallenge, + readSecret, + &settings->info.data)) != 0) + { + return ret; + } + bb_insertUInt8(&settings->info.data, 0, DLMS_DATA_TYPE_OCTET_STRING); + bb_insertUInt8(&settings->info.data, 1, (unsigned char)(settings->info.data.size - 1)); + object->associationStatus = DLMS_ASSOCIATION_STATUS_ASSOCIATED; + } + else + { + object->associationStatus = DLMS_ASSOCIATION_STATUS_NON_ASSOCIATED; + ret = DLMS_ERROR_CODE_READ_WRITE_DENIED; + } + } + else if (e->index == 2) + { +#ifdef DLMS_IGNORE_MALLOC + ret = cosem_getOctetString(e->parameters.byteArr, &object->secret); +#else +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + uint32_t size = bb_available(e->parameters.byteArr); +#else + uint16_t size = bb_available(e->parameters.byteArr); +#endif + if (size == 0) + { + ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } + else + { + bb_clear(&object->secret); + ret = bb_set(&object->secret, e->parameters.byteArr->data + e->parameters.byteArr->position, size); + } +#endif //DLMS_IGNORE_MALLOC + } + else if (e->index == 5) + { +#ifdef DLMS_IGNORE_MALLOC + gxUser* it; + if (!(object->userList.size < arr_getCapacity(&object->userList))) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + else + { + ++object->userList.size; + if ((ret = arr_getByIndex(&object->userList, object->userList.size - 1, (void**)&it, sizeof(gxUser))) == 0) + { + if ((ret = cosem_checkStructure(e->parameters.byteArr, 2)) != 0 || + (ret = cosem_getUInt8(e->parameters.byteArr, &it->id)) != 0 || + (ret = cosem_getString2(e->parameters.byteArr, it->name, sizeof(it->name))) != 0) + { + //Error code is returned at the end of the function. + } + } + } +#else + if (e->parameters.vt != DLMS_DATA_TYPE_STRUCTURE || e->parameters.Arr->size != 2) + { + ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } + else + { + dlmsVARIANT* tmp; + char* name; + gxKey2* it = (gxKey2*)gxmalloc(sizeof(gxKey2)); + if ((ret = va_getByIndex(e->parameters.Arr, 0, &tmp)) != 0) + { + gxfree(it); + return ret; + } + it->key = tmp->bVal; + if ((ret = va_getByIndex(e->parameters.Arr, 1, &tmp)) != 0) + { + gxfree(it); + return ret; + } + name = gxmalloc(tmp->strVal->size + 1); + it->value = name; + *(name + tmp->strVal->size) = '\0'; + memcpy(it->value, tmp->strVal->data, tmp->strVal->size); + ret = arr_push(&((gxAssociationLogicalName*)e->target)->userList, it); + } +#endif //DLMS_IGNORE_MALLOC + } + else if (e->index == 6) + { + int pos; +#ifdef DLMS_IGNORE_MALLOC + gxUser* it; + unsigned char id; + char name[MAX_SAP_ITEM_NAME_LENGTH]; + if ((ret = cosem_checkStructure(e->parameters.byteArr, 2)) == 0 && + (ret = cosem_getUInt8(e->parameters.byteArr, &id)) == 0 && + (ret = cosem_getString2(e->parameters.byteArr, name, sizeof(name))) == 0) + { + uint16_t size = (uint16_t)strlen(name); + for (pos = 0; pos != ((gxAssociationLogicalName*)e->target)->userList.size; ++pos) + { + if ((ret = arr_getByIndex(&((gxAssociationLogicalName*)e->target)->userList, pos, (void**)&it, sizeof(gxUser))) != 0) + { + return ret; + } + if (it->id == id && memcmp(it->name, name, size) == 0) + { + int pos2; + gxUser* it2; + for (pos2 = pos + 1; pos2 < ((gxAssociationLogicalName*)e->target)->userList.size; ++pos2) + { + if ((ret = arr_getByIndex(&((gxAssociationLogicalName*)e->target)->userList, pos2, (void**)&it2, sizeof(gxUser))) != 0) + { + break; + } + memcpy(it, it2, sizeof(gxUser)); + it = it2; + } + --((gxAssociationLogicalName*)e->target)->userList.size; + break; + } + } + } +#else + if (e->parameters.Arr->size != 2) + { + return DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } + else + { + gxKey2* it; + unsigned char id; + dlmsVARIANT* tmp; + unsigned char* name; + ret = va_getByIndex(e->parameters.Arr, 0, &tmp); + id = tmp->bVal; + ret = va_getByIndex(e->parameters.Arr, 1, &tmp); + name = tmp->strVal->data; + int len = tmp->strVal->size; + for (pos = 0; pos != ((gxAssociationLogicalName*)e->target)->userList.size; ++pos) + { + ret = arr_getByIndex(&((gxAssociationLogicalName*)e->target)->userList, pos, (void**)&it); + if (ret != 0) + { + return ret; + } + if (it->key == id && memcmp(it->value, name, len) == 0) + { + ret = arr_removeByIndex(&((gxAssociationLogicalName*)e->target)->userList, pos, (void**)&it); + gxfree(it->value); + gxfree(it); + break; + } + } + } +#endif //DLMS_IGNORE_MALLOC + } + else + { + ret = DLMS_ERROR_CODE_READ_WRITE_DENIED; + } + return ret; +} +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + +#ifndef DLMS_IGNORE_IMAGE_TRANSFER +int invoke_ImageTransfer( + gxImageTransfer* target, + gxValueEventArg* e) +{ + int pos, ret = 0; + //Image transfer initiate + if (e->index == 1) + { + gxByteBuffer tmp; + gxImageActivateInfo* it, * item = NULL; + target->imageFirstNotTransferredBlockNumber = 0; + ba_clear(&target->imageTransferredBlocksStatus); + dlmsVARIANT* imageIdentifier, * size; +#ifdef DLMS_IGNORE_MALLOC + dlmsVARIANT imageIdentifier2, size2; + uint16_t count; + unsigned char ch; + if ((ret = cosem_checkStructure(e->parameters.byteArr, 2)) != 0 || + (ret = bb_getUInt8(e->parameters.byteArr, &ch)) != 0 || + ch != DLMS_DATA_TYPE_OCTET_STRING || + (ret = hlp_getObjectCount2(e->parameters.byteArr, &count)) != 0) + { + e->error = DLMS_ERROR_CODE_HARDWARE_FAULT; + return ret; + } + imageIdentifier2.vt = DLMS_DATA_TYPE_OCTET_STRING; + size2.vt = DLMS_DATA_TYPE_UINT32; + //Attach image identifier so heap is not used. + gxByteBuffer bb; + bb_attach(&bb, e->parameters.byteArr->data + e->parameters.byteArr->position, count, count); + imageIdentifier2.byteArr = &bb; + e->parameters.byteArr->position += count; + if ((ret = cosem_getUInt32(e->parameters.byteArr, &size2.ulVal)) != 0) + { + e->error = DLMS_ERROR_CODE_HARDWARE_FAULT; + return ret; + } + imageIdentifier = &imageIdentifier2; + size = &size2; +#else + if ((ret = va_getByIndex(e->parameters.Arr, 0, &imageIdentifier)) != 0 || + (ret = va_getByIndex(e->parameters.Arr, 1, &size)) != 0) + { + e->error = DLMS_ERROR_CODE_HARDWARE_FAULT; + return ret; + } +#endif //DLMS_IGNORE_MALLOC + target->imageTransferStatus = DLMS_IMAGE_TRANSFER_STATUS_INITIATED; + unsigned char exists = 0; + for (pos = 0; pos != target->imageActivateInfo.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&target->imageActivateInfo, pos, (void**)&it, sizeof(gxImageActivateInfo))) != 0) + { + return ret; + } +#else + if ((ret = arr_getByIndex(&target->imageActivateInfo, pos, (void**)&it)) != 0) + { + return ret; + } +#endif //DLMS_IGNORE_MALLOC + bb_attach(&tmp, it->identification.data, it->identification.size, it->identification.size); + if (bb_size(imageIdentifier->byteArr) != 0 && + bb_compare(&tmp, imageIdentifier->byteArr->data, imageIdentifier->byteArr->size)) + { + item = it; + exists = 1; + } + } + if (!exists) + { +#ifdef DLMS_IGNORE_MALLOC + ++target->imageActivateInfo.size; + if ((ret = arr_getByIndex(&target->imageActivateInfo, pos, (void**)&item, sizeof(gxImageActivateInfo))) != 0) + { + --target->imageActivateInfo.size; + return ret; + } +#else + item = (gxImageActivateInfo*)gxmalloc(sizeof(gxImageActivateInfo)); + BYTE_BUFFER_INIT(&item->identification); + BYTE_BUFFER_INIT(&item->signature); + arr_push(&target->imageActivateInfo, item); +#endif //DLMS_IGNORE_MALLOC + item->size = var_toInteger(size); +#ifdef DLMS_IGNORE_MALLOC + item->identification.size = (uint16_t)imageIdentifier->byteArr->size; + if ((ret = bb_get(imageIdentifier->byteArr, item->identification.data, imageIdentifier->byteArr->size)) != 0) + { + return ret; + } +#else + item->identification.size = 0; + if ((ret = bb_set2(&item->identification, imageIdentifier->byteArr, 0, bb_size(imageIdentifier->byteArr))) != 0) + { + return ret; + } +#endif //DLMS_IGNORE_MALLOC + uint16_t cnt = (uint16_t)(item->size / target->imageBlockSize); + if (item->size % target->imageBlockSize != 0) + { + ++cnt; + } + cnt = ba_getByteCount(cnt); +#ifndef GX_DLMS_MICROCONTROLLER + target->imageTransferredBlocksStatus.position = 0; +#endif //GX_DLMS_MICROCONTROLLER +#ifdef DLMS_IGNORE_MALLOC + //Image transferred blocks status must handle in server side when malloc is not used if image size is huge. + if (target->imageTransferredBlocksStatus.capacity != 0) + { + if (cnt > ba_getCapacity(&target->imageTransferredBlocksStatus)) + { + e->error = DLMS_ERROR_CODE_HARDWARE_FAULT; + return ret; + } + else + { + target->imageTransferredBlocksStatus.size = 0; + if ((ret = ba_capacity(&target->imageTransferredBlocksStatus, cnt)) == 0) + { + for (pos = 0; pos != cnt; ++pos) + { + ba_set(&target->imageTransferredBlocksStatus, 0); + } + } + } + } +#else + target->imageTransferredBlocksStatus.size = 0; + if ((ret = ba_capacity(&target->imageTransferredBlocksStatus, cnt)) == 0) + { + for (pos = 0; pos != cnt; ++pos) + { + ba_set(&target->imageTransferredBlocksStatus, 0); + } + } +#endif //DLMS_IGNORE_MALLOC + } + } + //Image block transfer + else if (e->index == 2) + { + uint32_t index; +#ifdef DLMS_IGNORE_MALLOC + if ((ret = cosem_checkStructure(e->parameters.byteArr, 2)) != 0 || + (ret = cosem_getUInt32(e->parameters.byteArr, &index)) != 0) + { + e->error = DLMS_ERROR_CODE_HARDWARE_FAULT; + return ret; + } +#else + dlmsVARIANT* imageIndex; + if ((ret = va_getByIndex(e->parameters.Arr, 0, &imageIndex)) != 0) + { + e->error = DLMS_ERROR_CODE_HARDWARE_FAULT; + return ret; + } + index = (uint16_t)var_toInteger(imageIndex); +#endif //DLMS_IGNORE_MALLOC + if ((ret = ba_setByIndex(&target->imageTransferredBlocksStatus, (uint16_t)index, 1)) == 0) + { + target->imageFirstNotTransferredBlockNumber = index + 1; + target->imageTransferStatus = DLMS_IMAGE_TRANSFER_STATUS_INITIATED; + } +#ifdef DLMS_IGNORE_MALLOC + bb_clear(e->parameters.byteArr); +#endif //DLMS_IGNORE_MALLOC + } + //Image verify + else if (e->index == 3) + { + ret = 0; + } + //Image activate. + else if (e->index == 4) + { + ret = 0; + } + else + { + ret = DLMS_ERROR_CODE_READ_WRITE_DENIED; + } + return ret; +} +#endif //DLMS_IGNORE_IMAGE_TRANSFER + +#ifndef DLMS_IGNORE_SAP_ASSIGNMENT +int invoke_SapAssigment( + gxSapAssignment* target, + gxValueEventArg* e) +{ + int pos, ret = 0; + uint16_t id; + gxSapItem* it; + //Image transfer initiate + if (e->index == 1) + { +#ifdef DLMS_IGNORE_MALLOC + if (e->parameters.vt != DLMS_DATA_TYPE_OCTET_STRING) + { + ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } + else if ((ret = cosem_checkStructure(e->parameters.byteArr, 2)) == 0 && + (ret = cosem_getUInt16(e->parameters.byteArr, &id)) == 0) + { + if (id == 0) + { + uint16_t size; + unsigned char name[MAX_SAP_ITEM_NAME_LENGTH]; + if ((ret = cosem_getOctetString2(e->parameters.byteArr, name, sizeof(name), &size)) == 0) + { + name[size] = 0; + for (pos = 0; pos != target->sapAssignmentList.size; ++pos) + { + if ((ret = arr_getByIndex(&target->sapAssignmentList, pos, (void**)&it, sizeof(gxSapItem))) != 0) + { + return ret; + } + if (it->name.size == size && memcmp(it->name.value, name, size) == 0) + { + if ((ret = arr_removeByIndex(&target->sapAssignmentList, pos, sizeof(gxSapItem))) == 0) + { + //arr_removeByIndex is decreasing amount already. + break; + } + } + } + } + } + else + { + //If buffer is full. + if (!(target->sapAssignmentList.size < target->sapAssignmentList.capacity)) + { + ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } + else + { + ++target->sapAssignmentList.size; + if ((ret = arr_getByIndex(&target->sapAssignmentList, target->sapAssignmentList.size - 1, (void**)&it, sizeof(gxSapItem))) == 0 && + (ret = cosem_getOctetString2(e->parameters.byteArr, it->name.value, sizeof(it->name.value), &it->name.size)) == 0) + { + it->id = id; + } + else + { + --target->sapAssignmentList.size; + } + } + } + } +#else + dlmsVARIANT* tmp; + if ((ret = va_getByIndex(e->parameters.Arr, 0, &tmp)) != 0) + { + return ret; + } + id = tmp->uiVal; + if ((ret = va_getByIndex(e->parameters.Arr, 1, &tmp)) != 0) + { + return ret; + } + + gxByteBuffer* name; + if (tmp->vt == DLMS_DATA_TYPE_OCTET_STRING) + { + name = tmp->byteArr; + } + else + { + name = tmp->strVal; + } + if (id == 0) + { + for (pos = 0; pos != target->sapAssignmentList.size; ++pos) + { + if ((ret = arr_getByIndex(&target->sapAssignmentList, pos, (void**)&it)) != 0) + { + return ret; + } + it->name.position = 0; + if (name != NULL && bb_compare(&it->name, name->data, bb_size(name))) + { + ret = arr_removeByIndex(&target->sapAssignmentList, pos, (void**)&it); + bb_clear(&it->name); + gxfree(it); + return ret; + } + } + } + else + { + it = (gxSapItem*)gxmalloc(sizeof(gxSapItem)); + it->id = id; + BYTE_BUFFER_INIT(&it->name); + bb_set(&it->name, name->data, name->size); + arr_push(&target->sapAssignmentList, it); + } +#endif //DLMS_IGNORE_MALLOC + } + else + { + ret = DLMS_ERROR_CODE_READ_WRITE_DENIED; + } + return ret; +} +#endif //DLMS_IGNORE_SAP_ASSIGNMENT + +#ifndef DLMS_IGNORE_SECURITY_SETUP +int invoke_SecuritySetup(dlmsServerSettings* settings, gxSecuritySetup* target, gxValueEventArg* e) +{ + int ret = 0; +#ifndef DLMS_IGNORE_HIGH_GMAC + int pos; +#endif //DLMS_IGNORE_HIGH_GMAC + if (e->index == 1) + { + //The security policy can only be strengthened. + if (target->securityPolicy > var_toInteger(&e->parameters)) + { + ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } + else + { + target->securityPolicy = var_toInteger(&e->parameters); + } + } + else if (e->index == 2) + { +#ifdef DLMS_IGNORE_HIGH_GMAC + ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; +#else +#ifdef DLMS_IGNORE_MALLOC + if (e->parameters.vt != DLMS_DATA_TYPE_OCTET_STRING) + { + ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } + else + { + unsigned char TMP[24]; + gxByteBuffer tmp; + BB_ATTACH(tmp, TMP, 0); + unsigned char BUFF[24]; + gxByteBuffer bb; + BB_ATTACH(bb, BUFF, 0); + unsigned char type; + uint16_t count = 10; + if ((ret = cosem_checkArray(e->parameters.byteArr, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_checkStructure(e->parameters.byteArr, 2)) != 0 || + (ret = cosem_getEnum(e->parameters.byteArr, &type)) != 0 || + (ret = cosem_getOctetString(e->parameters.byteArr, &tmp)) != 0 || + (ret = cip_decryptKey(settings->base.kek, sizeof(settings->base.kek), &tmp, &bb)) != 0) + { + break; + } + if (bb.size != 16) + { + e->error = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + break; + } + switch (type) + { + case DLMS_GLOBAL_KEY_TYPE_UNICAST_ENCRYPTION: + memcpy(settings->base.cipher.blockCipherKey, BUFF, bb.size); + break; + case DLMS_GLOBAL_KEY_TYPE_BROADCAST_ENCRYPTION: + //Invalid type + ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + break; + case DLMS_GLOBAL_KEY_TYPE_AUTHENTICATION: + memcpy(settings->base.cipher.authenticationKey, BUFF, bb.size); + break; + case DLMS_GLOBAL_KEY_TYPE_KEK: + memcpy(settings->base.kek, BUFF, bb.size); + break; + default: + //Invalid type + ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + break; + } + } + } + } +#else + dlmsVARIANT* it, * type, * data; + if (e->parameters.vt != DLMS_DATA_TYPE_ARRAY) + { + ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } + else + { + gxByteBuffer bb; + BYTE_BUFFER_INIT(&bb); + for (pos = 0; pos != e->parameters.Arr->size; ++pos) + { + bb_clear(&bb); + if ((ret = va_getByIndex(e->parameters.Arr, pos, &it)) != 0 || + (ret = va_getByIndex(it->Arr, 0, &type)) != 0 || + (ret = va_getByIndex(it->Arr, 1, &data)) != 0 || + (ret = cip_decryptKey(settings->base.kek.data, (unsigned char)settings->base.kek.size, data->byteArr, &bb)) != 0) + { + break; + } + if (bb.size != 16) + { + e->error = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + break; + } + switch (type->cVal) + { + case DLMS_GLOBAL_KEY_TYPE_UNICAST_ENCRYPTION: + bb_clear(&settings->base.cipher.blockCipherKey); + bb_set(&settings->base.cipher.blockCipherKey, bb.data, bb.size); + break; + case DLMS_GLOBAL_KEY_TYPE_BROADCAST_ENCRYPTION: + //Invalid type + ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + break; + case DLMS_GLOBAL_KEY_TYPE_AUTHENTICATION: + bb_clear(&settings->base.cipher.authenticationKey); + bb_set(&settings->base.cipher.authenticationKey, bb.data, bb.size); + break; + case DLMS_GLOBAL_KEY_TYPE_KEK: + bb_clear(&settings->base.kek); + bb_set(&settings->base.kek, bb.data, bb.size); + break; + default: + //Invalid type + ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + break; + } + } + bb_clear(&bb); + } +#endif //DLMS_IGNORE_MALLOC +#endif //DLMS_IGNORE_HIGH_GMAC + } + else + { + ret = DLMS_ERROR_CODE_READ_WRITE_DENIED; + } + return ret; +} + +#endif //DLMS_IGNORE_SECURITY_SETUP + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME +int invoke_AssociationShortName( + dlmsServerSettings* settings, + gxValueEventArg* e) +{ + int ret; + unsigned char equal; + uint32_t ic = 0; +#ifndef DLMS_IGNORE_HIGH_GMAC + gxByteBuffer bb; +#endif //DLMS_IGNORE_HIGH_GMAC + gxByteBuffer* readSecret; + // Check reply_to_HLS_authentication + if (e->index == 8) + { +#ifndef DLMS_IGNORE_HIGH_GMAC + if (settings->base.authentication == DLMS_AUTHENTICATION_HIGH_GMAC) + { + unsigned char ch; + bb_attach(&bb, settings->base.sourceSystemTitle, sizeof(settings->base.sourceSystemTitle), sizeof(settings->base.sourceSystemTitle)); + readSecret = &bb; + if ((ret = bb_getUInt8(&settings->info.data, &ch)) != 0 || + (ret = bb_getUInt32(&settings->info.data, &ic)) != 0) + { + bb_clear(&settings->info.data); + return ret; + } + } + else +#endif //DLMS_IGNORE_HIGH_GMAC + { + readSecret = &((gxAssociationShortName*)e->target)->secret; + } + bb_clear(&settings->info.data); + if ((ret = dlms_secure(&settings->base, ic, + &settings->base.stoCChallenge, readSecret, &settings->info.data)) != 0) + { + bb_clear(&settings->info.data); + return ret; + } + equal = bb_size(e->parameters.byteArr) != 0 && + bb_compare(&settings->info.data, + e->parameters.byteArr->data, + e->parameters.byteArr->size); + bb_clear(&settings->info.data); + if (equal) + { + e->byteArray = 1; +#ifndef DLMS_IGNORE_HIGH_GMAC + if (settings->base.authentication == DLMS_AUTHENTICATION_HIGH_GMAC) + { +#ifdef DLMS_IGNORE_MALLOC + bb_attach(&bb, settings->base.cipher.systemTitle, sizeof(settings->base.cipher.systemTitle), sizeof(settings->base.cipher.systemTitle)); + readSecret = &bb; +#else + readSecret = &settings->base.cipher.systemTitle; +#endif //DLMS_IGNORE_MALLOC + ic = settings->base.cipher.invocationCounter; + } +#endif //DLMS_IGNORE_HIGH_GMAC + if ((ret = dlms_secure(&settings->base, + ic, + &settings->base.ctoSChallenge, + readSecret, + &settings->info.data)) != 0) + { + return ret; + } + bb_insertUInt8(&settings->info.data, 0, DLMS_DATA_TYPE_OCTET_STRING); + bb_insertUInt8(&settings->info.data, 1, (unsigned char)(settings->info.data.size - 1)); + } + else + { + return 0; + } + } + else + { + return DLMS_ERROR_CODE_READ_WRITE_DENIED; + } + return 0; +} +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME +#ifndef DLMS_IGNORE_SCRIPT_TABLE +int invoke_ScriptTable( + dlmsServerSettings* settings, + gxValueEventArg* e) +{ + gxScript* s; + gxScriptAction* sa; + gxValueEventArg* e1; + int ret = 0, pos, pos2; + unsigned char id = var_toInteger(&e->parameters); + //Find index and execute it. + if (e->index == 1) + { + gxValueEventCollection args; +#ifdef DLMS_IGNORE_MALLOC + gxValueEventArg tmp[1]; + ve_init(&tmp[0]); + vec_attach(&args, tmp, 1, 1); + e1 = &tmp[0]; +#else + e1 = (gxValueEventArg*)gxmalloc(sizeof(gxValueEventArg)); + ve_init(e1); + vec_init(&args); + vec_push(&args, e1); +#endif //DLMS_IGNORE_MALLOC + for (pos = 0; pos != ((gxScriptTable*)e->target)->scripts.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&((gxScriptTable*)e->target)->scripts, pos, (void**)&s, sizeof(gxScript))) != 0) +#else + if ((ret = arr_getByIndex(&((gxScriptTable*)e->target)->scripts, pos, (void**)&s)) != 0) +#endif //DLMS_IGNORE_MALLOC + { + break; + } + if (s->id == id) + { + for (pos2 = 0; pos2 != s->actions.size; ++pos2) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&s->actions, pos2, (void**)&sa, sizeof(gxScriptAction))) != 0) +#else + if ((ret = arr_getByIndex(&s->actions, pos2, (void**)&sa)) != 0) +#endif //DLMS_IGNORE_MALLOC + { + break; + } + if (sa->type == DLMS_SCRIPT_ACTION_TYPE_WRITE) + { + e1->value = sa->parameter; + } + else + { + e1->parameters = sa->parameter; + } + e1->index = sa->index; +#ifndef DLMS_IGNORE_OBJECT_POINTERS + e1->target = sa->target; +#else + if ((ret = oa_findByLN(&settings->base.objects, sa->objectType, sa->logicalName, &e1->target)) != 0) + { + break; + } + if (e1->target == NULL) + { + ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + break; + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + if (sa->type == DLMS_SCRIPT_ACTION_TYPE_WRITE) + { + svr_preWrite(&settings->base, &args); + if (e1->error != 0) + { + ret = e1->error; + } + else if (!e1->handled) + { + //Set action to true to indicate that this is called from the action method. + e1->action = 1; + if ((ret = cosem_setValue(&settings->base, e1)) != 0) + { + break; + } + svr_postWrite(&settings->base, &args); + if (e1->error != 0) + { + ret = e1->error; + } + } + } + else if (sa->type == DLMS_SCRIPT_ACTION_TYPE_EXECUTE) + { + svr_preAction(&settings->base, &args); + if (e1->error != 0) + { + ret = e1->error; + } + else if (!e1->handled) + { + if ((ret = cosem_invoke(settings, e1)) != 0) + { + break; + } + svr_postAction(&settings->base, &args); + if (e1->error != 0) + { + ret = e1->error; + } + } + } + else + { + ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } + if (ret != 0) + { + break; + } + } + } + } + vec_clear(&args); + } + else + { + ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } + var_clear(&e->value); + return ret; +} +#endif //DLMS_IGNORE_SCRIPT_TABLE + +#ifndef DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL +int invoke_zigbeeNetworkControl(gxZigBeeNetworkControl* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = 0, pos; +#ifndef DLMS_IGNORE_MALLOC + dlmsVARIANT* it; +#endif //DLMS_IGNORE_MALLOC + gxActiveDevice* ad; + uint32_t v; + //Register device. + if (index == 1) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->activeDevices, object->activeDevices.size, (void**)&ad, sizeof(gxActiveDevice))) == 0) + { + ++object->activeDevices.size; + BYTE_BUFFER_INIT(&ad->macAddress); + if ((ret = cosem_getOctetString(value->byteArr, &ad->macAddress)) == 0 && + (ret = cosem_getIntegerFromBitString(value->byteArr, &v)) == 0) + { + ad->status = (DLMS_ZIG_BEE_STATUS)v; + } + } +#else + if ((ret = va_getByIndex(value->Arr, 0, &it)) == 0) + { + ad = (gxActiveDevice*)gxcalloc(1, sizeof(gxActiveDevice)); + BYTE_BUFFER_INIT(&ad->macAddress); + if ((ret = bb_set(&ad->macAddress, it->byteArr->data, it->byteArr->size)) == 0 && + (ret = cosem_getIntegerFromBitString(it->byteArr, &v)) == 0) + { + ad->status = (DLMS_ZIG_BEE_STATUS)v; + arr_push(&object->activeDevices, ad); + } + else + { + gxfree(ad); + } + } +#endif //DLMS_IGNORE_MALLOC + } + //Unregister device. + else if (index == 2) + { + for (pos = 0; pos != object->activeDevices.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->activeDevices, pos, (void**)&ad, sizeof(gxActiveDevice))) != 0) + { + break; + } + if (memcpy(&ad->macAddress, &value->byteArr, 8) == 0) + { + int pos2; + gxActiveDevice* ad2; + for (pos2 = pos + 1; pos2 < object->activeDevices.size; ++pos2) + { + if ((ret = arr_getByIndex(&object->activeDevices, pos2, (void**)&ad2, sizeof(gxActiveDevice))) != 0) + { + break; + } + memcpy(ad, ad2, sizeof(gxActiveDevice)); + ad = ad2; + } + --object->activeDevices.size; + break; + } +#else + ret = arr_getByIndex(&object->activeDevices, pos, (void**)&ad); + if (ret != 0) + { + return ret; + } + if (memcpy(&ad->macAddress, &value->byteArr, 8) == 0) + { + ret = arr_removeByIndex(&object->activeDevices, pos, (void**)&ad); + if (ret != 0) + { + return ret; + } + gxfree(ad); + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + //Unregister all device. + else if (index == 3) + { + ret = obj_clearActiveDevices(&object->activeDevices); + } + //backup PAN + else if (index == 4) + { + } + //Restore PAN, + else if (index == 5) + { + // This method instructs the coordinator to restore a PAN using backup information. + // The storage location of the back-up is not currently defined and is an internal function + // of the DLMS/COSEM Server. + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL +#ifndef DLMS_IGNORE_EXTENDED_REGISTER +int invoke_ExtendedRegister( + dlmsServerSettings* settings, + gxExtendedRegister* object, + unsigned char index) +{ + int ret = 0; + //Reset. + if (index == 1) + { + ret = var_clear(&object->value); + if (ret != 0) + { + return ret; + } + if (settings->defaultClock != NULL) + { + object->captureTime = settings->defaultClock->time; + } + else + { + time_clear(&object->captureTime); + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_EXTENDED_REGISTER + +#ifndef DLMS_IGNORE_DEMAND_REGISTER +int invoke_DemandRegister( + dlmsServerSettings* settings, + gxDemandRegister* object, + unsigned char index) +{ + int ret = 0; + //Reset. + if (index == 1) + { + if ((ret = var_clear(&object->currentAverageValue)) != 0 || + (ret = var_clear(&object->lastAverageValue)) != 0) + { + return ret; + } + if (settings->defaultClock != NULL) + { + object->startTimeCurrent = object->captureTime = settings->defaultClock->time; + } + else + { + time_clear(&object->captureTime); + time_clear(&object->startTimeCurrent); + } + } + else if (index == 1) + { + if ((ret = var_copy(&object->lastAverageValue, &object->currentAverageValue)) != 0 || + (ret = var_clear(&object->currentAverageValue)) != 0) + { + return ret; + } + if (settings->defaultClock != NULL) + { + object->startTimeCurrent = object->captureTime = settings->defaultClock->time; + } + else + { + time_clear(&object->captureTime); + time_clear(&object->startTimeCurrent); + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_DEMAND_REGISTER + + +#ifndef DLMS_IGNORE_CLOCK +int invoke_Clock(gxClock* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = 0; +#ifndef DLMS_IGNORE_MALLOC + dlmsVARIANT* it; + dlmsVARIANT tmp; +#endif //DLMS_IGNORE_MALLOC + // Resets the value to the default value. + // The default value is an instance specific constant. + if (index == 1) + { +#ifdef DLMS_USE_EPOCH_TIME + int minutes = time_getMinutes(&object->time); +#else + int minutes = object->time.value.tm_min; +#endif // DLMS_USE_EPOCH_TIME + if (minutes < 8) + { + minutes = 0; + } + else if (minutes < 23) + { + minutes = 15; + } + else if (minutes < 38) + { + minutes = 30; + } + else if (minutes < 53) + { + minutes = 45; + } + else + { + minutes = 0; + time_addHours(&object->time, 1); + } +#ifdef DLMS_USE_EPOCH_TIME + time_addTime(&object->time, 0, -time_getMinutes(&object->time) + minutes, -time_getSeconds(&object->time)); +#else + time_addTime(&object->time, 0, -object->time.value.tm_min + minutes, -object->time.value.tm_sec); +#endif // DLMS_USE_EPOCH_TIME + } + // Sets the meter's time to the nearest minute. + else if (index == 3) + { +#ifdef DLMS_USE_EPOCH_TIME + int s = time_getSeconds(&object->time); +#else + int s = object->time.value.tm_sec; +#endif // DLMS_USE_EPOCH_TIME + if (s > 30) + { + time_addTime(&object->time, 0, 1, 0); + } + time_addTime(&object->time, 0, 0, -s); + } + //Adjust to preset time. + else if (index == 4) + { + object->time = object->presetTime; + } + // Presets the time to a new value (preset_time) and defines + // avalidity_interval within which the new time can be activated. + else if (index == 5) + { +#ifdef DLMS_IGNORE_MALLOC + ret = cosem_getDateFromOctetString(value->byteArr, &object->presetTime); +#else + ret = var_init(&tmp); + if (ret != 0) + { + return ret; + } + ret = va_getByIndex(value->Arr, 0, &it); + if (ret != 0) + { + return ret; + } + ret = dlms_changeType2(it, DLMS_DATA_TYPE_DATETIME, &tmp); + if (ret != 0) + { + return ret; + } + object->presetTime = *tmp.dateTime; +#endif //DLMS_IGNORE_MALLOC + } + // Shifts the time. + else if (index == 6) + { + time_addTime(&object->time, 0, 0, var_toInteger(value)); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_CLOCK +#ifndef DLMS_IGNORE_REGISTER +int invoke_Register( + gxRegister* object, + gxValueEventArg* e) +{ + int ret = 0; + //Reset. + if (e->index == 1) + { + ret = var_clear(&object->value); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_REGISTER + +#ifndef DLMS_IGNORE_PROFILE_GENERIC +/* +* Copies the values of the objects to capture into the buffer by reading +* capture objects. +*/ +int capture(dlmsSettings* settings, + gxProfileGeneric* object) +{ +#ifdef DLMS_IGNORE_MALLOC + gxValueEventArg e; + gxValueEventCollection args; + ve_init(&e); + e.action = 1; + e.target = &object->base; + e.index = 2; + gxValueEventArg p[1] = { e }; + vec_attach(&args, p, 1, 1); + svr_preGet(settings, &args); + svr_postGet(settings, &args); + vec_empty(&args); +#else + int ret, pos; + gxKey* kv; + dlmsVARIANT* value; + variantArray* row; + gxValueEventArg e; + gxValueEventCollection args; + ve_init(&e); + e.action = 1; + e.target = &object->base; + e.index = 2; + vec_init(&args); + vec_push(&args, &e); + svr_preGet(settings, &args); + if (!e.handled) + { + gxValueEventArg e2; + ve_init(&e2); + row = (variantArray*)gxmalloc(sizeof(variantArray)); + va_init(row); + for (pos = 0; pos != object->captureObjects.size; ++pos) + { + ret = arr_getByIndex(&object->captureObjects, pos, (void**)&kv); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + e2.target = (gxObject*)kv->key; + e2.index = ((gxTarget*)kv->value)->attributeIndex; + if ((ret = cosem_getData(&e2)) != 0) + { + return ret; + } + value = (dlmsVARIANT*)gxmalloc(sizeof(dlmsVARIANT)); + var_init(value); + var_copy(value, &e.value); + va_push(row, value); + } + // Remove first item if buffer is full. + if (object->profileEntries == object->buffer.size) + { + variantArray* removedRow; + arr_removeByIndex(&object->buffer, 0, (void**)&removedRow); + va_clear(removedRow); + } + arr_push(&object->buffer, row); + object->entriesInUse = object->buffer.size; + } + svr_postGet(settings, &args); + vec_empty(&args); +#endif //DLMS_IGNORE_MALLOC + return 0; +} + +int invoke_ProfileGeneric( + dlmsServerSettings* settings, + gxProfileGeneric* object, + unsigned char index) +{ + int ret = 0; + //Reset. + if (index == 1) + { +#ifndef DLMS_IGNORE_MALLOC + ret = obj_clearProfileGenericBuffer(&object->buffer); +#endif //DLMS_IGNORE_MALLOC + } + //Capture. + else if (index == 2) + { + // Capture. + ret = capture(&settings->base, object); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_PROFILE_GENERIC + + +#ifndef DLMS_IGNORE_COMPACT_DATA +int compactDataAppend(unsigned char byteArray, dlmsVARIANT* value3, gxByteBuffer* bb) +{ + if (byteArray && value3->vt == DLMS_DATA_TYPE_OCTET_STRING) + { + if (bb_size(value3->byteArr) == 1) + { + bb_setUInt8(bb, 0); + } + else + { + bb_set(bb, value3->byteArr->data + 1, value3->byteArr->size - 1); + } + return 0; + } + int ret; + uint16_t startPos = (uint16_t)bb->size; + if ((ret = dlms_setData(bb, value3->vt, value3)) != 0) + { + return ret; + } + //If data is empty. + if (bb->size - startPos == 1) + { + bb_setUInt8(bb, 0); + } + else + { + ret = bb_move(bb, startPos + 1, startPos, bb->size - startPos - 1); + } + return 0; +} + +int compactDataAppendArray(dlmsVARIANT* value, gxByteBuffer* bb, uint16_t dataIndex) +{ + int ret, pos; + int cnt = value->Arr->size; + if (dataIndex != 0) + { + cnt = dataIndex; + --dataIndex; + } + dlmsVARIANT* value2; + for (pos = dataIndex; pos != cnt; ++pos) + { + if ((ret = va_getByIndex(value->Arr, pos, &value2)) != 0) + { + return ret; + } + if (value2->vt == DLMS_DATA_TYPE_STRUCTURE) + { + dlmsVARIANT* value3; + int pos1; + for (pos1 = 0; pos1 != value2->Arr->size; ++pos1) + { + if ((ret = va_getByIndex(value2->Arr, pos1, &value3)) != 0 || + (ret = compactDataAppend(0, value3, bb)) != 0) + { + return ret; + } + } + } + else + { + if ((ret = compactDataAppend(0, value2, bb)) != 0) + { + return ret; + } + } + } + return 0; +} + +/* +* Copies the values of the objects to capture into the buffer by reading +* capture objects. +*/ +int cosem_captureCompactData( + dlmsSettings* settings, + gxCompactData* object) +{ + int ret = 0; + uint16_t pos; +#ifdef DLMS_IGNORE_MALLOC + gxTarget* kv; +#else + gxKey* kv; +#endif //DLMS_IGNORE_MALLOC + gxValueEventArg e; + gxValueEventCollection args; + bb_clear(&object->buffer); + ve_init(&e); + e.action = 1; + e.target = &object->base; + e.index = 2; +#ifdef DLMS_IGNORE_MALLOC + //Allocate space where captured values are saved before they are added to the buffer. + // We can't use server buffer because there might be transaction on progress when this is called. + unsigned char tmp[MAX_CAPTURE_OBJECT_BUFFER_SIZE]; + gxByteBuffer bb; + bb_attach(&bb, tmp, 0, sizeof(tmp)); + gxValueEventArg p[1] = { e }; + vec_attach(&args, p, 1, 1); +#else + vec_init(&args); + vec_push(&args, &e); +#endif //DLMS_IGNORE_MALLOC + svr_preGet(settings, &args); + if (!e.handled) + { + uint16_t dataIndex; + for (pos = 0; pos != object->captureObjects.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + ret = arr_getByIndex(&object->captureObjects, pos, (void**)&kv, sizeof(gxTarget)); +#else + ret = arr_getByIndex(&object->captureObjects, pos, (void**)&kv); +#endif //DLMS_IGNORE_MALLOC + if (ret != DLMS_ERROR_CODE_OK) + { + bb_clear(&object->buffer); + break; + } +#ifdef DLMS_IGNORE_MALLOC + e.value.byteArr = &bb; + e.value.vt = DLMS_DATA_TYPE_OCTET_STRING; + e.target = kv->target; + e.index = kv->attributeIndex; + dataIndex = kv->dataIndex; +#else + e.target = (gxObject*)kv->key; + e.index = ((gxTarget*)kv->value)->attributeIndex; + dataIndex = ((gxTarget*)kv->value)->dataIndex; +#endif //DLMS_IGNORE_MALLOC + if ((ret = cosem_getValue(settings, &e)) != 0) + { + bb_clear(&object->buffer); + break; + } + if (e.byteArray && e.value.vt == DLMS_DATA_TYPE_OCTET_STRING) + { + gxDataInfo info; + dlmsVARIANT value; + di_init(&info); + var_init(&value); + if ((ret = dlms_getData(e.value.byteArr, &info, &value)) != 0) + { + var_clear(&value); + break; + } + if (value.vt == DLMS_DATA_TYPE_STRUCTURE || + value.vt == DLMS_DATA_TYPE_ARRAY) + { +#ifdef DLMS_ITALIAN_STANDARD + //Some meters require that there is a array count in data. + if (value.vt == DLMS_DATA_TYPE_ARRAY && object->appendAA) + { + bb_setUInt8(&object->buffer, (unsigned char)value.Arr->size); + } +#endif //DLMS_ITALIAN_STANDARD + if ((ret = compactDataAppendArray(&value, &object->buffer, dataIndex)) != 0) + { + var_clear(&value); + break; + } + } + else + { + if ((ret = compactDataAppend(1, &e.value, &object->buffer)) != 0) + { + var_clear(&value); + break; + } + } + var_clear(&value); + } + else if ((ret = compactDataAppend(0, &e.value, &object->buffer)) != 0) + { + break; + } + ve_clear(&e); + } + } + svr_postGet(settings, &args); + if (ret != 0) + { + bb_clear(&object->buffer); + } + vec_empty(&args); + return ret; +} + +int invoke_CompactData( + dlmsServerSettings* settings, + gxCompactData* object, + unsigned char index) +{ + int ret = 0; + //Reset. + if (index == 1) + { + ret = bb_clear(&object->buffer); + } + //Capture. + else if (index == 2) + { + // Capture. + ret = cosem_captureCompactData(&settings->base, object); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_COMPACT_DATA + +#ifndef DLMS_IGNORE_DISCONNECT_CONTROL +int invoke_DisconnectControl( + dlmsServerSettings* settings, + gxDisconnectControl* object, + unsigned char index) +{ + int ret = 0; + //Reset. + if (index == 1) + { + object->controlState = DLMS_CONTROL_STATE_DISCONNECTED; + object->outputState = 0; + } + //Capture. + else if (index == 2) + { + object->controlState = DLMS_CONTROL_STATE_CONNECTED; + object->outputState = 1; + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_DISCONNECT_CONTROL + +#ifndef DLMS_IGNORE_LLC_SSCS_SETUP +int invoke_LlcSscsSetup( + gxLlcSscsSetup* object, + unsigned char index) +{ + int ret = 0; + //Reset. + if (index == 1) + { + object->serviceNodeAddress = 0xFFE; + object->baseNodeAddress = 0; + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_LLC_SSCS_SETUP + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +int invoke_PrimeNbOfdmPlcPhysicalLayerCounters( + gxPrimeNbOfdmPlcPhysicalLayerCounters* object, + unsigned char index) +{ + int ret = 0; + //Reset. + if (index == 1) + { + object->crcIncorrectCount = object->crcFailedCount = object->txDropCount = object->rxDropCount = 0; + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +int invoke_PrimeNbOfdmPlcMacCounters( + gxPrimeNbOfdmPlcMacCounters* object, + unsigned char index) +{ + int ret = 0; + //Reset. + if (index == 1) + { + object->txDataPktCount = object->rxDataPktCount = object->txCtrlPktCount = object->rxCtrlPktCount = object->csmaFailCount = object->csmaChBusyCount = 0; + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA +int invoke_PrimeNbOfdmPlcMacNetworkAdministrationData( + gxPrimeNbOfdmPlcMacNetworkAdministrationData* object, + unsigned char index) +{ + int ret = 0; + //Reset. + if (index == 1) + { + arr_clear(&object->multicastEntries); + arr_empty(&object->switchTable); + arr_clear(&object->directTable); + obj_clearAvailableSwitches(&object->availableSwitches); + arr_clear(&object->communications); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + +#ifndef DLMS_IGNORE_SPECIAL_DAYS_TABLE +int invoke_SpecialDaysTable( + gxSpecialDaysTable* object, + gxValueEventArg* e) +{ + int ret = 0; + uint16_t pos, index; + gxSpecialDay* specialDay; + //Insert. + if (e->index == 1) + { + unsigned char append = 1; +#ifdef DLMS_IGNORE_MALLOC + if ((ret = cosem_checkStructure(e->parameters.byteArr, 3)) == 0 && + (ret = cosem_getUInt16(e->parameters.byteArr, &index)) == 0) + { + for (pos = 0; pos != object->entries.size; ++pos) + { + if ((ret = arr_getByIndex(&object->entries, object->entries.size - 1, (void**)&specialDay, sizeof(gxSpecialDay))) != 0) + { + break; + } + //Overwrite existing item. + if (specialDay->index == index) + { + if ((ret = cosem_getDateFromOctetString(e->parameters.byteArr, &specialDay->date)) != 0 || + (ret = cosem_getUInt8(e->parameters.byteArr, &specialDay->dayId)) != 0) + { + } + append = 0; + break; + } + } + if (ret == 0 && append) + { + ++object->entries.size; + if ((ret = arr_getByIndex(&object->entries, object->entries.size - 1, (void**)&specialDay, sizeof(gxSpecialDay))) != 0) + { + --object->entries.size; + } + else + { + specialDay->index = index; + if ((ret = cosem_getDateFromOctetString(e->parameters.byteArr, &specialDay->date)) != 0 || + (ret = cosem_getUInt8(e->parameters.byteArr, &specialDay->dayId)) != 0) + { + } + } + } + } +#else + dlmsVARIANT* tmp3; + dlmsVARIANT tmp2; + if (e->parameters.Arr != NULL) + { + ret = va_getByIndex(e->parameters.Arr, 0, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + index = (uint16_t)var_toInteger(tmp3); + for (pos = 0; pos != object->entries.size; ++pos) + { + if ((ret = arr_getByIndex(&object->entries, object->entries.size - 1, (void**)&specialDay)) != 0) + { + break; + } + //Overwrite existing item. + if (specialDay->index == index) + { + append = 0; + break; + } + } + if (append) + { + specialDay = (gxSpecialDay*)gxmalloc(sizeof(gxSpecialDay)); + if (specialDay == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + arr_push(&object->entries, specialDay); + } + specialDay->index = index; + ret = va_getByIndex(e->parameters.Arr, 1, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + var_init(&tmp2); + ret = dlms_changeType2(tmp3, DLMS_DATA_TYPE_DATE, &tmp2); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + time_copy(&specialDay->date, tmp2.dateTime); + var_clear(&tmp2); + ret = va_getByIndex(e->parameters.Arr, 2, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + specialDay->dayId = (unsigned char)var_toInteger(tmp3); + } +#endif //DLMS_IGNORE_MALLOC + } + //Remove. + else if (e->index == 2) + { + uint16_t pos, index = e->parameters.uiVal; + for (pos = 0; pos != object->entries.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->entries, pos, (void**)&specialDay, sizeof(gxSpecialDay))) != 0) +#else + if ((ret = arr_getByIndex(&object->entries, pos, (void**)&specialDay)) != 0) +#endif //DLMS_IGNORE_MALLOC + { + break; + } + if (specialDay->index == index) + { + //Remove item. +#ifdef DLMS_IGNORE_MALLOC + ret = arr_removeByIndex(&object->entries, pos, sizeof(gxSpecialDay)); +#else + ret = arr_removeByIndex(&object->entries, pos, NULL); +#endif //DLMS_IGNORE_MALLOC + break; + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SPECIAL_DAYS_TABLE + +#ifndef DLMS_IGNORE_REGISTER_ACTIVATION +int invoke_RegisterActivation( + dlmsServerSettings* settings, + gxRegisterActivation* object, + gxValueEventArg* e) +{ + int ret = 0; + uint16_t count; + gxRegisterActivationMask* k; + uint16_t pos; +#ifdef DLMS_IGNORE_OBJECT_POINTERS + gxObjectDefinition* it; +#else + gxObject* it; +#endif //DLMS_IGNORE_OBJECT_POINTERS + //Add Register. + if (e->index == 1) + { +#ifdef DLMS_IGNORE_MALLOC + uint16_t ot; + unsigned char ln[6]; +#if !(defined(DLMS_IGNORE_OBJECT_POINTERS) || defined(DLMS_IGNORE_MALLOC)) + uint16_t count = oa_getCapacity(&object->registerAssignment); +#else + count = arr_getCapacity(&object->registerAssignment); + if (!(object->registerAssignment.size < count)) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } +#endif //!(defined(DLMS_IGNORE_OBJECT_POINTERS) || defined(DLMS_IGNORE_MALLOC)) + if ((ret = cosem_checkStructure(e->parameters.byteArr, 2)) != 0 || +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getUInt16(e->parameters.byteArr, &ot)) != 0 || + (ret = cosem_getOctetString2(e->parameters.byteArr, ln, 6, NULL)) != 0) + { + return ret; + } + if ((ret = oa_findByLN(&settings->base.objects, (DLMS_OBJECT_TYPE)ot, ln, &it)) != 0) + { + return ret; + } + if (it == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + if ((ret = arr_setByIndexRef(&object->registerAssignment, (void**)it)) != 0) + { + return ret; + } +#endif //DLMS_IGNORE_OBJECT_POINTERS +#else + dlmsVARIANT* tmp, * tmp3; + if (e->parameters.Arr != NULL) + { + short type; + ret = va_getByIndex(e->parameters.Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = va_getByIndex(tmp->Arr, 0, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + type = var_toInteger(tmp3); + ret = va_getByIndex(tmp->Arr, 1, &tmp3); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + const unsigned char* ln = tmp3->byteArr->data; +#ifdef DLMS_IGNORE_OBJECT_POINTERS + it = (gxObjectDefinition*)gxmalloc(sizeof(gxObjectDefinition)); + it->objectType = (DLMS_OBJECT_TYPE)type; + memcpy(it->logicalName, ln, 6); +#else + if ((ret = oa_findByLN(&settings->base.objects, type, ln, &it)) != 0) + { + return ret; + } + if (it == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } +#endif //DLMS_IGNORE_OBJECT_POINTERS +#if !defined(DLMS_IGNORE_OBJECT_POINTERS) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + oa_push(&object->registerAssignment, it); +#else + arr_push(&object->registerAssignment, it); +#endif //DLMS_IGNORE_OBJECT_POINTERS + } +#ifdef DLMS_IGNORE_OBJECT_POINTERS + if (ret != 0 && objectDefinition != NULL) + { + gxfree(objectDefinition); + } +#endif //DLMS_IGNORE_OBJECT_POINTERS +#endif //DLMS_IGNORE_MALLOC + } + else if (e->index == 2) + { + count = arr_getCapacity(&object->maskList); + if (!(object->registerAssignment.size < count)) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + ++object->maskList.size; +#ifdef DLMS_IGNORE_MALLOC + uint16_t size; + if ((ret = cosem_checkStructure(e->parameters.byteArr, 2)) == 0 && + (ret = arr_getByIndex(&object->maskList, object->maskList.size - 1, (void**)&k, sizeof(gxRegisterActivationMask))) == 0 && + (ret = cosem_getOctetString2(e->parameters.byteArr, k->name, sizeof(k->name), &size)) == 0) + { + k->length = (unsigned char)size; + size = sizeof(k->indexes); + if ((ret = cosem_checkArray(e->parameters.byteArr, &size)) == 0) + { + k->count = (unsigned char)size; + for (pos = 0; pos != k->count; ++pos) + { + if ((ret = cosem_getUInt8(e->parameters.byteArr, &k->indexes[pos])) != 0) + { + break; + } + } + } + } +#else +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + //Remove mask. + else if (e->index == 3) + { + unsigned char ch; + if ((ret = bb_getUInt8(e->parameters.byteArr, &ch)) == 0) + { + if (ch != DLMS_DATA_TYPE_OCTET_STRING) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + else + { + uint16_t count; + if ((ret = hlp_getObjectCount2(e->parameters.byteArr, &count)) == 0) + { + for (pos = 0; pos != object->maskList.size; ++pos) + { + if ((ret = arr_getByIndex2(&object->maskList, pos, (void**)&k, sizeof(gxRegisterActivationMask))) != 0) + { + break; + } +#if defined(DLMS_IGNORE_MALLOC) + if (bb_available(e->parameters.byteArr) == k->length && + memcmp(k->name, e->parameters.byteArr->data + e->parameters.byteArr->position, count) == 0) + { + //arr_removeByIndex is decreasing amount already. + ret = arr_removeByIndex(&object->maskList, pos, sizeof(gxRegisterActivationMask)); + break; + } +#else + if (bb_available(e->parameters.byteArr) == k->name.size && + memcmp(k->name.data, e->parameters.byteArr->data + e->parameters.byteArr->position, count) == 0) + { + //arr_removeByIndex is decreasing amount already. + if ((ret = arr_removeByIndex(&object->maskList, pos, (void**)&k)) == 0) + { + bb_clear(&k->name); + bb_clear(&k->indexes); + gxfree(k); + } + break; + } +#endif //defined(DLMS_IGNORE_MALLOC) + e->parameters.byteArr->position += count; + } + } + } + } + bb_clear(e->parameters.byteArr); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_REGISTER_ACTIVATION + + +#ifndef DLMS_IGNORE_ACTIVITY_CALENDAR + +int invoke_copySeasonProfile(gxArray* target, gxArray* source) +{ + int ret = obj_clearSeasonProfile(target); + if (ret == 0) + { + int pos; + gxSeasonProfile* sp, * it; +#if defined(DLMS_IGNORE_MALLOC) + target->size = source->size; +#endif // + for (pos = 0; pos != source->size; ++pos) + { + if (ret == 0) + { + if ((ret = arr_getByIndex2(source, pos, (void**)&sp, sizeof(gxSeasonProfile))) != 0) + { + break; + } +#if defined(DLMS_IGNORE_MALLOC) + if ((ret = arr_getByIndex2(target, pos, (void**)&it, sizeof(gxSeasonProfile))) != 0) + { + break; + } + memcpy(&it->name, &sp->name, sizeof(gxSeasonProfileName)); + it->start = sp->start; + memcpy(&it->weekName, &sp->weekName, sizeof(gxSeasonProfileWeekName)); +#else + it = gxmalloc(sizeof(gxSeasonProfile)); + arr_push(target, it); + BYTE_BUFFER_INIT(&it->name); + BYTE_BUFFER_INIT(&it->weekName); + bb_set(&it->name, sp->name.data, sp->name.size); + it->start = sp->start; + bb_set(&it->weekName, sp->weekName.data, sp->weekName.size); +#endif //#if defined(DLMS_IGNORE_MALLOC) + } + } + } + return ret; +} + +int invoke_copyWeekProfileTable(gxArray* target, gxArray* source) +{ + int ret = obj_clearWeekProfileTable(target); + if (ret == 0) + { + int pos; + gxWeekProfile* wp, * it; +#if defined(DLMS_IGNORE_MALLOC) + target->size = source->size; +#endif // + for (pos = 0; pos != source->size; ++pos) + { + if (ret == 0) + { + if ((ret = arr_getByIndex2(source, pos, (void**)&wp, sizeof(gxWeekProfile))) != 0) + { + break; + } +#if defined(DLMS_IGNORE_MALLOC) + if ((ret = arr_getByIndex2(target, pos, (void**)&it, sizeof(gxWeekProfile))) != 0) + { + break; + } + memcpy(&it->name, &wp->name, sizeof(gxWeekProfileName)); +#else + it = gxmalloc(sizeof(gxWeekProfile)); + arr_push(target, it); + BYTE_BUFFER_INIT(&it->name); + bb_set(&it->name, wp->name.data, wp->name.size); +#endif //#if defined(DLMS_IGNORE_MALLOC) + it->monday = wp->monday; + it->tuesday = wp->tuesday; + it->wednesday = wp->wednesday; + it->thursday = wp->thursday; + it->friday = wp->friday; + it->saturday = wp->saturday; + it->sunday = wp->sunday; + } + } + } + return ret; +} + +int invoke_copyDayProfileTable(gxArray* target, gxArray* source) +{ + int ret = obj_clearDayProfileTable(target); + if (ret == 0) + { + int pos, pos2; + gxDayProfile* it, * it2; + gxDayProfileAction* dp, * dp2; +#if defined(DLMS_IGNORE_MALLOC) + target->size = source->size; +#endif // + for (pos = 0; pos != source->size; ++pos) + { + if (ret == 0) + { + if ((ret = arr_getByIndex2(source, pos, (void**)&it, sizeof(gxDayProfile))) != 0) + { + break; + } +#if defined(DLMS_IGNORE_MALLOC) + if ((ret = arr_getByIndex2(target, pos, (void**)&it2, sizeof(gxDayProfile))) != 0) + { + break; + } + it2->daySchedules.size = it->daySchedules.size; +#else + it2 = gxmalloc(sizeof(gxDayProfile)); + arr_push(target, it); +#endif //#if defined(DLMS_IGNORE_MALLOC) + it2->dayId = it->dayId; + for (pos2 = 0; pos2 != it->daySchedules.size; ++pos2) + { + if ((ret = arr_getByIndex2(&it->daySchedules, pos2, (void**)&dp, sizeof(gxDayProfileAction))) != DLMS_ERROR_CODE_OK) + { + break; + } +#if defined(DLMS_IGNORE_MALLOC) + if ((ret = arr_getByIndex2(&it2->daySchedules, pos2, (void**)&dp2, sizeof(gxDayProfileAction))) != DLMS_ERROR_CODE_OK) + { + break; + } +#else + dp2 = gxmalloc(sizeof(gxDayProfileAction)); + arr_push(&it2->daySchedules, dp2); +#endif //#if defined(DLMS_IGNORE_MALLOC) + dp2->startTime = dp->startTime; +#ifndef DLMS_IGNORE_OBJECT_POINTERS + dp2->script = dp->script; +#else + memcpy(dp2->scriptLogicalName, dp->scriptLogicalName, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + dp2->scriptSelector = dp->scriptSelector; + } + } + } + } + return ret; +} + +int invoke_ActivityCalendar(gxValueEventArg* e) +{ + int ret; + if (e->index == 1) + { + //Copy all passive items to active. + gxActivityCalendar* object = (gxActivityCalendar*)e->target; + bb_clear(&object->calendarNameActive); + if ((ret = bb_set(&object->calendarNameActive, object->calendarNamePassive.data, object->calendarNamePassive.size)) != 0 || + (ret = invoke_copyDayProfileTable(&object->dayProfileTableActive, &object->dayProfileTablePassive)) != 0 || + (ret = invoke_copyWeekProfileTable(&object->weekProfileTableActive, &object->weekProfileTablePassive)) != 0 || + (ret = invoke_copySeasonProfile(&object->seasonProfileActive, &object->seasonProfilePassive)) != 0) + { + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_ACTIVITY_CALENDAR + +#ifndef DLMS_IGNORE_ARRAY_MANAGER + +int invoke_ArrayManagerInsertEntry( + dlmsServerSettings* settings, + gxValueEventArg* e, uint16_t index) +{ + int ret; + uint16_t count, pos, totalCount; + uint16_t origPos = 0; + unsigned char ch; + dlmsVARIANT value; + gxDataInfo info; + di_init(&info); + var_init(&value); + //Move new data to the begin of the buffer. + ret = bb_move(e->value.byteArr, e->value.byteArr->position, 0, bb_available(e->value.byteArr)); + uint16_t newDataSize = (uint16_t)e->value.byteArr->size; + if ((ret = cosem_getValue(&settings->base, e)) == 0 && bb_size(e->value.byteArr) != 0) + { + if ((ret = bb_getUInt8(e->value.byteArr, &ch)) != 0 || + ch != DLMS_DATA_TYPE_ARRAY) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if ((ret = hlp_getObjectCount2(e->value.byteArr, &totalCount)) != 0) + { + return ret; + } + //Change index to zero-based. + count = (uint16_t)e->value.byteArr->size; + e->value.byteArr->size = newDataSize + 1; + if ((ret = hlp_setObjectCount(1 + totalCount, e->value.byteArr)) != 0) + { + return ret; + } + totalCount = 0; + //Return original size. + e->value.byteArr->size = count; + for (pos = (uint16_t)e->value.byteArr->position; pos != bb_size(e->value.byteArr); ++pos) + { + //Get data type. + if ((ret = bb_getUInt8ByIndex(e->value.byteArr, e->value.byteArr->position, &ch)) != 0) + { + break; + } + if (ch == DLMS_DATA_TYPE_ARRAY || ch == DLMS_DATA_TYPE_STRUCTURE) + { + if (index == 0) + { + //Save start position. + origPos = (uint16_t)e->value.byteArr->position; + } + ++e->value.byteArr->position; + if ((ret = hlp_getObjectCount2(e->value.byteArr, &count)) != 0) + { + break; + } + totalCount += 1 + count; + } + else + { + if ((ret = dlms_getData(e->value.byteArr, &info, &value)) != 0) + { + var_clear(&value); + break; + } +#ifdef DLMS_IGNORE_MALLOC + if (value.vt == DLMS_DATA_TYPE_OCTET_STRING) + { + ++e->value.byteArr->position; + if ((ret = hlp_getObjectCount2(e->value.byteArr, &count)) != 0) + { + var_clear(&value); + break; + } + if (e->value.byteArr->size < e->value.byteArr->position + count) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + var_clear(&value); + break; + } + e->value.byteArr->position += count; + } +#endif //DLMS_IGNORE_MALLOC + di_init(&info); + var_clear(&value); + } + --totalCount; + if (index == 0 && totalCount == 0) + { + if (bb_available(e->value.byteArr) == 0) + { + //Move first item to last. + ret = bb_move(e->value.byteArr, 0, e->value.byteArr->size, newDataSize); + //Move all items to begin. + ret = bb_move(e->value.byteArr, newDataSize, 0, e->value.byteArr->size - newDataSize); + e->value.byteArr->position = 0; + ret = cosem_setValue(&settings->base, e); + bb_clear(e->value.byteArr); + break; + } + else if (index == 0) + { + //Make space for the new item. + ret = bb_move(e->value.byteArr, origPos, + origPos + newDataSize, e->value.byteArr->size - newDataSize); + //Move new item to new location. + totalCount = (uint16_t)e->value.byteArr->size; + ret = bb_move(e->value.byteArr, 0, origPos, newDataSize); + e->value.byteArr->size = totalCount; + //Move all items to first. + ret = bb_move(e->value.byteArr, newDataSize, 0, e->value.byteArr->size - newDataSize); + e->value.byteArr->position = 0; +#ifdef DLMS_IGNORE_MALLOC + ret = cosem_setValue(&settings->base, e); + bb_clear(e->value.byteArr); +#else + gxByteBuffer* bb = e->value.byteArr; + e->value.vt = DLMS_DATA_TYPE_NONE; + if ((ret = dlms_getData(e->value.byteArr, &info, &e->value))) + { + bb_clear(bb); + var_clear(&value); + break; + } + bb_clear(bb); + if ((ret = cosem_setValue(&settings->base, e)) != 0) + { + var_clear(&value); + break; + } +#endif //DLMS_IGNORE_MALLOC + break; + } + --index; + } + } + } + return ret; +} + +int invoke_ArrayManagerDeleteEntry( + dlmsServerSettings* settings, + gxValueEventArg* e, + uint16_t from, uint16_t to) +{ + int ret; + uint16_t count, pos, totalCount; + uint16_t origPos = 0; + unsigned char ch; + dlmsVARIANT value; + gxDataInfo info; + di_init(&info); + var_init(&value); + if ((ret = cosem_getValue(&settings->base, e)) == 0 && bb_size(e->value.byteArr) != 0) + { + if ((ret = bb_getUInt8(e->value.byteArr, &ch)) != 0 || + ch != DLMS_DATA_TYPE_ARRAY) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if ((ret = hlp_getObjectCount2(e->value.byteArr, &totalCount)) != 0) + { + return ret; + } + //Change from to zero-based. + --from; + if (to - from < totalCount) + { + totalCount -= to - from; + } + else + { + totalCount = from; + to = from + 1; + } + count = (uint16_t)e->value.byteArr->size; + e->value.byteArr->size = 1; + if ((ret = hlp_setObjectCount(totalCount, e->value.byteArr)) != 0) + { + return ret; + } + totalCount = 0; + //Return original size. + e->value.byteArr->size = count; + for (pos = (uint16_t)e->value.byteArr->position; pos != bb_size(e->value.byteArr); ++pos) + { + //Get data type. + if ((ret = bb_getUInt8ByIndex(e->value.byteArr, e->value.byteArr->position, &ch)) != 0) + { + break; + } + if (ch == DLMS_DATA_TYPE_ARRAY || ch == DLMS_DATA_TYPE_STRUCTURE) + { + if (from == 0) + { + //Save start position. + origPos = (uint16_t)e->value.byteArr->position; + } + ++e->value.byteArr->position; + if ((ret = hlp_getObjectCount2(e->value.byteArr, &count)) != 0) + { + break; + } + totalCount += 1 + count; + } + else + { + if ((ret = dlms_getData(e->value.byteArr, &info, &value)) != 0) + { + var_clear(&value); + break; + } +#ifdef DLMS_IGNORE_MALLOC + if (value.vt == DLMS_DATA_TYPE_OCTET_STRING) + { + ++e->value.byteArr->position; + if ((ret = hlp_getObjectCount2(e->value.byteArr, &count)) != 0) + { + break; + } + if (e->value.byteArr->size < e->value.byteArr->position + count) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + e->value.byteArr->position += count; + } +#endif //DLMS_IGNORE_MALLOC + di_init(&info); + var_clear(&value); + } + --totalCount; + if (totalCount == 0) + { + --to; + if (to == 0) + { + ret = bb_move(e->value.byteArr, e->value.byteArr->position, origPos, + bb_available(e->value.byteArr)); + e->value.byteArr->position = 0; + ret = cosem_setValue(&settings->base, e); + bb_clear(e->value.byteArr); + break; + } + --from; + } + } + } + return ret; +} + +int invoke_ArrayManager( + dlmsServerSettings* settings, + gxValueEventArg* e) +{ + int pos, ret = 0; + gxArrayManagerItem* it; + gxArrayManager* object = (gxArrayManager*)e->target; + unsigned char ch, found = 0; + uint16_t count, totalCount; + dlmsVARIANT tmp; + dlmsVARIANT value; + gxDataInfo info; +#ifndef DLMS_IGNORE_MALLOC + dlmsVARIANT* tmp2, * tmp3; + e->value.byteArr = &settings->info.data; +#endif//DLMS_IGNORE_MALLOC + e->byteArray = 1; + unsigned char id; + uint16_t index = 0, from = 0, to = 0, origSize, origPos = 0; + if (e->index == 1) + { + id = e->parameters.bVal; + bb_clear(e->value.byteArr); + } + else if (e->index == 3 || e->index == 4) + { + //Insert or update entry. +#ifdef DLMS_IGNORE_MALLOC + if ((ret = cosem_getStructure(e->parameters.byteArr, &count)) != 0 || + (ret = cosem_getUInt8(e->parameters.byteArr, &id)) != 0 || + (ret = cosem_getStructure(e->parameters.byteArr, &count)) != 0 || + (ret = cosem_getUInt16(e->parameters.byteArr, &index)) != 0) + { + return ret; + } +#else + if ((ret = va_getByIndex(e->parameters.Arr, 0, &tmp2)) != 0) + { + return ret; + } + id = tmp2->bVal; + if ((ret = va_getByIndex(e->parameters.Arr, 1, &tmp3)) != 0) + { + return ret; + } + if ((ret = va_getByIndex(tmp3->Arr, 0, &tmp2)) != 0) + { + return ret; + } + from = tmp2->uiVal; + if ((ret = va_getByIndex(tmp3->Arr, 1, &tmp2)) != 0) + { + return ret; + } + to = tmp2->uiVal; +#endif //DLMS_IGNORE_MALLOC + } + else + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = cosem_getStructure(e->parameters.byteArr, &count)) != 0 || + (ret = cosem_getUInt8(e->parameters.byteArr, &id)) != 0 || + (ret = cosem_getStructure(e->parameters.byteArr, &count)) != 0 || + (ret = cosem_getUInt16(e->parameters.byteArr, &from)) != 0 || + (ret = cosem_getUInt16(e->parameters.byteArr, &to)) != 0) + { + return ret; + } +#else + if ((ret = va_getByIndex(e->parameters.Arr, 0, &tmp2)) != 0) + { + return ret; + } + id = tmp2->bVal; + if ((ret = va_getByIndex(e->parameters.Arr, 1, &tmp3)) != 0) + { + return ret; + } + if ((ret = va_getByIndex(tmp3->Arr, 0, &tmp2)) != 0) + { + return ret; + } + from = tmp2->uiVal; + if ((ret = va_getByIndex(tmp3->Arr, 1, &tmp2)) != 0) + { + return ret; + } + to = tmp2->uiVal; +#endif //DLMS_IGNORE_MALLOC + bb_clear(e->value.byteArr); + } + for (pos = 0; pos != object->elements.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + ret = arr_getByIndex(&object->elements, pos, (void**)&it, sizeof(gxArrayManagerItem)); +#else + ret = arr_getByIndex(&object->elements, pos, (void**)&it); +#endif //DLMS_IGNORE_MALLOC + if (ret != 0) + { + break; + } + if (it->id == id) + { + if (e->index == 1) + { + //Number Of Entries. + if (it->element.target->objectType == DLMS_OBJECT_TYPE_PROFILE_GENERIC + && it->element.attributeIndex == 2) + { + //Entries in use is returned when buffer size is asked. + GX_UINT32(tmp) = ((gxProfileGeneric*)it->element.target)->entriesInUse; + } + else + { + e->index = it->element.attributeIndex; + e->target = it->element.target; + if ((ret = cosem_getValue(&settings->base, e)) != 0 || + (ret = bb_getUInt8(e->value.byteArr, &ch)) != 0) + { + break; + } + if (ch != DLMS_DATA_TYPE_ARRAY) + { + ret = DLMS_ERROR_CODE_READ_WRITE_DENIED; + break; + } + if (hlp_getObjectCount2(e->value.byteArr, &count) != 0) + { + break; + } + if (count < 0x100) + { + GX_UINT8(tmp) = (unsigned char)count; + } + else + { + GX_UINT16(tmp) = count; + } + } + bb_clear(e->value.byteArr); + if ((ret = dlms_setData(e->value.byteArr, tmp.vt, &tmp)) != 0) + { + break; + } + found = 1; + break; + } + else if (e->index == 2) + { + //Retrieve entries. + if (it->element.target->objectType == DLMS_OBJECT_TYPE_PROFILE_GENERIC) + { + + } + if (!found) + { + di_init(&info); + var_init(&value); + e->index = it->element.attributeIndex; + e->target = it->element.target; + if ((ret = cosem_getValue(&settings->base, e)) == 0 && bb_size(e->value.byteArr) != 0) + { + if ((ret = bb_getUInt8(e->value.byteArr, &ch)) != 0 || + ch != DLMS_DATA_TYPE_ARRAY) + { + break; + } + if ((ret = hlp_getObjectCount2(e->value.byteArr, &totalCount)) != 0) + { + break; + } + //Change from to zero-based. + --from; + if (to - from < totalCount) + { + totalCount = to - from; + } + else if (totalCount < to) + { + if (totalCount == 0) + { + to = 1; + } + else + { + to = totalCount; + } + } + count = (uint16_t)e->value.byteArr->size; + e->value.byteArr->size = 1; + if ((ret = hlp_setObjectCount(totalCount, e->value.byteArr)) != 0) + { + break; + } + totalCount = 0; + origSize = (uint16_t)e->value.byteArr->size; + //Return original size. + e->value.byteArr->size = count; + for (pos = e->value.byteArr->position; pos != bb_size(e->value.byteArr); ++pos) + { + //Get data type. + if ((ret = bb_getUInt8ByIndex(e->value.byteArr, e->value.byteArr->position, &ch)) != 0) + { + break; + } + if (ch == DLMS_DATA_TYPE_ARRAY || ch == DLMS_DATA_TYPE_STRUCTURE) + { + if (from == 0) + { + //Save start position. + origPos = (uint16_t)e->value.byteArr->position; + } + ++e->value.byteArr->position; + if ((ret = hlp_getObjectCount2(e->value.byteArr, &count)) != 0) + { + break; + } + totalCount += 1 + count; + } + else + { + if ((ret = dlms_getData(e->value.byteArr, &info, &value)) != 0) + { + var_clear(&value); + break; + } +#ifdef DLMS_IGNORE_MALLOC + if (value.vt == DLMS_DATA_TYPE_OCTET_STRING) + { + ++e->value.byteArr->position; + if ((ret = hlp_getObjectCount2(e->value.byteArr, &count)) != 0) + { + break; + } + if (e->value.byteArr->size < e->value.byteArr->position + count) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + e->value.byteArr->position += count; + } +#endif //DLMS_IGNORE_MALLOC + + di_init(&info); + var_clear(&value); + } + --totalCount; + if (totalCount == 0) + { + --to; + if (to == 0) + { + ret = bb_move(e->value.byteArr, origPos, + origSize, e->value.byteArr->position - origPos); + e->value.byteArr->position = 0; + break; + } + --from; + } + } + found = 1; + break; + } + } + break; + } + else if (e->index == 3) + { + e->index = it->element.attributeIndex; + e->target = it->element.target; + ret = invoke_ArrayManagerInsertEntry(settings, e, index); + found = 1; + break; + } + else if (e->index == 4) + { + e->index = it->element.attributeIndex; + e->target = it->element.target; + ret = invoke_ArrayManagerDeleteEntry(settings, e, index, index); + ret = invoke_ArrayManagerInsertEntry(settings, e, index); + found = 1; + break; + } + else if (e->index == 5) + { + e->index = it->element.attributeIndex; + e->target = it->element.target; + ret = invoke_ArrayManagerDeleteEntry(settings, e, from, to); + found = 1; + break; + } + } + } + if (!found) + { + bb_clear(e->value.byteArr); + ret = DLMS_ERROR_CODE_READ_WRITE_DENIED; + } + return ret; +} +#endif //DLMS_IGNORE_ARRAY_MANAGER + +#ifndef DLMS_IGNORE_G3_PLC_MAC_SETUP +int invoke_G3_PLC_MAC_Setup( + dlmsServerSettings* settings, + gxG3PlcMacSetup* object, + gxValueEventArg* e) +{ + uint16_t address, pos, count = 0; + int ret = 0; + e->byteArray = 1; + bb_clear(&settings->info.data); + e->value.byteArr = &settings->info.data; + if (e->parameters.vt != DLMS_DATA_TYPE_UINT16) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + address = e->parameters.uiVal; + if (e->index == 1) + { + //Get amount of neighbour tables. + gxNeighbourTable* it; + for (pos = 0; pos < (uint16_t)object->neighbourTable.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->neighbourTable, pos, (void**)&it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->neighbourTable, pos, + (void**)&it, sizeof(gxNeighbourTable))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if (it->shortAddress == address) + { + ++count; + } + } + if (ret == 0) + { + return cosem_getG3PlcMacSetupNeighbourTables(&object->neighbourTable, address, count, e); + } + } + else if (e->index == 2) + { + gxMacPosTable* it; + //Get amount of MAC POS tables. + for (pos = 0; pos < object->macPosTable.size; ++pos) + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex(&object->macPosTable, pos, (void**)&it)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->macPosTable, pos, (void**)&it, sizeof(gxMacPosTable))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if (it->shortAddress == address) + { + ++count; + } + } + if (ret == 0) + { + return cosem_getG3PlcMacSetupPosTables(&object->macPosTable, address, count, e); + } + } + bb_clear(e->value.byteArr); + return DLMS_ERROR_CODE_READ_WRITE_DENIED; +} +#endif //DLMS_IGNORE_G3_PLC_MAC_SETUP + +int cosem_invoke( + dlmsServerSettings* settings, + gxValueEventArg* e) +{ + int ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + //If invoke index is invalid. + if (e->index < 1 || e->index > obj_methodCount(e->target)) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + switch (e->target->objectType) + { +#ifndef DLMS_IGNORE_REGISTER + case DLMS_OBJECT_TYPE_REGISTER: + ret = invoke_Register( + (gxRegister*)e->target, + e); + break; +#endif //DLMS_IGNORE_REGISTER +#ifndef DLMS_IGNORE_CLOCK + case DLMS_OBJECT_TYPE_CLOCK: + ret = invoke_Clock( + (gxClock*)e->target, + e->index, &e->parameters); + break; +#endif //DLMS_IGNORE_CLOCK +#ifndef DLMS_IGNORE_EXTENDED_REGISTER + case DLMS_OBJECT_TYPE_EXTENDED_REGISTER: + ret = invoke_ExtendedRegister(settings, + (gxExtendedRegister*)e->target, + e->index); + break; +#endif //DLMS_IGNORE_EXTENDED_REGISTER +#ifndef DLMS_IGNORE_DEMAND_REGISTER + case DLMS_OBJECT_TYPE_DEMAND_REGISTER: + ret = invoke_DemandRegister(settings, + (gxDemandRegister*)e->target, + e->index); + break; +#endif //DLMS_IGNORE_DEMAND_REGISTER +#ifndef DLMS_IGNORE_PROFILE_GENERIC + case DLMS_OBJECT_TYPE_PROFILE_GENERIC: + ret = invoke_ProfileGeneric( + settings, + (gxProfileGeneric*)e->target, + e->index); + break; +#endif //DLMS_IGNORE_PROFILE_GENERIC +#ifndef DLMS_IGNORE_SCRIPT_TABLE + case DLMS_OBJECT_TYPE_SCRIPT_TABLE: + ret = invoke_ScriptTable(settings, e); + break; +#endif //DLMS_IGNORE_SCRIPT_TABLE +#ifndef DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL + case DLMS_OBJECT_TYPE_ZIG_BEE_NETWORK_CONTROL: + ret = invoke_zigbeeNetworkControl( + (gxZigBeeNetworkControl*)e->target, + e->index, + &e->parameters); + break; +#endif //DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL +#ifndef DLMS_IGNORE_CHARGE + case DLMS_OBJECT_TYPE_CHARGE: + ret = invoke_Charge( + (gxCharge*)e->target, + e->index, + &e->parameters); + break; +#endif //DLMS_IGNORE_CHARGE +#ifndef DLMS_IGNORE_CREDIT + case DLMS_OBJECT_TYPE_CREDIT: + ret = invoke_Credit( + (gxCredit*)e->target, + e->index, + &e->parameters); + break; +#endif //DLMS_IGNORE_CREDIT +#ifndef DLMS_IGNORE_TOKEN_GATEWAY + case DLMS_OBJECT_TYPE_TOKEN_GATEWAY: + ret = invoke_gxTokenGateway( + (gxTokenGateway*)e->target, + e->index, + &e->parameters); + break; +#endif //DLMS_IGNORE_TOKEN_GATEWAY +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + case DLMS_OBJECT_TYPE_ASSOCIATION_SHORT_NAME: +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + ret = invoke_AssociationShortName(settings, e); +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + break; +#endif //ASSOCIATION_SHORT_NAME +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + case DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME: + ret = invoke_AssociationLogicalName(settings, e); + break; +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME +#ifndef DLMS_IGNORE_IMAGE_TRANSFER + case DLMS_OBJECT_TYPE_IMAGE_TRANSFER: + ret = invoke_ImageTransfer((gxImageTransfer*)e->target, e); + break; +#endif //DLMS_IGNORE_IMAGE_TRANSFER +#ifndef DLMS_IGNORE_SAP_ASSIGNMENT + case DLMS_OBJECT_TYPE_SAP_ASSIGNMENT: + ret = invoke_SapAssigment((gxSapAssignment*)e->target, e); + break; +#endif //DLMS_IGNORE_SAP_ASSIGNMENT +#ifndef DLMS_IGNORE_SECURITY_SETUP + case DLMS_OBJECT_TYPE_SECURITY_SETUP: + ret = invoke_SecuritySetup(settings, (gxSecuritySetup*)e->target, e); + break; +#endif //DLMS_IGNORE_SECURITY_SETUP +#ifndef DLMS_IGNORE_COMPACT_DATA + case DLMS_OBJECT_TYPE_COMPACT_DATA: + ret = invoke_CompactData(settings, (gxCompactData*)e->target, e->index); + break; +#endif //DLMS_IGNORE_COMPACT_DATA +#ifndef DLMS_IGNORE_DISCONNECT_CONTROL + case DLMS_OBJECT_TYPE_DISCONNECT_CONTROL: + ret = invoke_DisconnectControl(settings, (gxDisconnectControl*)e->target, e->index); + break; +#endif //DLMS_IGNORE_DISCONNECT_CONTROL +#ifndef DLMS_IGNORE_LLC_SSCS_SETUP + case DLMS_OBJECT_TYPE_LLC_SSCS_SETUP: + ret = invoke_LlcSscsSetup((gxLlcSscsSetup*)e->target, e->index); + break; +#endif //DLMS_IGNORE_LLC_SSCS_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS: + ret = invoke_PrimeNbOfdmPlcPhysicalLayerCounters((gxPrimeNbOfdmPlcPhysicalLayerCounters*)e->target, e->index); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_COUNTERS: + ret = invoke_PrimeNbOfdmPlcMacCounters((gxPrimeNbOfdmPlcMacCounters*)e->target, e->index); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA: + ret = invoke_PrimeNbOfdmPlcMacNetworkAdministrationData((gxPrimeNbOfdmPlcMacNetworkAdministrationData*)e->target, e->index); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA +#ifndef DLMS_IGNORE_SPECIAL_DAYS_TABLE + case DLMS_OBJECT_TYPE_SPECIAL_DAYS_TABLE: + ret = invoke_SpecialDaysTable((gxSpecialDaysTable*)e->target, e); + break; +#endif //DLMS_IGNORE_SPECIAL_DAYS_TABLE +#ifndef DLMS_IGNORE_REGISTER_ACTIVATION + case DLMS_OBJECT_TYPE_REGISTER_ACTIVATION: + ret = invoke_RegisterActivation(settings, (gxRegisterActivation*)e->target, e); + break; +#endif //DLMS_IGNORE_REGISTER_ACTIVATION +#ifndef DLMS_IGNORE_ACTIVITY_CALENDAR + case DLMS_OBJECT_TYPE_ACTIVITY_CALENDAR: + ret = invoke_ActivityCalendar(e); + break; +#endif //DLMS_IGNORE_ACTIVITY_CALENDAR +#ifndef DLMS_IGNORE_ARRAY_MANAGER + case DLMS_OBJECT_TYPE_ARRAY_MANAGER: + ret = invoke_ArrayManager(settings, e); + break; +#endif //DLMS_IGNORE_ARRAY_MANAGER +#ifndef DLMS_IGNORE_G3_PLC_MAC_SETUP + case DLMS_OBJECT_TYPE_G3_PLC_MAC_SETUP: + ret = invoke_G3_PLC_MAC_Setup(settings, (gxG3PlcMacSetup*)e->target, e); + break; +#endif //DLMS_IGNORE_G3_PLC_MAC_SETUP + default: + //Unknown type. + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SERVER diff --git a/components/xt211/unused/gxinvoke.h b/components/xt211/unused/gxinvoke.h new file mode 100644 index 0000000..86afcfb --- /dev/null +++ b/components/xt211/unused/gxinvoke.h @@ -0,0 +1,70 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef COSEM_INVOKE_H +#define COSEM_INVOKE_H + +//#ifdef __cplusplus +//extern "C" { +//#endif +#include "gxignore.h" +#ifndef DLMS_IGNORE_SERVER + +#include "gxobjects.h" +#include "dlmssettings.h" + + int cosem_invoke( + dlmsServerSettings* settings, + gxValueEventArg* e); + +#ifndef DLMS_IGNORE_COMPACT_DATA + /* + * Copies the values of the objects to capture into the buffer by reading + * capture objects. + */ + int cosem_captureCompactData( + dlmsSettings* settings, + gxCompactData* object); +#endif //DLMS_IGNORE_COMPACT_DATA + +#ifndef DLMS_IGNORE_SCRIPT_TABLE + int invoke_ScriptTable( + dlmsServerSettings* settings, + gxValueEventArg* e); +#endif //DLMS_IGNORE_SCRIPT_TABLE + +//#ifdef __cplusplus +//} +//#endif +#endif //DLMS_IGNORE_SERVER + +#endif //COSEM_INVOKE_H diff --git a/components/xt211/unused/gxmd5.c b/components/xt211/unused/gxmd5.c new file mode 100644 index 0000000..bddb977 --- /dev/null +++ b/components/xt211/unused/gxmd5.c @@ -0,0 +1,264 @@ +// +// -------------------------------------------------------------------------- +// 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" +#ifndef DLMS_IGNORE_HIGH_MD5 +#include +#include "gxmd5.h" + +unsigned int gxmd5_F(unsigned int x, unsigned int y, unsigned int z) +{ + return (x & y) | (~x & z); +} + +unsigned int gxmd5_G(unsigned int x, unsigned int y, unsigned int z) +{ + return (x & z) | (y & ~z); +} + +unsigned int gxmd5_H(unsigned int x, unsigned int y, unsigned int z) +{ + return x ^ y ^ z; +} + +unsigned int gxmd5_I(uint32_t x, uint32_t y, uint32_t z) +{ + return y ^ (x | ~z); +} + +unsigned int gxmd5_rotate_left(unsigned int x, int n) +{ + return (x << n) | (x >> (32 - n)); +} + +void gxmd5_FF(uint32_t* a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac) +{ + *a = gxmd5_rotate_left(*a + gxmd5_F(b, c, d) + x + ac, s) + b; +} + +void gxmd5_GG(uint32_t* a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac) { + *a = gxmd5_rotate_left(*a + gxmd5_G(b, c, d) + x + ac, s) + b; +} + +void gxmd5_HH(uint32_t* a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac) { + *a = gxmd5_rotate_left(*a + gxmd5_H(b, c, d) + x + ac, s) + b; +} + +void gxmd5_II(uint32_t* a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac) { + *a = gxmd5_rotate_left(*a + gxmd5_I(b, c, d) + x + ac, s) + b; +} + +void gxmd5_decode(uint32_t* output, unsigned char* input, unsigned int len) +{ + unsigned int i, j; + for (i = 0, j = 0; j < len; i++, j += 4) + { + output[i] = (input[j]) | (((uint32_t)input[j + 1]) << 8) | + (((uint32_t)input[j + 2]) << 16) | (((uint32_t)input[j + 3]) << 24); + } +} + +void gxmd5_encode(unsigned char* output, uint32_t* input, unsigned int len) +{ + unsigned int i, pos = 0; + for (i = 0; i != len; ++i) + { + output[pos] = input[i] & 0xff; + ++pos; + output[pos] = (input[i] >> 8) & 0xff; + ++pos; + output[pos] = (input[i] >> 16) & 0xff; + ++pos; + output[pos] = (input[i] >> 24) & 0xff; + ++pos; + } +} + +void gxmd5_transform(unsigned char* block, uint32_t* state) +{ + uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + gxmd5_decode(x, block, 64); + + /* Round 1 */ + gxmd5_FF(&a, b, c, d, x[0], S11, 0xd76aa478); + gxmd5_FF(&d, a, b, c, x[1], S12, 0xe8c7b756); + gxmd5_FF(&c, d, a, b, x[2], S13, 0x242070db); + gxmd5_FF(&b, c, d, a, x[3], S14, 0xc1bdceee); + gxmd5_FF(&a, b, c, d, x[4], S11, 0xf57c0faf); + gxmd5_FF(&d, a, b, c, x[5], S12, 0x4787c62a); + gxmd5_FF(&c, d, a, b, x[6], S13, 0xa8304613); + gxmd5_FF(&b, c, d, a, x[7], S14, 0xfd469501); + gxmd5_FF(&a, b, c, d, x[8], S11, 0x698098d8); + gxmd5_FF(&d, a, b, c, x[9], S12, 0x8b44f7af); + gxmd5_FF(&c, d, a, b, x[10], S13, 0xffff5bb1); + gxmd5_FF(&b, c, d, a, x[11], S14, 0x895cd7be); + gxmd5_FF(&a, b, c, d, x[12], S11, 0x6b901122); + gxmd5_FF(&d, a, b, c, x[13], S12, 0xfd987193); + gxmd5_FF(&c, d, a, b, x[14], S13, 0xa679438e); + gxmd5_FF(&b, c, d, a, x[15], S14, 0x49b40821); + + /* Round 2 */ + gxmd5_GG(&a, b, c, d, x[1], S21, 0xf61e2562); + gxmd5_GG(&d, a, b, c, x[6], S22, 0xc040b340); + gxmd5_GG(&c, d, a, b, x[11], S23, 0x265e5a51); + gxmd5_GG(&b, c, d, a, x[0], S24, 0xe9b6c7aa); + gxmd5_GG(&a, b, c, d, x[5], S21, 0xd62f105d); + gxmd5_GG(&d, a, b, c, x[10], S22, 0x2441453); + gxmd5_GG(&c, d, a, b, x[15], S23, 0xd8a1e681); + gxmd5_GG(&b, c, d, a, x[4], S24, 0xe7d3fbc8); + gxmd5_GG(&a, b, c, d, x[9], S21, 0x21e1cde6); + gxmd5_GG(&d, a, b, c, x[14], S22, 0xc33707d6); + gxmd5_GG(&c, d, a, b, x[3], S23, 0xf4d50d87); + gxmd5_GG(&b, c, d, a, x[8], S24, 0x455a14ed); + gxmd5_GG(&a, b, c, d, x[13], S21, 0xa9e3e905); + gxmd5_GG(&d, a, b, c, x[2], S22, 0xfcefa3f8); + gxmd5_GG(&c, d, a, b, x[7], S23, 0x676f02d9); + gxmd5_GG(&b, c, d, a, x[12], S24, 0x8d2a4c8a); + + /* Round 3 */ + gxmd5_HH(&a, b, c, d, x[5], S31, 0xfffa3942); + gxmd5_HH(&d, a, b, c, x[8], S32, 0x8771f681); + gxmd5_HH(&c, d, a, b, x[11], S33, 0x6d9d6122); + gxmd5_HH(&b, c, d, a, x[14], S34, 0xfde5380c); + gxmd5_HH(&a, b, c, d, x[1], S31, 0xa4beea44); + gxmd5_HH(&d, a, b, c, x[4], S32, 0x4bdecfa9); + gxmd5_HH(&c, d, a, b, x[7], S33, 0xf6bb4b60); + gxmd5_HH(&b, c, d, a, x[10], S34, 0xbebfbc70); + gxmd5_HH(&a, b, c, d, x[13], S31, 0x289b7ec6); + gxmd5_HH(&d, a, b, c, x[0], S32, 0xeaa127fa); + gxmd5_HH(&c, d, a, b, x[3], S33, 0xd4ef3085); + gxmd5_HH(&b, c, d, a, x[6], S34, 0x4881d05); + gxmd5_HH(&a, b, c, d, x[9], S31, 0xd9d4d039); + gxmd5_HH(&d, a, b, c, x[12], S32, 0xe6db99e5); + gxmd5_HH(&c, d, a, b, x[15], S33, 0x1fa27cf8); + gxmd5_HH(&b, c, d, a, x[2], S34, 0xc4ac5665); + + /* Round 4 */ + gxmd5_II(&a, b, c, d, x[0], S41, 0xf4292244); + gxmd5_II(&d, a, b, c, x[7], S42, 0x432aff97); + gxmd5_II(&c, d, a, b, x[14], S43, 0xab9423a7); + gxmd5_II(&b, c, d, a, x[5], S44, 0xfc93a039); + gxmd5_II(&a, b, c, d, x[12], S41, 0x655b59c3); + gxmd5_II(&d, a, b, c, x[3], S42, 0x8f0ccc92); + gxmd5_II(&c, d, a, b, x[10], S43, 0xffeff47d); + gxmd5_II(&b, c, d, a, x[1], S44, 0x85845dd1); + gxmd5_II(&a, b, c, d, x[8], S41, 0x6fa87e4f); + gxmd5_II(&d, a, b, c, x[15], S42, 0xfe2ce6e0); + gxmd5_II(&c, d, a, b, x[6], S43, 0xa3014314); + gxmd5_II(&b, c, d, a, x[13], S44, 0x4e0811a1); + gxmd5_II(&a, b, c, d, x[4], S41, 0xf7537e82); + gxmd5_II(&d, a, b, c, x[11], S42, 0xbd3af235); + gxmd5_II(&c, d, a, b, x[2], S43, 0x2ad7d2bb); + gxmd5_II(&b, c, d, a, x[9], S44, 0xeb86d391); + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; +} + +int gxmd5_update(unsigned char* data, uint32_t len, unsigned char* buffer, uint32_t* count, uint32_t* state) +{ + unsigned int i; + // Number of bytes. + unsigned int index = count[0] / 8 % 64; + + // Update number of bits + if ((count[0] += (len << 3)) < (len << 3)) + { + count[1]++; + } + count[1] += (len >> 29); + + // number of bytes we need to fill in buffer + unsigned int firstpart = 64 - index; + + + // transform as many times as possible. + if (len >= firstpart) + { + memcpy(&buffer[index], data, firstpart); + gxmd5_transform(buffer, state); + + // Transform block + for (i = firstpart; i + 64 <= len; i += 64) + { + gxmd5_transform(data + i, state); + } + index = 0; + } + else + { + i = 0; + } + + memcpy(&buffer[index], &data[i], len - i); + return 0; +} + +int gxmd5_encrypt(gxByteBuffer* data, gxByteBuffer* digest) +{ + // Bytes that didn't fit in last 64 byte chunk + unsigned char buffer[64]; + // Number of bits (lo, hi) + uint32_t count[2] = { 0, 0 }; + // Digest + uint32_t state[4] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; + bb_capacity(digest, 16); + + gxmd5_update(data->data, data->size, buffer, count, state); + + static unsigned char padding[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + // Save number of bits + unsigned char bits[8]; + gxmd5_encode(bits, count, 2); + + // Pad out to 56 mod 64. + unsigned int index = count[0] / 8 % 64; + unsigned int padLen = (index < 56) ? (56 - index) : (120 - index); + gxmd5_update(padding, padLen, buffer, count, state); + + // Append length (before padding) + gxmd5_update(bits, 8, buffer, count, state); + + // Store state in digest + gxmd5_encode(digest->data, state, 4); + digest->size = 16; + return 0; +} + +#endif //DLMS_IGNORE_HIGH_MD5 diff --git a/components/xt211/unused/gxmd5.h b/components/xt211/unused/gxmd5.h new file mode 100644 index 0000000..b844302 --- /dev/null +++ b/components/xt211/unused/gxmd5.h @@ -0,0 +1,73 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef GXMD5_H +#define GXMD5_H + +#ifdef __cplusplus +extern "C" { +#endif + +//If MD5 is not used. +#include "gxignore.h" +#ifndef DLMS_IGNORE_HIGH_MD5 + +#include "bytebuffer.h" + + // Constants . +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + + + int gxmd5_encrypt(gxByteBuffer* data, gxByteBuffer* crypted); + +#endif //DLMS_IGNORE_HIGH_MD5 + +#ifdef __cplusplus +} +#endif + +#endif //GXMD5_H diff --git a/components/xt211/unused/gxserializer.c b/components/xt211/unused/gxserializer.c new file mode 100644 index 0000000..b4e14df --- /dev/null +++ b/components/xt211/unused/gxserializer.c @@ -0,0 +1,9275 @@ +// +// -------------------------------------------------------------------------- +// 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" +#ifndef DLMS_IGNORE_SERIALIZER + +#include "gxmem.h" +#include "gxserializer.h" +#include "helpers.h" +#include "objectarray.h" +#include "cosem.h" +#include "dlms.h" +#include "bytebuffer.h" +#ifdef DLMS_DEBUG +#include "serverevents.h" +#endif //DLMS_DEBUG + +//Serialization version is increased every time when structure of serialized data is changed. +#define SERIALIZATION_VERSION 1 + +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) +#include +#endif +#include "gxmem.h" +#if _MSC_VER > 1400 +#include +#endif + +unsigned char ser_isEof(gxSerializerSettings* serializeSettings) +{ +#if !defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + return feof(serializeSettings->stream); +#else + return !(serializeSettings->position < SERIALIZER_SIZE()); +#endif //(!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +} + +int ser_loadUInt8(gxSerializerSettings* serializeSettings, unsigned char* value) +{ +#if !defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + return fread(value, sizeof(unsigned char), 1, serializeSettings->stream) != 1; +#else + int ret = SERIALIZER_LOAD((uint16_t)serializeSettings->position, sizeof(unsigned char), (void*)value); + if (ret == 0) + { + ++serializeSettings->position; + } + return ret; +#endif //(!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +} + +int ser_loadUInt16(gxSerializerSettings* serializeSettings, uint16_t* value) +{ +#if !defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + return fread(value, sizeof(uint16_t), 1, serializeSettings->stream) != 1; +#else + int ret = SERIALIZER_LOAD(serializeSettings->position, sizeof(uint16_t), (void*)value); + if (ret == 0) + { + serializeSettings->position += sizeof(uint16_t); + } + return ret; +#endif //(!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +} + +int ser_loadUInt32(gxSerializerSettings* serializeSettings, void* value) +{ +#if !defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + return fread(value, sizeof(uint32_t), 1, serializeSettings->stream) != 1; +#else + int ret = SERIALIZER_LOAD(serializeSettings->position, sizeof(uint32_t), value); + if (ret == 0) + { + serializeSettings->position += sizeof(uint32_t); + } + return ret; +#endif //(!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +} + +int ser_loadUInt64(gxSerializerSettings* serializeSettings, uint64_t* value) +{ +#if !defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + return fread(value, sizeof(uint64_t), 1, serializeSettings->stream) != 1; +#else + int ret = SERIALIZER_LOAD(serializeSettings->position, sizeof(uint64_t), (void*)value); + if (ret == 0) + { + serializeSettings->position += sizeof(uint64_t); + } + return ret; +#endif //(!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +} + +int ser_loadInt8(gxSerializerSettings* serializeSettings, signed char* value) +{ + return ser_loadUInt8(serializeSettings, (unsigned char*)value); +} + +int ser_loadInt16(gxSerializerSettings* serializeSettings, int16_t* value) +{ + return ser_loadUInt16(serializeSettings, (uint16_t*)value); +} + +int ser_loadInt32(gxSerializerSettings* serializeSettings, int32_t* value) +{ + return ser_loadUInt32(serializeSettings, (uint32_t*)value); +} + +int ser_loadInt64(gxSerializerSettings* serializeSettings, int64_t* value) +{ + return ser_loadUInt64(serializeSettings, (uint64_t*)value); +} + +int ser_seek(gxSerializerSettings* serializeSettings, int count) +{ +#if !defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + if (fseek(serializeSettings->stream, count, SEEK_CUR) != 0) + { + return DLMS_ERROR_CODE_HARDWARE_FAULT; + } +#else + serializeSettings->position += count; +#endif //(!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + return 0; +} + +#ifdef DLMS_IGNORE_MALLOC +//Whether to save the item. +unsigned char ser_serialize(gxSerializerSettings* serializeSettings) +{ + if (serializeSettings->savedObject != NULL && serializeSettings->currentIndex != 0) + { + return serializeSettings->savedObject == serializeSettings->currentObject && + (serializeSettings->savedAttributes & 1 << (serializeSettings->currentIndex - 1)) != 0; + } + return 1; +} +#endif //DLMS_IGNORE_MALLOC + +int ser_save(gxSerializerSettings* serializeSettings, const void* item, uint16_t count) +{ +#ifdef DLMS_IGNORE_MALLOC + if (!ser_serialize(serializeSettings)) + { + return ser_seek(serializeSettings, count); + } +#endif //DLMS_IGNORE_MALLOC +#if !defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + if (fwrite(item, count, 1, serializeSettings->stream) != 1) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + return 0; +#else + int ret = SERIALIZER_SAVE(serializeSettings->position, count, item); + //Update changed positions. + if (serializeSettings->position < serializeSettings->updateStart) + { + serializeSettings->updateStart = serializeSettings->position; + } + serializeSettings->position += count; + if (serializeSettings->updateEnd < serializeSettings->position) + { + serializeSettings->updateEnd = serializeSettings->position; + } + return ret; +#endif //(!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +} + +int ser_saveUInt8( + gxSerializerSettings* serializeSettings, + unsigned char item) +{ + return ser_save(serializeSettings, &item, 1); +} + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +int ser_set( + gxSerializerSettings* serializeSettings, + const unsigned char* pSource, + uint32_t count +#ifdef DLMS_IGNORE_MALLOC + , uint32_t capacity +#endif //DLMS_IGNORE_MALLOC +) +#else +int ser_set( + gxSerializerSettings* serializeSettings, + const unsigned char* pSource, + uint16_t count +#ifdef DLMS_IGNORE_MALLOC + , uint16_t capacity +#endif //DLMS_IGNORE_MALLOC +) +#endif +{ + int ret; +#ifdef DLMS_IGNORE_MALLOC + if (capacity < count) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if (!ser_serialize(serializeSettings)) + { + return ser_seek(serializeSettings, capacity); + } +#endif //DLMS_IGNORE_MALLOC + ret = 0; + uint16_t pos; + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_saveUInt8(serializeSettings, pSource[pos])) != 0) + { + break; + } + } +#if !(!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +#ifdef DLMS_IGNORE_MALLOC + serializeSettings->position += capacity - count; + //Update changed positions. + if (serializeSettings->position < serializeSettings->updateStart) + { + serializeSettings->updateStart = serializeSettings->position; + } + if (serializeSettings->updateEnd < serializeSettings->position) + { + serializeSettings->updateEnd = serializeSettings->position; + } +#endif //DLMS_IGNORE_MALLOC +#endif //!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + return ret; +} + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +int ser_get( + gxSerializerSettings* serializeSettings, + unsigned char* value, + uint32_t count +#ifdef DLMS_IGNORE_MALLOC + , uint32_t capacity +#endif //DLMS_IGNORE_MALLOC +) +#else +int ser_get( + gxSerializerSettings* serializeSettings, + unsigned char* value, + uint16_t count +#ifdef DLMS_IGNORE_MALLOC + , uint16_t capacity +#endif //DLMS_IGNORE_MALLOC +) +#endif +{ + int ret = 0; +#ifdef DLMS_IGNORE_MALLOC + if (capacity < count) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } +#endif //DLMS_IGNORE_MALLOC +#if !defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + if (fread(value, sizeof(unsigned char), count, serializeSettings->stream) != count) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } +#else + if ((ret = SERIALIZER_LOAD((uint16_t)serializeSettings->position, count, value)) == 0) + { + serializeSettings->position += count; + } +#endif//!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) +#if !(!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +#ifdef DLMS_IGNORE_MALLOC + if (ret == 0) + { + serializeSettings->position += capacity - count; + } +#endif //#ifdef DLMS_IGNORE_MALLOC +#endif //!(!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + return ret; +} + + +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) || (!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +int ser_set2( + gxByteBuffer* arr, + gxSerializerSettings* serializeSettings, + uint32_t count +#ifdef DLMS_IGNORE_MALLOC + , uint16_t capacity +#endif //DLMS_IGNORE_MALLOC +) +#else +int ser_set2( + gxByteBuffer* arr, + gxSerializerSettings* serializeSettings, + uint16_t count +#ifdef DLMS_IGNORE_MALLOC + , uint16_t capacity +#endif //DLMS_IGNORE_MALLOC +) +#endif +{ + int ret = 0; +#ifdef DLMS_IGNORE_MALLOC + if (capacity != 0) +#else + if (count != 0) +#endif //DLMS_IGNORE_MALLOC + { + if (count != 0) + { + ret = bb_allocate(arr, arr->size, count); + } + if (ret == 0) + { +#if !defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + int pos; + for (pos = 0; pos != count; ++pos) + { + if (fread(&arr->data[pos + arr->size], sizeof(unsigned char), 1, serializeSettings->stream) != 1) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + } +#else + if ((ret = SERIALIZER_LOAD(serializeSettings->position, count, arr->data + arr->size)) == 0) + { + serializeSettings->position += count; + } +#endif //(!defined(GX_DLMS_MICROCONTROLLER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + if (ret == 0) + { + arr->size += count; +#if !(!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +#ifdef DLMS_IGNORE_MALLOC + serializeSettings->position += capacity - count; +#endif //DLMS_IGNORE_MALLOC +#endif //!(!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + } + } + } + return ret; +} + +int ser_loadObjectCount(gxSerializerSettings* serializeSettings, uint16_t* count) +{ + int ret; +#ifdef DLMS_IGNORE_MALLOC + uint16_t tmp; + ret = ser_loadUInt16(serializeSettings, &tmp); + *count = tmp; +#else + unsigned char ch; + ret = ser_loadUInt8(serializeSettings, &ch); + if (ret != 0) + { + return ret; + } + if (ch > 0x80) + { + if (ch == 0x81) + { + ret = ser_loadUInt8(serializeSettings, &ch); + *count = ch; + } + else if (ch == 0x82) + { + uint16_t tmp; + ret = ser_loadUInt16(serializeSettings, &tmp); + *count = tmp; + } + else if (ch == 0x84) + { + uint32_t value; + ret = ser_loadUInt32(serializeSettings, &value); + *count = (uint16_t)value; + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + } + else + { + *count = ch; + } +#endif //DLMS_IGNORE_MALLOC + return ret; +} + +int ser_checkArray2(gxSerializerSettings* serializeSettings, uint16_t* count, unsigned char checkDataType) +{ + int ret; + unsigned char ch; + uint16_t cnt; + if (checkDataType) + { + if ((ret = ser_loadUInt8(serializeSettings, &ch)) != 0) + { + return ret; + } + if (ch != DLMS_DATA_TYPE_ARRAY) + { + return DLMS_ERROR_CODE_UNMATCH_TYPE; + } + } + //Get array count. + if ((ret = ser_loadObjectCount(serializeSettings, &cnt)) != 0) + { + return ret; + } +#ifndef DLMS_COSEM_EXACT_DATA_TYPES + if (*count < cnt) + { + return DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } +#endif //DLMS_COSEM_EXACT_DATA_TYPES + * count = cnt; + return 0; +} + + +int ser_loadDateTime(gxtime* value, gxSerializerSettings* serializeSettings, DLMS_DATA_TYPE type) +{ + int ret = 0; + time_clear(value); + uint16_t size; + if (type == DLMS_DATA_TYPE_DATETIME) + { + size = 12; + } + else if (type == DLMS_DATA_TYPE_DATE) + { + size = 5; + } + else if (type == DLMS_DATA_TYPE_TIME) + { + size = 4; + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + if (ret == 0) + { + dlmsVARIANT tmp; + GX_DATETIME(tmp) = value; + unsigned char buff[12]; + gxByteBuffer bb; + bb_attach(&bb, buff, size, sizeof(buff)); +#if !defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + int pos; + for (pos = 0; pos != size; ++pos) + { + if (fread(&buff[pos], sizeof(unsigned char), 1, serializeSettings->stream) != 1) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + } +#else + if ((ret = SERIALIZER_LOAD(serializeSettings->position, size, buff)) == 0) + { + serializeSettings->position += size; + } +#endif //!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + ret = dlms_changeType(&bb, type, &tmp); + } + return ret; +} + +int ser_loadVariantArray(gxSerializerSettings* serializeSettings, variantArray* arr, uint16_t* count) +{ + int ret = ser_loadObjectCount(serializeSettings, count); + if (ret == 0) + { + va_clear(arr); +#ifdef DLMS_IGNORE_MALLOC + arr->size = *count; + ret = ser_loadObjectCount(serializeSettings, count); +#else +#endif //DLMS_IGNORE_MALLOC + va_capacity(arr, *count); + } + return ret; +} + +#if defined(DLMS_IGNORE_MALLOC) +int ser_loadBitStringtoVariant(gxSerializerSettings* serializeSettings, dlmsVARIANT* value) +{ + int ret; + uint16_t count; + if ((ret = ser_loadObjectCount(serializeSettings, &count)) != 0) + { + return ret; + } + uint16_t capacity; + if ((ret = ser_loadObjectCount(serializeSettings, &capacity)) != 0) + { + return ret; + } +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + if (value->capacity != capacity) + { + printf("Warning! Serialized capacity is different than allocated capacity.\n"); + } +#endif //defined(_WIN32) || defined(_WIN64) || defined(__linux__) + value->size = count; + return ser_get(serializeSettings, value->pVal, ba_getByteCount(count), ba_getByteCount(capacity)); +} +#endif //DLMS_IGNORE_MALLOC + + +int ser_loadOctetString(gxSerializerSettings* serializeSettings, gxByteBuffer* value) +{ + int ret; + uint16_t count; + if ((ret = ser_loadObjectCount(serializeSettings, &count)) != 0) + { + return ret; + } +#ifdef DLMS_IGNORE_MALLOC + uint16_t capacity; + if ((ret = ser_loadObjectCount(serializeSettings, &capacity)) != 0) + { + return ret; + } +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + if (bb_getCapacity(value) != capacity) + { + printf("Warning! Serialized capacity is different than allocated capacity.\n"); + } +#endif //defined(_WIN32) || defined(_WIN64) || defined(__linux__) + if ((ret = bb_clear(value)) == 0 && + (ret = ser_set2(value, serializeSettings, count, capacity)) == 0) + { + } +#else + if ((ret = bb_clear(value)) == 0 && + (ret = ser_set2(value, serializeSettings, count)) == 0) + { + } +#endif //DLMS_IGNORE_MALLOC + return ret; +} + +int ser_loadOctetString2(gxSerializerSettings* serializeSettings, char** value) +{ + int ret; + uint16_t count; + if ((ret = ser_loadObjectCount(serializeSettings, &count)) != 0) + { + return ret; + } +#ifdef DLMS_IGNORE_MALLOC + uint16_t capacity; + if ((ret = ser_loadObjectCount(serializeSettings, &capacity)) != 0) + { + return ret; + } +#endif //DLMS_IGNORE_MALLOC +#if !defined(DLMS_USE_CUSTOM_MALLOC) && !defined(DLMS_IGNORE_MALLOC) + if (*value != NULL) + { + gxfree(*value); + } + *value = (char*)gxmalloc(count + 1); +#endif //#if !defined(DLMS_USE_CUSTOM_MALLOC) && !defined(DLMS_IGNORE_MALLOC) + if ((ret = ser_get(serializeSettings, (unsigned char*)*value, count +#ifdef DLMS_IGNORE_MALLOC + , capacity +#endif//DLMS_IGNORE_MALLOC + )) == 0) + { + (*value)[count] = 0; + } + return ret; +} + +int ser_loadOctetString3( + gxSerializerSettings* serializeSettings, + unsigned char* value, + uint16_t* count) +{ + int ret; + if ((ret = ser_loadObjectCount(serializeSettings, count)) != 0) + { + return ret; + } +#ifdef DLMS_IGNORE_MALLOC + uint16_t capacity; + if ((ret = ser_loadObjectCount(serializeSettings, &capacity)) != 0) + { + return ret; + } +#endif //DLMS_IGNORE_MALLOC + ret = ser_get(serializeSettings, value, *count +#ifdef DLMS_IGNORE_MALLOC + , capacity +#endif //DLMS_IGNORE_MALLOC + ); +#ifdef DLMS_IGNORE_MALLOC + if (*count < capacity) + { + value[*count] = 0; + } +#endif //DLMS_IGNORE_MALLOC + return ret; +} + +int ser_getOctetString2(gxSerializerSettings* serializeSettings, unsigned char* value, uint16_t* size) +{ + uint16_t tmp; + int ret; + if ((ret = ser_loadOctetString3(serializeSettings, value, &tmp)) == 0) + { + if (size != NULL) + { + *size = tmp; + } + } + return ret; +} + +int ser_getOctetString(gxSerializerSettings* serializeSettings, gxByteBuffer* value) +{ + int ret; + uint16_t count; + if ((ret = ser_loadObjectCount(serializeSettings, &count)) != 0) + { + return ret; + } + bb_clear(value); +#ifdef DLMS_IGNORE_MALLOC + uint16_t capacity; + if ((ret = ser_loadObjectCount(serializeSettings, &capacity)) != 0) + { + return ret; + } + bb_capacity(value, capacity); +#else + if ((ret = bb_capacity(value, count)) != 0) + { + return ret; + } +#endif //DLMS_IGNORE_MALLOC + value->size = count; + return ret = ser_get(serializeSettings, value->data, count +#ifdef DLMS_IGNORE_MALLOC + , capacity +#endif //DLMS_IGNORE_MALLOC + ); +} + +#ifndef DLMS_IGNORE_FLOAT32 +int ser_loadFloat( + gxSerializerSettings* serializeSettings, + float* value) +{ + typedef union + { + float value; + unsigned char b[sizeof(float)]; + } HELPER; + HELPER tmp; + int ret; + if ((ret = ser_loadUInt8(serializeSettings, &tmp.b[3])) == 0 && + (ret = ser_loadUInt8(serializeSettings, &tmp.b[2])) == 0 && + (ret = ser_loadUInt8(serializeSettings, &tmp.b[1])) == 0 && + (ret = ser_loadUInt8(serializeSettings, &tmp.b[0])) == 0) + { + *value = tmp.value; + } + return ret; +} +#endif //DLMS_IGNORE_FLOAT32 + +#ifndef DLMS_IGNORE_FLOAT64 +int ser_loadDouble( + gxSerializerSettings* serializeSettings, + double* value) +{ + typedef union + { + double value; + unsigned char b[sizeof(double)]; + } HELPER; + HELPER tmp; + int ret; + if ((ret = ser_loadUInt8(serializeSettings, &tmp.b[7])) == 0 && + (ret = ser_loadUInt8(serializeSettings, &tmp.b[6])) == 0 && + (ret = ser_loadUInt8(serializeSettings, &tmp.b[5])) == 0 && + (ret = ser_loadUInt8(serializeSettings, &tmp.b[4])) == 0 && + (ret = ser_loadUInt8(serializeSettings, &tmp.b[3])) == 0 && + (ret = ser_loadUInt8(serializeSettings, &tmp.b[2])) == 0 && + (ret = ser_loadUInt8(serializeSettings, &tmp.b[1])) == 0 && + (ret = ser_loadUInt8(serializeSettings, &tmp.b[0])) == 0) + { + *value = tmp.value; + } + return ret; +} +#endif //DLMS_IGNORE_FLOAT64 + +int ser_loadBitString(gxSerializerSettings* serializeSettings, bitArray* value) +{ + int ret; + uint16_t count; + if ((ret = ser_loadObjectCount(serializeSettings, &count)) != 0) + { + return ret; + } +#ifdef DLMS_IGNORE_MALLOC + uint16_t capacity; + if ((ret = ser_loadObjectCount(serializeSettings, &capacity)) != 0) + { + return ret; + } +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + uint16_t size = ba_getByteCount(ba_getCapacity(value)); + if (size != capacity) + { + printf("Warning! Serialized capacity is different than allocated capacity.\n"); + } +#endif //defined(_WIN32) || defined(_WIN64) || defined(__linux__) +#endif //DLMS_IGNORE_MALLOC +#ifndef DLMS_IGNORE_MALLOC + if ((ret = ba_capacity(value, count)) != 0) + { + return ret; + } +#endif // DLMS_IGNORE_MALLOC + value->size = count; + ret = ser_get(serializeSettings, value->data, ba_getByteCount(count) +#ifdef DLMS_IGNORE_MALLOC + , capacity +#endif //DLMS_IGNORE_MALLOC + ); + return ret; +} + +#ifdef DLMS_IGNORE_MALLOC +int ser_loadBitString2(gxSerializerSettings* serializeSettings, + unsigned char* value, + uint16_t expectedCapacity, + uint16_t* size) +{ + int ret; + uint16_t count; + if ((ret = ser_loadObjectCount(serializeSettings, &count)) != 0) + { + return ret; + } + uint16_t capacity; + if ((ret = ser_loadObjectCount(serializeSettings, &capacity)) != 0) + { + return ret; + } + if (expectedCapacity != capacity) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + *size = count; + ret = ser_get(serializeSettings, value, ba_getByteCount(count) + , capacity + ); + return ret; +} +#endif //DLMS_IGNORE_MALLOC + +// Get item from the buffer if DLMS_IGNORE_MALLOC is defined. +// Otherwice create the variant object dynamically. +int ser_getVariantArrayItem(variantArray* arr, uint16_t index, dlmsVARIANT** value) +{ +#ifdef DLMS_IGNORE_MALLOC + int ret = va_getByIndex(arr, index, value); + if (ret == 0) + { + var_clear(*value); + } + return ret; +#else + * value = gxmalloc(sizeof(dlmsVARIANT)); + if (*value == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + var_init(*value); + return va_push(arr, *value); +#endif //DLMS_COSEM_EXACT_DATA_TYPES +} + +int ser_loadVariant(dlmsVARIANT* data, + gxSerializerSettings* serializeSettings) +{ + int ret; + unsigned char ch; + var_clear(data); + if ((ret = ser_loadUInt8(serializeSettings, &ch)) == 0) + { + //Update data type if not reference. + if ((data->vt & DLMS_DATA_TYPE_BYREF) == 0) + { + data->vt = ch; + } + if (ch == DLMS_DATA_TYPE_NONE) + { + //Do nothing. + return DLMS_ERROR_CODE_OK; + } + switch (data->vt & ~DLMS_DATA_TYPE_BYREF) + { + case DLMS_DATA_TYPE_ARRAY: + case DLMS_DATA_TYPE_STRUCTURE: + { + uint16_t pos, count; + dlmsVARIANT* tmp; +#ifndef DLMS_IGNORE_MALLOC + data->Arr = gxmalloc(sizeof(variantArray)); + va_init(data->Arr); +#else + dlmsVARIANT tmp2; + var_init(&tmp2); + va_clear(data->Arr); +#endif //DLMS_IGNORE_MALLOC + if ((ret = ser_loadVariantArray(serializeSettings, data->Arr, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if (pos < data->Arr->size) + { + if ((ret = ser_getVariantArrayItem(data->Arr, pos, &tmp)) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + else + { + var_clear(&tmp2); + tmp = &tmp2; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = ser_loadVariant(tmp, serializeSettings)) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + //Return original size. + data->Arr->size = count; +#endif //DLMS_IGNORE_MALLOC + } + break; + } + case DLMS_DATA_TYPE_BOOLEAN: + { + ret = ser_loadUInt8(serializeSettings, (data->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &data->boolVal : data->pboolVal); + break; + } + case DLMS_DATA_TYPE_BIT_STRING: +#if !defined(DLMS_IGNORE_MALLOC) + data->bitArr = (bitArray*)gxmalloc(sizeof(bitArray)); + ba_init(data->bitArr); + ret = ser_loadBitString(serializeSettings, data->bitArr); +#else + ret = ser_loadBitStringtoVariant(serializeSettings, data); +#endif //!defined(DLMS_IGNORE_MALLOC) + break; + case DLMS_DATA_TYPE_INT32: + ret = ser_loadInt32(serializeSettings, (data->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &data->lVal : data->plVal); + break; + case DLMS_DATA_TYPE_UINT32: + ret = ser_loadUInt32(serializeSettings, (data->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &data->ulVal : data->pulVal); + break; + case DLMS_DATA_TYPE_STRING: +#if !defined(DLMS_IGNORE_MALLOC) + data->byteArr = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + bb_init(data->byteArr); + ret = ser_getOctetString(serializeSettings, data->byteArr); +#else + ret = ser_loadOctetString3(serializeSettings, (unsigned char*)data->pVal, &data->size); +#endif //!defined(DLMS_IGNORE_MALLOC) + break; + case DLMS_DATA_TYPE_STRING_UTF8: +#if !defined(DLMS_IGNORE_MALLOC) + data->byteArr = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + bb_init(data->byteArr); + ret = ser_getOctetString(serializeSettings, data->byteArr); +#else + ret = ser_loadOctetString3(serializeSettings, data->pVal, &data->size); +#endif //!defined(DLMS_IGNORE_MALLOC) + break; + case DLMS_DATA_TYPE_OCTET_STRING: +#if !defined(DLMS_IGNORE_MALLOC) + data->byteArr = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + bb_init(data->byteArr); + ret = ser_getOctetString(serializeSettings, data->byteArr); +#else + ret = ser_loadOctetString3(serializeSettings, data->pVal, &data->size); +#endif // DLMS_IGNORE_MALLOC + break; + case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL: + ret = ser_loadUInt8(serializeSettings, (data->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &data->bVal : data->pbVal); + break; + case DLMS_DATA_TYPE_INT8: + ret = ser_loadInt8(serializeSettings, (data->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &data->cVal : data->pcVal); + break; + case DLMS_DATA_TYPE_INT16: + ret = ser_loadInt16(serializeSettings, (data->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &data->iVal : data->piVal); + break; + case DLMS_DATA_TYPE_UINT8: + ret = ser_loadUInt8(serializeSettings, (data->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &data->bVal : data->pbVal); + break; + case DLMS_DATA_TYPE_UINT16: + ret = ser_loadUInt16(serializeSettings, (data->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &data->uiVal : data->puiVal); + break; + case DLMS_DATA_TYPE_COMPACT_ARRAY: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + case DLMS_DATA_TYPE_INT64: + ret = ser_loadInt64(serializeSettings, (data->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &data->llVal : data->pllVal); + break; + case DLMS_DATA_TYPE_UINT64: + ret = ser_loadUInt64(serializeSettings, (data->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &data->ullVal : data->pullVal); + break; + case DLMS_DATA_TYPE_ENUM: + ret = ser_loadUInt8(serializeSettings, (data->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &data->bVal : data->pbVal); + break; +#ifndef DLMS_IGNORE_FLOAT32 + case DLMS_DATA_TYPE_FLOAT32: + ret = ser_loadFloat(serializeSettings, (data->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &data->fltVal : data->pfltVal); + break; +#endif //DLMS_IGNORE_FLOAT32 +#ifndef DLMS_IGNORE_FLOAT64 + case DLMS_DATA_TYPE_FLOAT64: + ret = ser_loadDouble(serializeSettings, (data->vt & DLMS_DATA_TYPE_BYREF) == 0 ? &data->dblVal : data->pdblVal); + break; +#endif //DLMS_IGNORE_FLOAT64 + case DLMS_DATA_TYPE_DATETIME: +#if defined(DLMS_IGNORE_MALLOC) + ret = ser_loadDateTime((gxtime*)data->pVal, serializeSettings, DLMS_DATA_TYPE_DATETIME); +#else + data->dateTime = (gxtime*)gxmalloc(sizeof(gxtime)); + ret = ser_loadDateTime(data->dateTime, serializeSettings, DLMS_DATA_TYPE_DATETIME); +#endif //DLMS_IGNORE_MALLOC + break; + case DLMS_DATA_TYPE_DATE: +#if defined(DLMS_IGNORE_MALLOC) + ret = ser_loadDateTime((gxtime*)data->pVal, serializeSettings, DLMS_DATA_TYPE_DATE); +#else + data->dateTime = (gxtime*)gxmalloc(sizeof(gxtime)); + ret = ser_loadDateTime(data->dateTime, serializeSettings, DLMS_DATA_TYPE_DATE); +#endif //DLMS_IGNORE_MALLOC + break; + case DLMS_DATA_TYPE_TIME: +#if defined(DLMS_IGNORE_MALLOC) + ret = ser_loadDateTime((gxtime*)data->pVal, serializeSettings, DLMS_DATA_TYPE_TIME); +#else + data->dateTime = (gxtime*)gxmalloc(sizeof(gxtime)); + ret = ser_loadDateTime(data->dateTime, serializeSettings, DLMS_DATA_TYPE_TIME); +#endif //DLMS_IGNORE_MALLOC + break; + default: +#ifdef _DEBUG + //Assert in debug version. +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif +#endif + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + } + return ret; +} + +int ser_saveUInt16( + gxSerializerSettings* serializeSettings, + uint16_t item) +{ +#ifdef DLMS_IGNORE_MALLOC + if (!ser_serialize(serializeSettings)) + { + return ser_seek(serializeSettings, sizeof(uint16_t)); + } +#endif //DLMS_IGNORE_MALLOC + return ser_save(serializeSettings, &item, sizeof(uint16_t)); +} + +int ser_saveUInt32( + gxSerializerSettings* serializeSettings, + uint32_t item) +{ +#ifdef DLMS_IGNORE_MALLOC + if (!ser_serialize(serializeSettings)) + { + return ser_seek(serializeSettings, sizeof(uint32_t)); + } +#endif //DLMS_IGNORE_MALLOC + return ser_save(serializeSettings, &item, sizeof(uint32_t)); +} + +int ser_saveUInt64( + gxSerializerSettings* serializeSettings, + uint64_t item) +{ +#ifdef DLMS_IGNORE_MALLOC + if (!ser_serialize(serializeSettings)) + { + return ser_seek(serializeSettings, sizeof(uint64_t)); + } +#endif //DLMS_IGNORE_MALLOC + return ser_save(serializeSettings, &item, sizeof(uint64_t)); +} + +int ser_saveInt8( + gxSerializerSettings* serializeSettings, + signed char item) +{ + return ser_saveUInt8(serializeSettings, (unsigned char)item); +} + +int ser_saveInt16( + gxSerializerSettings* serializeSettings, + int16_t item) +{ + return ser_saveUInt16(serializeSettings, (uint16_t)item); +} + +int ser_saveInt32( + gxSerializerSettings* serializeSettings, + int32_t item) +{ + return ser_saveUInt32(serializeSettings, (uint32_t)item); +} + +int ser_saveInt64( + gxSerializerSettings* serializeSettings, + int64_t item) +{ + return ser_saveUInt64(serializeSettings, (uint64_t)item); +} + + +int ser_saveDateTime2( + gxtime* dateTime, + gxSerializerSettings* serializeSettings) +{ + int ret; + unsigned char buff[12]; + gxByteBuffer bb; + BB_ATTACH(bb, buff, 0); + if ((ret = var_getDateTime2(dateTime, &bb)) == 0 && + (ret = ser_set(serializeSettings, bb.data, bb.size +#ifdef DLMS_IGNORE_MALLOC + , bb_getCapacity(&bb) +#endif //DLMS_IGNORE_MALLOC + )) == 0) + { + + } + return ret; +} + +int ser_saveDate( + gxtime* dateTime, + gxSerializerSettings* serializeSettings) +{ + int ret; + unsigned char buff[5]; + gxByteBuffer bb; + BB_ATTACH(bb, buff, 0); + if ((ret = var_getDate(dateTime, &bb)) == 0 && + (ret = ser_set(serializeSettings, bb.data, bb.size +#ifdef DLMS_IGNORE_MALLOC + , bb_getCapacity(&bb) +#endif //DLMS_IGNORE_MALLOC + )) == 0) + { + + } + return ret; +} + +int ser_saveTime( + gxtime* dateTime, + gxSerializerSettings* serializeSettings) +{ + int ret; + unsigned char buff[4]; + gxByteBuffer bb; + BB_ATTACH(bb, buff, 0); + if ((ret = var_getTime(dateTime, &bb)) == 0 && + (ret = ser_set(serializeSettings, bb.data, bb.size +#ifdef DLMS_IGNORE_MALLOC + , bb_getCapacity(&bb) +#endif //DLMS_IGNORE_MALLOC + )) == 0) + { + + } + return ret; +} + + +#ifndef DLMS_IGNORE_FLOAT32 +int ser_saveFloat( + gxSerializerSettings* serializeSettings, + float value) +{ + typedef union + { + float value; + char b[sizeof(float)]; + } HELPER; + HELPER tmp; + tmp.value = value; + int ret; + if ((ret = ser_saveUInt8(serializeSettings, tmp.b[3])) == 0 && + (ret = ser_saveUInt8(serializeSettings, tmp.b[2])) == 0 && + (ret = ser_saveUInt8(serializeSettings, tmp.b[1])) == 0 && + (ret = ser_saveUInt8(serializeSettings, tmp.b[0])) == 0) + { + } + return ret; +} +#endif //DLMS_IGNORE_FLOAT32 + +#ifndef DLMS_IGNORE_FLOAT64 +int ser_saveDouble( + gxSerializerSettings* serializeSettings, + double value) +{ + typedef union + { + double value; + char b[sizeof(double)]; + } HELPER; + + HELPER tmp; + tmp.value = value; + int ret; + if ((ret = ser_saveUInt8(serializeSettings, tmp.b[7])) == 0 && + (ret = ser_saveUInt8(serializeSettings, tmp.b[6])) == 0 && + (ret = ser_saveUInt8(serializeSettings, tmp.b[5])) == 0 && + (ret = ser_saveUInt8(serializeSettings, tmp.b[4])) == 0 && + (ret = ser_saveUInt8(serializeSettings, tmp.b[3])) == 0 && + (ret = ser_saveUInt8(serializeSettings, tmp.b[2])) == 0 && + (ret = ser_saveUInt8(serializeSettings, tmp.b[1])) == 0 && + (ret = ser_saveUInt8(serializeSettings, tmp.b[0])) == 0) + { + } + return ret; +} +#endif //DLMS_IGNORE_FLOAT64 + +// Set count of items. +int ser_saveObjectCount(uint32_t count, gxSerializerSettings* serializeSettings) +{ + int ret; +#ifdef DLMS_IGNORE_MALLOC + ret = ser_saveUInt16(serializeSettings, (uint16_t)count); +#else + if (count < 0x80) + { + ret = ser_saveUInt8(serializeSettings, (unsigned char)count); + } + else if (count < 0x100) + { + if ((ret = ser_saveUInt8(serializeSettings, 0x81)) == 0) + { + ret = ser_saveUInt8(serializeSettings, (unsigned char)count); + } + } + else if (count < 0x10000) + { + if ((ret = ser_saveUInt8(serializeSettings, 0x82)) == 0) + { + ret = ser_saveUInt16(serializeSettings, (uint16_t)count); + } + } + else + { + if ((ret = ser_saveUInt8(serializeSettings, 0x84)) == 0) + { + ret = ser_saveUInt32(serializeSettings, count); + } + } +#endif// DLMS_IGNORE_MALLOC + return ret; +} + +int ser_setOctetString2( + gxSerializerSettings* serializeSettings, + const unsigned char* value, + uint16_t size, + uint16_t capacity) +{ + int ret; + if (value == NULL) + { + size = 0; + } + if ((ret = ser_saveObjectCount(size, serializeSettings)) != 0 || +#ifdef DLMS_IGNORE_MALLOC + (ret = ser_saveObjectCount(capacity, serializeSettings)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = ser_set(serializeSettings, value, size +#ifdef DLMS_IGNORE_MALLOC + , capacity +#endif //DLMS_IGNORE_MALLOC + )) != 0) + { + //Error code is returned at the end of the function. + } + return ret; +} + + +//Returns bytes as Big Endian byteorder. +int ser_saveBytes3( + dlmsVARIANT* data, + DLMS_DATA_TYPE type, + gxSerializerSettings* serializeSettings) +{ + int ret = 0, pos; + if ((type & DLMS_DATA_TYPE_BYREF) != 0) + { + return ser_saveBytes3(data, type & ~DLMS_DATA_TYPE_BYREF, serializeSettings); + } + if ((ret = ser_saveUInt8(serializeSettings, type)) != 0) + { + return ret; + } + if (type == DLMS_DATA_TYPE_STRUCTURE || + type == DLMS_DATA_TYPE_ARRAY) + { + dlmsVARIANT* tmp; + if ((ret = ser_saveObjectCount(data->Arr->size, serializeSettings)) == 0) + { +#ifdef DLMS_IGNORE_MALLOC + uint16_t originalSize = va_size(data->Arr); + uint16_t count = va_getCapacity(data->Arr); + if ((ret = ser_saveObjectCount(count, serializeSettings)) != 0) + { + return ret; + } + data->Arr->size = count; +#endif //DLMS_IGNORE_MALLOC + for (pos = 0; pos != va_size(data->Arr); ++pos) + { + if ((ret = va_getByIndex(data->Arr, pos, &tmp)) != DLMS_ERROR_CODE_OK || + (ret = ser_saveBytes3(tmp, tmp->vt, serializeSettings)) != DLMS_ERROR_CODE_OK) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + //Return original size. + data->Arr->size = originalSize; +#endif //DLMS_IGNORE_MALLOC + } + return ret; + } + switch (type) + { + case DLMS_DATA_TYPE_NONE: + break; + case DLMS_DATA_TYPE_UINT8: + case DLMS_DATA_TYPE_ENUM: + ret = ser_saveUInt8(serializeSettings, (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 = ser_saveUInt8(serializeSettings, *data->pbVal == 0 ? 0 : 1); + } + else + { + ret = ser_saveUInt8(serializeSettings, data->bVal == 0 ? 0 : 1); + } + break; + case DLMS_DATA_TYPE_UINT16: + ret = ser_saveUInt16(serializeSettings, (data->vt & DLMS_DATA_TYPE_BYREF) != 0 ? *data->puiVal : data->uiVal); + break; + case DLMS_DATA_TYPE_UINT32: + ret = ser_saveUInt32(serializeSettings, (data->vt & DLMS_DATA_TYPE_BYREF) != 0 ? *data->pulVal : data->ulVal); + break; + case DLMS_DATA_TYPE_UINT64: + ret = ser_saveUInt64(serializeSettings, (data->vt & DLMS_DATA_TYPE_BYREF) != 0 ? *data->pullVal : data->ullVal); + break; + case DLMS_DATA_TYPE_INT8: + ret = ser_saveUInt8(serializeSettings, (data->vt & DLMS_DATA_TYPE_BYREF) != 0 ? *data->pcVal : data->cVal); + break; + case DLMS_DATA_TYPE_INT16: + ret = ser_saveInt16(serializeSettings, (data->vt & DLMS_DATA_TYPE_BYREF) != 0 ? *data->puiVal : data->uiVal); + break; + case DLMS_DATA_TYPE_INT32: + ret = ser_saveUInt32(serializeSettings, (data->vt & DLMS_DATA_TYPE_BYREF) != 0 ? *data->plVal : data->lVal); + break; + case DLMS_DATA_TYPE_INT64: + ret = ser_saveInt64(serializeSettings, (data->vt & DLMS_DATA_TYPE_BYREF) != 0 ? *data->pllVal : data->llVal); + break; + case DLMS_DATA_TYPE_FLOAT32: +#ifndef DLMS_IGNORE_FLOAT32 + ret = ser_saveFloat(serializeSettings, (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 = ser_saveDouble(serializeSettings, (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: +#ifdef DLMS_IGNORE_MALLOC + ret = ser_setOctetString2(serializeSettings, data->pbVal, data->size, data->capacity); +#else + ret = ser_setOctetString2(serializeSettings, data->byteArr->data, (uint16_t)data->byteArr->size, (uint16_t)data->byteArr->capacity); +#endif //DLMS_IGNORE_MALLOC + break; + case DLMS_DATA_TYPE_OCTET_STRING: +#ifndef DLMS_IGNORE_MALLOC + if (data->vt == DLMS_DATA_TYPE_DATETIME) + { + if ((ret = ser_saveUInt8(serializeSettings, 12)) == 0) + { + ret = ser_saveDateTime2(data->dateTime, serializeSettings); + } + } + else if (data->vt == DLMS_DATA_TYPE_DATE) + { + if ((ret = ser_saveUInt8(serializeSettings, 5)) == 0) + { + ret = ser_saveDate(data->dateTime, serializeSettings); + } + } + else if (data->vt == DLMS_DATA_TYPE_TIME) + { + if ((ret = ser_saveUInt8(serializeSettings, 4)) == 0) + { + ret = ser_saveTime(data->dateTime, serializeSettings); + } + } + else + { + ret = ser_setOctetString2(serializeSettings, data->byteArr->data, (uint16_t)data->byteArr->size, (uint16_t)data->byteArr->capacity); + } +#else + if (data->vt == (DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_DATETIME)) + { + if ((ret = ser_saveUInt8(serializeSettings, 12)) == 0) + { + ret = ser_saveDateTime2(data->pVal, serializeSettings); + } + } + else if (data->vt == (DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_DATE)) + { + if ((ret = ser_saveUInt8(serializeSettings, 5)) == 0) + { + ret = ser_saveDate(data->pVal, serializeSettings); + } + } + else if (data->vt == (DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_TIME)) + { + if ((ret = ser_saveUInt8(serializeSettings, 4)) == 0) + { + ret = ser_saveTime(data->pVal, serializeSettings); + } + } + else if (data->vt == (DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_OCTET_STRING)) + { + if ((ret = ser_saveObjectCount(data->size, serializeSettings)) != 0 || +#ifdef DLMS_IGNORE_MALLOC + (ret = ser_saveObjectCount(data->capacity, serializeSettings)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = ser_set(serializeSettings, data->pbVal, data->size, data->capacity)) != 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 = ser_saveDateTime2(data->pVal, serializeSettings); +#else + ret = ser_saveDateTime2(data->dateTime, serializeSettings); +#endif //DLMS_IGNORE_MALLOC + break; + } + case DLMS_DATA_TYPE_DATE: + { +#ifdef DLMS_IGNORE_MALLOC + ret = ser_saveDate(data->pVal, serializeSettings); +#else + ret = ser_saveDate(data->dateTime, serializeSettings); +#endif //DLMS_IGNORE_MALLOC + + break; + } + case DLMS_DATA_TYPE_TIME: + { +#ifdef DLMS_IGNORE_MALLOC + ret = ser_saveTime(data->pVal, serializeSettings); +#else + ret = ser_saveTime(data->dateTime, serializeSettings); +#endif //DLMS_IGNORE_MALLOC + + break; + } + case DLMS_DATA_TYPE_BIT_STRING: + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = ser_saveObjectCount(data->size, serializeSettings)) == 0 && + (ret = ser_saveObjectCount(data->capacity, serializeSettings)) == 0) + { + ret = ser_set(serializeSettings, data->pVal, ba_getByteCount(data->size), ba_getByteCount(data->capacity)); + } +#else + if ((ret = ser_saveObjectCount(data->bitArr->size, serializeSettings)) == 0) + { + ret = ser_set(serializeSettings, data->bitArr->data, ba_getByteCount(data->bitArr->size) +#ifdef DLMS_IGNORE_MALLOC + , ba_getByteCount(ba_getCapacity(data->bitArr)) +#endif //DLMS_IGNORE_MALLOC + ); + } +#endif //DLMS_IGNORE_MALLOC + break; + } + default: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} + +//Returns bytes as Big Endian byteorder. +int ser_saveBytes( + dlmsVARIANT* data, + gxSerializerSettings* serializeSettings) +{ + return ser_saveBytes3(data, data->vt, serializeSettings); +} + +unsigned char isAttributeSet(gxSerializerSettings* serializeSettings, uint16_t attributes, unsigned char index) +{ +#ifdef DLMS_IGNORE_MALLOC + serializeSettings->currentIndex = index; +#endif //DLMS_IGNORE_MALLOC + return (attributes & 1 << (index - 1)) != 0; +} + +//Returns ignored attributes. +uint16_t ser_getIgnoredAttributes(gxSerializerSettings* serializeSettings, gxObject* object) +{ + uint16_t ret = 0; + if (serializeSettings != NULL) + { + int pos; + for (pos = 0; pos != serializeSettings->count; ++pos) + { + if (serializeSettings->ignoredAttributes[pos].target == object || + serializeSettings->ignoredAttributes[pos].objectType == object->objectType) + { + ret |= serializeSettings->ignoredAttributes[pos].attributes; + } + } + } + return ret; +} + +int ser_saveDateTime(gxtime* value, gxSerializerSettings* serializeSettings) +{ + int ret; + if ((ret = ser_saveDateTime2(value, serializeSettings)) != 0) + { + //Error code is returned at the end of the function. + } + return ret; +} + +int ser_saveOctetString(gxSerializerSettings* serializeSettings, gxByteBuffer* value) +{ + int ret; + if ((ret = ser_saveObjectCount(bb_size(value), serializeSettings)) == 0 && +#ifndef DLMS_IGNORE_MALLOC + (ret = ser_set(serializeSettings, value->data, bb_size(value) +#ifdef DLMS_IGNORE_MALLOC + , bb_getCapacity(value) +#endif //DLMS_IGNORE_MALLOC + )) == 0) +#else + (ret = ser_saveObjectCount(bb_getCapacity(value), serializeSettings)) == 0 && + (ret = ser_set(serializeSettings, value->data, bb_getCapacity(value), bb_getCapacity(value))) == 0) +#endif //DLMS_IGNORE_MALLOC + { + //Error code is returned at the end of the function. + } + return ret; +} + +int ser_saveOctetString3(gxSerializerSettings* serializeSettings, char* value, uint16_t len, uint16_t capacity) +{ + int ret; + if (capacity < len) + { + //size is bigger then the capacity. + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + else + { + if ((ret = ser_saveObjectCount(len, serializeSettings)) != 0 || +#ifndef DLMS_IGNORE_MALLOC + (ret = ser_set(serializeSettings, (unsigned char*)value, len)) != 0) +#else + (ret = ser_saveObjectCount(capacity, serializeSettings)) != 0 || + (ret = ser_set(serializeSettings, (unsigned char*)value, len, capacity)) != 0) +#endif //DLMS_IGNORE_MALLOC + { + //Error code is returned at the end of the function. + } + } + return ret; +} + +int ser_saveOctetString2(gxSerializerSettings* serializeSettings, char* value, uint16_t capacity) +{ + uint16_t len; + if (value != NULL) + { + len = (uint16_t)strlen(value); + } + else + { + len = 0; + } + return ser_saveOctetString3(serializeSettings, value, len, capacity); +} + +int ser_saveBitString(gxSerializerSettings* serializeSettings, bitArray* value) +{ + int ret; + if ((ret = ser_saveObjectCount(value->size, serializeSettings)) != 0 || +#ifndef DLMS_IGNORE_MALLOC + (ret = ser_set(serializeSettings, value->data, ba_getByteCount(value->size))) != 0) +#else + (ret = ser_saveObjectCount(ba_getByteCount(ba_getCapacity(value)), serializeSettings)) != 0 || + (ret = ser_set(serializeSettings, value->data, ba_getByteCount(ba_getCapacity(value)), ba_getByteCount(ba_getCapacity(value)))) != 0) +#endif + + { + //Error code is returned at the end of the function. + } + return ret; +} + +int ser_saveBitString2(gxSerializerSettings* serializeSettings, unsigned char* value, int size, int capacity) +{ + int ret; + if ((ret = ser_saveObjectCount(size, serializeSettings)) != 0 || +#ifndef DLMS_IGNORE_MALLOC + (ret = ser_set(serializeSettings, value, ba_getByteCount(size))) != 0) +#else + (ret = ser_saveObjectCount(ba_getByteCount(capacity), serializeSettings)) != 0 || + (ret = ser_set(serializeSettings, value, ba_getByteCount(capacity), ba_getByteCount(capacity))) != 0) +#endif + + { + //Error code is returned at the end of the function. + } + return ret; +} + +int ser_saveObjectArrayCount(gxSerializerSettings* serializeSettings, objectArray* arr, uint16_t* count) +{ + int ret; + if ((ret = ser_saveObjectCount(arr->size, serializeSettings)) == 0) + { + *count = arr->size; +#ifdef DLMS_IGNORE_MALLOC + arr->size = oa_getCapacity(arr); + if ((ret = ser_saveObjectCount(arr->size, serializeSettings)) != 0) + { + return ret; + } +#else +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +int ser_saveVariantArrayCount(gxSerializerSettings* serializeSettings, variantArray* arr, uint16_t* count) +{ + int ret; + if ((ret = ser_saveObjectCount(arr->size, serializeSettings)) == 0) + { + *count = arr->size; +#ifdef DLMS_IGNORE_MALLOC + arr->size = va_getCapacity(arr); + if ((ret = ser_saveObjectCount(arr->size, serializeSettings)) != 0) + { + return ret; + } +#else +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +int ser_saveArrayCount(gxSerializerSettings* serializeSettings, gxArray* arr, uint16_t* count) +{ + int ret; + if ((ret = ser_saveObjectCount(arr->size, serializeSettings)) == 0) + { + *count = arr->size; +#ifdef DLMS_IGNORE_MALLOC + arr->size = arr_getCapacity(arr); + if ((ret = ser_saveObjectCount(arr->size, serializeSettings)) != 0) + { + return ret; + } +#else +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +#ifndef DLMS_IGNORE_DATA +int ser_saveData(gxSerializerSettings* serializeSettings, gxData* object) +{ + if (!isAttributeSet(serializeSettings, ser_getIgnoredAttributes(serializeSettings, (gxObject*)object), 2)) + { + return ser_saveBytes(&object->value, serializeSettings); + } + return 0; +} + +#endif //DLMS_IGNORE_DATA +#ifndef DLMS_IGNORE_REGISTER +int ser_saveRegister( + gxSerializerSettings* serializeSettings, + gxRegister* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 3)) + { + if ((ret = ser_saveUInt8(serializeSettings, object->scaler)) != 0 || + (ret = ser_saveUInt8(serializeSettings, object->unit)) != 0) + { + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 2)) + { + if ((ret = ser_saveBytes(&object->value, serializeSettings)) != 0) + { + } + } + return ret; +} +#endif //DLMS_IGNORE_REGISTER +#ifndef DLMS_IGNORE_CLOCK +int ser_saveClock( + gxSerializerSettings* serializeSettings, + gxClock* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveDateTime(&object->time, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveInt16(serializeSettings, object->timeZone)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveUInt8(serializeSettings, object->status)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveDateTime(&object->begin, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_saveDateTime(&object->end, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_saveUInt8(serializeSettings, object->deviation)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_saveUInt8(serializeSettings, object->enabled)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_saveUInt8(serializeSettings, object->clockBase)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_CLOCK +#ifndef DLMS_IGNORE_SCRIPT_TABLE +int ser_saveScriptTable( + gxSerializerSettings* serializeSettings, + gxScriptTable* object) +{ + int ret = 0, pos, pos2; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + uint16_t count, count2; + gxScript* s; + gxScriptAction* sa; + if ((ret = ser_saveArrayCount(serializeSettings, &object->scripts, &count)) == 0) + { + for (pos = 0; pos != object->scripts.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(&object->scripts, pos, (void**)&s, sizeof(gxScript), 0)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex3(&object->scripts, pos, (void**)&s, 0)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = ser_saveUInt16(serializeSettings, s->id)) == 0 && + (ret = ser_saveArrayCount(serializeSettings, &s->actions, &count2)) == 0) + { + for (pos2 = 0; pos2 != s->actions.size; ++pos2) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(&s->actions, pos2, (void**)&sa, sizeof(gxScriptAction), 0)) != 0 || + (ret = ser_saveUInt8(serializeSettings, sa->type)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex3(&s->actions, pos2, (void**)&sa, 0)) != 0 || + (ret = ser_saveUInt8(serializeSettings, sa->type)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if (sa->target == NULL) + { + if ((ret = ser_saveUInt16(serializeSettings, 0)) != 0 || + (ret = ser_set(serializeSettings, EMPTY_LN, sizeof(EMPTY_LN) +#ifdef DLMS_IGNORE_MALLOC + , sizeof(EMPTY_LN) +#endif //DLMS_IGNORE_MALLOC + )) != 0) + { + break; + } + } + else + { + if ((ret = ser_saveUInt16(serializeSettings, sa->target->objectType)) != 0 || + (ret = ser_set(serializeSettings, sa->target->logicalName, sizeof(sa->target->logicalName) +#ifdef DLMS_IGNORE_MALLOC + , sizeof(sa->target->logicalName) +#endif //DLMS_IGNORE_MALLOC + )) != 0) + { + break; + } + } +#else + if ((ret = ser_saveUInt16(serializeSettings, sa->objectType)) != 0 || + (ret = ser_set(serializeSettings, sa->logicalName, sizeof(sa->logicalName))) != 0) + { + break; + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + if ((ret = ser_saveUInt8(serializeSettings, sa->index)) != 0 || + (ret = ser_saveBytes(&sa->parameter, serializeSettings)) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + s->actions.size = count2; +#endif //DLMS_IGNORE_MALLOC + } + if (ret != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + object->scripts.size = count; +#endif //DLMS_IGNORE_MALLOC + } + } + return ret; +} +#endif //DLMS_IGNORE_SCRIPT_TABLE +#ifndef DLMS_IGNORE_SPECIAL_DAYS_TABLE +int ser_saveSpecialDaysTable( + gxSerializerSettings* serializeSettings, + gxSpecialDaysTable* object) +{ + int ret = 0; + uint16_t pos, count; + gxSpecialDay* sd; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + if ((ret = ser_saveArrayCount(serializeSettings, &object->entries, &count)) == 0) + { + for (pos = 0; pos != object->entries.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(&object->entries, pos, (void**)&sd, sizeof(gxSpecialDay), 0)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex3(&object->entries, pos, (void**)&sd, 0)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = ser_saveUInt16(serializeSettings, sd->index)) != 0 || + (ret = ser_saveDateTime(&sd->date, serializeSettings)) != 0 || + (ret = ser_saveUInt8(serializeSettings, sd->dayId)) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + object->entries.size = count; +#endif //DLMS_IGNORE_MALLOC + } + } + return ret; +} +#endif //DLMS_IGNORE_SPECIAL_DAYS_TABLE +#ifndef DLMS_IGNORE_TCP_UDP_SETUP +int ser_saveTcpUdpSetup( + gxSerializerSettings* serializeSettings, + gxTcpUdpSetup* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveUInt16(serializeSettings, object->port)) != 0) || +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_set(serializeSettings, obj_getLogicalName(object->ipSetup), 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0) || +#else + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_set(&ba, object->ipReference, 6)) != 0) || +#endif //DLMS_IGNORE_OBJECT_POINTERS + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveUInt16(serializeSettings, object->maximumSegmentSize)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveUInt8(serializeSettings, object->maximumSimultaneousConnections)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_saveUInt16(serializeSettings, object->inactivityTimeout)) != 0)) + { + + } + return ret; +} +#endif //DLMS_IGNORE_TCP_UDP_SETUP +#ifndef DLMS_IGNORE_MBUS_MASTER_PORT_SETUP +int ser_saveMBusMasterPortSetup( + gxSerializerSettings* serializeSettings, + gxMBusMasterPortSetup* object) +{ + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + return ser_saveUInt8(serializeSettings, object->commSpeed); + } + return 0; +} +#endif //DLMS_IGNORE_MBUS_MASTER_PORT_SETUP + +int saveTimeWindow(gxSerializerSettings* serializeSettings, gxArray* arr) +{ + int ret; + uint16_t count, pos; +#ifdef DLMS_IGNORE_MALLOC + gxTimePair* k; +#else + gxKey* k; +#endif //DLMS_IGNORE_MALLOC + if ((ret = ser_saveArrayCount(serializeSettings, arr, &count)) == 0) + { + for (pos = 0; pos != arr->size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(arr, pos, (void**)&k, sizeof(gxTimePair), 0)) != 0 || + (ret = ser_saveDateTime(&k->first, serializeSettings)) != 0 || + (ret = ser_saveDateTime(&k->second, serializeSettings)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex(arr, pos, (void**)&k), 0) != 0 || + (ret = ser_saveDateTime((gxtime*)k->key, serializeSettings)) != 0 || + (ret = ser_saveDateTime((gxtime*)k->value, serializeSettings)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } +#ifdef DLMS_IGNORE_MALLOC + arr->size = count; +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +int saveObjectsInternal(gxSerializerSettings* serializeSettings, gxArray* objects) +{ + uint16_t count, pos; + int ret; +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + gxTarget* it; +#else + gxKey* it; +#endif //DLMS_IGNORE_MALLOC + if ((ret = ser_saveArrayCount(serializeSettings, objects, &count)) == 0) + { + for (pos = 0; pos != objects->size; ++pos) + { +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(objects, pos, (void**)&it, sizeof(gxTarget), 0)) != 0 || + (ret = ser_saveUInt16(serializeSettings, pos < count ? it->target->objectType : 0)) != 0 || + (ret = ser_set(serializeSettings, pos < count ? obj_getLogicalName(it->target) : EMPTY_LN, 6, 6)) != 0 || + (ret = ser_saveUInt8(serializeSettings, pos < count ? it->attributeIndex : 0)) != 0 || + (ret = ser_saveUInt16(serializeSettings, pos < count ? it->dataIndex : 0)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex3(objects, pos, (void**)&it, 0)) != 0 || + (ret = ser_saveUInt16(serializeSettings, pos < objects->size ? it->target->objectType : 0)) != 0 || + (ret = ser_set(serializeSettings, obj_getLogicalName(it->target), 6, 6)) != 0 || + (ret = ser_saveUInt8(serializeSettings, pos < objects->size ? it->attributeIndex : 0)) != 0 || + (ret = ser_saveUInt16(serializeSettings, pos < objects->size ? it->dataIndex : 0)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC +#else + if ((ret = arr_getByIndex3(objects, pos, (void**)&it, 0)) != 0 || + (ret = ser_saveUInt16(serializeSettings, pos < objects->size ? ((gxObject*)it->key)->objectType : 0)) != 0 || + (ret = ser_set(serializeSettings, obj_getLogicalName((gxObject*)it->key), 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0 || + (ret = ser_saveUInt8(serializeSettings, pos < objects->size ? ((gxTarget*)it->value)->attributeIndex : 0)) != 0 || + (ret = ser_saveUInt16(serializeSettings, pos < objects->size ? ((gxTarget*)it->value)->dataIndex : 0)) != 0) + { + break; + } +#endif //defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + } +#ifdef DLMS_IGNORE_MALLOC + objects->size = count; +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +#ifndef DLMS_IGNORE_PUSH_SETUP +int ser_savePushSetup( + gxSerializerSettings* serializeSettings, + gxPushSetup* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = saveObjectsInternal(serializeSettings, &object->pushObjectList)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && + ((ret = ser_saveUInt8(serializeSettings, object->service)) != 0 || + (ret = ser_saveOctetString(serializeSettings, &object->destination)) != 0 || + (ret = ser_saveUInt8(serializeSettings, object->message)) != 0)) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = saveTimeWindow(serializeSettings, &object->communicationWindow)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveUInt16(serializeSettings, object->randomisationStartInterval)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_saveUInt8(serializeSettings, object->numberOfRetries)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_saveUInt16(serializeSettings, object->repetitionDelay)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_PUSH_SETUP +#ifndef DLMS_IGNORE_AUTO_CONNECT +int ser_saveAutoConnect( + gxSerializerSettings* serializeSettings, + gxAutoConnect* object) +{ +#ifdef DLMS_IGNORE_MALLOC + gxDestination* dest; +#else + gxByteBuffer* dest; +#endif //DLMS_IGNORE_MALLOC + uint16_t pos, count; + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveUInt8(serializeSettings, object->mode)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveUInt8(serializeSettings, object->repetitions)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveUInt16(serializeSettings, object->repetitionDelay)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = saveTimeWindow(serializeSettings, &object->callingWindow)) != 0)) + { + } + else + { + if (!isAttributeSet(serializeSettings, ignored, 6)) + { + if ((ret = ser_saveArrayCount(serializeSettings, &object->destinations, &count)) == 0) + { + for (pos = 0; pos != object->destinations.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(&object->destinations, pos, (void**)&dest, sizeof(gxDestination), 0)) != 0 || + (ret = ser_saveOctetString3(serializeSettings, (char*)dest->value, dest->size, sizeof(dest->value))) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex3(&object->destinations, pos, (void**)&dest, 0)) != 0 || + (ret = ser_saveOctetString3(serializeSettings, (char*)dest->data, (unsigned short)dest->size, (unsigned short)dest->capacity)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } +#ifdef DLMS_IGNORE_MALLOC + object->destinations.size = count; +#endif //DLMS_IGNORE_MALLOC + } + } + return ret; +} +#endif //DLMS_IGNORE_AUTO_CONNECT + +#ifndef DLMS_IGNORE_ACTIVITY_CALENDAR +int ser_saveSeasonProfile(gxArray* arr, gxSerializerSettings* serializeSettings) +{ + gxSeasonProfile* it; + int ret; + uint16_t pos, count; + if ((ret = ser_saveArrayCount(serializeSettings, arr, &count)) == 0) + { + for (pos = 0; pos != arr->size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(arr, pos, (void**)&it, sizeof(gxSeasonProfile), 0)) != 0) + { + break; + } + if ((ret = ser_saveOctetString3(serializeSettings, (char*)it->name.value, it->name.size, sizeof(it->name.value))) != 0 || + (ret = ser_saveDateTime(&it->start, serializeSettings)) != 0 || + (ret = ser_saveOctetString3(serializeSettings, (char*)it->weekName.value, it->weekName.size, sizeof(it->weekName.value))) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex3(arr, pos, (void**)&it, 0)) != 0) + { + break; + } + if ((ret = ser_saveOctetString(serializeSettings, &it->name)) != 0 || + (ret = ser_saveDateTime(&it->start, serializeSettings)) != 0 || + (ret = ser_saveOctetString(serializeSettings, &it->weekName)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } +#ifdef DLMS_IGNORE_MALLOC + arr->size = count; +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +int ser_saveweekProfile(gxArray* arr, gxSerializerSettings* serializeSettings) +{ + gxWeekProfile* it; + int ret; + uint16_t pos, count; + if ((ret = ser_saveArrayCount(serializeSettings, arr, &count)) == 0) + { + for (pos = 0; pos != arr->size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(arr, pos, (void**)&it, sizeof(gxWeekProfile), 0)) != 0 || + (ret = ser_saveOctetString3(serializeSettings, (char*)it->name.value, it->name.size, sizeof(it->name.value))) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex3(arr, pos, (void**)&it, 0)) != 0 || + (ret = ser_saveOctetString(serializeSettings, &it->name)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = ser_saveUInt8(serializeSettings, it->monday)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->tuesday)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->wednesday)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->thursday)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->friday)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->saturday)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->sunday)) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + arr->size = count; +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +int ser_saveDayProfile(gxArray* arr, gxSerializerSettings* serializeSettings) +{ + gxDayProfile* dp; + gxDayProfileAction* it; + int ret; + uint16_t pos, pos2, count, count2; + if ((ret = ser_saveArrayCount(serializeSettings, arr, &count)) == 0) + { + for (pos = 0; pos != arr->size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(arr, pos, (void**)&dp, sizeof(gxDayProfile), 0)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex3(arr, pos, (void**)&dp, 0)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = ser_saveUInt8(serializeSettings, dp->dayId)) != 0 || + (ret = ser_saveArrayCount(serializeSettings, &dp->daySchedules, &count2)) != 0) + { + break; + } + for (pos2 = 0; pos2 != dp->daySchedules.size; ++pos2) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(&dp->daySchedules, pos2, (void**)&it, sizeof(gxDayProfileAction), 0)) != 0 || +#else + if ((ret = arr_getByIndex3(&dp->daySchedules, pos2, (void**)&it, 0)) != 0 || +#endif //DLMS_IGNORE_MALLOC +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = ser_set(serializeSettings, obj_getLogicalName(it->script), 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0 || +#else + (ret = hlp_appendLogicalName(serializeSettings, it->scriptLogicalName)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + (ret = ser_saveUInt16(serializeSettings, it->scriptSelector)) != 0 || + (ret = ser_saveDateTime(&it->startTime, serializeSettings)) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + dp->daySchedules.size = count2; +#endif //DLMS_IGNORE_MALLOC + } +#ifdef DLMS_IGNORE_MALLOC + arr->size = count; +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +int ser_saveActivityCalendar( + gxSerializerSettings* serializeSettings, + gxActivityCalendar* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveOctetString(serializeSettings, &object->calendarNameActive)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveSeasonProfile(&object->seasonProfileActive, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveweekProfile(&object->weekProfileTableActive, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveDayProfile(&object->dayProfileTableActive, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_saveOctetString(serializeSettings, &object->calendarNamePassive)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_saveSeasonProfile(&object->seasonProfilePassive, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_saveweekProfile(&object->weekProfileTablePassive, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_saveDayProfile(&object->dayProfileTablePassive, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 10) && (ret = ser_saveDateTime(&object->time, serializeSettings)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_ACTIVITY_CALENDAR + +#ifndef DLMS_IGNORE_SECURITY_SETUP +int ser_saveSecuritySetup( + gxSerializerSettings* serializeSettings, + gxSecuritySetup* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveUInt8(serializeSettings, object->securityPolicy)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveUInt8(serializeSettings, object->securitySuite)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveOctetString(serializeSettings, &object->serverSystemTitle)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveOctetString(serializeSettings, &object->clientSystemTitle)) != 0)) + { + + } + return ret; +} +#endif //DLMS_IGNORE_SECURITY_SETUP +#ifndef DLMS_IGNORE_IEC_HDLC_SETUP +int ser_saveHdlcSetup( + gxSerializerSettings* serializeSettings, + gxIecHdlcSetup* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveUInt8(serializeSettings, object->communicationSpeed)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveUInt8(serializeSettings, object->windowSizeTransmit)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveUInt8(serializeSettings, object->windowSizeReceive)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveUInt16(serializeSettings, object->maximumInfoLengthTransmit)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_saveUInt16(serializeSettings, object->maximumInfoLengthReceive)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_saveUInt16(serializeSettings, object->interCharachterTimeout)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_saveUInt16(serializeSettings, object->inactivityTimeout)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_saveUInt16(serializeSettings, object->deviceAddress)) != 0)) + { + + } + return ret; +} +#endif //DLMS_IGNORE_IEC_HDLC_SETUP +#ifndef DLMS_IGNORE_IEC_LOCAL_PORT_SETUP +int ser_saveLocalPortSetup( + gxSerializerSettings* serializeSettings, + gxLocalPortSetup* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveUInt8(serializeSettings, object->defaultMode)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveUInt8(serializeSettings, object->defaultBaudrate)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveUInt8(serializeSettings, object->proposedBaudrate)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveUInt8(serializeSettings, object->responseTime)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_saveOctetString(serializeSettings, &object->deviceAddress)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_saveOctetString(serializeSettings, &object->password1)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_saveOctetString(serializeSettings, &object->password2)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_saveOctetString(serializeSettings, &object->password5)) != 0)) + { + + } + return ret; +} +#endif //DLMS_IGNORE_IEC_LOCAL_PORT_SETUP + +#ifndef DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP +int ser_saveIecTwistedPairSetup( + gxSerializerSettings* serializeSettings, + gxIecTwistedPairSetup* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveUInt8(serializeSettings, object->mode)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveUInt8(serializeSettings, object->speed)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveOctetString(serializeSettings, &object->primaryAddresses)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveOctetString(serializeSettings, &object->tabis)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP + +#ifndef DLMS_IGNORE_DEMAND_REGISTER +int ser_saveDemandRegister( + gxSerializerSettings* serializeSettings, + gxDemandRegister* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveBytes(&object->currentAverageValue, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveBytes(&object->lastAverageValue, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveUInt8(serializeSettings, object->scaler)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveUInt8(serializeSettings, object->unit)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_saveBytes(&object->status, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_saveDateTime(&object->captureTime, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_saveDateTime(&object->startTimeCurrent, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_saveUInt32(serializeSettings, object->period)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 10) && (ret = ser_saveUInt16(serializeSettings, object->numberOfPeriods)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_DEMAND_REGISTER +#ifndef DLMS_IGNORE_REGISTER_ACTIVATION +int ser_saveRegisterActivation( + gxSerializerSettings* serializeSettings, + gxRegisterActivation* object) +{ + int ret = 0; + uint16_t count, pos; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); +#ifdef DLMS_IGNORE_OBJECT_POINTERS + gxObjectDefinition* od; +#else + gxObject* od; +#endif //DLMS_IGNORE_OBJECT_POINTERS +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + gxRegisterActivationMask* it; +#else + gxKey* it; +#endif //DLMS_IGNORE_MALLOC + if (!isAttributeSet(serializeSettings, ignored, 2)) + { +#if defined(DLMS_IGNORE_MALLOC) + if ((ret = ser_saveArrayCount(serializeSettings, &object->registerAssignment, &count)) == 0) +#else + if ((ret = ser_saveObjectArrayCount(serializeSettings, &object->registerAssignment, &count)) == 0) +#endif //DLMS_IGNORE_MALLOC + { + for (pos = 0; pos != object->registerAssignment.size; ++pos) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS +#if defined(DLMS_IGNORE_MALLOC) + if ((ret = arr_getByIndexRef(&object->registerAssignment, pos, (void**)&od)) != 0 || +#else +#if defined(DLMS_COSEM_EXACT_DATA_TYPES) + if ((ret = arr_getByIndex3(&object->registerAssignment, pos, (void**)&od, 0)) != 0 || +#else + if ((ret = oa_getByIndex(&object->registerAssignment, pos, &od)) != 0 || +#endif //defined(DLMS_COSEM_EXACT_DATA_TYPES) +#endif //DLMS_IGNORE_MALLOC +#else + if ((ret = arr_getByIndex3(&object->registerAssignment, pos, (void**)&od, 0)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + (ret = ser_saveUInt16(serializeSettings, pos < count && od != NULL ? od->objectType : 0)) != 0 || + (ret = ser_set(serializeSettings, pos < count && od != NULL ? obj_getLogicalName(od) : EMPTY_LN, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + object->registerAssignment.size = count; +#endif //DLMS_IGNORE_MALLOC + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3) && + (ret = ser_saveArrayCount(serializeSettings, &object->maskList, &count)) == 0) + { + for (pos = 0; pos != object->maskList.size; ++pos) + { +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(&object->maskList, pos, (void**)&it, sizeof(gxRegisterActivationMask), 0)) != 0 || + (ret = ser_saveOctetString3(serializeSettings, (char*)it->name, it->length, sizeof(it->name))) != 0 || + (ret = ser_saveOctetString3(serializeSettings, (char*)it->indexes, it->count, sizeof(it->indexes))) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex4(&object->maskList, pos, (void**)&it, sizeof(gxRegisterActivationMask), 0)) != 0 || + (ret = ser_saveOctetString(serializeSettings, &it->name)) != 0 || + (ret = ser_saveOctetString(serializeSettings, &it->indexes)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC +#else + if ((ret = arr_getByIndex3(&object->maskList, pos, (void**)&it, 0)) != 0 || + (ret = ser_saveOctetString(serializeSettings, (gxByteBuffer*)it->key)) != 0 || + (ret = ser_saveOctetString(serializeSettings, (gxByteBuffer*)it->value)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } +#ifdef DLMS_IGNORE_MALLOC + object->maskList.size = count; +#endif //DLMS_IGNORE_MALLOC + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 4)) + { + ret = ser_saveOctetString(serializeSettings, &object->activeMask); + } + return ret; +} +#endif //DLMS_IGNORE_REGISTER_ACTIVATION + +#if !(defined(DLMS_IGNORE_REGISTER_MONITOR) && defined(DLMS_IGNORE_LIMITER)) +int ser_saveActionItem( + gxActionItem* item, + gxSerializerSettings* serializeSettings) +{ + int ret; +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = ser_set(serializeSettings, obj_getLogicalName((gxObject*)item->script), 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0 || +#else + if ((ret = ser_set(serializeSettings, item->logicalName, 6)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + (ret = ser_saveUInt16(serializeSettings, item->scriptSelector)) != 0) + { + } + return ret; +} +#endif //!defined(DLMS_IGNORE_REGISTER_MONITOR) && !defined(DLMS_IGNORE_LIMITER) + +#ifndef DLMS_IGNORE_REGISTER_MONITOR +int ser_saveRegisterMonitor( + gxSerializerSettings* serializeSettings, + gxRegisterMonitor* object) +{ + int ret = 0; + uint16_t count, pos; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + dlmsVARIANT* tmp; + gxActionSet* as; + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + if ((ret = ser_saveVariantArrayCount(serializeSettings, &object->thresholds, &count)) == 0) + { + for (pos = 0; pos != object->thresholds.size; ++pos) + { + if (pos < object->thresholds.size) + { + if ((ret = va_getByIndex(&object->thresholds, pos, &tmp)) != 0) + { + break; + } + } + if ((ret = ser_saveBytes(tmp, serializeSettings)) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + object->thresholds.size = count; +#endif //DLMS_IGNORE_MALLOC + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3)) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if (((ret = ser_saveUInt16(serializeSettings, object->monitoredValue.target == NULL ? 0 : object->monitoredValue.target->objectType)) != 0 || + (ret = ser_set(serializeSettings, obj_getLogicalName(object->monitoredValue.target), 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0)) + { + + } +#else + if ((ret = ser_saveUInt16(serializeSettings, object->monitoredValue.target == NULL ? 0 : object->monitoredValue.objectType)) != 0 || + (ret = ser_set(serializeSettings, obj_getLogicalName(object->monitoredValue.logicalName), 6)) != 0) + { + + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + if (ret == 0) + { + ret = ser_saveUInt8(serializeSettings, object->monitoredValue.attributeIndex); + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 4)) + { + if ((ret = ser_saveArrayCount(serializeSettings, &object->actions, &count)) == 0) + { + for (pos = 0; pos != object->actions.size; ++pos) + { + +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(&object->actions, pos, (void**)&as, sizeof(gxActionSet), 0)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex3(&object->actions, pos, (void**)&as, 0)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = ser_saveActionItem(&as->actionUp, serializeSettings)) != 0 || + (ret = ser_saveActionItem(&as->actionDown, serializeSettings)) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + object->actions.size = count; +#endif //DLMS_IGNORE_MALLOC + } + } + return ret; +} +#endif //DLMS_IGNORE_REGISTER_MONITOR +#ifndef DLMS_IGNORE_ACTION_SCHEDULE +int ser_saveActionSchedule( + gxSerializerSettings* serializeSettings, + gxActionSchedule* object) +{ + uint16_t pos, count; + int ret = 0; + gxtime* tm; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = ser_set(serializeSettings, obj_getLogicalName((gxObject*)object->executedScript), 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) == 0) + { + ret = ser_saveUInt16(serializeSettings, object->executedScriptSelector); + } +#else + if ((ret = ser_set(serializeSettings, object->executedScriptLogicalName, 6)) == 0) + { + ret = ser_saveUInt16(serializeSettings, object->executedScriptSelector); + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3)) + { + ret = ser_saveUInt8(serializeSettings, object->type); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 4)) + { + //Add count. + if ((ret = ser_saveArrayCount(serializeSettings, &object->executionTime, &count)) == 0) + { + for (pos = 0; pos != object->executionTime.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(&object->executionTime, pos, (void**)&tm, sizeof(gxtime), 0)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex3(&object->executionTime, pos, (void**)&tm, 0)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = ser_saveDateTime(tm, serializeSettings)) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + object->executionTime.size = count; +#endif //DLMS_IGNORE_MALLOC + } + } + return ret; +} +#endif //DLMS_IGNORE_ACTION_SCHEDULE +#ifndef DLMS_IGNORE_SAP_ASSIGNMENT +int ser_saveSapAssignment( + gxSerializerSettings* serializeSettings, + gxSapAssignment* object) +{ + uint16_t pos, count; + int ret = 0; + gxSapItem* it; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + //Add count. + if ((ret = ser_saveArrayCount(serializeSettings, &object->sapAssignmentList, &count)) == 0) + { + for (pos = 0; pos != object->sapAssignmentList.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(&object->sapAssignmentList, pos, (void**)&it, sizeof(gxSapItem), 0)) != 0 || + (ret = ser_saveUInt16(serializeSettings, it->id)) != 0 || + (ret = ser_saveOctetString3(serializeSettings, (char*)it->name.value, it->name.size, sizeof(it->name.value))) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex3(&object->sapAssignmentList, pos, (void**)&it, 0)) != 0 || + (ret = ser_saveUInt16(serializeSettings, it->id)) != 0 || + (ret = ser_saveOctetString(serializeSettings, &it->name)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } +#ifdef DLMS_IGNORE_MALLOC + object->sapAssignmentList.size = count; +#endif //DLMS_IGNORE_MALLOC + } + } + return ret; +} +#endif //DLMS_IGNORE_SAP_ASSIGNMENT + +#ifndef DLMS_IGNORE_AUTO_ANSWER +int ser_saveAutoAnswer( + gxSerializerSettings* serializeSettings, + gxAutoAnswer* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveUInt8(serializeSettings, object->mode)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = saveTimeWindow(serializeSettings, &object->listeningWindow)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveUInt8(serializeSettings, object->status)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveUInt8(serializeSettings, object->numberOfCalls)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_saveUInt8(serializeSettings, object->numberOfRingsInListeningWindow)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_saveUInt8(serializeSettings, object->numberOfRingsOutListeningWindow)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_saveUInt8(serializeSettings, object->numberOfRingsOutListeningWindow)) != 0)) + { + + } + return ret; +} +#endif //DLMS_IGNORE_AUTO_ANSWER +#ifndef DLMS_IGNORE_IP4_SETUP +int ser_saveIp4Setup( + gxSerializerSettings* serializeSettings, + gxIp4Setup* object) +{ + uint16_t pos, count; + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + uint32_t* tmp; +#else + dlmsVARIANT* tmp; +#endif //DLMS_IGNORE_MALLOC + gxip4SetupIpOption* ip; + if (!isAttributeSet(serializeSettings, ignored, 2)) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + ret = ser_set(serializeSettings, obj_getLogicalName(object->dataLinkLayer), 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + ); + +#else + ret = ser_set(serializeSettings, object->dataLinkLayerReference, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3)) + { + (ret = ser_saveUInt32(serializeSettings, object->ipAddress)); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 4)) + { +#if defined(DLMS_IGNORE_MALLOC) + if ((ret = ser_saveArrayCount(serializeSettings, &object->multicastIPAddress, &count)) == 0) +#else + if ((ret = ser_saveVariantArrayCount(serializeSettings, &object->multicastIPAddress, &count)) == 0) +#endif //DLMS_IGNORE_MALLOC + { + for (pos = 0; pos != object->multicastIPAddress.size; ++pos) + { +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + if ((ret = arr_getByIndex4(&object->multicastIPAddress, pos, (void**)&tmp, sizeof(uint32_t), 0)) != 0 || + (ret = ser_saveUInt32(serializeSettings, *tmp)) != 0) + { + break; + } +#else + if ((ret = va_getByIndex(&object->multicastIPAddress, pos, &tmp)) != 0 || + (ret = ser_saveUInt32(serializeSettings, tmp->ulVal)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } +#ifdef DLMS_IGNORE_MALLOC + object->multicastIPAddress.size = count; +#endif //DLMS_IGNORE_MALLOC + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 5) && + (ret = ser_saveArrayCount(serializeSettings, &object->ipOptions, &count)) == 0) + { + for (pos = 0; pos != object->ipOptions.size; ++pos) + { + +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(&object->ipOptions, pos, (void**)&ip, sizeof(gxip4SetupIpOption), 0)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex3(&object->ipOptions, pos, (void**)&ip, 0)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = ser_saveUInt8(serializeSettings, ip->type)) != 0) + { + break; + } + +#ifdef DLMS_IGNORE_MALLOC + if ((ret = ser_saveOctetString3(serializeSettings, (char*)ip->data.value, ip->data.size, sizeof(ip->data.value))) != 0) + { + break; + } +#else + if ((ret = ser_saveOctetString(serializeSettings, &ip->data)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } +#ifdef DLMS_IGNORE_MALLOC + object->ipOptions.size = count; +#endif //DLMS_IGNORE_MALLOC + } + if (ret == 0) + { + if ((!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_saveUInt32(serializeSettings, object->subnetMask)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_saveUInt32(serializeSettings, object->gatewayIPAddress)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_saveUInt8(serializeSettings, object->useDHCP)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_saveUInt32(serializeSettings, object->primaryDNSAddress)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 10) && (ret = ser_saveUInt32(serializeSettings, object->secondaryDNSAddress)) != 0)) + { + } + } + return ret; +} +#endif //DLMS_IGNORE_IP4_SETUP + +#ifndef DLMS_IGNORE_IP6_SETUP + +int saveIpv6Address(IN6_ADDR* address, gxSerializerSettings* serializeSettings) +{ + unsigned char* tmp; +#if defined(_WIN32) || defined(_WIN64)//Windows includes + tmp = address->u.Byte; +#else //Linux includes. + tmp = address->s6_addr; +#endif + return ser_set(serializeSettings, tmp, 16 +#ifdef DLMS_IGNORE_MALLOC + , 16 +#endif //DLMS_IGNORE_MALLOC + ); +} + +int saveAddressList(gxArray* list, gxSerializerSettings* serializeSettings) +{ + IN6_ADDR* it; + uint16_t pos, count; + int ret = 0; + if ((ret = ser_saveArrayCount(serializeSettings, list, &count)) == 0) + { + for (pos = 0; pos != list->size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(list, pos, (void**)&it, sizeof(IN6_ADDR), 0)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex3(list, pos, (void**)&it, 0)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = saveIpv6Address(it, serializeSettings)) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + list->size = count; +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +int ser_saveIp6Setup( + gxSerializerSettings* serializeSettings, + gxIp6Setup* object) +{ + uint16_t pos, count; + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + ret = ser_set(serializeSettings, obj_getLogicalName(object->dataLinkLayer), 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + ); +#else + ret = ser_set(serializeSettings, object->dataLinkLayerReference, 6)); +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + if (ret == 0) + { + if ((!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveUInt8(serializeSettings, object->addressConfigMode)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = saveAddressList(&object->unicastIPAddress, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = saveAddressList(&object->multicastIPAddress, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = saveAddressList(&object->gatewayIPAddress, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = saveIpv6Address(&object->primaryDNSAddress, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = saveIpv6Address(&object->secondaryDNSAddress, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_saveUInt8(serializeSettings, object->trafficClass)) != 0)) + { + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 10)) + { + gxNeighborDiscoverySetup* it; + if ((ret = ser_saveArrayCount(serializeSettings, &object->neighborDiscoverySetup, &count)) == 0) + { + for (pos = 0; pos != object->neighborDiscoverySetup.size; ++pos) + { + if ((ret = arr_getByIndex4(&object->neighborDiscoverySetup, pos, (void**)&it, sizeof(gxNeighborDiscoverySetup), 0)) != 0) + { + break; + } + if ((ret = ser_saveUInt8(serializeSettings, it->maxRetry)) != 0 || + (ret = ser_saveUInt16(serializeSettings, it->retryWaitTime)) != 0 || + (ret = ser_saveUInt32(serializeSettings, it->sendPeriod)) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + object->neighborDiscoverySetup.size = count; +#endif //DLMS_IGNORE_MALLOC + } + } + return ret; +} +#endif //DLMS_IGNORE_IP6_SETUP + + +#ifndef DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS +int ser_saveG3PlcMacLayerCounters( + gxSerializerSettings* serializeSettings, + gxG3PlcMacLayerCounters* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveUInt32(serializeSettings, object->txDataPacketCount)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveUInt32(serializeSettings, object->rxDataPacketCount)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveUInt32(serializeSettings, object->txCmdPacketCount)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveUInt32(serializeSettings, object->rxCmdPacketCount)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_saveUInt32(serializeSettings, object->cSMAFailCount)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_saveUInt32(serializeSettings, object->cSMANoAckCount)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_saveUInt32(serializeSettings, object->badCrcCount)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_saveUInt32(serializeSettings, object->txDataBroadcastCount)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 10) && (ret = ser_saveUInt32(serializeSettings, object->rxDataBroadcastCount)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS + +#ifndef DLMS_IGNORE_G3_PLC_MAC_SETUP +int ser_saveKeyTable(gxSerializerSettings* serializeSettings, gxArray* keys) +{ + int ret; + uint16_t pos, count; + gxG3MacKeyTable* it; + if ((ret = ser_saveArrayCount(serializeSettings, keys, &count)) == 0) + { + for (pos = 0; pos != keys->size; ++pos) + { + if ((ret = arr_getByIndex4(keys, pos, (void**)&it, sizeof(gxG3MacKeyTable), 0)) != 0) + { + break; + } + if ((ret = ser_saveUInt8(serializeSettings, it->id)) != 0 || + (ret = ser_saveOctetString3(serializeSettings, (char*)it->key, MAX_G3_MAC_KEY_TABLE_KEY_SIZE, MAX_G3_MAC_KEY_TABLE_KEY_SIZE)) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + keys->size = count; +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +int ser_saveNeighbourTable(gxSerializerSettings* serializeSettings, gxArray* neighbours) +{ + int ret; + uint16_t pos, count; + gxNeighbourTable* it; + if ((ret = ser_saveArrayCount(serializeSettings, neighbours, &count)) == 0) + { + for (pos = 0; pos != neighbours->size; ++pos) + { + if ((ret = arr_getByIndex4(neighbours, pos, (void**)&it, sizeof(gxNeighbourTable), 0)) != 0) + { + break; + } + if ((ret = ser_saveUInt16(serializeSettings, it->shortAddress)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->payloadModulationScheme)) != 0 || +#ifdef DLMS_IGNORE_MALLOC + (ret = ser_saveBitString2(serializeSettings, it->toneMap[pos].value, it->toneMap[pos].size, 8 * MAX_G3_MAC_NEIGHBOUR_TABLE_TONE_MAP_ITEM_SIZE)) != 0 || +#else + (ret = ser_saveBitString(serializeSettings, &it->toneMap)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = ser_saveUInt8(serializeSettings, it->modulation)) != 0 || + (ret = ser_saveInt8(serializeSettings, it->txGain)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->txRes)) != 0 || +#ifdef DLMS_IGNORE_MALLOC + (ret = ser_saveBitString2(serializeSettings, it->txCoeff[pos].value, it->txCoeff[pos].size, 8 * MAX_G3_MAC_NEIGHBOUR_TABLE_GAIN_ITEM_SIZE)) != 0 || +#else + (ret = ser_saveBitString(serializeSettings, &it->txCoeff)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = ser_saveUInt8(serializeSettings, it->lqi)) != 0 || + (ret = ser_saveInt8(serializeSettings, it->phaseDifferential)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->tmrValidTime)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->noData)) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + neighbours->size = count; +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +int ser_saveMacPosTable(gxSerializerSettings* serializeSettings, gxArray* table) +{ + int ret; + uint16_t pos, count; + gxMacPosTable* it; + if ((ret = ser_saveArrayCount(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != table->size; ++pos) + { + if ((ret = arr_getByIndex4(table, pos, (void**)&it, sizeof(gxMacPosTable), 0)) != 0) + { + break; + } + if ((ret = ser_saveUInt16(serializeSettings, it->shortAddress)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->lqi)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->validTime)) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + table->size = count; +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +int ser_saveG3PlcMacSetup( + gxSerializerSettings* serializeSettings, + gxG3PlcMacSetup* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveUInt16(serializeSettings, object->shortAddress)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveUInt16(serializeSettings, object->rcCoord)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveUInt16(serializeSettings, object->panId)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveKeyTable(serializeSettings, &object->keyTable)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_saveUInt32(serializeSettings, object->frameCounter)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_saveBitString(serializeSettings, &object->toneMask)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_saveUInt8(serializeSettings, object->tmrTtl)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_saveUInt8(serializeSettings, object->maxFrameRetries)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 10) && (ret = ser_saveUInt8(serializeSettings, object->neighbourTableEntryTtl)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 11) && (ret = ser_saveNeighbourTable(serializeSettings, &object->neighbourTable)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 12) && (ret = ser_saveUInt8(serializeSettings, object->highPriorityWindowSize)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 13) && (ret = ser_saveUInt8(serializeSettings, object->cscmFairnessLimit)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 14) && (ret = ser_saveUInt8(serializeSettings, object->beaconRandomizationWindowLength)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 15) && (ret = ser_saveUInt8(serializeSettings, object->macA)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 16) && (ret = ser_saveUInt8(serializeSettings, object->macK)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 17) && (ret = ser_saveUInt8(serializeSettings, object->minCwAttempts)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 18) && (ret = ser_saveUInt8(serializeSettings, object->cenelecLegacyMode)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 19) && (ret = ser_saveUInt8(serializeSettings, object->fccLegacyMode)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 20) && (ret = ser_saveUInt8(serializeSettings, object->maxBe)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 21) && (ret = ser_saveUInt8(serializeSettings, object->maxCsmaBackoffs)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 22) && (ret = ser_saveUInt8(serializeSettings, object->minBe)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 23) && (ret = ser_saveUInt8(serializeSettings, object->macBroadcastMaxCwEnabled)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 24) && (ret = ser_saveUInt8(serializeSettings, object->macTransmitAtten)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 25) && (ret = ser_saveMacPosTable(serializeSettings, &object->macPosTable)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_G3_PLC_MAC_SETUP + +#ifndef DLMS_IGNORE_G3_PLC_6LO_WPAN + +int ser_saveRoutingConfiguration(gxSerializerSettings* serializeSettings, gxArray* table) +{ + int ret; + uint16_t pos, count; + gxRoutingConfiguration* it; + if ((ret = ser_saveArrayCount(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != table->size; ++pos) + { + if ((ret = arr_getByIndex4(table, pos, (void**)&it, sizeof(gxRoutingConfiguration), 0)) != 0) + { + break; + } + if ((ret = ser_saveUInt8(serializeSettings, it->netTraversalTime)) != 0 || + (ret = ser_saveUInt16(serializeSettings, it->routingTableEntryTtl)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->kr)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->km)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->kc)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->kq)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->kh)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->krt)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->rReqRetries)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->rReqReqWait)) != 0 || + (ret = ser_saveUInt16(serializeSettings, it->blacklistTableEntryTtl)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->unicastRreqGenEnable)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->rlcEnabled)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->addRevLinkCost)) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + table->size = count; +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +int ser_saveRoutingTable(gxSerializerSettings* serializeSettings, gxArray* table) +{ + int ret; + uint16_t pos, count; + gxRoutingTable* it; + if ((ret = ser_saveArrayCount(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != table->size; ++pos) + { + if ((ret = arr_getByIndex4(table, pos, (void**)&it, sizeof(gxRoutingTable), 0)) != 0) + { + break; + } + if ((ret = ser_saveUInt16(serializeSettings, it->destinationAddress)) != 0 || + (ret = ser_saveUInt16(serializeSettings, it->nextHopAddress)) != 0 || + (ret = ser_saveUInt16(serializeSettings, it->routeCost)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->hopCount)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->weakLinkCount)) != 0 || + (ret = ser_saveUInt16(serializeSettings, it->validTime)) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + table->size = count; +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +int ser_saveContextInformationTable(gxSerializerSettings* serializeSettings, gxArray* table) +{ + int ret; + uint16_t pos, count; + gxContextInformationTable* it; + if ((ret = ser_saveArrayCount(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != table->size; ++pos) + { + if ((ret = arr_getByIndex4(table, pos, (void**)&it, sizeof(gxContextInformationTable), 0)) != 0) + { + break; + } + if ((ret = ser_saveUInt8(serializeSettings, it->cid)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->contextLength)) != 0 || + (ret = ser_saveOctetString3(serializeSettings, (char*)it->context, 16, 16)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->compression)) != 0 || + (ret = ser_saveUInt16(serializeSettings, it->validLifetime)) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + table->size = count; +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +int ser_saveBlacklistTable(gxSerializerSettings* serializeSettings, gxArray* table) +{ + int ret; + uint16_t pos, count; + gxBlacklistTable* it; + if ((ret = ser_saveArrayCount(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != table->size; ++pos) + { + if ((ret = arr_getByIndex4(table, pos, (void**)&it, sizeof(gxBlacklistTable), 0)) != 0) + { + break; + } + if ((ret = ser_saveUInt16(serializeSettings, it->neighbourAddress)) != 0 || + (ret = ser_saveUInt16(serializeSettings, it->validTime)) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + table->size = count; +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +int ser_saveBroadcastLogTable(gxSerializerSettings* serializeSettings, gxArray* table) +{ + int ret; + uint16_t pos, count; + gxBroadcastLogTable* it; + if ((ret = ser_saveArrayCount(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != table->size; ++pos) + { + if ((ret = arr_getByIndex4(table, pos, (void**)&it, sizeof(gxBroadcastLogTable), 0)) != 0) + { + break; + } + if ((ret = ser_saveUInt16(serializeSettings, it->sourceAddress)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->sequenceNumber)) != 0 || + (ret = ser_saveUInt16(serializeSettings, it->validTime)) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + table->size = count; +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) +int ser_saveUInt16Array(gxSerializerSettings* serializeSettings, gxArray* table) +{ + int ret; + uint16_t pos, count; + uint16_t* it; + if ((ret = ser_saveArrayCount(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != table->size; ++pos) + { + if ((ret = arr_getByIndex4(table, pos, (void**)&it, sizeof(uint16_t), 0)) != 0) + { + break; + } + if ((ret = ser_saveUInt16(serializeSettings, *it)) != 0) + { + break; + } + } + table->size = count; + } + return ret; +} +#else +int ser_saveUInt16Array(gxSerializerSettings* serializeSettings, variantArray* table) +{ + int ret; + uint16_t pos, count; + dlmsVARIANT* it; + if ((ret = ser_saveVariantArrayCount(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != table->size; ++pos) + { + if ((ret = va_getByIndex(table, pos, &it)) != 0) + { + break; + } + if ((ret = ser_saveUInt16(serializeSettings, it->uiVal)) != 0) + { + break; + } + } + } + return ret; +} +#endif //defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + +int ser_saveG3Plc6LoWPAN( + gxSerializerSettings* serializeSettings, + gxG3Plc6LoWPAN* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveUInt8(serializeSettings, object->maxHops)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveUInt8(serializeSettings, object->weakLqiValue)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveUInt8(serializeSettings, object->securityLevel)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveOctetString(serializeSettings, &object->prefixTable)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_saveRoutingConfiguration(serializeSettings, &object->routingConfiguration)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_saveUInt16(serializeSettings, object->broadcastLogTableEntryTtl)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_saveRoutingTable(serializeSettings, &object->routingTable)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_saveContextInformationTable(serializeSettings, &object->contextInformationTable)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 10) && (ret = ser_saveBlacklistTable(serializeSettings, &object->blacklistTable)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 11) && (ret = ser_saveBroadcastLogTable(serializeSettings, &object->broadcastLogTable)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 12) && (ret = ser_saveUInt16Array(serializeSettings, &object->groupTable)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 13) && (ret = ser_saveUInt16(serializeSettings, object->maxJoinWaitTime)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 14) && (ret = ser_saveUInt8(serializeSettings, object->pathDiscoveryTime)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 15) && (ret = ser_saveUInt8(serializeSettings, object->activeKeyIndex)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 16) && (ret = ser_saveUInt8(serializeSettings, object->metricType)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 17) && (ret = ser_saveUInt16(serializeSettings, object->coordShortAddress)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 18) && (ret = ser_saveUInt8(serializeSettings, object->disableDefaultRouting)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 19) && (ret = ser_saveUInt8(serializeSettings, object->deviceType)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 20) && (ret = ser_saveUInt8(serializeSettings, object->defaultCoordRouteEnabled)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 21) && (ret = ser_saveUInt16Array(serializeSettings, &object->destinationAddress)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 22) && (ret = ser_saveUInt8(serializeSettings, object->lowLQI)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 23) && (ret = ser_saveUInt8(serializeSettings, object->highLQI)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_G3_PLC_6LO_WPAN + +#ifndef DLMS_IGNORE_FUNCTION_CONTROL + +int ser_saveActivationStatus(gxSerializerSettings* serializeSettings, gxArray* table) +{ + int ret; + uint16_t pos, count; + functionStatus* it; + if ((ret = ser_saveArrayCount(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != table->size; ++pos) + { + if ((ret = arr_getByIndex4(table, pos, (void**)&it, sizeof(functionStatus), 0)) != 0) + { + break; + } +#ifdef DLMS_IGNORE_MALLOC + if ((ret = ser_saveOctetString3(serializeSettings, (char*)it->name, it->size, sizeof(it->name))) != 0) + { + break; + } +#else + if ((ret = ser_saveOctetString(serializeSettings, &it->name)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + + if ((ret = ser_saveUInt8(serializeSettings, it->status)) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + table->size = count; +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +int ser_saveFunctionList(gxSerializerSettings* serializeSettings, gxArray* table) +{ + int ret; + uint16_t pos, pos2, count; + functionalBlock* it; + gxObject* obj; + if ((ret = ser_saveArrayCount(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != table->size; ++pos) + { + if ((ret = arr_getByIndex4(table, pos, (void**)&it, sizeof(functionalBlock), 0)) != 0) + { + break; + } +#ifdef DLMS_IGNORE_MALLOC + if ((ret = ser_saveOctetString3(serializeSettings, (char*)it->name, it->nameSize, sizeof(it->name))) != 0) + { + break; + } + //Save count. + if ((ret = ser_saveObjectCount(it->functionSpecificationsSize, serializeSettings)) == 0 && + //Save capacity. + (ret = ser_saveObjectCount(MAX_FUNCTION_TARGET_LENGTH, serializeSettings)) == 0) +#else + if ((ret = ser_saveOctetString(serializeSettings, &it->name)) != 0) + { + break; + } + if ((ret = ser_saveObjectArrayCount(serializeSettings, &it->functionSpecifications, &count)) == 0) +#endif //DLMS_IGNORE_MALLOC + { +#ifdef DLMS_IGNORE_MALLOC + for (pos2 = 0; pos2 != MAX_FUNCTION_TARGET_LENGTH; ++pos2) +#else + for (pos2 = 0; pos2 != it->functionSpecifications.size; ++pos2) +#endif //DLMS_IGNORE_MALLOC + { +#ifndef DLMS_IGNORE_MALLOC + if ((ret = oa_getByIndex(&it->functionSpecifications, pos2, &obj)) != DLMS_ERROR_CODE_OK || + (ret = ser_saveUInt16(serializeSettings, obj->objectType)) != DLMS_ERROR_CODE_OK || + (ret = ser_set(serializeSettings, obj->logicalName, 6)) != 0) + { + break; + } +#else + if (pos < it->functionSpecificationsSize) + { + obj = it->functionSpecifications[pos2]; + } + else + { + obj = NULL; + } + if ((ret = ser_saveUInt16(serializeSettings, obj == NULL ? 0 : obj->objectType)) != DLMS_ERROR_CODE_OK || + (ret = ser_set(serializeSettings, obj_getLogicalName(obj), 6, 6)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + if (ret != 0) + { + return ret; + } + } +#ifdef DLMS_IGNORE_MALLOC + table->size = count; +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +int ser_saveFunctionControl( + gxSerializerSettings* serializeSettings, + gxFunctionControl* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveActivationStatus(serializeSettings, &object->activationStatus)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveFunctionList(serializeSettings, &object->functions)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_FUNCTION_CONTROL + +#ifndef DLMS_IGNORE_ARRAY_MANAGER + +int ser_saveArrayManagerElements(gxSerializerSettings* serializeSettings, gxArray* table) +{ + int ret; + uint16_t pos, count; + gxArrayManagerItem* it; + if ((ret = ser_saveArrayCount(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != table->size; ++pos) + { + if ((ret = arr_getByIndex4(table, pos, (void**)&it, sizeof(gxArrayManagerItem), 0)) != 0) + { + break; + } + if ((ret = ser_saveUInt8(serializeSettings, it->id)) != 0 || + (ret = ser_saveUInt16(serializeSettings, it->element.target != NULL ? it->element.target->objectType : 0)) != 0 || + (ret = ser_set(serializeSettings, obj_getLogicalName(it->element.target), 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0 || + (ret = ser_saveInt8(serializeSettings, it->element.attributeIndex)) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + table->size = count; +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +int ser_saveArrayManager( + gxSerializerSettings* serializeSettings, + gxArrayManager* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveArrayManagerElements(serializeSettings, &object->elements)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_ARRAY_MANAGER + +#ifndef DLMS_IGNORE_UTILITY_TABLES +int ser_saveUtilityTables( + gxSerializerSettings* serializeSettings, + gxUtilityTables* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveUInt16(serializeSettings, object->tableId)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveOctetString(serializeSettings, &object->buffer)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_UTILITY_TABLES + +#ifndef DLMS_IGNORE_MBUS_DIAGNOSTIC +int ser_saveMbusDiagnostic( + gxSerializerSettings* serializeSettings, + gxMbusDiagnostic* object) +{ + gxBroadcastFrameCounter* it; + int ret = 0; + uint16_t pos, count; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveUInt8(serializeSettings, object->receivedSignalStrength)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveUInt8(serializeSettings, object->channelId)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveUInt8(serializeSettings, object->linkStatus)) != 0)) + { + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 5)) + { + if ((ret = ser_saveArrayCount(serializeSettings, &object->broadcastFrames, &count)) == 0) + { + for (pos = 0; pos != object->broadcastFrames.size; ++pos) + { + if ((ret = arr_getByIndex4(&object->broadcastFrames, pos, (void**)&it, sizeof(gxBroadcastFrameCounter), 0)) != 0) + { + break; + } + if ((ret = ser_saveUInt8(serializeSettings, it->clientId)) != 0 || + (ret = ser_saveUInt32(serializeSettings, it->counter)) != 0 || + (ret = ser_saveDateTime(&it->timeStamp, serializeSettings)) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + object->broadcastFrames.size = count; +#endif //DLMS_IGNORE_MALLOC + } + if (ret == 0) + { + if ((!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_saveUInt32(serializeSettings, object->transmissions)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_saveUInt32(serializeSettings, object->receivedFrames)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_saveUInt32(serializeSettings, object->failedReceivedFrames)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_saveUInt8(serializeSettings, object->captureTime.attributeId)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_saveDateTime(&object->captureTime.timeStamp, serializeSettings)) != 0)) + { + } + } + } + return ret; +} +#endif //DLMS_IGNORE_MBUS_DIAGNOSTIC + +int ser_loadArray(gxSerializerSettings* serializeSettings, gxArray* arr, uint16_t* count) +{ + int ret = ser_loadObjectCount(serializeSettings, count); + if (ret == 0) + { +#ifdef DLMS_IGNORE_MALLOC + arr->size = *count; + ret = ser_loadObjectCount(serializeSettings, count); + if (arr_getCapacity(arr) != *count) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } +#else + arr_clear(arr); + arr_capacity(arr, *count); +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +int loadTimeWindow( + gxSerializerSettings* serializeSettings, + gxArray* arr) +{ + int ret; + uint16_t pos; + gxtime* start, * end; + uint16_t count; +#ifdef DLMS_IGNORE_MALLOC + gxTimePair* k; +#endif //DLMS_IGNORE_MALLOC + arr_clearKeyValuePair(arr); + if ((ret = ser_loadArray(serializeSettings, arr, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(arr, pos, (void**)&k, sizeof(gxTimePair), 0)) != 0) + { + break; + } + start = &k->first; + end = &k->second; +#else + start = (gxtime*)gxmalloc(sizeof(gxtime)); + if (start == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + end = (gxtime*)gxmalloc(sizeof(gxtime)); + if (end == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + if ((ret = arr_push(arr, key_init(start, end))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = ser_loadDateTime(start, serializeSettings, DLMS_DATA_TYPE_DATETIME)) != 0 || + (ret = ser_loadDateTime(end, serializeSettings, DLMS_DATA_TYPE_DATETIME)) != 0) + { + break; + } + } + } + return ret; +} + +#ifndef DLMS_IGNORE_MBUS_PORT_SETUP +int ser_saveMbusPortSetup( + gxSerializerSettings* serializeSettings, + gxMBusPortSetup* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_set(serializeSettings, object->profileSelection, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveUInt8(serializeSettings, object->portCommunicationStatus)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveUInt8(serializeSettings, object->dataHeaderType)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveUInt8(serializeSettings, object->primaryAddress)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_saveUInt32(serializeSettings, object->identificationNumber)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_saveUInt16(serializeSettings, object->manufacturerId)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_saveUInt8(serializeSettings, object->mBusVersion)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_saveUInt8(serializeSettings, object->deviceType)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 10) && (ret = ser_saveUInt16(serializeSettings, object->maxPduSize)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 11) && (ret = saveTimeWindow(serializeSettings, &object->listeningWindow)) != 0)) + + { + } + return ret; +} +#endif //DLMS_IGNORE_MBUS_PORT_SETUP + +#ifndef DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP +int ser_saveMbusSlavePortSetup( + gxSerializerSettings* serializeSettings, + gxMbusSlavePortSetup* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveUInt8(serializeSettings, object->defaultBaud)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveUInt8(serializeSettings, object->availableBaud)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveUInt8(serializeSettings, object->addressState)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveUInt8(serializeSettings, object->busAddress)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP +#ifndef DLMS_IGNORE_IMAGE_TRANSFER +int ser_saveImageTransfer( + gxSerializerSettings* serializeSettings, + gxImageTransfer* object) +{ + uint16_t pos, count; + int ret = 0; + gxImageActivateInfo* it; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveUInt32(serializeSettings, object->imageBlockSize)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveBitString(serializeSettings, &object->imageTransferredBlocksStatus)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveUInt32(serializeSettings, object->imageFirstNotTransferredBlockNumber)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveUInt8(serializeSettings, object->imageTransferEnabled)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_saveUInt8(serializeSettings, object->imageTransferStatus)) != 0)) + { + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 7)) + { + if ((ret = ser_saveArrayCount(serializeSettings, &object->imageActivateInfo, &count)) == 0) + { + for (pos = 0; pos != object->imageActivateInfo.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(&object->imageActivateInfo, pos, (void**)&it, sizeof(gxImageActivateInfo), 0)) != 0) + { + break; + } + if ((ret = ser_saveUInt32(serializeSettings, it->size)) != 0 || + (ret = ser_saveOctetString3(serializeSettings, (char*)it->identification.data, it->identification.size, sizeof(it->identification.data))) != 0 || + (ret = ser_saveOctetString3(serializeSettings, (char*)it->signature.data, it->signature.size, sizeof(it->signature.data))) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex3(&object->imageActivateInfo, pos, (void**)&it, 0)) != 0) + { + break; + } + if ((ret = ser_saveUInt32(serializeSettings, it->size)) != 0 || + (ret = ser_saveOctetString(serializeSettings, &it->identification)) != 0 || + (ret = ser_saveOctetString(serializeSettings, &it->signature)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } +#ifdef DLMS_IGNORE_MALLOC + object->imageActivateInfo.size = count; +#endif //DLMS_IGNORE_MALLOC + } + } + return ret; +} +#endif //DLMS_IGNORE_IMAGE_TRANSFER +#ifndef DLMS_IGNORE_DISCONNECT_CONTROL +int ser_saveDisconnectControl( + gxSerializerSettings* serializeSettings, + gxDisconnectControl* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveUInt8(serializeSettings, object->outputState)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveUInt8(serializeSettings, object->controlState)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveUInt8(serializeSettings, object->controlMode)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_DISCONNECT_CONTROL +#ifndef DLMS_IGNORE_LIMITER +int ser_saveLimiter( + gxSerializerSettings* serializeSettings, + gxLimiter* object) +{ + uint16_t pos, count; + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + uint16_t* it; +#else + dlmsVARIANT* it; +#endif //DLMS_IGNORE_MALLOC + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + if ((ret = ser_set(serializeSettings, obj_getLogicalName(object->monitoredValue), 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) == 0) + ret = ser_saveUInt8(serializeSettings, object->selectedAttributeIndex); + } + if (ret == 0) + { + if ((!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveBytes(&object->thresholdActive, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveBytes(&object->thresholdNormal, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveBytes(&object->thresholdEmergency, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_saveUInt32(serializeSettings, object->minOverThresholdDuration)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_saveUInt32(serializeSettings, object->minUnderThresholdDuration)) != 0)) + { + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 8)) + { + if ((ret = ser_saveUInt16(serializeSettings, object->emergencyProfile.id)) != 0 || + (ret = ser_saveDateTime(&object->emergencyProfile.activationTime, serializeSettings)) != 0 || + (ret = ser_saveUInt32(serializeSettings, object->emergencyProfile.duration)) != 0) + { + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 9)) + { +#if defined(DLMS_IGNORE_MALLOC) + if ((ret = ser_saveArrayCount(serializeSettings, &object->emergencyProfileGroupIDs, &count)) == 0) +#else + if ((ret = ser_saveVariantArrayCount(serializeSettings, &object->emergencyProfileGroupIDs, &count)) == 0) +#endif //DLMS_IGNORE_MALLOC + { + for (pos = 0; pos != object->emergencyProfileGroupIDs.size; ++pos) + { +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + if ((ret = arr_getByIndex4(&object->emergencyProfileGroupIDs, pos, (void**)&it, sizeof(uint16_t), 0)) != 0 || + (ret = ser_saveUInt16(serializeSettings, *it)) != 0) + { + break; + } +#else + if ((ret = va_getByIndex(&object->emergencyProfileGroupIDs, pos, &it)) != 0 || + (ret = ser_saveBytes(it, serializeSettings)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } +#ifdef DLMS_IGNORE_MALLOC + object->emergencyProfileGroupIDs.size = count; +#endif //DLMS_IGNORE_MALLOC + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 10)) + { + ret = ser_saveUInt8(serializeSettings, object->emergencyProfileActive); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 11)) + { + if ((ret = ser_saveActionItem(&object->actionOverThreshold, serializeSettings)) == 0) + { + ret = ser_saveActionItem(&object->actionUnderThreshold, serializeSettings); + } + } + return ret; +} +#endif //DLMS_IGNORE_LIMITER +#ifndef DLMS_IGNORE_MBUS_CLIENT +int ser_saveMBusClient( + gxSerializerSettings* serializeSettings, + gxMBusClient* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveUInt32(serializeSettings, object->capturePeriod)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveUInt8(serializeSettings, object->primaryAddress)) != 0) || +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_set(serializeSettings, obj_getLogicalName(object->mBusPort), 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0) || +#else + (!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_set(serializeSettings, obj_getLogicalName(object->mBusPortReference), 6)) != 0) || +#endif //DLMS_IGNORE_OBJECT_POINTERS + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_saveUInt32(serializeSettings, object->identificationNumber)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_saveUInt16(serializeSettings, object->manufacturerID)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_saveUInt8(serializeSettings, object->dataHeaderVersion)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_saveUInt8(serializeSettings, object->deviceType)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 10) && (ret = ser_saveUInt8(serializeSettings, object->accessNumber)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 11) && (ret = ser_saveUInt8(serializeSettings, object->status)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 12) && (ret = ser_saveUInt8(serializeSettings, object->alarm)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 13) && (ret = ser_saveUInt16(serializeSettings, object->configuration)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 14) && (ret = ser_saveUInt8(serializeSettings, object->encryptionKeyStatus)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_MBUS_CLIENT +#ifndef DLMS_IGNORE_MODEM_CONFIGURATION +int ser_saveModemConfiguration( + gxSerializerSettings* serializeSettings, + gxModemConfiguration* object) +{ + int ret = 0; + uint16_t pos, count; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + gxModemInitialisation* mi; +#ifdef DLMS_IGNORE_MALLOC + gxModemProfile* it; +#else + gxByteBuffer* it; +#endif //DLMS_IGNORE_MALLOC + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + ret = ser_saveUInt8(serializeSettings, object->communicationSpeed); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3) && + (ret = ser_saveArrayCount(serializeSettings, &object->initialisationStrings, &count)) == 0) + { + for (pos = 0; pos != object->initialisationStrings.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(&object->initialisationStrings, pos, (void**)&mi, sizeof(gxModemInitialisation), 0)) != 0 || + (ret = ser_saveOctetString3(serializeSettings, (char*)mi->request.value, mi->request.size, sizeof(mi->request.value))) != 0 || + (ret = ser_saveOctetString3(serializeSettings, (char*)mi->response.value, mi->response.size, sizeof(mi->response.value))) != 0 || + (ret = ser_saveUInt16(serializeSettings, mi->delay)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex3(&object->initialisationStrings, pos, (void**)&mi, 0)) != 0 || + (ret = ser_saveOctetString(serializeSettings, &mi->request)) != 0 || + (ret = ser_saveOctetString(serializeSettings, &mi->response)) != 0 || + (ret = ser_saveInt16(serializeSettings, mi->delay)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } +#ifdef DLMS_IGNORE_MALLOC + object->initialisationStrings.size = count; +#endif //DLMS_IGNORE_MALLOC + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 4) && + (ret = ser_saveArrayCount(serializeSettings, &object->modemProfile, &count)) == 0) + { + for (pos = 0; pos != object->modemProfile.size; ++pos) + { + +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(&object->modemProfile, pos, (void**)&it, sizeof(gxModemProfile), 0)) != 0 || + (ret = ser_saveOctetString3(serializeSettings, (char*)it->value, it->size, sizeof(it->value))) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex3(&object->modemProfile, pos, (void**)&it, 0)) != 0 || + (ret = ser_saveOctetString(serializeSettings, it)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } +#ifdef DLMS_IGNORE_MALLOC + object->modemProfile.size = count; +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} +#endif //DLMS_IGNORE_MODEM_CONFIGURATION +#ifndef DLMS_IGNORE_MAC_ADDRESS_SETUP +int ser_saveMacAddressSetup( + gxSerializerSettings* serializeSettings, + gxMacAddressSetup* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + ret = ser_saveOctetString(serializeSettings, &object->macAddress); + } + return ret; +} +#endif //DLMS_IGNORE_MAC_ADDRESS_SETUP + +#ifndef DLMS_IGNORE_GPRS_SETUP +int ser_saveQualityOfService( + gxQualityOfService* object, + gxSerializerSettings* serializeSettings) +{ + int ret; + if ((ret = ser_saveUInt8(serializeSettings, object->precedence)) != 0 || + (ret = ser_saveUInt8(serializeSettings, object->delay)) != 0 || + (ret = ser_saveUInt8(serializeSettings, object->reliability)) != 0 || + (ret = ser_saveUInt8(serializeSettings, object->peakThroughput)) != 0 || + (ret = ser_saveUInt8(serializeSettings, object->meanThroughput)) != 0) + { + + } + return ret; +} + +int ser_saveGPRSSetup( + gxSerializerSettings* serializeSettings, + gxGPRSSetup* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveOctetString(serializeSettings, &object->apn)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveInt16(serializeSettings, object->pinCode)) != 0)) + { + + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 4)) + { + if (((ret = ser_saveQualityOfService(&object->defaultQualityOfService, serializeSettings)) != 0 || + (ret = ser_saveQualityOfService(&object->requestedQualityOfService, serializeSettings)) != 0)) + { + } + } + return ret; +} +#endif //DLMS_IGNORE_GPRS_SETUP +#ifndef DLMS_IGNORE_EXTENDED_REGISTER +int ser_saveExtendedRegister( + gxSerializerSettings* serializeSettings, + gxExtendedRegister* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + ret = ser_saveBytes(&object->value, serializeSettings); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3)) + { + if ((ret = ser_saveUInt8(serializeSettings, object->scaler)) != 0 || + (ret = ser_saveUInt8(serializeSettings, object->unit)) != 0) + { + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 4)) + { + ret = ser_saveBytes(&object->status, serializeSettings); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 5)) + { + ret = ser_saveDateTime(&object->captureTime, serializeSettings); + } + return ret; +} +#endif //DLMS_IGNORE_EXTENDED_REGISTER + +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME +int ser_saveApplicationContextName(gxSerializerSettings* serializeSettings, gxApplicationContextName* object) +{ + int ret; + if ((ret = ser_set(serializeSettings, object->logicalName, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0 || + (ret = ser_saveUInt8(serializeSettings, object->jointIsoCtt)) != 0 || + (ret = ser_saveUInt8(serializeSettings, object->country)) != 0 || + (ret = ser_saveUInt16(serializeSettings, object->countryName)) != 0 || + (ret = ser_saveUInt8(serializeSettings, object->identifiedOrganization)) != 0 || + (ret = ser_saveUInt8(serializeSettings, object->dlmsUA)) != 0 || + (ret = ser_saveUInt8(serializeSettings, object->applicationContext)) != 0 || + (ret = ser_saveUInt8(serializeSettings, object->contextId)) != 0) + { + + } + return ret; +} + + +int ser_savexDLMSContextType(gxSerializerSettings* serializeSettings, gxXDLMSContextType* object) +{ + int ret; + if ((ret = ser_saveUInt32(serializeSettings, object->conformance)) != 0 || + (ret = ser_saveUInt16(serializeSettings, object->maxReceivePduSize)) != 0 || + (ret = ser_saveUInt16(serializeSettings, object->maxSendPduSize)) != 0 || + (ret = ser_saveUInt8(serializeSettings, object->qualityOfService)) != 0 || + (ret = ser_saveOctetString(serializeSettings, &object->cypheringInfo)) != 0) + { + + } + return ret; +} + +int ser_saveAuthenticationMechanismName( + gxSerializerSettings* serializeSettings, + gxAuthenticationMechanismName* object) +{ + int ret; + if ((ret = ser_saveUInt8(serializeSettings, object->jointIsoCtt)) != 0 || + (ret = ser_saveUInt8(serializeSettings, object->country)) != 0 || + (ret = ser_saveUInt16(serializeSettings, object->countryName)) != 0 || + (ret = ser_saveUInt8(serializeSettings, object->identifiedOrganization)) != 0 || + (ret = ser_saveUInt8(serializeSettings, object->dlmsUA)) != 0 || + (ret = ser_saveUInt8(serializeSettings, object->authenticationMechanismName)) != 0 || + (ret = ser_saveUInt8(serializeSettings, object->mechanismId)) != 0) + { + + } + return ret; +} + +int ser_saveAssociationLogicalName( + gxSerializerSettings* serializeSettings, + gxAssociationLogicalName* object) +{ + int ret = 0; + uint16_t pos, count; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); +#ifdef DLMS_IGNORE_MALLOC + gxUser* it; +#else + gxKey2* it; +#endif //DLMS_IGNORE_MALLOC + + //Save object list. + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + gxObject* obj; + if ((ret = ser_saveObjectArrayCount(serializeSettings, &object->objectList, &count)) == 0) + { + for (pos = 0; pos != object->objectList.size; ++pos) + { + if ((ret = oa_getByIndex(&object->objectList, pos, &obj)) != DLMS_ERROR_CODE_OK || + (ret = ser_saveUInt8(serializeSettings, obj->version)) != DLMS_ERROR_CODE_OK || + (ret = ser_saveUInt16(serializeSettings, obj->objectType)) != DLMS_ERROR_CODE_OK || + (ret = ser_set(serializeSettings, obj->logicalName, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + object->objectList.size = count; +#endif //DLMS_IGNORE_MALLOC + } + if (ret != 0) + { + return ret; + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3)) + { + if ((ret = ser_saveUInt8(serializeSettings, object->clientSAP)) != 0 || + (ret = ser_saveUInt16(serializeSettings, object->serverSAP)) != 0) + { + } + } + if (ret == 0) + { + if ((!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveApplicationContextName(serializeSettings, &object->applicationContextName)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_savexDLMSContextType(serializeSettings, &object->xDLMSContextInfo)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_saveAuthenticationMechanismName(serializeSettings, &object->authenticationMechanismName)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_saveOctetString(serializeSettings, &object->secret)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_saveUInt8(serializeSettings, object->associationStatus)) != 0)) + { + } + } + //Security Setup Reference is from version 1. + if (ret == 0 && object->base.version > 0) + { +#ifndef DLMS_IGNORE_SECURITY_SETUP + if (!isAttributeSet(serializeSettings, ignored, 9)) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + ret = ser_set(serializeSettings, obj_getLogicalName((gxObject*)object->securitySetup), 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + ); +#else + ret = ser_set(&ba, object->securitySetupReference, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + } +#endif //DLMS_IGNORE_SECURITY_SETUP + } + if (ret == 0 && object->base.version > 1) + { + if (!isAttributeSet(serializeSettings, ignored, 10) && + (ret = ser_saveArrayCount(serializeSettings, &object->userList, &count)) == 0) + { + for (pos = 0; pos != object->userList.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(&object->userList, pos, (void**)&it, sizeof(gxUser), 0)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->id)) != 0 || + (ret = ser_saveOctetString2(serializeSettings, it->name, MAX_USER_NAME_LENGTH)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex3(&object->userList, pos, (void**)&it, 0)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->key)) != 0 || + (ret = ser_saveOctetString2(serializeSettings, it->value, (uint16_t)((gxByteBuffer*)it->value)->size)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } +#ifdef DLMS_IGNORE_MALLOC + object->userList.size = count; +#endif //DLMS_IGNORE_MALLOC + } + } + return ret; +} +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME +int ser_saveAssociationShortName( + gxSerializerSettings* serializeSettings, + gxAssociationShortName* object) +{ + int ret = 0; + uint16_t pos, count; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); +#ifdef DLMS_IGNORE_MALLOC + gxUser* it; +#else + gxKey2* it; +#endif //DLMS_IGNORE_MALLOC + + //Save object list. + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + gxObject* obj; + if ((ret = ser_saveObjectArrayCount(serializeSettings, &object->objectList, &count)) == 0) + { + for (pos = 0; pos != object->objectList.size; ++pos) + { + if ((ret = oa_getByIndex(&object->objectList, pos, &obj)) != DLMS_ERROR_CODE_OK || + (ret = ser_saveInt16(serializeSettings, obj->shortName)) != DLMS_ERROR_CODE_OK || + (ret = ser_saveUInt8(serializeSettings, obj->version)) != DLMS_ERROR_CODE_OK || + (ret = ser_saveUInt16(serializeSettings, obj->objectType)) != DLMS_ERROR_CODE_OK || + (ret = ser_set(serializeSettings, obj->logicalName, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + object->objectList.size = count; +#endif //DLMS_IGNORE_MALLOC + } + if (ret != 0) + { + return ret; + } + } + //Security Setup Reference is from version 2. + if (ret == 0 && object->base.version > 2) + { +#ifndef DLMS_IGNORE_SECURITY_SETUP + if (!isAttributeSet(serializeSettings, ignored, 9)) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + ret = ser_set(serializeSettings, obj_getLogicalName((gxObject*)object->securitySetup), 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + ); +#else + ret = ser_set(&ba, object->securitySetupReference, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + } +#endif //DLMS_IGNORE_SECURITY_SETUP + } + if (ret == 0 && object->base.version > 3) + { + if (!isAttributeSet(serializeSettings, ignored, 10) && + (ret = ser_saveArrayCount(serializeSettings, &object->userList, &count)) == 0) + { + for (pos = 0; pos != object->userList.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(&object->userList, pos, (void**)&it, sizeof(gxUser), 0)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->id)) != 0 || + (ret = ser_saveOctetString2(serializeSettings, it->name, MAX_USER_NAME_LENGTH)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex3(&object->userList, pos, (void**)&it, 0)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it->key)) != 0 || + (ret = ser_saveOctetString2(serializeSettings, it->value, (uint16_t)((gxByteBuffer*)it->value)->size)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } +#ifdef DLMS_IGNORE_MALLOC + object->userList.size = count; +#endif //DLMS_IGNORE_MALLOC + } + } + return ret; +} + +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME +#ifndef DLMS_IGNORE_PPP_SETUP +int ser_savePppSetup( + gxSerializerSettings* serializeSettings, + gxPppSetup* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); +#ifndef DLMS_IGNORE_OBJECT_POINTER1S + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_set(serializeSettings, obj_getLogicalName(object->phy), 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0)) + { + } +#else + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_set(&ba, object->PHYReference, 6)) != 0)) + { + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 5)) + { + if ((ret = ser_saveOctetString(serializeSettings, &object->userName)) != 0 || + (ret = ser_saveOctetString(serializeSettings, &object->password)) != 0 || + (ret = ser_saveUInt8(serializeSettings, object->authentication)) != 0) + { + } + } + return ret; +} +#endif //DLMS_IGNORE_PPP_SETUP + +#ifndef DLMS_IGNORE_PROFILE_GENERIC + +int ser_saveProfileGeneric( + gxSerializerSettings* serializeSettings, + gxProfileGeneric* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 3) && (ret = saveObjectsInternal(serializeSettings, &object->captureObjects)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveUInt32(serializeSettings, object->capturePeriod)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveUInt8(serializeSettings, object->sortMethod)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_set(serializeSettings, obj_getLogicalName(object->sortObject), 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_saveUInt32(serializeSettings, object->entriesInUse)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_saveUInt32(serializeSettings, object->profileEntries)) != 0)) + { + + } + return ret; +} +#endif //DLMS_IGNORE_PROFILE_GENERIC +#ifndef DLMS_IGNORE_ACCOUNT +int ser_saveAccount( + gxSerializerSettings* serializeSettings, + gxAccount* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + if ((ret = ser_saveUInt8(serializeSettings, object->paymentMode)) == 0) + { + ret = ser_saveUInt8(serializeSettings, object->accountStatus); + } + } + if (ret == 0) + { + if ((!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveUInt8(serializeSettings, object->currentCreditInUse)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveUInt8(serializeSettings, object->currentCreditStatus)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveInt32(serializeSettings, object->availableCredit)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_saveInt32(serializeSettings, object->amountToClear)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_saveInt32(serializeSettings, object->clearanceThreshold)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_saveInt32(serializeSettings, object->aggregatedDebt)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 13) && (ret = ser_saveDateTime(&object->accountActivationTime, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 14) && (ret = ser_saveDateTime(&object->accountClosureTime, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 16) && (ret = ser_saveInt32(serializeSettings, object->lowCreditThreshold)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 17) && (ret = ser_saveInt32(serializeSettings, object->nextCreditAvailableThreshold)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 18) && (ret = ser_saveUInt16(serializeSettings, object->maxProvision)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 19) && (ret = ser_saveInt32(serializeSettings, object->maxProvisionPeriod)) != 0)) + { + } + } + return ret; +} +#endif //DLMS_IGNORE_ACCOUNT +#ifndef DLMS_IGNORE_CREDIT +int ser_saveCredit( + gxSerializerSettings* serializeSettings, + gxCredit* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveInt32(serializeSettings, object->currentCreditAmount)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveUInt8(serializeSettings, object->type)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveUInt8(serializeSettings, object->priority)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveInt32(serializeSettings, object->warningThreshold)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_saveInt32(serializeSettings, object->limit)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_saveUInt8(serializeSettings, object->creditConfiguration)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_saveUInt8(serializeSettings, object->status)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_saveInt32(serializeSettings, object->presetCreditAmount)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 10) && (ret = ser_saveInt32(serializeSettings, object->creditAvailableThreshold)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 11) && (ret = ser_saveDateTime(&object->period, serializeSettings)) != 0)) + { + + } + return ret; +} +#endif //DLMS_IGNORE_CREDIT +#ifndef DLMS_IGNORE_CHARGE + +int ser_saveUnitCharge(gxSerializerSettings* serializeSettings, gxUnitCharge* target) +{ + uint16_t pos, count; + int ret = 0; + gxChargeTable* it; + if (//commodity scale + (ret = ser_saveUInt8(serializeSettings, target->chargePerUnitScaling.commodityScale)) != 0 || + //price scale + (ret = ser_saveUInt8(serializeSettings, target->chargePerUnitScaling.priceScale)) != 0 || + //------------- + //commodity + //type +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = ser_saveUInt16(serializeSettings, target->commodity.target == NULL ? 0 : target->commodity.target->objectType)) != 0 || +#else + (ret = ser_saveUInt16(serializeSettings, target->commodity.type)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + //logicalName +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = ser_setOctetString2(serializeSettings, obj_getLogicalName(target->commodity.target), 6, 6)) != 0 || +#else + (ret = ser_setOctetString2(serializeSettings, target->commodity.logicalName, 6, 6)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + //attributeIndex + (ret = ser_saveUInt8(serializeSettings, target->commodity.attributeIndex)) != 0 || + //------------- + //chargeTables + (ret = ser_saveArrayCount(serializeSettings, &target->chargeTables, &count)) != 0) + { + return ret; + } + for (pos = 0; pos != target->chargeTables.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(&target->chargeTables, pos, (void**)&it, sizeof(gxChargeTable), 0)) != 0 || + //index + (ret = ser_setOctetString2(serializeSettings, it->index.data, it->index.size, sizeof(it->index.data))) != 0 || + //chargePerUnit + (ret = ser_saveInt16(serializeSettings, it != NULL ? it->chargePerUnit : 0)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex3(&target->chargeTables, pos, (void**)&it, 0)) != 0 || + //index + (ret = ser_setOctetString2(serializeSettings, it->index.data, (uint16_t)it->index.size, (uint16_t)it->index.capacity)) != 0 || + //chargePerUnit + (ret = ser_saveInt16(serializeSettings, it->chargePerUnit)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } +#ifdef DLMS_IGNORE_MALLOC + target->chargeTables.size = count; +#endif //DLMS_IGNORE_MALLOC + return ret; +} + + +int ser_saveCharge( + gxSerializerSettings* serializeSettings, + gxCharge* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveInt32(serializeSettings, object->totalAmountPaid)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveUInt8(serializeSettings, object->chargeType)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveUInt8(serializeSettings, object->priority)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveUnitCharge(serializeSettings, &object->unitChargeActive)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_saveUnitCharge(serializeSettings, &object->unitChargePassive)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_saveDateTime(&object->unitChargeActivationTime, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_saveUInt32(serializeSettings, object->period)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_saveUInt8(serializeSettings, object->chargeConfiguration)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 10) && (ret = ser_saveDateTime(&object->lastCollectionTime, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 11) && (ret = ser_saveUInt32(serializeSettings, object->lastCollectionAmount)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 12) && (ret = ser_saveUInt32(serializeSettings, object->totalAmountRemaining)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 13) && (ret = ser_saveUInt16(serializeSettings, object->proportion)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_CHARGE +#ifndef DLMS_IGNORE_TOKEN_GATEWAY +int ser_saveTokenGateway( + gxSerializerSettings* serializeSettings, + gxTokenGateway* object) +{ + return 0; +} +#endif //DLMS_IGNORE_TOKEN_GATEWAY +#ifndef DLMS_IGNORE_GSM_DIAGNOSTIC +int ser_saveGsmDiagnostic( + gxSerializerSettings* serializeSettings, + gxGsmDiagnostic* object) +{ + uint16_t pos, count; + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + gxAdjacentCell* it; + if (!isAttributeSet(serializeSettings, ignored, 2)) + { +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + ret = ser_saveOctetString(serializeSettings, &object->operatorName); +#else + ret = ser_saveOctetString2(serializeSettings, object->operatorName, (uint16_t)strlen(object->operatorName)); +#endif //DLMS_IGNORE_MALLOC + } + if ((!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveUInt8(serializeSettings, object->status)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveUInt8(serializeSettings, object->circuitSwitchStatus)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveUInt8(serializeSettings, object->packetSwitchStatus)) != 0)) + { + } + + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 6)) + { + if ((ret = ser_saveUInt32(serializeSettings, object->cellInfo.cellId)) != 0 || + (ret = ser_saveUInt16(serializeSettings, object->cellInfo.locationId)) != 0 || + (ret = ser_saveUInt8(serializeSettings, object->cellInfo.signalQuality)) != 0 || + (ret = ser_saveUInt8(serializeSettings, object->cellInfo.ber)) != 0) + { + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 7) && + (ret = ser_saveArrayCount(serializeSettings, &object->adjacentCells, &count)) == 0) + { + for (pos = 0; pos != object->adjacentCells.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(&object->adjacentCells, pos, (void**)&it, sizeof(gxAdjacentCell), 0)) != 0) + { + break; + } +#else + if ((ret = arr_getByIndex3(&object->adjacentCells, pos, (void**)&it, 0)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = ser_saveUInt32(serializeSettings, it != NULL ? it->cellId : 0)) != 0 || + (ret = ser_saveUInt8(serializeSettings, it != NULL ? it->signalQuality : 0)) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + object->adjacentCells.size = count; +#endif //DLMS_IGNORE_MALLOC + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 8)) + { + ret = ser_saveDateTime(&object->captureTime, serializeSettings); + } + return ret; +} +#endif //DLMS_IGNORE_GSM_DIAGNOSTIC + +#ifndef DLMS_IGNORE_COMPACT_DATA +int ser_saveCompactData( + gxSerializerSettings* serializeSettings, + gxCompactData* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveOctetString(serializeSettings, &object->buffer)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = saveObjectsInternal(serializeSettings, &object->captureObjects)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_saveUInt8(serializeSettings, object->templateId)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_saveOctetString(serializeSettings, &object->templateDescription)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_saveUInt8(serializeSettings, object->captureMethod)) != 0)) + { + + } + return ret; +} +#endif //DLMS_IGNORE_COMPACT_DATA + +#ifndef DLMS_IGNORE_LLC_SSCS_SETUP +int ser_saveLlcSscsSetup( + gxSerializerSettings* serializeSettings, + gxLlcSscsSetup* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_saveUInt16(serializeSettings, object->serviceNodeAddress)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_saveUInt16(serializeSettings, object->baseNodeAddress)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_LLC_SSCS_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +int ser_savePrimeNbOfdmPlcPhysicalLayerCounters( + gxSerializerSettings* serializeSettings, + gxPrimeNbOfdmPlcPhysicalLayerCounters* object) +{ + return 0; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +int ser_savePrimeNbOfdmPlcMacSetup( + gxSerializerSettings* serializeSettings, + gxPrimeNbOfdmPlcMacSetup* object) +{ + return 0; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +int ser_savePrimeNbOfdmPlcMacFunctionalParameters( + gxSerializerSettings* serializeSettings, + gxPrimeNbOfdmPlcMacFunctionalParameters* object) +{ + return 0; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +int ser_savePrimeNbOfdmPlcMacCounters( + gxSerializerSettings* serializeSettings, + gxPrimeNbOfdmPlcMacCounters* object) +{ + return 0; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA +int ser_savePrimeNbOfdmPlcMacNetworkAdministrationData( + gxSerializerSettings* serializeSettings, + gxPrimeNbOfdmPlcMacNetworkAdministrationData* object) +{ + return 0; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION +int ser_savePrimeNbOfdmPlcApplicationsIdentification( + gxSerializerSettings* serializeSettings, + gxPrimeNbOfdmPlcApplicationsIdentification* object) +{ + return 0; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION +#ifndef DLMS_IGNORE_ARBITRATOR +int ser_saveArbitrator( + gxSerializerSettings* serializeSettings, + gxArbitrator* object) +{ + return 0; +} +#endif //DLMS_IGNORE_ARBITRATOR +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +int ser_saveIec8802LlcType1Setup( + gxSerializerSettings* serializeSettings, + gxIec8802LlcType1Setup* object) +{ + return 0; +} +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP +int ser_saveIec8802LlcType2Setup( + gxSerializerSettings* serializeSettings, + gxIec8802LlcType2Setup* object) +{ + return 0; +} +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP +int ser_saveIec8802LlcType3Setup( + gxSerializerSettings* serializeSettings, + gxIec8802LlcType3Setup* object) +{ + return 0; +} +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP +#ifndef DLMS_IGNORE_SFSK_ACTIVE_INITIATOR +int ser_saveSFSKActiveInitiator( + gxSerializerSettings* serializeSettings, + gxSFSKActiveInitiator* object) +{ + return 0; +} +#endif //DLMS_IGNORE_SFSK_ACTIVE_INITIATOR +#ifndef DLMS_IGNORE_SFSK_MAC_COUNTERS +int ser_saveFSKMacCounters( + gxSerializerSettings* serializeSettings, + gxFSKMacCounters* object) +{ + return 0; +} +#endif //DLMS_IGNORE_SFSK_MAC_COUNTERS +#ifndef DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS +int ser_saveSFSKMacSynchronizationTimeouts( + gxSerializerSettings* serializeSettings, + gxSFSKMacSynchronizationTimeouts* object) +{ + return 0; +} +#endif //DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS +#ifndef DLMS_IGNORE_SFSK_PHY_MAC_SETUP +int ser_saveSFSKPhyMacSetUp( + gxSerializerSettings* serializeSettings, + gxSFSKPhyMacSetUp* object) +{ + return 0; +} +#endif //DLMS_IGNORE_SFSK_PHY_MAC_SETUP +#ifndef DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST +int ser_saveSFSKReportingSystemList( + gxSerializerSettings* serializeSettings, + gxSFSKReportingSystemList* object) +{ + return 0; +} +#endif //DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST +#ifndef DLMS_IGNORE_SCHEDULE +int ser_saveSchedule( + gxSerializerSettings* serializeSettings, + gxSchedule* object) +{ + return 0; +} +#endif //DLMS_IGNORE_SCHEDULE + +#ifdef DLMS_ITALIAN_STANDARD +int ser_saveTariffPlan( + gxSerializerSettings* serializeSettings, + gxTariffPlan* object) +{ + int ret; + if ((ret = bb_addString(serializeSettings, object->calendarName)) != 0 || + (ret = ser_saveUInt8(serializeSettings, object->enabled)) != 0 || + (ret = ser_saveDateTime(&object->activationTime, serializeSettings)) != 0) + { + } + return ret; +} +#endif //DLMS_ITALIAN_STANDARD + +void ser_init(gxSerializerSettings* settings) +{ + memset(settings, 0, sizeof(gxSerializerSettings)); +} + +int ser_saveObject( + gxSerializerSettings* serializeSettings, + gxObject* object) +{ + int ret = 0; + switch (object->objectType) + { +#ifndef DLMS_IGNORE_DATA + case DLMS_OBJECT_TYPE_DATA: + ret = ser_saveData(serializeSettings, (gxData*)object); + break; +#endif //DLMS_IGNORE_DATA +#ifndef DLMS_IGNORE_REGISTER + case DLMS_OBJECT_TYPE_REGISTER: + ret = ser_saveRegister(serializeSettings, (gxRegister*)object); + break; +#endif //DLMS_IGNORE_REGISTER +#ifndef DLMS_IGNORE_CLOCK + case DLMS_OBJECT_TYPE_CLOCK: + ret = ser_saveClock(serializeSettings, (gxClock*)object); + break; +#endif //DLMS_IGNORE_CLOCK +#ifndef DLMS_IGNORE_ACTION_SCHEDULE + case DLMS_OBJECT_TYPE_ACTION_SCHEDULE: + ret = ser_saveActionSchedule(serializeSettings, (gxActionSchedule*)object); + break; +#endif //DLMS_IGNORE_ACTION_SCHEDULE +#ifndef DLMS_IGNORE_ACTIVITY_CALENDAR + case DLMS_OBJECT_TYPE_ACTIVITY_CALENDAR: + ret = ser_saveActivityCalendar(serializeSettings, (gxActivityCalendar*)object); + break; +#endif //DLMS_IGNORE_ACTIVITY_CALENDAR +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + case DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME: + ret = ser_saveAssociationLogicalName(serializeSettings, (gxAssociationLogicalName*)object); + break; +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + case DLMS_OBJECT_TYPE_ASSOCIATION_SHORT_NAME: +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + ret = ser_saveAssociationShortName(serializeSettings, (gxAssociationShortName*)object); +#else + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + break; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME +#ifndef DLMS_IGNORE_AUTO_ANSWER + case DLMS_OBJECT_TYPE_AUTO_ANSWER: + ret = ser_saveAutoAnswer(serializeSettings, (gxAutoAnswer*)object); + break; +#endif //DLMS_IGNORE_AUTO_ANSWER +#ifndef DLMS_IGNORE_AUTO_CONNECT + case DLMS_OBJECT_TYPE_AUTO_CONNECT: + ret = ser_saveAutoConnect(serializeSettings, (gxAutoConnect*)object); + break; +#endif //DLMS_IGNORE_AUTO_CONNECT +#ifndef DLMS_IGNORE_DEMAND_REGISTER + case DLMS_OBJECT_TYPE_DEMAND_REGISTER: + ret = ser_saveDemandRegister(serializeSettings, (gxDemandRegister*)object); + break; +#endif //DLMS_IGNORE_DEMAND_REGISTER +#ifndef DLMS_IGNORE_MAC_ADDRESS_SETUP + case DLMS_OBJECT_TYPE_MAC_ADDRESS_SETUP: + ret = ser_saveMacAddressSetup(serializeSettings, (gxMacAddressSetup*)object); + break; +#endif //DLMS_IGNORE_MAC_ADDRESS_SETUP +#ifndef DLMS_IGNORE_EXTENDED_REGISTER + case DLMS_OBJECT_TYPE_EXTENDED_REGISTER: + ret = ser_saveExtendedRegister(serializeSettings, (gxExtendedRegister*)object); + break; +#endif //DLMS_IGNORE_EXTENDED_REGISTER +#ifndef DLMS_IGNORE_GPRS_SETUP + case DLMS_OBJECT_TYPE_GPRS_SETUP: +#ifndef DLMS_IGNORE_GPRS_SETUP + ret = ser_saveGPRSSetup(serializeSettings, (gxGPRSSetup*)object); +#endif //DLMS_IGNORE_GPRS_SETUP + break; +#endif //DLMS_IGNORE_GPRS_SETUP +#ifndef DLMS_IGNORE_SECURITY_SETUP + case DLMS_OBJECT_TYPE_SECURITY_SETUP: + ret = ser_saveSecuritySetup(serializeSettings, (gxSecuritySetup*)object); + break; +#endif //DLMS_IGNORE_SECURITY_SETUP +#ifndef DLMS_IGNORE_IEC_HDLC_SETUP + case DLMS_OBJECT_TYPE_IEC_HDLC_SETUP: + ret = ser_saveHdlcSetup(serializeSettings, (gxIecHdlcSetup*)object); + break; +#endif //DLMS_IGNORE_IEC_HDLC_SETUP +#ifndef DLMS_IGNORE_IEC_LOCAL_PORT_SETUP + case DLMS_OBJECT_TYPE_IEC_LOCAL_PORT_SETUP: + ret = ser_saveLocalPortSetup(serializeSettings, (gxLocalPortSetup*)object); + break; +#endif //DLMS_IGNORE_IEC_LOCAL_PORT_SETUP +#ifndef DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP + case DLMS_OBJECT_TYPE_IEC_TWISTED_PAIR_SETUP: + ret = ser_saveIecTwistedPairSetup(serializeSettings, (gxIecTwistedPairSetup*)object); + break; +#endif //DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP +#ifndef DLMS_IGNORE_IP4_SETUP + case DLMS_OBJECT_TYPE_IP4_SETUP: + ret = ser_saveIp4Setup(serializeSettings, (gxIp4Setup*)object); + break; +#endif //DLMS_IGNORE_IP4_SETUP +#ifndef DLMS_IGNORE_IP6_SETUP + case DLMS_OBJECT_TYPE_IP6_SETUP: + ret = ser_saveIp6Setup(serializeSettings, (gxIp6Setup*)object); + break; +#endif //DLMS_IGNORE_IP6_SETUP +#ifndef DLMS_IGNORE_MBUS_DIAGNOSTIC + case DLMS_OBJECT_TYPE_MBUS_DIAGNOSTIC: + ret = ser_saveMbusDiagnostic(serializeSettings, (gxMbusDiagnostic*)object); + break; +#endif //DLMS_IGNORE_MBUS_DIAGNOSTIC +#ifndef DLMS_IGNORE_MBUS_PORT_SETUP + case DLMS_OBJECT_TYPE_MBUS_PORT_SETUP: + ret = ser_saveMbusPortSetup(serializeSettings, (gxMBusPortSetup*)object); + break; +#endif //DLMS_IGNORE_MBUS_PORT_SETUP +#ifndef DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP + case DLMS_OBJECT_TYPE_MBUS_SLAVE_PORT_SETUP: + ret = ser_saveMbusSlavePortSetup(serializeSettings, (gxMbusSlavePortSetup*)object); + break; +#endif //DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP +#ifndef DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS + case DLMS_OBJECT_TYPE_G3_PLC_MAC_LAYER_COUNTERS: + ret = ser_saveG3PlcMacLayerCounters(serializeSettings, (gxG3PlcMacLayerCounters*)object); + break; +#endif //DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS +#ifndef DLMS_IGNORE_G3_PLC_MAC_SETUP + case DLMS_OBJECT_TYPE_G3_PLC_MAC_SETUP: + ret = ser_saveG3PlcMacSetup(serializeSettings, (gxG3PlcMacSetup*)object); + break; +#endif //DLMS_IGNORE_G3_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_G3_PLC_6LO_WPAN + case DLMS_OBJECT_TYPE_G3_PLC_6LO_WPAN: + ret = ser_saveG3Plc6LoWPAN(serializeSettings, (gxG3Plc6LoWPAN*)object); + break; +#endif //DLMS_IGNORE_G3_PLC_6LO_WPAN +#ifndef DLMS_IGNORE_FUNCTION_CONTROL + case DLMS_OBJECT_TYPE_FUNCTION_CONTROL: + ret = ser_saveFunctionControl(serializeSettings, (gxFunctionControl*)object); + break; +#endif //DLMS_IGNORE_FUNCTION_CONTROL +#ifndef DLMS_IGNORE_ARRAY_MANAGER + case DLMS_OBJECT_TYPE_ARRAY_MANAGER: + ret = ser_saveArrayManager(serializeSettings, (gxArrayManager*)object); + break; +#endif //DLMS_IGNORE_ARRAY_MANAGER +#ifndef DLMS_IGNORE_IMAGE_TRANSFER + case DLMS_OBJECT_TYPE_IMAGE_TRANSFER: + ret = ser_saveImageTransfer(serializeSettings, (gxImageTransfer*)object); + break; +#endif //DLMS_IGNORE_IMAGE_TRANSFER +#ifndef DLMS_IGNORE_DISCONNECT_CONTROL + case DLMS_OBJECT_TYPE_DISCONNECT_CONTROL: + ret = ser_saveDisconnectControl(serializeSettings, (gxDisconnectControl*)object); + break; +#endif //DLMS_IGNORE_DISCONNECT_CONTROL +#ifndef DLMS_IGNORE_LIMITER + case DLMS_OBJECT_TYPE_LIMITER: + ret = ser_saveLimiter(serializeSettings, (gxLimiter*)object); + break; +#endif //DLMS_IGNORE_LIMITER +#ifndef DLMS_IGNORE_MBUS_CLIENT + case DLMS_OBJECT_TYPE_MBUS_CLIENT: + ret = ser_saveMBusClient(serializeSettings, (gxMBusClient*)object); + break; +#endif //DLMS_IGNORE_MBUS_CLIENT +#ifndef DLMS_IGNORE_MODEM_CONFIGURATION + case DLMS_OBJECT_TYPE_MODEM_CONFIGURATION: + ret = ser_saveModemConfiguration(serializeSettings, (gxModemConfiguration*)object); + break; +#endif //DLMS_IGNORE_MODEM_CONFIGURATION +#ifndef DLMS_IGNORE_PPP_SETUP + case DLMS_OBJECT_TYPE_PPP_SETUP: + ret = ser_savePppSetup(serializeSettings, (gxPppSetup*)object); + break; +#endif //DLMS_IGNORE_PPP_SETUP +#ifndef DLMS_IGNORE_PROFILE_GENERIC + case DLMS_OBJECT_TYPE_PROFILE_GENERIC: + ret = ser_saveProfileGeneric(serializeSettings, (gxProfileGeneric*)object); + break; +#endif //DLMS_IGNORE_PROFILE_GENERIC +#ifndef DLMS_IGNORE_REGISTER_ACTIVATION + case DLMS_OBJECT_TYPE_REGISTER_ACTIVATION: + ret = ser_saveRegisterActivation(serializeSettings, (gxRegisterActivation*)object); + break; +#endif //DLMS_IGNORE_REGISTER_ACTIVATION +#ifndef DLMS_IGNORE_REGISTER_MONITOR + case DLMS_OBJECT_TYPE_REGISTER_MONITOR: + ret = ser_saveRegisterMonitor(serializeSettings, (gxRegisterMonitor*)object); + break; +#endif //DLMS_IGNORE_REGISTER_MONITOR +#ifndef DLMS_IGNORE_REGISTER_TABLE + case DLMS_OBJECT_TYPE_REGISTER_TABLE: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_REGISTER_TABLE +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_STARTUP + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_STARTUP: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_ZIG_BEE_SAS_STARTUP +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_JOIN + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_JOIN: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_ZIG_BEE_SAS_JOIN +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_APS_FRAGMENTATION + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_APS_FRAGMENTATION: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_ZIG_BEE_SAS_APS_FRAGMENTATION +#ifndef DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL + case DLMS_OBJECT_TYPE_ZIG_BEE_NETWORK_CONTROL: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL +#ifndef DLMS_IGNORE_SAP_ASSIGNMENT + case DLMS_OBJECT_TYPE_SAP_ASSIGNMENT: + ret = ser_saveSapAssignment(serializeSettings, (gxSapAssignment*)object); + break; +#endif //DLMS_IGNORE_SAP_ASSIGNMENT +#ifndef DLMS_IGNORE_SCHEDULE + case DLMS_OBJECT_TYPE_SCHEDULE: + ret = ser_saveSchedule(serializeSettings, (gxSchedule*)object); + break; +#endif //DLMS_IGNORE_SCHEDULE +#ifndef DLMS_IGNORE_SCRIPT_TABLE + case DLMS_OBJECT_TYPE_SCRIPT_TABLE: + ret = ser_saveScriptTable(serializeSettings, (gxScriptTable*)object); + break; +#endif //DLMS_IGNORE_SCRIPT_TABLE +#ifndef DLMS_IGNORE_SMTP_SETUP + case DLMS_OBJECT_TYPE_SMTP_SETUP: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_SMTP_SETUP +#ifndef DLMS_IGNORE_SPECIAL_DAYS_TABLE + case DLMS_OBJECT_TYPE_SPECIAL_DAYS_TABLE: + ret = ser_saveSpecialDaysTable(serializeSettings, (gxSpecialDaysTable*)object); + break; +#endif //DLMS_IGNORE_SPECIAL_DAYS_TABLE +#ifndef DLMS_IGNORE_STATUS_MAPPING + case DLMS_OBJECT_TYPE_STATUS_MAPPING: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_STATUS_MAPPING +#ifndef DLMS_IGNORE_TCP_UDP_SETUP + case DLMS_OBJECT_TYPE_TCP_UDP_SETUP: + ret = ser_saveTcpUdpSetup(serializeSettings, (gxTcpUdpSetup*)object); + break; +#endif //DLMS_IGNORE_TCP_UDP_SETUP +#ifndef DLMS_IGNORE_UTILITY_TABLES + case DLMS_OBJECT_TYPE_UTILITY_TABLES: + ret = ser_saveUtilityTables(serializeSettings, (gxUtilityTables*)object); + break; +#endif //DLMS_IGNORE_UTILITY_TABLES +#ifndef DLMS_IGNORE_MBUS_MASTER_PORT_SETUP + case DLMS_OBJECT_TYPE_MBUS_MASTER_PORT_SETUP: + ret = ser_saveMBusMasterPortSetup(serializeSettings, (gxMBusMasterPortSetup*)object); + break; +#endif //DLMS_IGNORE_MBUS_MASTER_PORT_SETUP +#ifndef DLMS_IGNORE_PUSH_SETUP + case DLMS_OBJECT_TYPE_PUSH_SETUP: + ret = ser_savePushSetup(serializeSettings, (gxPushSetup*)object); + break; +#endif //DLMS_IGNORE_PUSH_SETUP +#ifndef DLMS_IGNORE_DATA_PROTECTION + case DLMS_OBJECT_TYPE_DATA_PROTECTION: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_DATA_PROTECTION +#ifndef DLMS_IGNORE_ACCOUNT + case DLMS_OBJECT_TYPE_ACCOUNT: + ret = ser_saveAccount(serializeSettings, (gxAccount*)object); + break; +#endif //DLMS_IGNORE_ACCOUNT +#ifndef DLMS_IGNORE_CREDIT + case DLMS_OBJECT_TYPE_CREDIT: + ret = ser_saveCredit(serializeSettings, (gxCredit*)object); + break; +#endif //DLMS_IGNORE_CREDIT +#ifndef DLMS_IGNORE_CHARGE + case DLMS_OBJECT_TYPE_CHARGE: + ret = ser_saveCharge(serializeSettings, (gxCharge*)object); + break; +#endif //DLMS_IGNORE_CHARGE +#ifndef DLMS_IGNORE_TOKEN_GATEWAY + case DLMS_OBJECT_TYPE_TOKEN_GATEWAY: + ret = ser_saveTokenGateway(serializeSettings, (gxTokenGateway*)object); + break; +#endif //DLMS_IGNORE_TOKEN_GATEWAY +#ifndef DLMS_IGNORE_GSM_DIAGNOSTIC + case DLMS_OBJECT_TYPE_GSM_DIAGNOSTIC: + ret = ser_saveGsmDiagnostic(serializeSettings, (gxGsmDiagnostic*)object); + break; +#endif //DLMS_IGNORE_GSM_DIAGNOSTIC +#ifndef DLMS_IGNORE_COMPACT_DATA + case DLMS_OBJECT_TYPE_COMPACT_DATA: + ret = ser_saveCompactData(serializeSettings, (gxCompactData*)object); + break; +#endif //DLMS_IGNORE_COMPACT_DATA +#ifndef DLMS_IGNORE_LLC_SSCS_SETUP + case DLMS_OBJECT_TYPE_LLC_SSCS_SETUP: + ret = ser_saveLlcSscsSetup(serializeSettings, (gxLlcSscsSetup*)object); + break; +#endif //DLMS_IGNORE_LLC_SSCS_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS: + ret = ser_savePrimeNbOfdmPlcPhysicalLayerCounters(serializeSettings, (gxPrimeNbOfdmPlcPhysicalLayerCounters*)object); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_SETUP: + ret = ser_savePrimeNbOfdmPlcMacSetup(serializeSettings, (gxPrimeNbOfdmPlcMacSetup*)object); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS: + ret = ser_savePrimeNbOfdmPlcMacFunctionalParameters(serializeSettings, (gxPrimeNbOfdmPlcMacFunctionalParameters*)object); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_COUNTERS: + ret = ser_savePrimeNbOfdmPlcMacCounters(serializeSettings, (gxPrimeNbOfdmPlcMacCounters*)object); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA: + ret = ser_savePrimeNbOfdmPlcMacNetworkAdministrationData(serializeSettings, (gxPrimeNbOfdmPlcMacNetworkAdministrationData*)object); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION: + ret = ser_savePrimeNbOfdmPlcApplicationsIdentification(serializeSettings, (gxPrimeNbOfdmPlcApplicationsIdentification*)object); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION +#ifndef DLMS_IGNORE_PARAMETER_MONITOR + case DLMS_OBJECT_TYPE_PARAMETER_MONITOR: + break; +#endif //DLMS_IGNORE_PARAMETER_MONITOR +#ifndef DLMS_IGNORE_ARBITRATOR + case DLMS_OBJECT_TYPE_ARBITRATOR: + ret = ser_saveArbitrator(serializeSettings, (gxArbitrator*)object); + break; +#endif //DLMS_IGNORE_ARBITRATOR +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE1_SETUP: + ret = ser_saveIec8802LlcType1Setup(serializeSettings, (gxIec8802LlcType1Setup*)object); + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE2_SETUP: + ser_saveIec8802LlcType2Setup(serializeSettings, (gxIec8802LlcType2Setup*)object); + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE3_SETUP: + ser_saveIec8802LlcType3Setup(serializeSettings, (gxIec8802LlcType3Setup*)object); + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP +#ifndef DLMS_IGNORE_SFSK_ACTIVE_INITIATOR + case DLMS_OBJECT_TYPE_SFSK_ACTIVE_INITIATOR: + ser_saveSFSKActiveInitiator(serializeSettings, (gxSFSKActiveInitiator*)object); + break; +#endif //DLMS_IGNORE_SFSK_ACTIVE_INITIATOR +#ifndef DLMS_IGNORE_SFSK_MAC_COUNTERS + case DLMS_OBJECT_TYPE_SFSK_MAC_COUNTERS: + ser_saveFSKMacCounters(serializeSettings, (gxFSKMacCounters*)object); + break; +#endif //DLMS_IGNORE_SFSK_MAC_COUNTERS +#ifndef DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS + case DLMS_OBJECT_TYPE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS: + ser_saveSFSKMacSynchronizationTimeouts(serializeSettings, (gxSFSKMacSynchronizationTimeouts*)object); + break; +#endif //DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS +#ifndef DLMS_IGNORE_SFSK_PHY_MAC_SETUP + case DLMS_OBJECT_TYPE_SFSK_PHY_MAC_SETUP: + ser_saveSFSKPhyMacSetUp(serializeSettings, (gxSFSKPhyMacSetUp*)object); + break; +#endif //DLMS_IGNORE_SFSK_PHY_MAC_SETUP +#ifndef DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST + case DLMS_OBJECT_TYPE_SFSK_REPORTING_SYSTEM_LIST: + ser_saveSFSKReportingSystemList(serializeSettings, (gxSFSKReportingSystemList*)object); + break; +#endif //DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST +#ifdef DLMS_ITALIAN_STANDARD + case DLMS_OBJECT_TYPE_TARIFF_PLAN: + ret = ser_saveTariffPlan(serializeSettings, (gxTariffPlan*)object); + break; +#endif //DLMS_ITALIAN_STANDARD + default: //Unknown type. + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} + +#if !(!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +void ResetPosition(gxSerializerSettings* serializeSettings) +{ +#ifdef DLMS_IGNORE_MALLOC + serializeSettings->currentObject = NULL; + serializeSettings->currentIndex = 0; +#endif //DLMS_IGNORE_MALLOC + serializeSettings->position = 0; + serializeSettings->updateEnd = 0; +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) && !defined(GX_DLMS_MICROCONTROLLER) + serializeSettings->updateStart = 0xFFFFFFFF; +#else + serializeSettings->updateStart = 0xFFFF; +#endif //defined(GX_DLMS_BYTE_BUFFER_SIZE_32) && !defined(GX_DLMS_MICROCONTROLLER) +} +#endif //!(!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + +//Serialize objects to bytebuffer. +int ser_saveObjects( + gxSerializerSettings* serializeSettings, + gxObject** objects, + uint16_t count) +{ + uint16_t pos; + int ret = 0; +#if !(!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + ResetPosition(serializeSettings); +#endif //!(!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + +#ifdef DLMS_IGNORE_MALLOC + if (serializeSettings->savedAttributes == 0) + { + serializeSettings->savedAttributes = 0xFFFF; + } +#endif //DLMS_IGNORE_MALLOC + unsigned char ver = 0; + uint32_t dataSize = 0; + //Serializer version number only if it's changed. + ret = ser_loadUInt8(serializeSettings, &ver); + //If version has changed. + if (ret != 0 || ver != SERIALIZATION_VERSION) + { + if (ret == 0) + { + ret = ser_seek(serializeSettings, -1); + } + if ((ret = ser_saveUInt8(serializeSettings, SERIALIZATION_VERSION)) != 0 || + //Data size. + (ret = ser_saveUInt32(serializeSettings, 0)) != 0) + { + return ret; + } +#ifdef DLMS_IGNORE_MALLOC + //All objects are saved on the first time. + serializeSettings->savedAttributes = 0xFFFF; + serializeSettings->savedObject = NULL; +#endif //DLMS_IGNORE_MALLOC +#if !(!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) && !defined(GX_DLMS_MICROCONTROLLER) + serializeSettings->updateStart = 0xFFFFFFFF; +#else + serializeSettings->updateStart = 0xFFFF; +#endif //defined(GX_DLMS_BYTE_BUFFER_SIZE_32) && !defined(GX_DLMS_MICROCONTROLLER) +#endif //!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + } + else + { + ret = ser_loadUInt32(serializeSettings, &dataSize); + } + if (ret == 0) + { + for (pos = 0; pos != count; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + serializeSettings->currentObject = objects[pos]; +#endif //DLMS_IGNORE_MALLOC + if ((ret = ser_saveObject(serializeSettings, objects[pos])) != DLMS_ERROR_CODE_OK) + { + break; + } + } + } +#ifdef DLMS_IGNORE_MALLOC + serializeSettings->currentObject = NULL; + serializeSettings->currentIndex = 0; +#endif //DLMS_IGNORE_MALLOC + if (ret == 0) + { +#if !defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + int index = ftell(serializeSettings->stream); + uint32_t size = (uint32_t)(index - 5); +#else + int index = serializeSettings->position; + uint32_t size = (uint16_t)serializeSettings->position - 5; +#endif //#!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + if (dataSize == 0 || dataSize != size) + { + --index; + ret = ser_seek(serializeSettings, -index); + //Data size. + ret = ser_saveUInt32(serializeSettings, size); + //Seek to end. + ret = ser_seek(serializeSettings, size); + } + } + return ret; +} + +int ser_saveObjects2( + gxSerializerSettings* serializeSettings, + objectArray* objects) +{ + uint16_t pos; + int ret; + gxObject* obj; +#if !(!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + ResetPosition(serializeSettings); +#endif //!(!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +#ifdef DLMS_IGNORE_MALLOC + if (serializeSettings->savedAttributes == 0) + { + serializeSettings->savedAttributes = 0xFFFF; + } +#endif //DLMS_IGNORE_MALLOC + unsigned char ver = 0; + //Serializer version number only if it's changed. + ret = ser_loadUInt8(serializeSettings, &ver); + uint32_t dataSize = 0; + //If version has changed. + if (ret != 0 || ver != SERIALIZATION_VERSION) + { + if (ret == 0) + { + ret = ser_seek(serializeSettings, -1); + } + if ((ret = ser_saveUInt8(serializeSettings, SERIALIZATION_VERSION)) != 0 || + //Data size. + (ret = ser_saveUInt32(serializeSettings, 0)) != 0) + { + return ret; + } +#ifdef DLMS_IGNORE_MALLOC + //All objects are saved on the first time. + serializeSettings->savedAttributes = 0xFFFF; + serializeSettings->savedObject = NULL; +#endif //DLMS_IGNORE_MALLOC +#if !(!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +#if defined(GX_DLMS_BYTE_BUFFER_SIZE_32) && !defined(GX_DLMS_MICROCONTROLLER) + serializeSettings->updateStart = 0xFFFFFFFF; +#else + serializeSettings->updateStart = 0xFFFF; +#endif //defined(GX_DLMS_BYTE_BUFFER_SIZE_32) && !defined(GX_DLMS_MICROCONTROLLER) +#endif //!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + } + else + { + ret = ser_loadUInt32(serializeSettings, &dataSize); + } + if (ret == 0) + { + for (pos = 0; pos != objects->size; ++pos) + { + if ((ret = oa_getByIndex(objects, pos, &obj)) != DLMS_ERROR_CODE_OK) + { + break; + } +#ifdef DLMS_IGNORE_MALLOC + serializeSettings->currentObject = obj; +#endif //DLMS_IGNORE_MALLOC + if ((ret = ser_saveObject(serializeSettings, obj)) != DLMS_ERROR_CODE_OK) + { + break; + } + } + } + +#ifdef DLMS_IGNORE_MALLOC + serializeSettings->currentObject = NULL; + serializeSettings->currentIndex = 0; +#endif //DLMS_IGNORE_MALLOC + if (ret == 0) + { +#if !defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + int index = ftell(serializeSettings->stream); + uint32_t size = (uint32_t)(index - 5); +#else + int index = serializeSettings->position; + uint32_t size = (uint16_t)serializeSettings->position - 5; +#endif //#!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + if (dataSize == 0 || dataSize != size) + { + --index; + ret = ser_seek(serializeSettings, -index); + //Data size. + ret = ser_saveUInt32(serializeSettings, size); + //Seek to end. + ret = ser_seek(serializeSettings, size); + } + } + return ret; +} + +// -------------------------------------------------------------------------- +//Load functionality. + +// Get item from the buffer if DLMS_IGNORE_MALLOC is defined. +// Otherwice create the object dynamically. +int ser_getArrayItem(gxArray* arr, uint16_t index, void** value, uint16_t itemSize) +{ +#ifdef DLMS_IGNORE_MALLOC + return arr_getByIndex4(arr, index, value, itemSize, 0); +#else + void* it = gxcalloc(1, itemSize); + if (it == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + *value = it; + return arr_push(arr, it); +#endif //DLMS_COSEM_EXACT_DATA_TYPES +} + +int ser_verifyObjectArray(gxSerializerSettings* serializeSettings, objectArray* arr, uint16_t* count) +{ + oa_empty(arr); + int ret = ser_loadObjectCount(serializeSettings, count); + if (ret == 0) + { +#ifdef DLMS_IGNORE_MALLOC + uint16_t capacity; + ret = ser_loadObjectCount(serializeSettings, &capacity); + arr->size = capacity; +#else + ret = oa_capacity(arr, *count); +#endif //DLMS_IGNORE_MALLOC + } + return ret; +} + +#ifndef DLMS_IGNORE_DATA +int ser_loadData(gxSerializerSettings* serializeSettings, gxData* object) +{ + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + return ser_loadVariant(&object->value, serializeSettings); + } + return 0; +} + +#endif //DLMS_IGNORE_DATA +#ifndef DLMS_IGNORE_REGISTER +int ser_loadRegister(gxSerializerSettings* serializeSettings, gxRegister* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 3)) + { + if ((ret = ser_loadInt8(serializeSettings, &object->scaler)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &object->unit)) != 0) + { + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 2)) + { + ret = ser_loadVariant(&object->value, serializeSettings); + } + return ret; +} +#endif //DLMS_IGNORE_REGISTER +#ifndef DLMS_IGNORE_CLOCK +int ser_loadClock(gxSerializerSettings* serializeSettings, gxClock* object) +{ + int ret = 0; + unsigned char status = 0, clockBase = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!(!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_loadDateTime(&object->time, serializeSettings, DLMS_DATA_TYPE_DATETIME)) == 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_loadInt16(serializeSettings, &object->timeZone)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_loadUInt8(serializeSettings, &status)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_loadDateTime(&object->begin, serializeSettings, DLMS_DATA_TYPE_DATETIME)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_loadDateTime(&object->end, serializeSettings, DLMS_DATA_TYPE_DATETIME)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_loadInt8(serializeSettings, &object->deviation)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_loadUInt8(serializeSettings, &object->enabled)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_loadUInt8(serializeSettings, &clockBase)) != 0)) + { + object->status = status; + object->clockBase = clockBase; + } + return ret; +} +#endif //DLMS_IGNORE_CLOCK +#ifndef DLMS_IGNORE_SCRIPT_TABLE +int ser_loadScriptTable( + gxSerializerSettings* serializeSettings, + dlmsSettings* settings, + gxScriptTable* object) +{ + int ret = 0, pos, pos2; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + gxScript* s; + gxScriptAction* sa; + uint16_t count, count2; + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + obj_clearScriptTable(&object->scripts); + if ((ret = ser_loadArray(serializeSettings, &object->scripts, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(&object->scripts, pos, (void**)&s, sizeof(gxScript))) != 0) + { + break; + } + if ((ret = ser_loadUInt16(serializeSettings, &s->id)) != 0) + { + break; + } + if ((ret = ser_loadArray(serializeSettings, &s->actions, &count2)) == 0) + { + for (pos2 = 0; pos2 != count2; ++pos2) + { + if ((ret = ser_getArrayItem(&s->actions, pos2, (void**)&sa, sizeof(gxScriptAction))) != 0) + { + break; + } + if ((ret = ser_loadUInt8(serializeSettings, (unsigned char*)&sa->type)) != 0) + { + break; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + uint16_t ot; + unsigned char ln[6]; + if ((ret = ser_loadUInt16(serializeSettings, &ot)) != 0 || + (ret = ser_get(serializeSettings, ln, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0) + { + break; + } + if (pos2 < count2) + { + sa->target = NULL; + if ((ret = cosem_findObjectByLN(settings, ot, ln, &sa->target)) != 0) + { + break; + } + if (sa->target == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + } +#else + if ((ret = ser_loadUInt16(serializeSettings, sa->objectType)) != 0 || + (ret = ser_get(serializeSettings, sa->logicalName, sizeof(sa->logicalName))) != 0) + { + break; + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + if ((ret = ser_loadInt8(serializeSettings, &sa->index)) != 0 || + (ret = ser_loadVariant(&sa->parameter, serializeSettings)) != 0) + { + break; + } + } + } + if (ret != 0) + { + break; + } + } + } + } + return ret; +} +#endif //DLMS_IGNORE_SCRIPT_TABLE +#ifndef DLMS_IGNORE_SPECIAL_DAYS_TABLE +int ser_loadSpecialDaysTable( + gxSerializerSettings* serializeSettings, + gxSpecialDaysTable* object) +{ + int ret = 0, pos; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + gxSpecialDay* sd; + uint16_t count; + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + arr_clear(&object->entries); + if ((ret = ser_loadArray(serializeSettings, &object->entries, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(&object->entries, pos, (void**)&sd, sizeof(gxSpecialDay))) != 0) + { + break; + } + if ((ret = ser_loadUInt16(serializeSettings, &sd->index)) != 0 || + (ret = ser_loadDateTime(&sd->date, serializeSettings, DLMS_DATA_TYPE_DATETIME)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &sd->dayId)) != 0) + { + break; + } + } + } + } + return ret; +} +#endif //DLMS_IGNORE_SPECIAL_DAYS_TABLE +#ifndef DLMS_IGNORE_TCP_UDP_SETUP +int ser_loadTcpUdpSetup( + gxSerializerSettings* serializeSettings, + dlmsSettings* settings, + gxTcpUdpSetup* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + unsigned char ln[6]; + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + ret = ser_loadUInt16(serializeSettings, &object->port); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3)) + { + if ((ret = ser_get(serializeSettings, ln, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) == 0) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_NONE, ln, &object->ipSetup)) != 0) + { + return ret; + } +#else + if (ret = ser_get(&ba, object->ipReference, 6)) != 0 || + { + return ret; + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + } + if (ret == 0) + { + if ((!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_loadUInt16(serializeSettings, &object->maximumSegmentSize)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_loadUInt8(serializeSettings, &object->maximumSimultaneousConnections)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_loadUInt16(serializeSettings, &object->inactivityTimeout)) != 0)) + { + } + } + return ret; +} +#endif //DLMS_IGNORE_TCP_UDP_SETUP +#ifndef DLMS_IGNORE_MBUS_MASTER_PORT_SETUP +int ser_loadMBusMasterPortSetup( + gxSerializerSettings* serializeSettings, + gxMBusMasterPortSetup* object) +{ + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + return ser_loadUInt8(serializeSettings, (unsigned char*)&object->commSpeed); + } + return 0; +} +#endif //DLMS_IGNORE_MBUS_MASTER_PORT_SETUP + +int ser_loadObjectsInternal( + dlmsSettings* settings, + gxSerializerSettings* serializeSettings, + gxArray* objects) +{ + uint16_t pos; + int ret; + uint16_t count; + uint16_t ot; + unsigned char ln[6]; +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + gxTarget* it; +#else + gxObject* key; + gxTarget* value; +#endif //DLMS_IGNORE_MALLOC + obj_clearProfileGenericCaptureObjects(objects); + if ((ret = ser_loadArray(serializeSettings, objects, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + if ((ret = ser_getArrayItem(objects, pos, (void**)&it, sizeof(gxTarget))) != 0) + { + break; + } + if ((ret = ser_loadUInt16(serializeSettings, &ot)) != 0 || + (ret = ser_get(serializeSettings, ln, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0 || + (ret = ser_loadInt8(serializeSettings, &it->attributeIndex)) != 0 || + (ret = ser_loadUInt16(serializeSettings, &it->dataIndex)) != 0 || + (ret = cosem_findObjectByLN(settings, ot, ln, &it->target)) != 0) + { + break; + } + +#else + value = (gxTarget*)gxmalloc(sizeof(gxTarget)); + if (value == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + if ((ret = ser_loadUInt16(serializeSettings, &ot)) != 0 || + (ret = ser_get(serializeSettings, ln, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0 || + (ret = cosem_findObjectByLN(settings, ot, ln, &key)) != 0 || + (ret = ser_loadInt8(serializeSettings, &value->attributeIndex)) != 0 || + (ret = ser_loadUInt16(serializeSettings, &value->dataIndex)) != 0) + { + gxfree(value); + break; + } + if ((ret = arr_push(objects, key_init(key, value))) != 0) + { + break; + } +#endif //!defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + } + } + return ret; +} + +#ifndef DLMS_IGNORE_PUSH_SETUP +int ser_loadPushSetup( + gxSerializerSettings* serializeSettings, + dlmsSettings* settings, + gxPushSetup* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + ret = ser_loadObjectsInternal(settings, serializeSettings, &object->pushObjectList); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3)) + { + if ((ret = ser_loadUInt8(serializeSettings, (unsigned char*)&object->service)) != 0 || + (ret = ser_loadOctetString(serializeSettings, &object->destination)) != 0 || + (ret = ser_loadUInt8(serializeSettings, (unsigned char*)&object->message)) != 0) + { + } + } + if (ret == 0) + { + if ((!isAttributeSet(serializeSettings, ignored, 4) && (ret = loadTimeWindow(serializeSettings, &object->communicationWindow)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_loadUInt16(serializeSettings, &object->randomisationStartInterval)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_loadUInt8(serializeSettings, &object->numberOfRetries)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_loadUInt16(serializeSettings, &object->repetitionDelay)) != 0)) + { + } + } + return ret; +} +#endif //DLMS_IGNORE_PUSH_SETUP + +#ifndef DLMS_IGNORE_AUTO_CONNECT +int ser_loadAutoConnect( + gxSerializerSettings* serializeSettings, + gxAutoConnect* object) +{ + uint16_t count; +#ifdef DLMS_IGNORE_MALLOC + gxDestination* dest; +#else + gxByteBuffer* dest; +#endif //DLMS_IGNORE_MALLOC + int pos, ret = 0; + unsigned char ch; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + if ((ret = ser_loadUInt8(serializeSettings, &ch)) == 0) + { + object->mode = (DLMS_AUTO_CONNECT_MODE)ch; + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3)) + { + ret = ser_loadUInt8(serializeSettings, &object->repetitions); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 4)) + { + ret = ser_loadUInt16(serializeSettings, &object->repetitionDelay); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 5)) + { + ret = loadTimeWindow(serializeSettings, &object->callingWindow); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 6)) + { + arr_clearStrings(&object->destinations); + if (ret == 0 && (ret = ser_loadArray(serializeSettings, &object->destinations, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(&object->destinations, pos, (void**)&dest, sizeof(gxDestination), 0)) != 0) + { + break; + } + if ((ret = ser_loadOctetString3(serializeSettings, dest->value, &dest->size)) != 0) + { + break; + } +#else + dest = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + if (dest == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + BYTE_BUFFER_INIT(dest); + if ((ret = arr_push(&object->destinations, dest)) != 0) + { + break; + } + if ((ret = ser_loadOctetString(serializeSettings, dest)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + } + return ret; +} +#endif //DLMS_IGNORE_AUTO_CONNECT + +#ifndef DLMS_IGNORE_ACTIVITY_CALENDAR +int ser_loadSeasonProfile( + gxArray* arr, + gxSerializerSettings* serializeSettings) +{ + gxSeasonProfile* it; + int pos, ret; + uint16_t count; + if ((ret = obj_clearSeasonProfile(arr)) == 0 && + (ret = ser_loadArray(serializeSettings, arr, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(arr, pos, (void**)&it, sizeof(gxSeasonProfile))) != 0) + { + break; + } +#ifdef DLMS_IGNORE_MALLOC + if ((ret = ser_loadOctetString3(serializeSettings, it->name.value, &it->name.size)) != 0 || + (ret = ser_loadDateTime(&it->start, serializeSettings, DLMS_DATA_TYPE_DATETIME)) != 0 || + (ret = ser_loadOctetString3(serializeSettings, it->weekName.value, &it->weekName.size)) != 0) + { + break; + } +#else + if ((ret = ser_loadOctetString(serializeSettings, &it->name)) != 0 || + (ret = ser_loadDateTime(&it->start, serializeSettings, DLMS_DATA_TYPE_DATETIME)) != 0 || + (ret = ser_loadOctetString(serializeSettings, &it->weekName)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + return ret; +} + +int ser_loadweekProfile( + gxArray* arr, + gxSerializerSettings* serializeSettings) +{ + gxWeekProfile* it; + int pos, ret; + uint16_t count; + if ((ret = obj_clearWeekProfileTable(arr)) == 0 && + (ret = ser_loadArray(serializeSettings, arr, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(arr, pos, (void**)&it, sizeof(gxWeekProfile))) != 0) + { + break; + } +#ifdef DLMS_IGNORE_MALLOC + if ((ret = ser_loadOctetString3(serializeSettings, it->name.value, &it->name.size)) != 0) + { + break; + } +#else + if ((ret = ser_loadOctetString(serializeSettings, &it->name)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = ser_loadUInt8(serializeSettings, &it->monday)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->tuesday)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->wednesday)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->thursday)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->friday)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->saturday)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->sunday)) != 0) + { + break; + } + } + } + return ret; +} + +int ser_loadDayProfile( + dlmsSettings* settings, + gxArray* arr, + gxSerializerSettings* serializeSettings) +{ + gxDayProfile* dp; + gxDayProfileAction* it; + int pos, pos2, ret; + uint16_t count, count2; +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + if ((ret = obj_clearDayProfileTable(arr)) == 0 && + (ret = ser_loadArray(serializeSettings, arr, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(arr, pos, (void**)&dp, sizeof(gxDayProfile))) != 0) + { + break; + } + if ((ret = ser_loadUInt8(serializeSettings, &dp->dayId)) != 0 || + (ret = ser_loadArray(serializeSettings, &dp->daySchedules, &count2)) != 0) + { + break; + } + for (pos2 = 0; pos2 != count2; ++pos2) + { + if ((ret = ser_getArrayItem(&dp->daySchedules, pos2, (void**)&it, sizeof(gxDayProfileAction))) != 0) + { + break; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = ser_get(serializeSettings, ln, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0) + { + break; + } + if (pos2 < count2) + { + if ((ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_NONE, ln, &it->script)) != 0) + { + break; + } + } + else + { + it->script = NULL; + } +#else + if ((ret = ser_get(serializeSettings, it->scriptLogicalName, 6)) != 0) + { + break; + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + if ((ret = ser_loadUInt16(serializeSettings, &it->scriptSelector)) != 0 || + (ret = ser_loadDateTime(&it->startTime, serializeSettings, DLMS_DATA_TYPE_DATETIME)) != 0) + { + break; + } + } + } + } + return ret; +} + +int ser_loadActivityCalendar( + gxSerializerSettings* serializeSettings, + dlmsSettings* settings, + gxActivityCalendar* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_loadOctetString(serializeSettings, &object->calendarNameActive)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_loadSeasonProfile(&object->seasonProfileActive, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_loadweekProfile(&object->weekProfileTableActive, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_loadDayProfile(settings, &object->dayProfileTableActive, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_loadOctetString(serializeSettings, &object->calendarNamePassive)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_loadSeasonProfile(&object->seasonProfilePassive, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_loadweekProfile(&object->weekProfileTablePassive, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_loadDayProfile(settings, &object->dayProfileTablePassive, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 10) && (ret = ser_loadDateTime(&object->time, serializeSettings, DLMS_DATA_TYPE_DATETIME)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_ACTIVITY_CALENDAR + +#ifndef DLMS_IGNORE_SECURITY_SETUP +int ser_loadSecuritySetup( + gxSerializerSettings* serializeSettings, + gxSecuritySetup* object) +{ + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + unsigned char v; + int ret = 0; + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + if ((ret = ser_loadUInt8(serializeSettings, &v)) == 0) + { + object->securityPolicy = (DLMS_SECURITY_POLICY)v; + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3)) + { + if ((ret = ser_loadUInt8(serializeSettings, &v)) == 0) + { + object->securitySuite = (DLMS_SECURITY_SUITE)v; + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 4)) + { + if ((ret = bb_clear(&object->serverSystemTitle)) == 0) + { + ret = ser_loadOctetString(serializeSettings, &object->serverSystemTitle); + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 5)) + { + if ((ret = bb_clear(&object->clientSystemTitle)) == 0) + { + ret = ser_loadOctetString(serializeSettings, &object->clientSystemTitle); + } + } + return ret; +} +#endif //DLMS_IGNORE_SECURITY_SETUP +#ifndef DLMS_IGNORE_IEC_HDLC_SETUP +int ser_loadHdlcSetup( + gxSerializerSettings* serializeSettings, + gxIecHdlcSetup* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_loadUInt8(serializeSettings, (unsigned char*)&object->communicationSpeed)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_loadUInt8(serializeSettings, &object->windowSizeTransmit)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_loadUInt8(serializeSettings, &object->windowSizeReceive)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_loadUInt16(serializeSettings, &object->maximumInfoLengthTransmit)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_loadUInt16(serializeSettings, &object->maximumInfoLengthReceive)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_loadUInt16(serializeSettings, &object->interCharachterTimeout)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_loadUInt16(serializeSettings, &object->inactivityTimeout)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_loadUInt16(serializeSettings, &object->deviceAddress)) != 0)) + { + + } + return ret; +} +#endif //DLMS_IGNORE_IEC_HDLC_SETUP +#ifndef DLMS_IGNORE_IEC_LOCAL_PORT_SETUP +int ser_loadLocalPortSetup( + gxSerializerSettings* serializeSettings, + gxLocalPortSetup* object) +{ + int ret = 0; + unsigned char ch; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + if ((ret = ser_loadUInt8(serializeSettings, &ch)) == 0) + { + object->defaultMode = (DLMS_OPTICAL_PROTOCOL_MODE)ch; + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3)) + { + if ((ret = ser_loadUInt8(serializeSettings, &ch)) == 0) + { + object->defaultBaudrate = (DLMS_BAUD_RATE)ch; + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 4)) + { + if ((ret = ser_loadUInt8(serializeSettings, &ch)) == 0) + { + object->proposedBaudrate = (DLMS_BAUD_RATE)ch; + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 5)) + { + if ((ret = ser_loadUInt8(serializeSettings, &ch)) == 0) + { + object->responseTime = (DLMS_LOCAL_PORT_RESPONSE_TIME)ch; + } + } + if (ret == 0) + { + if ((!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_loadOctetString(serializeSettings, &object->deviceAddress)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_loadOctetString(serializeSettings, &object->password1)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_loadOctetString(serializeSettings, &object->password2)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_loadOctetString(serializeSettings, &object->password5)) != 0)) + { + + } + } + return ret; +} +#endif //DLMS_IGNORE_IEC_LOCAL_PORT_SETUP + +#ifndef DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP +int ser_loadIecTwistedPairSetup( + gxSerializerSettings* serializeSettings, + gxIecTwistedPairSetup* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_loadUInt8(serializeSettings, (unsigned char*)&object->mode)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_loadUInt8(serializeSettings, (unsigned char*)&object->speed)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_loadOctetString(serializeSettings, &object->primaryAddresses)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_loadOctetString(serializeSettings, &object->tabis)) != 0)) + { + + } + return ret; +} +#endif //DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP + +#ifndef DLMS_IGNORE_DEMAND_REGISTER +int ser_loadDemandRegister( + gxSerializerSettings* serializeSettings, + gxDemandRegister* object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_loadVariant(&object->currentAverageValue, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_loadVariant(&object->lastAverageValue, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_loadInt8(serializeSettings, &object->scaler)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_loadUInt8(serializeSettings, &object->unit)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_loadVariant(&object->status, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_loadDateTime(&object->captureTime, serializeSettings, DLMS_DATA_TYPE_DATETIME)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_loadDateTime(&object->startTimeCurrent, serializeSettings, DLMS_DATA_TYPE_DATETIME)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_loadUInt32(serializeSettings, &object->period)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 10) && (ret = ser_loadUInt16(serializeSettings, &object->numberOfPeriods)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_DEMAND_REGISTER +#ifndef DLMS_IGNORE_REGISTER_ACTIVATION +int ser_loadRegisterActivation( + gxSerializerSettings* serializeSettings, + dlmsSettings* settings, + gxRegisterActivation* object) +{ + int pos, ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + unsigned char ln[6]; + uint16_t ot; +#ifdef DLMS_IGNORE_OBJECT_POINTERS + gxObjectDefinition* od; +#else +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + gxRegisterActivationMask* it; +#if defined(DLMS_IGNORE_MALLOC) + uint16_t v; + uint16_t size; +#endif //defined(DLMS_IGNORE_MALLOC) +#else + gxByteBuffer* key, * value; +#endif //DLMS_IGNORE_MALLOC + gxObject* od; +#endif //DLMS_IGNORE_OBJECT_POINTERS + uint16_t count; + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + obj_clearRegisterActivationAssignment(&object->registerAssignment); +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + if ((ret = ser_loadArray(serializeSettings, &object->registerAssignment, &count)) == 0) + { + size = object->registerAssignment.size; + object->registerAssignment.size = count; +#else + if ((ret = ser_verifyObjectArray(serializeSettings, &object->registerAssignment, &count)) == 0) + { +#endif //defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + for (pos = 0; pos != count; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndexRef(&object->registerAssignment, pos, (void**)&od)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = ser_loadUInt16(serializeSettings, &ot)) != 0 || + (ret = ser_get(serializeSettings, ln, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0 || + (ot != 0 && (ret = cosem_findObjectByLN(settings, ot, ln, &od)) != 0)) + { + break; + } +#if defined(DLMS_COSEM_EXACT_DATA_TYPES) + if ((ret = arr_push(&object->registerAssignment, od)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC +#ifndef DLMS_IGNORE_MALLOC + if ((ret = oa_push(&object->registerAssignment, od)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } +#ifdef DLMS_IGNORE_MALLOC + object->registerAssignment.size = size; +#endif //DLMS_IGNORE_MALLOC + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3)) + { + obj_clearRegisterActivationMaskList(&object->maskList); + if (ret == 0 && (ret = ser_loadArray(serializeSettings, &object->maskList, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + if ((ret = ser_getArrayItem(&object->maskList, pos, (void**)&it, sizeof(gxRegisterActivationMask))) != 0) + { + break; + } +#if defined(DLMS_IGNORE_MALLOC) + if ((ret = ser_loadOctetString3(serializeSettings, it->name, &v)) != 0) + { + break; + } + it->length = (unsigned char)v; + if ((ret = ser_loadOctetString3(serializeSettings, it->indexes, &v)) != 0) + { + break; + } + it->count = (unsigned char)v; +#else + if ((ret = ser_loadOctetString(serializeSettings, &it->name)) != 0 || + (ret = ser_loadOctetString(serializeSettings, &it->indexes)) != 0) + { + break; + } +#endif //defined(DLMS_IGNORE_MALLOC) +#else + key = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + if (key == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + BYTE_BUFFER_INIT(key); + value = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + if (value == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + BYTE_BUFFER_INIT(value); + if ((ret = arr_push(&object->maskList, key_init(key, value))) != 0) + { + break; + } + if ((ret = ser_loadOctetString(serializeSettings, key)) != 0 || + (ret = ser_loadOctetString(serializeSettings, value)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 4)) + { + ret = ser_loadOctetString(serializeSettings, &object->activeMask); + } + return ret; +} +#endif //DLMS_IGNORE_REGISTER_ACTIVATION +#if !(defined(DLMS_IGNORE_REGISTER_MONITOR) && defined(DLMS_IGNORE_LIMITER)) + +int ser_loadActionItem( + dlmsSettings * settings, + gxActionItem * item, + gxSerializerSettings * serializeSettings) +{ + int ret; +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; + if ((ret = ser_get(serializeSettings, ln, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0 || + (ret = ser_loadUInt16(serializeSettings, &item->scriptSelector)) != 0 || + (ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_SCRIPT_TABLE, ln, (gxObject**)&item->script)) != 0) + { + } +#else + if ((ret = ser_get(serializeSettings, item->logicalName, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0 || + (ret = ser_loadUInt16(serializeSettings, item->scriptSelector)) != 0) + { + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + return ret; +} +#endif //!(defined(DLMS_IGNORE_REGISTER_MONITOR) && defined(DLMS_IGNORE_LIMITER)) + +#ifndef DLMS_IGNORE_REGISTER_MONITOR +int ser_loadRegisterMonitor( + gxSerializerSettings * serializeSettings, + dlmsSettings * settings, + gxRegisterMonitor * object) +{ + int pos, ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + dlmsVARIANT_PTR tmp; + dlmsVARIANT tmp2; + var_init(&tmp2); + gxActionSet* as; + uint16_t count; + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + va_clear(&object->thresholds); + if ((ret = ser_loadVariantArray(serializeSettings, &object->thresholds, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if (pos < object->thresholds.size) + { + if ((ret = ser_getVariantArrayItem(&object->thresholds, pos, &tmp)) != 0) + { + break; + } + } + else + { + var_clear(&tmp2); + tmp = &tmp2; + } + if ((ret = ser_loadVariant(tmp, serializeSettings)) != 0) + { + break; + } + } + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3)) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + uint16_t ot; + unsigned char ln[6]; + if ((ret = ser_loadUInt16(serializeSettings, &ot)) != 0 || + (ret = ser_get(serializeSettings, ln, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0 || + (ret = cosem_findObjectByLN(settings, (DLMS_OBJECT_TYPE)ot, ln, &object->monitoredValue.target)) != 0 || + (ret = ser_loadInt8(serializeSettings, &object->monitoredValue.attributeIndex)) != 0) + { + + } +#else + if ((ret = ser_loadUInt16(serializeSettings, &object->monitoredValue.objectType)) != 0) + (ret = ser_get(serializeSettings, object->monitoredValue.logicalName, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0 || + (ret = ser_loadInt8(serializeSettings, &object->monitoredValue.attributeIndex)) != 0) + { + + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 4)) + { + obj_clearRegisterMonitorActions(&object->actions); + if ((ret = ser_loadArray(serializeSettings, &object->actions, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(&object->actions, pos, (void**)&as, sizeof(gxActionSet))) != 0 || + (ret = ser_loadActionItem(settings, &as->actionUp, serializeSettings)) != 0 || + (ret = ser_loadActionItem(settings, &as->actionDown, serializeSettings)) != 0) + { + break; + } + } + } + } + return ret; +} +#endif //DLMS_IGNORE_REGISTER_MONITOR +#ifndef DLMS_IGNORE_ACTION_SCHEDULE +int ser_loadActionSchedule( + gxSerializerSettings * serializeSettings, + dlmsSettings * settings, + gxActionSchedule * object) +{ + int pos, ret = 0; + unsigned char ch; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + gxtime* tm; + uint16_t count; + if (!isAttributeSet(serializeSettings, ignored, 2)) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; + if ((ret = ser_get(serializeSettings, ln, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0 || + (ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_SCRIPT_TABLE, ln, (gxObject**)&object->executedScript)) != 0 || + (ret = ser_loadUInt16(serializeSettings, &object->executedScriptSelector)) != 0) + { + } +#else + if ((ret = ser_get(serializeSettings, object->executedScriptLogicalName +#ifdef DLMS_IGNORE_MALLOC + , capacity +#endif //DLMS_IGNORE_MALLOC + )) != 0 || + (ret = ser_loadUInt16(serializeSettings, &object->executedScriptSelector)) == 0) + { + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3)) + { + if ((ret = ser_loadUInt8(serializeSettings, &ch)) == 0) + { + object->type = ch; + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 4)) + { + arr_clear(&object->executionTime); + if ((ret = ser_loadArray(serializeSettings, &object->executionTime, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(&object->executionTime, pos, (void**)&tm, sizeof(gxtime))) != 0 || + (ret = ser_loadDateTime(tm, serializeSettings, DLMS_DATA_TYPE_DATETIME)) != 0) + { + break; + } + } + } + } + return ret; +} +#endif //DLMS_IGNORE_ACTION_SCHEDULE +#ifndef DLMS_IGNORE_SAP_ASSIGNMENT +int ser_loadSapAssignment( + gxSerializerSettings * serializeSettings, + gxSapAssignment * object) +{ + int ret = 0, pos; + gxSapItem* it; + uint16_t count; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + obj_clearSapList(&object->sapAssignmentList); + //Add count. + if ((ret = ser_loadArray(serializeSettings, &object->sapAssignmentList, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(&object->sapAssignmentList, pos, (void**)&it, sizeof(gxSapItem))) != 0 || + (ret = ser_loadUInt16(serializeSettings, &it->id)) != 0) + { + break; + } +#ifdef DLMS_IGNORE_MALLOC + if ((ret = ser_loadOctetString3(serializeSettings, it->name.value, &it->name.size)) != 0) + { + break; + } +#else + if ((ret = ser_loadOctetString(serializeSettings, &it->name)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + } + return ret; +} +#endif //DLMS_IGNORE_SAP_ASSIGNMENT + +#ifndef DLMS_IGNORE_AUTO_ANSWER +int ser_loadAutoAnswer( + gxSerializerSettings * serializeSettings, + gxAutoAnswer * object) +{ + int ret = 0; + unsigned char ch; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + if ((ret = ser_loadUInt8(serializeSettings, &ch)) == 0) + { + object->mode = ch; + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3)) + { + ret = loadTimeWindow(serializeSettings, &object->listeningWindow); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 4)) + { + if ((ret = ser_loadUInt8(serializeSettings, &ch)) == 0) + { + object->status = ch; + } + } + if (ret == 0) + { + if ((!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_loadUInt8(serializeSettings, &object->numberOfCalls)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_loadUInt8(serializeSettings, &object->numberOfRingsInListeningWindow)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_loadUInt8(serializeSettings, &object->numberOfRingsOutListeningWindow)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_loadUInt8(serializeSettings, &object->numberOfRingsOutListeningWindow)) != 0)) + { + } + } + return ret; +} +#endif //DLMS_IGNORE_AUTO_ANSWER +#ifndef DLMS_IGNORE_IP4_SETUP +int ser_loadIp4Setup( + gxSerializerSettings * serializeSettings, + dlmsSettings * settings, + gxIp4Setup * object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + uint32_t* tmp; +#else + dlmsVARIANT* tmp; +#endif //DLMS_IGNORE_MALLOC + gxip4SetupIpOption* ip; + uint16_t pos, count; +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + if ((ret = ser_get(serializeSettings, ln, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0 || + (ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_NONE, ln, &object->dataLinkLayer)) != 0) + { + return ret; + } +#else + if ((ret = ser_get(serializeSettings, object->dataLinkLayerReference, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0) + { + return ret; + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + } +if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3)) +{ + ret = ser_loadUInt32(serializeSettings, &object->ipAddress); +} +if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 4)) +{ +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + arr_clear(&object->multicastIPAddress); +#else + va_clear(&object->multicastIPAddress); +#endif //DLMS_IGNORE_MALLOC +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + if ((ret = ser_loadArray(serializeSettings, &object->multicastIPAddress, &count)) == 0) +#else + if ((ret = ser_loadVariantArray(serializeSettings, &object->multicastIPAddress, &count)) == 0) +#endif //defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + { + for (pos = 0; pos != count; ++pos) + { +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + if ((ret = ser_getArrayItem(&object->multicastIPAddress, pos, (void**)&tmp, sizeof(uint32_t))) != 0 || + (ret = ser_loadUInt32(serializeSettings, tmp)) != 0) + { + break; + } +#else + tmp = (dlmsVARIANT*)gxmalloc(sizeof(dlmsVARIANT)); + if (tmp == NULL) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + break; + } + tmp->vt = DLMS_DATA_TYPE_UINT32; + if ((ret = va_push(&object->multicastIPAddress, tmp)) != 0 || + (ret = ser_loadUInt32(serializeSettings, &tmp->ulVal)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 5)) + { + arr_clear(&object->ipOptions); + if ((ret = ser_loadArray(serializeSettings, &object->ipOptions, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(&object->ipOptions, pos, (void**)&ip, sizeof(gxip4SetupIpOption))) != 0 || + (ret = ser_loadUInt8(serializeSettings, (unsigned char*)&ip->type)) != 0) + { + break; + } +#ifdef DLMS_IGNORE_MALLOC + if ((ret = ser_loadOctetString3(serializeSettings, ip->data.value, &ip->data.size)) != 0) + { + break; + } +#else + if ((ret = ser_loadOctetString(serializeSettings, &ip->data)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + } +} +if (ret == 0) +{ + if ((!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_loadUInt32(serializeSettings, &object->subnetMask)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_loadUInt32(serializeSettings, &object->gatewayIPAddress)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_loadUInt8(serializeSettings, &object->useDHCP)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_loadUInt32(serializeSettings, &object->primaryDNSAddress)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 10) && (ret = ser_loadUInt32(serializeSettings, &object->secondaryDNSAddress)) != 0)) + { + } +} +return ret; +} +#endif //DLMS_IGNORE_IP4_SETUP + +#ifndef DLMS_IGNORE_IP6_SETUP +int ser_loadIp6Setup( + gxSerializerSettings * serializeSettings, + dlmsSettings * settings, + gxIp6Setup * object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + IN6_ADDR* ip; + uint16_t pos, count; + unsigned char ch; + if (!isAttributeSet(serializeSettings, ignored, 2)) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; + obj_clear((gxObject*)object); + if ((ret = ser_get(serializeSettings, ln, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0 || + (ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_NONE, ln, &object->dataLinkLayer)) != 0) + { + return ret; + } +#else + if ((ret = ser_get(serializeSettings, object->dataLinkLayerReference, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0) + { + return ret; + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3)) + { + if ((ret = ser_loadUInt8(serializeSettings, &ch)) == 0) + { + object->addressConfigMode = (DLMS_IP6_ADDRESS_CONFIG_MODE)ch; + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 4)) + { + arr_clear(&object->unicastIPAddress); + if (ret == 0 && (ret = ser_loadArray(serializeSettings, &object->unicastIPAddress, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(&object->unicastIPAddress, pos, (void**)&ip, sizeof(IN6_ADDR))) != 0 || + (ret = ser_get(serializeSettings, (unsigned char*)ip, 16 +#ifdef DLMS_IGNORE_MALLOC + , 16 +#endif //DLMS_IGNORE_MALLOC + )) != 0) + { + break; + } + } + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 5)) + { + arr_clear(&object->multicastIPAddress); + if (ret == 0 && (ret = ser_loadArray(serializeSettings, &object->multicastIPAddress, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(&object->multicastIPAddress, pos, (void**)&ip, sizeof(IN6_ADDR))) != 0 || + (ret = ser_get(serializeSettings, (unsigned char*)ip, 16 +#ifdef DLMS_IGNORE_MALLOC + , 16 +#endif //DLMS_IGNORE_MALLOC + )) != 0) + { + break; + } + } +#ifdef DLMS_IGNORE_MALLOC + object->multicastIPAddress.size = count; +#endif //DLMS_IGNORE_MALLOC + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 6)) + { + arr_clear(&object->gatewayIPAddress); + if (ret == 0 && (ret = ser_loadArray(serializeSettings, &object->gatewayIPAddress, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(&object->gatewayIPAddress, pos, (void**)&ip, sizeof(IN6_ADDR))) != 0 || + (ret = ser_get(serializeSettings, (unsigned char*)ip, 16 +#ifdef DLMS_IGNORE_MALLOC + , 16 +#endif //DLMS_IGNORE_MALLOC + )) != 0) + { + break; + } + } + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 7)) + { + ret = ser_get(serializeSettings, (unsigned char*)&object->primaryDNSAddress, 16 +#ifdef DLMS_IGNORE_MALLOC + , 16 +#endif //DLMS_IGNORE_MALLOC + ); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 8)) + { + ret = ser_get(serializeSettings, (unsigned char*)&object->secondaryDNSAddress, 16 +#ifdef DLMS_IGNORE_MALLOC + , 16 +#endif //DLMS_IGNORE_MALLOC + ); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 9)) + { + ret = ser_loadUInt8(serializeSettings, &object->trafficClass); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 10)) + { + arr_clear(&object->neighborDiscoverySetup); + gxNeighborDiscoverySetup* it2; + if ((ret = ser_loadArray(serializeSettings, &object->neighborDiscoverySetup, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(&object->neighborDiscoverySetup, pos, (void**)&it2, sizeof(gxNeighborDiscoverySetup))) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it2->maxRetry)) != 0 || + (ret = ser_loadUInt16(serializeSettings, &it2->retryWaitTime)) != 0 || + (ret = ser_loadUInt32(serializeSettings, &it2->sendPeriod)) != 0) + { + break; + } + } + } + } + return ret; +} +#endif //DLMS_IGNORE_IP6_SETUP + +#ifndef DLMS_IGNORE_UTILITY_TABLES +int ser_loadUtilityTables( + gxSerializerSettings * serializeSettings, + gxUtilityTables * object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_loadUInt16(serializeSettings, &object->tableId)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_loadOctetString(serializeSettings, &object->buffer)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_UTILITY_TABLES + +#ifndef DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP +int ser_loadMbusSlavePortSetup( + gxSerializerSettings * serializeSettings, + gxMbusSlavePortSetup * object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_loadUInt8(serializeSettings, (unsigned char*)&object->defaultBaud)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_loadUInt8(serializeSettings, (unsigned char*)&object->availableBaud)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_loadUInt8(serializeSettings, (unsigned char*)&object->addressState)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_loadUInt8(serializeSettings, (unsigned char*)&object->busAddress)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP +#ifndef DLMS_IGNORE_IMAGE_TRANSFER +int ser_loadImageTransfer( + gxSerializerSettings * serializeSettings, + gxImageTransfer * object) +{ + uint16_t count; + int pos, ret = 0; + gxImageActivateInfo* it; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + obj_clear((gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_loadUInt32(serializeSettings, &object->imageBlockSize)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_loadBitString(serializeSettings, &object->imageTransferredBlocksStatus)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_loadUInt32(serializeSettings, &object->imageFirstNotTransferredBlockNumber)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_loadUInt8(serializeSettings, &object->imageTransferEnabled)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_loadUInt8(serializeSettings, (unsigned char*)&object->imageTransferStatus)) != 0)) + { + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 7)) + { + arr_clear(&object->imageActivateInfo); + if ((ret = ser_loadArray(serializeSettings, &object->imageActivateInfo, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(&object->imageActivateInfo, pos, (void**)&it, sizeof(gxImageActivateInfo))) != 0 || + (ret = ser_loadUInt32(serializeSettings, &it->size)) != 0) + { + break; + } +#ifdef DLMS_IGNORE_MALLOC + if ((ret = ser_loadOctetString3(serializeSettings, it->identification.data, &it->identification.size)) != 0 || + (ret = ser_loadOctetString3(serializeSettings, it->signature.data, &it->signature.size)) != 0) + { + break; + } +#else + if ((ret = ser_loadOctetString(serializeSettings, &it->identification)) != 0 || + (ret = ser_loadOctetString(serializeSettings, &it->signature)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + } + return ret; +} +#endif //DLMS_IGNORE_IMAGE_TRANSFER +#ifndef DLMS_IGNORE_DISCONNECT_CONTROL +int ser_loadDisconnectControl( + gxSerializerSettings * serializeSettings, + gxDisconnectControl * object) +{ + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + unsigned char v; + int ret = 0; + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + ret = ser_loadUInt8(serializeSettings, &object->outputState); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3)) + { + if ((ret = ser_loadUInt8(serializeSettings, &v)) == 0) + { + object->controlState = (DLMS_CONTROL_STATE)v; + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 4)) + { + if ((ret = ser_loadUInt8(serializeSettings, &v)) == 0) + { + object->controlMode = (DLMS_CONTROL_MODE)v; + } + } + return ret; +} +#endif //DLMS_IGNORE_DISCONNECT_CONTROL +#ifndef DLMS_IGNORE_LIMITER +int ser_loadLimiter( + gxSerializerSettings * serializeSettings, + dlmsSettings * settings, + gxLimiter * object) +{ + int pos, ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + uint16_t* it; +#else + dlmsVARIANT* it; +#endif //DLMS_IGNORE_MALLOC + uint16_t count; + unsigned char ln[6]; + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + if ((ret = ser_get(serializeSettings, ln, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) == 0 && + (ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_NONE, ln, &object->monitoredValue)) == 0 && + (ret = ser_loadInt8(serializeSettings, &object->selectedAttributeIndex)) == 0) + { + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3)) + { + ret = ser_loadVariant(&object->thresholdActive, serializeSettings); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 4)) + { + ret = ser_loadVariant(&object->thresholdNormal, serializeSettings); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 5)) + { + ret = ser_loadVariant(&object->thresholdEmergency, serializeSettings); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 6)) + { + ret = ser_loadUInt32(serializeSettings, &object->minOverThresholdDuration); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 7)) + { + ret = ser_loadUInt32(serializeSettings, &object->minUnderThresholdDuration); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 8)) + { + if ((ret = ser_loadUInt16(serializeSettings, &object->emergencyProfile.id)) == 0 && + (ret = ser_loadDateTime(&object->emergencyProfile.activationTime, serializeSettings, DLMS_DATA_TYPE_DATETIME)) == 0 && + (ret = ser_loadUInt32(serializeSettings, &object->emergencyProfile.duration)) == 0) + { + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 9)) + { +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + if ((ret = ser_loadArray(serializeSettings, &object->emergencyProfileGroupIDs, &count)) == 0) +#else + if ((ret = ser_loadVariantArray(serializeSettings, &object->emergencyProfileGroupIDs, &count)) == 0) +#endif //defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + { + for (pos = 0; pos != count; ++pos) + { +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + if ((ret = ser_getArrayItem(&object->emergencyProfileGroupIDs, pos, (void**)&it, sizeof(uint16_t))) != 0 || + (ret = ser_loadUInt16(serializeSettings, it)) != 0) + { + break; + } +#else + it = (dlmsVARIANT*)gxmalloc(sizeof(dlmsVARIANT)); + if (it == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + var_init(it); + if ((ret = va_push(&object->emergencyProfileGroupIDs, it)) != 0 || + (ret = ser_loadVariant(it, serializeSettings)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 10)) + { + ret = ser_loadUInt8(serializeSettings, &object->emergencyProfileActive); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 11)) + { + if ((ret = ser_loadActionItem(settings, &object->actionOverThreshold, serializeSettings)) != 0 || + (ret = ser_loadActionItem(settings, &object->actionUnderThreshold, serializeSettings)) != 0) + { + } + } + } + return ret; +} +#endif //DLMS_IGNORE_LIMITER +#ifndef DLMS_IGNORE_MBUS_DIAGNOSTIC +int ser_loadMBusDiagnostic( + gxSerializerSettings * serializeSettings, + dlmsSettings * settings, + gxMbusDiagnostic * object) +{ + int ret = 0; + uint16_t pos, count; + unsigned char status = 0; + gxBroadcastFrameCounter* it; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_loadUInt8(serializeSettings, &object->receivedSignalStrength)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_loadUInt8(serializeSettings, &object->channelId)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_loadUInt8(serializeSettings, &status)) != 0)) + { + } + if (ret == 0) + { + object->linkStatus = status; + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 5)) + { + arr_clear(&object->broadcastFrames); + if ((ret = ser_loadArray(serializeSettings, &object->broadcastFrames, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(&object->broadcastFrames, pos, (void**)&it, sizeof(gxBroadcastFrameCounter))) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->clientId)) != 0 || + (ret = ser_loadUInt32(serializeSettings, &it->counter)) != 0 || + (ret = ser_loadDateTime(&it->timeStamp, serializeSettings, DLMS_DATA_TYPE_DATETIME)) != 0) + { + break; + } + } + } + } + if ((!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_loadUInt32(serializeSettings, &object->transmissions)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_loadUInt32(serializeSettings, &object->receivedFrames)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_loadUInt32(serializeSettings, &object->failedReceivedFrames)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_loadUInt8(serializeSettings, &object->captureTime.attributeId)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_loadDateTime(&object->captureTime.timeStamp, serializeSettings, DLMS_DATA_TYPE_DATETIME)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_MBUS_DIAGNOSTIC + +#ifndef DLMS_IGNORE_MBUS_PORT_SETUP +int ser_loadMBusPortSetup( + gxSerializerSettings * serializeSettings, + dlmsSettings * settings, + gxMBusPortSetup * object) +{ + int ret = 0; + unsigned char ht, st, dt; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_get(serializeSettings, object->profileSelection, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_loadUInt8(serializeSettings, &st)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_loadUInt8(serializeSettings, &ht)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_loadUInt8(serializeSettings, &object->primaryAddress)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_loadUInt32(serializeSettings, &object->identificationNumber)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_loadUInt16(serializeSettings, &object->manufacturerId)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_loadUInt8(serializeSettings, &object->mBusVersion)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_loadUInt8(serializeSettings, &dt)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 10) && (ret = ser_loadUInt16(serializeSettings, &object->maxPduSize)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 10) && (ret = loadTimeWindow(serializeSettings, &object->listeningWindow)) != 0)) + { + } + if (ret == 0) + { + object->portCommunicationStatus = st; + object->dataHeaderType = ht; + object->deviceType = dt; + } + return ret; +} +#endif //DLMS_IGNORE_MBUS_PORT_SETUP + +#ifndef DLMS_IGNORE_MBUS_CLIENT +int ser_loadMBusClient( + gxSerializerSettings * serializeSettings, + dlmsSettings * settings, + gxMBusClient * object) +{ + int ret = 0; + unsigned char ch; + unsigned char ln[6]; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_loadUInt32(serializeSettings, &object->capturePeriod)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_loadUInt8(serializeSettings, &object->primaryAddress)) != 0)) + { + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 2)) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = ser_get(serializeSettings, ln, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0 || + (ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_NONE, ln, &object->mBusPort)) != 0) + { + return ret; + } +#else + if ((ret = ser_get(serializeSettings, object->mBusPortReference +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0) + { + return ret; + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + if ((!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_loadUInt32(serializeSettings, &object->identificationNumber)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_loadUInt16(serializeSettings, &object->manufacturerID)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_loadUInt8(serializeSettings, &object->dataHeaderVersion)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_loadUInt8(serializeSettings, &object->deviceType)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 10) && (ret = ser_loadUInt8(serializeSettings, &object->accessNumber)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 11) && (ret = ser_loadUInt8(serializeSettings, &object->status)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 12) && (ret = ser_loadUInt8(serializeSettings, &object->alarm)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 13) && (ret = ser_loadUInt16(serializeSettings, &object->configuration)) != 0)) + { + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 14) && (ret = ser_loadUInt8(serializeSettings, &ch)) == 0) + { + object->encryptionKeyStatus = (DLMS_MBUS_ENCRYPTION_KEY_STATUS)ch; + } + return ret; +} +#endif //DLMS_IGNORE_MBUS_CLIENT + +#ifndef DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS +int ser_loadG3PlcMacLayerCounters( + gxSerializerSettings * serializeSettings, + dlmsSettings * settings, + gxG3PlcMacLayerCounters * object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_loadUInt32(serializeSettings, &object->txDataPacketCount)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_loadUInt32(serializeSettings, &object->rxDataPacketCount)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_loadUInt32(serializeSettings, &object->txCmdPacketCount)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_loadUInt32(serializeSettings, &object->rxCmdPacketCount)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_loadUInt32(serializeSettings, &object->cSMAFailCount)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_loadUInt32(serializeSettings, &object->cSMANoAckCount)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_loadUInt32(serializeSettings, &object->badCrcCount)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_loadUInt32(serializeSettings, &object->txDataBroadcastCount)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 10) && (ret = ser_loadUInt32(serializeSettings, &object->rxDataBroadcastCount)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS + +#ifndef DLMS_IGNORE_G3_PLC_MAC_SETUP +int ser_loadkeyTable(gxSerializerSettings * serializeSettings, gxArray * table) +{ + int ret; + uint16_t pos, count, size; + gxG3MacKeyTable* it; + arr_clear(table); + if ((ret = ser_loadArray(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(table, pos, (void**)&it, sizeof(gxG3MacKeyTable))) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->id)) != 0 || + (ret = ser_loadOctetString3(serializeSettings, it->key, &size)) != 0) + { + break; + } + } + } + return ret; +} + +int ser_loadNeighbourTable(gxSerializerSettings * serializeSettings, gxArray * table) +{ + int ret; + uint16_t pos, count; +#ifdef DLMS_IGNORE_MALLOC + uint16_t toneMapSize, txCoeffSize; +#endif //DLMS_IGNORE_MALLOC + gxNeighbourTable* it; + unsigned char modulation, txRes; + arr_clear(table); + if ((ret = ser_loadArray(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(table, pos, (void**)&it, sizeof(gxNeighbourTable))) != 0 || + (ret = ser_loadUInt16(serializeSettings, &it->shortAddress)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->payloadModulationScheme)) != 0 || +#ifdef DLMS_IGNORE_MALLOC + (ret = ser_loadBitString2(serializeSettings, it->toneMap[pos].value, MAX_G3_MAC_NEIGHBOUR_TABLE_TONE_MAP_ITEM_SIZE, &toneMapSize)) != 0 || +#else + (ret = ser_loadBitString(serializeSettings, &it->toneMap)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = ser_loadUInt8(serializeSettings, &modulation)) != 0 || + (ret = ser_loadInt8(serializeSettings, &it->txGain)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &txRes)) != 0 || +#ifdef DLMS_IGNORE_MALLOC + (ret = ser_loadBitString2(serializeSettings, it->txCoeff[pos].value, MAX_G3_MAC_NEIGHBOUR_TABLE_GAIN_ITEM_SIZE, &txCoeffSize)) != 0 || +#else + (ret = ser_loadBitString(serializeSettings, &it->txCoeff)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = ser_loadUInt8(serializeSettings, &it->lqi)) != 0 || + (ret = ser_loadInt8(serializeSettings, &it->phaseDifferential)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->tmrValidTime)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->noData)) != 0) + { + break; + } + it->modulation = modulation; + it->txRes = txRes; +#ifdef DLMS_IGNORE_MALLOC + it->toneMap[pos].size = (unsigned char)toneMapSize; + it->txCoeff[pos].size = (unsigned char)txCoeffSize; +#endif //DLMS_IGNORE_MALLOC + } + } + return ret; +} + +int ser_loadPosTable(gxSerializerSettings * serializeSettings, gxArray * table) +{ + int ret; + uint16_t pos, count; + gxMacPosTable* it; + arr_clear(table); + if ((ret = ser_loadArray(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(table, pos, (void**)&it, sizeof(gxMacPosTable))) != 0 || + (ret = ser_loadUInt16(serializeSettings, &it->shortAddress)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->lqi)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->validTime)) != 0) + { + break; + } + } + } + return ret; +} + +int ser_loadG3PlcMacSetup( + gxSerializerSettings * serializeSettings, + dlmsSettings * settings, + gxG3PlcMacSetup * object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_loadUInt16(serializeSettings, &object->shortAddress)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_loadUInt16(serializeSettings, &object->rcCoord)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_loadUInt16(serializeSettings, &object->panId)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_loadkeyTable(serializeSettings, &object->keyTable)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_loadUInt32(serializeSettings, &object->frameCounter)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_loadBitString(serializeSettings, &object->toneMask)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_loadUInt8(serializeSettings, &object->tmrTtl)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_loadUInt8(serializeSettings, &object->maxFrameRetries)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 10) && (ret = ser_loadUInt8(serializeSettings, &object->neighbourTableEntryTtl)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 11) && (ret = ser_loadNeighbourTable(serializeSettings, &object->neighbourTable)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 12) && (ret = ser_loadUInt8(serializeSettings, &object->highPriorityWindowSize)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 13) && (ret = ser_loadUInt8(serializeSettings, &object->cscmFairnessLimit)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 14) && (ret = ser_loadUInt8(serializeSettings, &object->beaconRandomizationWindowLength)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 15) && (ret = ser_loadUInt8(serializeSettings, &object->macA)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 16) && (ret = ser_loadUInt8(serializeSettings, &object->macK)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 17) && (ret = ser_loadUInt8(serializeSettings, &object->minCwAttempts)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 18) && (ret = ser_loadUInt8(serializeSettings, &object->cenelecLegacyMode)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 19) && (ret = ser_loadUInt8(serializeSettings, &object->fccLegacyMode)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 20) && (ret = ser_loadUInt8(serializeSettings, &object->maxBe)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 21) && (ret = ser_loadUInt8(serializeSettings, &object->maxCsmaBackoffs)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 22) && (ret = ser_loadUInt8(serializeSettings, &object->minBe)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 23) && (ret = ser_loadUInt8(serializeSettings, &object->macBroadcastMaxCwEnabled)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 24) && (ret = ser_loadUInt8(serializeSettings, &object->macTransmitAtten)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 25) && (ret = ser_loadPosTable(serializeSettings, &object->macPosTable)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_G3_PLC_MAC_SETUP + +#ifndef DLMS_IGNORE_G3_PLC_6LO_WPAN + +int ser_loadRoutingConfiguration(gxSerializerSettings * serializeSettings, gxArray * table) +{ + int ret; + uint16_t pos, count; + gxRoutingConfiguration* it; + arr_clear(table); + if ((ret = ser_loadArray(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(table, pos, (void**)&it, sizeof(gxRoutingConfiguration))) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->netTraversalTime)) != 0 || + (ret = ser_loadUInt16(serializeSettings, &it->routingTableEntryTtl)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->kr)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->km)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->kc)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->kq)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->kh)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->krt)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->rReqRetries)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->rReqReqWait)) != 0 || + (ret = ser_loadUInt16(serializeSettings, &it->blacklistTableEntryTtl)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->unicastRreqGenEnable)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->rlcEnabled)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->addRevLinkCost)) != 0) + { + break; + } + } + } + return ret; +} + +int ser_loadRoutingTable(gxSerializerSettings * serializeSettings, gxArray * table) +{ + int ret; + uint16_t pos, count; + gxRoutingTable* it; + arr_clear(table); + if ((ret = ser_loadArray(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(table, pos, (void**)&it, sizeof(gxRoutingTable))) != 0 || + (ret = ser_loadUInt16(serializeSettings, &it->destinationAddress)) != 0 || + (ret = ser_loadUInt16(serializeSettings, &it->nextHopAddress)) != 0 || + (ret = ser_loadUInt16(serializeSettings, &it->routeCost)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->hopCount)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->weakLinkCount)) != 0 || + (ret = ser_loadUInt16(serializeSettings, &it->validTime)) != 0) + { + break; + } + } + } + return ret; +} + +int ser_loadContextInformationTable(gxSerializerSettings * serializeSettings, gxArray * table) +{ + int ret; + uint16_t pos, count, count2; + gxContextInformationTable* it; + arr_clear(table); + if ((ret = ser_loadArray(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(table, pos, (void**)&it, sizeof(gxContextInformationTable))) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->cid)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->contextLength)) != 0 || + (ret = ser_loadOctetString3(serializeSettings, it->context, &count2)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->compression)) != 0 || + (ret = ser_loadUInt16(serializeSettings, &it->validLifetime)) != 0) + { + break; + } + } + } + return ret; +} + +int ser_loadBlacklistTable(gxSerializerSettings * serializeSettings, gxArray * table) +{ + int ret; + uint16_t pos, count; + gxBlacklistTable* it; + arr_clear(table); + if ((ret = ser_loadArray(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(table, pos, (void**)&it, sizeof(gxBlacklistTable))) != 0 || + (ret = ser_loadUInt16(serializeSettings, &it->neighbourAddress)) != 0 || + (ret = ser_loadUInt16(serializeSettings, &it->validTime)) != 0) + { + break; + } + } + } + return ret; +} + +int ser_loadBroadcastLogTable(gxSerializerSettings * serializeSettings, gxArray * table) +{ + int ret; + uint16_t pos, count; + gxBroadcastLogTable* it; + arr_clear(table); + if ((ret = ser_loadArray(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(table, pos, (void**)&it, sizeof(gxBroadcastLogTable))) != 0 || + (ret = ser_loadUInt16(serializeSettings, &it->sourceAddress)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->sequenceNumber)) != 0 || + (ret = ser_loadUInt16(serializeSettings, &it->validTime)) != 0) + { + break; + } + } + } + return ret; +} + +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) +int ser_loadUInt16Array(gxSerializerSettings * serializeSettings, gxArray * table) +{ + int ret; + uint16_t pos, count; + uint16_t* it; + if ((ret = ser_loadArray(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = arr_getByIndex4(table, pos, (void**)&it, sizeof(uint16_t), 0)) != 0) + { + break; + } + if ((ret = ser_loadUInt16(serializeSettings, it)) != 0) + { + break; + } + } + table->size = count; + } + return ret; +} +#else +int ser_loadUInt16Array(gxSerializerSettings * serializeSettings, variantArray * table) +{ + int ret; + uint16_t tmp, pos, count; + dlmsVARIANT* it; + if ((ret = ser_loadVariantArray(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_loadUInt16(serializeSettings, &tmp)) != 0) + { + break; + } + if ((ret = ser_getVariantArrayItem(table, pos, &it)) != 0) + { + break; + } + it->vt = DLMS_DATA_TYPE_UINT16; + it->uiVal = tmp; + } + } + return ret; +} +#endif //defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + + +int ser_loadG3Plc6LoWPAN( + gxSerializerSettings * serializeSettings, + dlmsSettings * settings, + gxG3Plc6LoWPAN * object) +{ + int ret = 0; + unsigned char deviceType = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_loadUInt8(serializeSettings, &object->maxHops)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_loadUInt8(serializeSettings, &object->weakLqiValue)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_loadUInt8(serializeSettings, &object->securityLevel)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_loadOctetString(serializeSettings, &object->prefixTable)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_loadRoutingConfiguration(serializeSettings, &object->routingConfiguration)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_loadUInt16(serializeSettings, &object->broadcastLogTableEntryTtl)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_loadRoutingTable(serializeSettings, &object->routingTable)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 9) && (ret = ser_loadContextInformationTable(serializeSettings, &object->contextInformationTable)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 10) && (ret = ser_loadBlacklistTable(serializeSettings, &object->blacklistTable)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 11) && (ret = ser_loadBroadcastLogTable(serializeSettings, &object->broadcastLogTable)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 12) && (ret = ser_loadUInt16Array(serializeSettings, &object->groupTable)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 13) && (ret = ser_loadUInt16(serializeSettings, &object->maxJoinWaitTime)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 14) && (ret = ser_loadUInt8(serializeSettings, &object->pathDiscoveryTime)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 15) && (ret = ser_loadUInt8(serializeSettings, &object->activeKeyIndex)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 16) && (ret = ser_loadUInt8(serializeSettings, &object->metricType)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 17) && (ret = ser_loadUInt16(serializeSettings, &object->coordShortAddress)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 18) && (ret = ser_loadUInt8(serializeSettings, &object->disableDefaultRouting)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 19) && (ret = ser_loadUInt8(serializeSettings, &deviceType)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 20) && (ret = ser_loadUInt8(serializeSettings, &object->defaultCoordRouteEnabled)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 21) && (ret = ser_loadUInt16Array(serializeSettings, &object->destinationAddress)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 22) && (ret = ser_loadUInt8(serializeSettings, &object->lowLQI)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 23) && (ret = ser_loadUInt8(serializeSettings, &object->highLQI)) != 0)) + { + } + if (ret == 0) + { + object->deviceType = (DLMS_PAN_DEVICE_TYPE)deviceType; + } + return ret; +} +#endif //DLMS_IGNORE_G3_PLC_6LO_WPAN + +#ifndef DLMS_IGNORE_FUNCTION_CONTROL + +int ser_loadActivationStatus( + gxSerializerSettings * serializeSettings, + gxArray * table) +{ + int ret; + uint16_t pos, count; + functionStatus* it; + arr_clear(table); + if ((ret = ser_loadArray(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(table, pos, (void**)&it, sizeof(functionStatus))) != 0) + { + break; + } +#ifdef DLMS_IGNORE_MALLOC + if ((ret = ser_loadOctetString3(serializeSettings, it->name, &it->size)) != 0) + { + break; + } +#else + if ((ret = ser_loadOctetString(serializeSettings, &it->name)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = ser_loadUInt8(serializeSettings, &it->status)) != 0) + { + break; + } + + } + } + return ret; +} + +#ifdef DLMS_IGNORE_MALLOC +int ser_loadFunctions( + gxSerializerSettings * serializeSettings, + dlmsSettings * settings, + gxArray * table) +{ + int ret; + unsigned char ln[6]; + uint16_t ot, pos, pos2, count, count2; + functionalBlock* it; + gxObject* obj; + arr_clear(table); + if ((ret = ser_loadArray(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(table, pos, (void**)&it, sizeof(functionalBlock))) != 0) + { + break; + } + if ((ret = ser_loadOctetString3(serializeSettings, it->name, &it->nameSize)) != 0) + { + break; + } + //Load count. + if ((ret = ser_loadObjectCount(serializeSettings, &it->functionSpecificationsSize)) == 0 && + //Load capacity. + (ret = ser_loadObjectCount(serializeSettings, &count2)) == 0) + { + for (pos2 = 0; pos2 != count2; ++pos2) + { + obj = NULL; + if ((ret = ser_loadUInt16(serializeSettings, &ot)) != 0) + { + break; + } + if ((ret = ser_get(serializeSettings, ln, 6, 6)) != 0) + { + break; + } + if (ot != 0) + { + if ((ret = oa_findByLN(&settings->objects, ot, ln, &obj)) != 0) + { + break; + } + if (obj == NULL) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + } + } + } + } + } + return ret; +} +#else +int ser_loadFunctions( + gxSerializerSettings * serializeSettings, + dlmsSettings * settings, + gxArray * table) +{ + int ret; + unsigned char ln[6]; + uint16_t ot, pos, pos2, count, count2; + functionalBlock* it; + gxObject* obj; + arr_clear(table); + if ((ret = ser_loadArray(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(table, pos, (void**)&it, sizeof(functionalBlock))) != 0) + { + break; + } + if ((ret = ser_loadOctetString(serializeSettings, &it->name)) != 0) + { + break; + } + oa_empty(&it->functionSpecifications); + if ((ret = ser_loadArray(serializeSettings, + (gxArray*)&it->functionSpecifications, &count2)) == 0) + { + for (pos2 = 0; pos2 != count2; ++pos2) + { + obj = NULL; + if ((ret = ser_loadUInt16(serializeSettings, &ot)) != 0) + { + break; + } + if ((ret = ser_get(serializeSettings, ln, 6)) != 0 || + (ret = oa_findByLN(&settings->objects, ot, ln, &obj)) != 0) + { + break; + } + if (obj == NULL) + { + if ((ret = cosem_createObject(ot, &obj)) != DLMS_ERROR_CODE_OK) + { + //If unknown object. + if (ret == DLMS_ERROR_CODE_INVALID_PARAMETER) + { + ret = 0; + continue; + } + break; + } + if ((ret = cosem_setLogicalName(obj, ln)) != DLMS_ERROR_CODE_OK) + { + break; + } + oa_push(&it->functionSpecifications, obj); + } + } + } + } + } + return ret; +} +#endif //DLMS_IGNORE_MALLOC + +int ser_loadFunctionControl( + gxSerializerSettings * serializeSettings, + dlmsSettings * settings, + gxFunctionControl * object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_loadActivationStatus(serializeSettings, &object->activationStatus)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_loadFunctions(serializeSettings, settings, &object->functions)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_G3_PLC_6LO_WPAN + +#ifndef DLMS_IGNORE_ARRAY_MANAGER + +int ser_loadArrayManagerElements( + gxSerializerSettings * serializeSettings, + dlmsSettings * settings, + gxArray * table) +{ + int ret; + uint16_t pos, count, ot; + unsigned char ln[6]; + gxArrayManagerItem* it; + arr_clear(table); + if ((ret = ser_loadArray(serializeSettings, table, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(table, pos, (void**)&it, sizeof(gxArrayManagerItem))) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->id)) != 0 || + (ret = ser_loadUInt16(serializeSettings, &ot)) != 0 || + (ret = ser_get(serializeSettings, ln, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0 || + (ret = ser_loadInt8(serializeSettings, &it->element.attributeIndex)) != 0) + { + break; + } + if (pos < table->size) + { + if ((ret = oa_findByLN(&settings->objects, ot, ln, &it->element.target)) != 0) + { + break; + } + if (it->element.target == NULL) + { +#ifdef DLMS_IGNORE_MALLOC + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; +#else + if ((ret = cosem_createObject(ot, &it->element.target)) != DLMS_ERROR_CODE_OK) + { + //If unknown object. + break; + } + if ((ret = cosem_setLogicalName(it->element.target, ln)) != DLMS_ERROR_CODE_OK) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + } +} + return ret; +} + +int ser_loadArrayManager( + gxSerializerSettings * serializeSettings, + dlmsSettings * settings, + gxArrayManager * object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && + (ret = ser_loadArrayManagerElements(serializeSettings, settings, &object->elements)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_ARRAY_MANAGER + + +#ifndef DLMS_IGNORE_MODEM_CONFIGURATION +int ser_loadModemConfiguration( + gxSerializerSettings * serializeSettings, + gxModemConfiguration * object) +{ + unsigned char ch; + int pos, ret = 0; + gxModemInitialisation* mi; +#ifdef DLMS_IGNORE_MALLOC + gxModemProfile* it; +#else + gxByteBuffer* it; +#endif //DLMS_IGNORE_MALLOC + uint16_t count; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + if ((ret = ser_loadUInt8(serializeSettings, &ch)) == 0) + { + object->communicationSpeed = (DLMS_BAUD_RATE)ch; + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3)) + { + obj_clearModemConfigurationInitialisationStrings(&object->initialisationStrings); + if ((ret = ser_loadArray(serializeSettings, &object->initialisationStrings, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(&object->initialisationStrings, pos, (void**)&mi, sizeof(gxModemInitialisation))) != 0) + { + break; + } +#ifdef DLMS_IGNORE_MALLOC + if ((ret = ser_loadOctetString3(serializeSettings, mi->request.value, &mi->request.size)) != 0 || + (ret = ser_loadOctetString3(serializeSettings, mi->response.value, &mi->response.size)) != 0 || + (ret = ser_loadUInt16(serializeSettings, &mi->delay)) != 0) + { + break; + } +#else + if ((ret = ser_loadOctetString(serializeSettings, &mi->request)) != 0 || + (ret = ser_loadOctetString(serializeSettings, &mi->response)) != 0 || + (ret = ser_loadUInt16(serializeSettings, &mi->delay)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 4)) + { + arr_clearStrings(&object->modemProfile); + if ((ret = ser_loadArray(serializeSettings, &object->modemProfile, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex3(&object->modemProfile, pos, (void**)&it, sizeof(gxModemProfile), 0)) != 0) + { + break; + } + if ((ret = ser_loadOctetString3(serializeSettings, it->value, &it->size)) != 0) + { + break; + } +#else + it = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + if (it == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + BYTE_BUFFER_INIT(it); + if ((ret = arr_push(&object->modemProfile, it)) != 0) + { + break; + } + if ((ret = ser_loadOctetString(serializeSettings, it)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + } + return ret; +} +#endif //DLMS_IGNORE_MODEM_CONFIGURATION +#ifndef DLMS_IGNORE_MAC_ADDRESS_SETUP +int ser_loadMacAddressSetup( + gxSerializerSettings * serializeSettings, + gxMacAddressSetup * object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + if ((ret = ser_loadOctetString(serializeSettings, &object->macAddress)) != 0) + { + } + } + return ret; +} +#endif //DLMS_IGNORE_MAC_ADDRESS_SETUP + +#ifndef DLMS_IGNORE_GPRS_SETUP +int ser_loadQualityOfService( + gxQualityOfService * object, + gxSerializerSettings * serializeSettings) +{ + int ret; + if ((ret = ser_loadUInt8(serializeSettings, &object->precedence)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &object->delay)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &object->reliability)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &object->peakThroughput)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &object->meanThroughput)) != 0) + { + + } + return ret; +} + +int ser_loadGPRSSetup( + gxSerializerSettings * serializeSettings, + gxGPRSSetup * object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_loadOctetString(serializeSettings, &object->apn)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_loadUInt16(serializeSettings, &object->pinCode)) != 0)) + { + + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 4)) + { + if ((ret = ser_loadQualityOfService(&object->defaultQualityOfService, serializeSettings)) != 0 || + (ret = ser_loadQualityOfService(&object->requestedQualityOfService, serializeSettings)) != 0) + { + } + } + return ret; +} +#endif //DLMS_IGNORE_GPRS_SETUP +#ifndef DLMS_IGNORE_EXTENDED_REGISTER +int ser_loadExtendedRegister( + gxSerializerSettings * serializeSettings, + gxExtendedRegister * object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + ret = ser_loadVariant(&object->value, serializeSettings); + } + if (!isAttributeSet(serializeSettings, ignored, 3)) + { + if ((ret = ser_loadInt8(serializeSettings, &object->scaler)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &object->unit)) != 0) + { + } + } + if ((!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_loadVariant(&object->status, serializeSettings)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_loadDateTime(&object->captureTime, serializeSettings, DLMS_DATA_TYPE_DATETIME)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_EXTENDED_REGISTER + +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME +int ser_loadApplicationContextName( + gxSerializerSettings * serializeSettings, + gxApplicationContextName * object) +{ + int ret; + if ((ret = ser_get(serializeSettings, object->logicalName, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0 || + (ret = ser_loadUInt8(serializeSettings, &object->jointIsoCtt)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &object->country)) != 0 || + (ret = ser_loadUInt16(serializeSettings, &object->countryName)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &object->identifiedOrganization)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &object->dlmsUA)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &object->applicationContext)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &object->contextId)) != 0) + { + + } + return ret; +} + +int ser_loadxDLMSContextType(gxSerializerSettings * serializeSettings, gxXDLMSContextType * object) +{ + int ret; + if ((ret = ser_loadUInt32(serializeSettings, (uint32_t*)&object->conformance)) != 0 || + (ret = ser_loadUInt16(serializeSettings, &object->maxReceivePduSize)) != 0 || + (ret = ser_loadUInt16(serializeSettings, &object->maxSendPduSize)) != 0 || + (ret = ser_loadInt8(serializeSettings, &object->qualityOfService)) != 0 || + (ret = ser_loadOctetString(serializeSettings, &object->cypheringInfo)) != 0) + { + + } + return ret; +} + +int ser_loadAuthenticationMechanismName(gxSerializerSettings * serializeSettings, gxAuthenticationMechanismName * object) +{ + unsigned char ch; + int ret; + if ((ret = ser_loadUInt8(serializeSettings, &object->jointIsoCtt)) == 0 && + (ret = ser_loadUInt8(serializeSettings, &object->country)) == 0 && + (ret = ser_loadUInt16(serializeSettings, &object->countryName)) == 0 && + (ret = ser_loadUInt8(serializeSettings, &object->identifiedOrganization)) == 0 && + (ret = ser_loadUInt8(serializeSettings, &object->dlmsUA)) == 0 && + (ret = ser_loadUInt8(serializeSettings, &object->authenticationMechanismName)) == 0 && + (ret = ser_loadUInt8(serializeSettings, &ch)) == 0) + { + object->mechanismId = ch; + } + return ret; +} + +int ser_loadAssociationLogicalName( + gxSerializerSettings * serializeSettings, + dlmsSettings * settings, + gxAssociationLogicalName * object) +{ +#ifdef DLMS_IGNORE_MALLOC + gxUser* it; +#endif //DLMS_IGNORE_MALLOC + unsigned char ch; + int pos, ret = 0; + uint16_t count, value; +#ifdef DLMS_IGNORE_MALLOC + uint16_t capacity2; +#endif //DLMS_IGNORE_MALLOC + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + gxObject* obj = NULL; + unsigned char version; + DLMS_OBJECT_TYPE type = DLMS_OBJECT_TYPE_NONE; + unsigned char ln[6]; + oa_empty(&object->objectList); + if ((ret = ser_loadArray(serializeSettings, (gxArray*)&object->objectList, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + obj = NULL; + if ((ret = ser_loadUInt8(serializeSettings, &version)) != 0 || + (ret = ser_loadUInt16(serializeSettings, &value)) != 0) + { + break; + } + type = value; + if ((ret = ser_get(serializeSettings, ln, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0 || + (ret = oa_findByLN(&settings->objects, type, ln, &obj)) != 0) + { + break; + } + if (obj == NULL) + { +#ifdef DLMS_IGNORE_MALLOC + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; +#else + if ((ret = cosem_createObject(type, &obj)) != DLMS_ERROR_CODE_OK) + { + //If unknown object. + if (ret == DLMS_ERROR_CODE_INVALID_PARAMETER) + { + ret = 0; + continue; + } + break; + } + if ((ret = cosem_setLogicalName(obj, ln)) != DLMS_ERROR_CODE_OK) + { + break; + } + obj->version = version; + oa_push(&object->objectList, obj); +#endif //DLMS_IGNORE_MALLOC + } + } + } + if (ret != 0) + { + return ret; + } + } + if (!isAttributeSet(serializeSettings, ignored, 3)) + { + if ((ret = ser_loadInt8(serializeSettings, &object->clientSAP)) != 0 || + (ret = ser_loadUInt16(serializeSettings, &object->serverSAP)) != 0) + { + } + } + if (ret == 0) + { + if ((!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_loadApplicationContextName(serializeSettings, &object->applicationContextName)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_loadxDLMSContextType(serializeSettings, &object->xDLMSContextInfo)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_loadAuthenticationMechanismName(serializeSettings, &object->authenticationMechanismName)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_loadOctetString(serializeSettings, &object->secret)) != 0)) + { + + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_loadUInt8(serializeSettings, &ch)) == 0) + { + object->associationStatus = ch; + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 9)) + { +#ifndef DLMS_IGNORE_SECURITY_SETUP + //Security Setup Reference is from version 1. + if (object->base.version > 0) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; + if ((ret = ser_get(serializeSettings, ln, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0 || + (ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_SECURITY_SETUP, ln, (gxObject**)&object->securitySetup)) != 0) + { + } +#else + if ((ret = ser_get(&ba, object->securitySetupReference, 6)) != 0) + { + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + } +#endif //DLMS_IGNORE_SECURITY_SETUP + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 10)) + { + obj_clearUserList(&object->userList); + if (object->base.version > 1) + { + if ((ret = ser_loadArray(serializeSettings, &object->userList, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = ser_getArrayItem(&object->userList, pos, (void**)&it, sizeof(gxUser))) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->id)) != 0 || + (ret = ser_loadOctetString3(serializeSettings, (unsigned char*)it->name, &capacity2)) != 0) + { + break; + } +#else + uint8_t id; + gxByteBuffer* value = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + if (value == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + if ((ret = ser_loadUInt8(serializeSettings, &id)) != 0 || + (ret = ser_loadOctetString(serializeSettings, value)) != 0) + { + break; + } + if ((ret = arr_push(&object->userList, key_init2(id, value))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + } +} + return ret; +} +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME +int ser_loadAssociationShortName( + gxSerializerSettings * serializeSettings, + dlmsSettings * settings, + gxAssociationShortName * object) +{ +#ifdef DLMS_IGNORE_MALLOC + gxUser* it; +#endif //DLMS_IGNORE_MALLOC + int pos, ret = 0; + uint16_t count, value; +#ifdef DLMS_IGNORE_MALLOC + uint16_t capacity2; +#endif //DLMS_IGNORE_MALLOC + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + gxObject* obj = NULL; + unsigned char version; +#ifndef DLMS_IGNORE_MALLOC + DLMS_OBJECT_TYPE type = DLMS_OBJECT_TYPE_NONE; +#endif //DLMS_IGNORE_MALLOC + unsigned char ln[6]; + uint16_t shortName; + oa_empty(&object->objectList); + if ((ret = ser_loadArray(serializeSettings, (gxArray*)&object->objectList, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + obj = NULL; + if ((ret = ser_loadUInt16(serializeSettings, &shortName)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &version)) != 0 || + (ret = ser_loadUInt16(serializeSettings, &value)) != 0) + { + break; + } +#ifndef DLMS_IGNORE_MALLOC + type = value; +#endif //DLMS_IGNORE_MALLOC + if ((ret = ser_get(serializeSettings, ln, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0 || + (ret = oa_findBySN(&settings->objects, shortName, &obj)) != 0) + { + break; + } + if (obj == NULL) + { +#ifdef DLMS_IGNORE_MALLOC + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; +#else + if ((ret = cosem_createObject(type, &obj)) != DLMS_ERROR_CODE_OK) + { + //If unknown object. + if (ret == DLMS_ERROR_CODE_INVALID_PARAMETER) + { + ret = 0; + continue; + } + break; + } + if ((ret = cosem_setLogicalName(obj, ln)) != DLMS_ERROR_CODE_OK) + { + break; + } + obj->shortName = shortName; + obj->version = version; + //Add object to released objects list. + ret = oa_push(&settings->releasedObjects, obj); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } +#endif //DLMS_IGNORE_MALLOC + } +#ifndef DLMS_IGNORE_MALLOC + oa_push(&object->objectList, obj); +#endif //DLMS_IGNORE_MALLOC + // obj->version = (unsigned char)version; + } + } + if (ret != 0) + { + return ret; + } +} + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 9)) + { +#ifndef DLMS_IGNORE_SECURITY_SETUP + //Security Setup Reference is from version 1. + if (object->base.version > 0) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; + if ((ret = ser_get(serializeSettings, ln, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0 || + (ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_SECURITY_SETUP, ln, (gxObject**)&object->securitySetup)) != 0) + { + } +#else + if ((ret = ser_get(&ba, object->securitySetupReference, 6)) != 0) + { + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + } +#endif //DLMS_IGNORE_SECURITY_SETUP + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 10)) + { + obj_clearUserList(&object->userList); + if (object->base.version > 1) + { + if ((ret = ser_loadArray(serializeSettings, &object->userList, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = ser_getArrayItem(&object->userList, pos, (void**)&it, sizeof(gxUser))) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->id)) != 0 || + (ret = ser_loadOctetString3(serializeSettings, (unsigned char*)it->name, &capacity2)) != 0) + { + break; + } +#else + uint8_t id; + gxByteBuffer* value = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + if (value == NULL) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + if ((ret = ser_loadUInt8(serializeSettings, &id)) != 0 || + (ret = ser_loadOctetString(serializeSettings, value)) != 0) + { + break; + } + if ((ret = arr_push(&object->userList, key_init2(id, value))) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + } + } + } + } + return ret; +} + +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME +#ifndef DLMS_IGNORE_PPP_SETUP +int ser_loadPppSetup( + gxSerializerSettings * serializeSettings, + dlmsSettings * settings, + gxPppSetup * object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; + if ((ret = ser_get(serializeSettings, ln, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0 || + (ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_NONE, ln, &object->phy)) != 0) + { + return ret; + } +#else + if ((ret = ser_get(serializeSettings, object->PHYReference, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0) + { + return ret; + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 5)) + { + if ((ret = ser_loadOctetString(serializeSettings, &object->userName)) != 0 || + (ret = ser_loadOctetString(serializeSettings, &object->password)) != 0 || + (ret = ser_loadUInt8(serializeSettings, (unsigned char*)&object->authentication)) != 0) + { + } + } + return ret; +} +#endif //DLMS_IGNORE_PPP_SETUP + +#ifndef DLMS_IGNORE_PROFILE_GENERIC + +int ser_loadProfileGeneric( + gxSerializerSettings * serializeSettings, + dlmsSettings * settings, + gxProfileGeneric * object) +{ + unsigned char ch; + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + unsigned char ln[6]; + if ((!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_loadObjectsInternal(settings, serializeSettings, &object->captureObjects)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_loadUInt32(serializeSettings, &object->capturePeriod)) != 0)) + { + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_loadUInt8(serializeSettings, &ch)) == 0) + { + object->sortMethod = ch; + } + if (ret == 0) + { + if ((!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_get(serializeSettings, ln, 6 +#ifdef DLMS_IGNORE_MALLOC + , 6 +#endif //DLMS_IGNORE_MALLOC + )) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_NONE, ln, &object->sortObject)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_loadUInt32(serializeSettings, &object->entriesInUse)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_loadUInt32(serializeSettings, &object->profileEntries)) != 0)) + { + } + } + return ret; +} +#endif //DLMS_IGNORE_PROFILE_GENERIC +#ifndef DLMS_IGNORE_ACCOUNT +int ser_loadAccount( + gxSerializerSettings * serializeSettings, + gxAccount * object) +{ + unsigned char ch; + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + if ((ret = ser_loadUInt8(serializeSettings, &ch)) == 0) + { + object->paymentMode = ch; + if ((ret = ser_loadUInt8(serializeSettings, &ch)) == 0) + { + object->accountStatus = ch; + } + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3)) + { + ret = ser_loadUInt8(serializeSettings, &object->currentCreditInUse); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_loadUInt8(serializeSettings, &ch)) == 0) + { + object->currentCreditStatus = ch; + } + if ((!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_loadInt32(serializeSettings, &object->availableCredit)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_loadInt32(serializeSettings, &object->amountToClear)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 7) && (ret = ser_loadInt32(serializeSettings, &object->clearanceThreshold)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 8) && (ret = ser_loadInt32(serializeSettings, &object->aggregatedDebt)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 13) && (ret = ser_loadDateTime(&object->accountActivationTime, serializeSettings, DLMS_DATA_TYPE_DATETIME)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 14) && (ret = ser_loadDateTime(&object->accountClosureTime, serializeSettings, DLMS_DATA_TYPE_DATETIME)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 16) && (ret = ser_loadInt32(serializeSettings, &object->lowCreditThreshold)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 17) && (ret = ser_loadInt32(serializeSettings, &object->nextCreditAvailableThreshold)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 18) && (ret = ser_loadUInt16(serializeSettings, &object->maxProvision)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 19) && (ret = ser_loadInt32(serializeSettings, &object->maxProvisionPeriod)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_ACCOUNT +#ifndef DLMS_IGNORE_CREDIT +int ser_loadCredit( + gxSerializerSettings * serializeSettings, + gxCredit * object) +{ + unsigned char ch; + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + ret = ser_loadInt32(serializeSettings, &object->currentCreditAmount); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3)) + { + if ((ret = ser_loadUInt8(serializeSettings, &ch)) == 0) + { + object->type = (DLMS_CREDIT_TYPE)ch; + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 4)) + { + ret = ser_loadUInt8(serializeSettings, &object->priority); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 5)) + { + ret = ser_loadInt32(serializeSettings, &object->warningThreshold); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 6)) + { + ret = ser_loadInt32(serializeSettings, &object->limit); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 7)) + { + if ((ret = ser_loadUInt8(serializeSettings, &ch)) == 0) + { + object->creditConfiguration = (DLMS_CREDIT_CONFIGURATION)ch; + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 8)) + { + ret = ser_loadUInt8(serializeSettings, &object->status); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 9)) + { + ret = ser_loadInt32(serializeSettings, &object->presetCreditAmount); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 10)) + { + ret = ser_loadInt32(serializeSettings, &object->creditAvailableThreshold); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 11)) + { + ret = ser_loadDateTime(&object->period, serializeSettings, DLMS_DATA_TYPE_DATETIME); + } + return ret; +} +#endif //DLMS_IGNORE_CREDIT +#ifndef DLMS_IGNORE_CHARGE + +int ser_loadUnitCharge( + gxSerializerSettings * serializeSettings, + dlmsSettings * settings, + gxUnitCharge * target) +{ + gxChargeTable* ct; + int ret, pos; + if ((ret = obj_clearChargeTables(&target->chargeTables)) == 0) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + uint16_t type; +#endif //DLMS_IGNORE_OBJECT_POINTERS +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + uint16_t count; + if (//charge per unit scaling + (ret = ser_loadInt8(serializeSettings, &target->chargePerUnitScaling.commodityScale)) != 0 || + (ret = ser_loadInt8(serializeSettings, &target->chargePerUnitScaling.priceScale)) != 0 || + //commodity +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = ser_loadUInt16(serializeSettings, &type)) != 0 || + (ret = ser_getOctetString2(serializeSettings, ln, NULL)) != 0 || +#else + (ret = cosem_getInt16(serializeSettings, (short*)&target->commodity.type)) != 0 || + (ret = ser_getOctetString2(serializeSettings, target->commodity.logicalName, NULL)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + (ret = ser_loadInt8(serializeSettings, &target->commodity.attributeIndex)) != 0 || + (ret = ser_loadArray(serializeSettings, &target->chargeTables, &count)) != 0) + { + return ret; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = cosem_findObjectByLN(settings, type, ln, &target->commodity.target)) != 0) + { + return ret; + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(&target->chargeTables, pos, (void**)&ct, sizeof(gxChargeTable))) != 0 || +#ifdef DLMS_IGNORE_MALLOC + (ret = ser_getOctetString2(serializeSettings, ct->index.data, &ct->index.size)) != 0 || +#else + (ret = ser_getOctetString(serializeSettings, &ct->index)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = ser_loadInt16(serializeSettings, &ct->chargePerUnit)) != 0) + { + break; + } + } + } + return ret; +} + +int ser_loadCharge( + gxSerializerSettings * serializeSettings, + dlmsSettings * settings, + gxCharge * object) +{ + unsigned char ch; + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { + ret = ser_loadInt32(serializeSettings, &object->totalAmountPaid); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 3)) + { + if ((ret = ser_loadUInt8(serializeSettings, &ch)) == 0) + { + object->chargeType = (DLMS_CHARGE_TYPE)ch; + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 4)) + { + ret = ser_loadUInt8(serializeSettings, &object->priority); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 5)) + { + ret = ser_loadUnitCharge(serializeSettings, settings, &object->unitChargeActive); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 6)) + { + ret = ser_loadUnitCharge(serializeSettings, settings, &object->unitChargePassive); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 7)) + { + ret = ser_loadDateTime(&object->unitChargeActivationTime, serializeSettings, DLMS_DATA_TYPE_DATETIME); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 8)) + { + ret = ser_loadUInt32(serializeSettings, &object->period); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 9)) + { + if ((ret = ser_loadUInt8(serializeSettings, &ch)) == 0) + { + object->chargeConfiguration = (DLMS_CHARGE_CONFIGURATION)ch; + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 10)) + { + ret = ser_loadDateTime(&object->lastCollectionTime, serializeSettings, DLMS_DATA_TYPE_DATETIME); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 11)) + { + ret = ser_loadInt32(serializeSettings, &object->lastCollectionAmount); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 12)) + { + ret = ser_loadInt32(serializeSettings, &object->totalAmountRemaining); + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 13)) + { + ret = ser_loadUInt16(serializeSettings, &object->proportion); + } + return ret; +} +#endif //DLMS_IGNORE_CHARGE +#ifndef DLMS_IGNORE_TOKEN_GATEWAY +int ser_loadTokenGateway( + gxSerializerSettings * serializeSettings, + gxTokenGateway * object) +{ + return 0; +} +#endif //DLMS_IGNORE_TOKEN_GATEWAY +#ifndef DLMS_IGNORE_GSM_DIAGNOSTIC +int ser_loadGsmDiagnostic( + gxSerializerSettings * serializeSettings, + gxGsmDiagnostic * object) +{ + int ret = 0, pos; + gxAdjacentCell* it; + uint16_t count; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if (!isAttributeSet(serializeSettings, ignored, 2)) + { +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + ret = ser_loadOctetString(serializeSettings, &object->operatorName); +#else + ret = ser_loadOctetString2(serializeSettings, &object->operatorName); +#endif //DLMS_IGNORE_MALLOC + } + if (ret == 0) + { + if ((!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_loadUInt8(serializeSettings, (unsigned char*)&object->status)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_loadUInt8(serializeSettings, (unsigned char*)&object->circuitSwitchStatus)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_loadUInt8(serializeSettings, (unsigned char*)&object->packetSwitchStatus)) != 0)) + { + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 6)) + { + if ((ret = ser_loadUInt32(serializeSettings, &object->cellInfo.cellId)) == 0 && + (ret = ser_loadUInt16(serializeSettings, &object->cellInfo.locationId)) == 0 && + (ret = ser_loadUInt8(serializeSettings, &object->cellInfo.signalQuality)) == 0 && + (ret = ser_loadUInt8(serializeSettings, &object->cellInfo.ber)) == 0) + { + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 7)) + { + arr_clear(&object->adjacentCells); + if ((ret = ser_loadArray(serializeSettings, &object->adjacentCells, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = ser_getArrayItem(&object->adjacentCells, pos, (void**)&it, sizeof(gxAdjacentCell))) != 0 || + (ret = ser_loadUInt32(serializeSettings, &it->cellId)) != 0 || + (ret = ser_loadUInt8(serializeSettings, &it->signalQuality)) != 0) + { + break; + } + } + } + } + if (ret == 0 && !isAttributeSet(serializeSettings, ignored, 8)) + { + ret = ser_loadDateTime(&object->captureTime, serializeSettings, DLMS_DATA_TYPE_DATETIME); + } + return ret; +} +#endif //DLMS_IGNORE_GSM_DIAGNOSTIC + +#ifndef DLMS_IGNORE_COMPACT_DATA +int ser_loadCompactData( + gxSerializerSettings * serializeSettings, + dlmsSettings * settings, + gxCompactData * object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_loadOctetString(serializeSettings, &object->buffer)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_loadObjectsInternal(settings, serializeSettings, &object->captureObjects)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 4) && (ret = ser_loadUInt8(serializeSettings, &object->templateId)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 5) && (ret = ser_loadOctetString(serializeSettings, &object->templateDescription)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 6) && (ret = ser_loadUInt8(serializeSettings, (unsigned char*)&object->captureMethod)) != 0)) + { + + } + return ret; +} +#endif //DLMS_IGNORE_COMPACT_DATA + +#ifndef DLMS_IGNORE_LLC_SSCS_SETUP +int ser_loadLlcSscsSetup( + gxSerializerSettings * serializeSettings, + gxLlcSscsSetup * object) +{ + int ret = 0; + uint16_t ignored = ser_getIgnoredAttributes(serializeSettings, (gxObject*)object); + if ((!isAttributeSet(serializeSettings, ignored, 2) && (ret = ser_loadUInt16(serializeSettings, &object->serviceNodeAddress)) != 0) || + (!isAttributeSet(serializeSettings, ignored, 3) && (ret = ser_loadUInt16(serializeSettings, &object->baseNodeAddress)) != 0)) + { + } + return ret; +} +#endif //DLMS_IGNORE_LLC_SSCS_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +int ser_loadPrimeNbOfdmPlcPhysicalLayerCounters( + gxSerializerSettings * serializeSettings, + gxPrimeNbOfdmPlcPhysicalLayerCounters * object) +{ + return 0; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +int ser_loadPrimeNbOfdmPlcMacSetup( + gxSerializerSettings * serializeSettings, + gxPrimeNbOfdmPlcMacSetup * object) +{ + return 0; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +int ser_loadPrimeNbOfdmPlcMacFunctionalParameters( + gxSerializerSettings * serializeSettings, + gxPrimeNbOfdmPlcMacFunctionalParameters * object) +{ + return 0; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +int ser_loadPrimeNbOfdmPlcMacCounters( + gxSerializerSettings * serializeSettings, + gxPrimeNbOfdmPlcMacCounters * object) +{ + return 0; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA +int ser_loadPrimeNbOfdmPlcMacNetworkAdministrationData( + gxSerializerSettings * serializeSettings, + gxPrimeNbOfdmPlcMacNetworkAdministrationData * object) +{ + return 0; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION +int ser_loadPrimeNbOfdmPlcApplicationsIdentification( + gxSerializerSettings * serializeSettings, + gxPrimeNbOfdmPlcApplicationsIdentification * object) +{ + return 0; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION + +#ifndef DLMS_IGNORE_ARBITRATOR +int ser_loadArbitrator( + gxSerializerSettings * serializeSettings, + gxArbitrator * object) +{ + return 0; +} +#endif //DLMS_IGNORE_ARBITRATOR +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +int ser_loadIec8802LlcType1Setup( + gxSerializerSettings * serializeSettings, + gxIec8802LlcType1Setup * object) +{ + return 0; +} +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP +int ser_loadIec8802LlcType2Setup( + gxSerializerSettings * serializeSettings, + gxIec8802LlcType2Setup * object) +{ + return 0; +} +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP +int ser_loadIec8802LlcType3Setup( + gxSerializerSettings * serializeSettings, + gxIec8802LlcType3Setup * object) +{ + return 0; +} +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP +#ifndef DLMS_IGNORE_SFSK_ACTIVE_INITIATOR +int ser_loadSFSKActiveInitiator( + gxSerializerSettings * serializeSettings, + gxSFSKActiveInitiator * object) +{ + return 0; +} +#endif //DLMS_IGNORE_SFSK_ACTIVE_INITIATOR +#ifndef DLMS_IGNORE_SFSK_MAC_COUNTERS +int ser_loadFSKMacCounters( + gxSerializerSettings * serializeSettings, + gxFSKMacCounters * object) +{ + return 0; +} +#endif //DLMS_IGNORE_SFSK_MAC_COUNTERS +#ifndef DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS +int ser_loadSFSKMacSynchronizationTimeouts( + gxSerializerSettings * serializeSettings, + gxSFSKMacSynchronizationTimeouts * object) +{ + return 0; +} +#endif //DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS +#ifndef DLMS_IGNORE_SFSK_PHY_MAC_SETUP +int ser_loadSFSKPhyMacSetUp( + gxSerializerSettings * serializeSettings, + gxSFSKPhyMacSetUp * object) +{ + return 0; +} +#endif //DLMS_IGNORE_SFSK_PHY_MAC_SETUP +#ifndef DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST +int ser_loadSFSKReportingSystemList( + gxSerializerSettings * serializeSettings, + gxSFSKReportingSystemList * object) +{ + return 0; +} +#endif //DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST + +#ifndef DLMS_IGNORE_SCHEDULE +int ser_loadSchedule( + gxSerializerSettings * serializeSettings, + gxSchedule * object) +{ + return 0; +} +#endif //DLMS_IGNORE_SCHEDULE + +#ifdef DLMS_ITALIAN_STANDARD +int ser_loadTariffPlan( + gxSerializerSettings * serializeSettings, + gxTariffPlan * object) +{ + int ret; + if ((ret = bb_addString(serializeSettings, object->calendarName)) != 0 || + (ret = ser_loadUInt8(serializeSettings, object->enabled)) != 0 || + (ret = ser_loadDateTime(&object->activationTime, serializeSettings, DLMS_DATA_TYPE_DATETIME)) != 0) +{ +} + return ret; +} +#endif //DLMS_ITALIAN_STANDARD + +int ser_loadObject( + dlmsSettings * settings, + gxSerializerSettings * serializeSettings, + gxObject * object) +{ + int ret = 0; + switch (object->objectType) + { +#ifndef DLMS_IGNORE_DATA + + case DLMS_OBJECT_TYPE_DATA: + ret = ser_loadData(serializeSettings, (gxData*)object); + break; +#endif //DLMS_IGNORE_DATA +#ifndef DLMS_IGNORE_REGISTER + case DLMS_OBJECT_TYPE_REGISTER: + ret = ser_loadRegister(serializeSettings, (gxRegister*)object); + break; +#endif //DLMS_IGNORE_REGISTER +#ifndef DLMS_IGNORE_CLOCK + case DLMS_OBJECT_TYPE_CLOCK: + ret = ser_loadClock(serializeSettings, (gxClock*)object); + break; +#endif //DLMS_IGNORE_CLOCK +#ifndef DLMS_IGNORE_ACTION_SCHEDULE + case DLMS_OBJECT_TYPE_ACTION_SCHEDULE: + ret = ser_loadActionSchedule(serializeSettings, settings, (gxActionSchedule*)object); + break; +#endif //DLMS_IGNORE_ACTION_SCHEDULE +#ifndef DLMS_IGNORE_ACTIVITY_CALENDAR + case DLMS_OBJECT_TYPE_ACTIVITY_CALENDAR: + ret = ser_loadActivityCalendar(serializeSettings, settings, (gxActivityCalendar*)object); + break; +#endif //DLMS_IGNORE_ACTIVITY_CALENDAR +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + case DLMS_OBJECT_TYPE_ASSOCIATION_LOGICAL_NAME: + ret = ser_loadAssociationLogicalName(serializeSettings, settings, (gxAssociationLogicalName*)object); + break; +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + case DLMS_OBJECT_TYPE_ASSOCIATION_SHORT_NAME: +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + ret = ser_loadAssociationShortName(serializeSettings, settings, (gxAssociationShortName*)object); +#else + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + break; +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME +#ifndef DLMS_IGNORE_AUTO_ANSWER + case DLMS_OBJECT_TYPE_AUTO_ANSWER: + ret = ser_loadAutoAnswer(serializeSettings, (gxAutoAnswer*)object); + break; +#endif //DLMS_IGNORE_AUTO_ANSWER +#ifndef DLMS_IGNORE_AUTO_CONNECT + case DLMS_OBJECT_TYPE_AUTO_CONNECT: + ret = ser_loadAutoConnect(serializeSettings, (gxAutoConnect*)object); + break; +#endif //DLMS_IGNORE_AUTO_CONNECT +#ifndef DLMS_IGNORE_DEMAND_REGISTER + case DLMS_OBJECT_TYPE_DEMAND_REGISTER: + ret = ser_loadDemandRegister(serializeSettings, (gxDemandRegister*)object); + break; +#endif //DLMS_IGNORE_DEMAND_REGISTER +#ifndef DLMS_IGNORE_MAC_ADDRESS_SETUP + case DLMS_OBJECT_TYPE_MAC_ADDRESS_SETUP: + ret = ser_loadMacAddressSetup(serializeSettings, (gxMacAddressSetup*)object); + break; +#endif //DLMS_IGNORE_MAC_ADDRESS_SETUP +#ifndef DLMS_IGNORE_EXTENDED_REGISTER + case DLMS_OBJECT_TYPE_EXTENDED_REGISTER: + ret = ser_loadExtendedRegister(serializeSettings, (gxExtendedRegister*)object); + break; +#endif //DLMS_IGNORE_EXTENDED_REGISTER +#ifndef DLMS_IGNORE_GPRS_SETUP + case DLMS_OBJECT_TYPE_GPRS_SETUP: +#ifndef DLMS_IGNORE_GPRS_SETUP + ret = ser_loadGPRSSetup(serializeSettings, (gxGPRSSetup*)object); +#endif //DLMS_IGNORE_GPRS_SETUP + break; +#endif //DLMS_IGNORE_GPRS_SETUP +#ifndef DLMS_IGNORE_SECURITY_SETUP + case DLMS_OBJECT_TYPE_SECURITY_SETUP: + ret = ser_loadSecuritySetup(serializeSettings, (gxSecuritySetup*)object); + break; +#endif //DLMS_IGNORE_SECURITY_SETUP +#ifndef DLMS_IGNORE_IEC_HDLC_SETUP + case DLMS_OBJECT_TYPE_IEC_HDLC_SETUP: + ret = ser_loadHdlcSetup(serializeSettings, (gxIecHdlcSetup*)object); + break; +#endif //DLMS_IGNORE_IEC_HDLC_SETUP +#ifndef DLMS_IGNORE_IEC_LOCAL_PORT_SETUP + case DLMS_OBJECT_TYPE_IEC_LOCAL_PORT_SETUP: + ret = ser_loadLocalPortSetup(serializeSettings, (gxLocalPortSetup*)object); + break; +#endif //DLMS_IGNORE_IEC_LOCAL_PORT_SETUP +#ifndef DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP + case DLMS_OBJECT_TYPE_IEC_TWISTED_PAIR_SETUP: + ret = ser_loadIecTwistedPairSetup(serializeSettings, (gxIecTwistedPairSetup*)object); + break; +#endif //DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP +#ifndef DLMS_IGNORE_IP4_SETUP + case DLMS_OBJECT_TYPE_IP4_SETUP: + ret = ser_loadIp4Setup(serializeSettings, settings, (gxIp4Setup*)object); + break; +#endif //DLMS_IGNORE_IP4_SETUP +#ifndef DLMS_IGNORE_IP6_SETUP + case DLMS_OBJECT_TYPE_IP6_SETUP: + ret = ser_loadIp6Setup(serializeSettings, settings, (gxIp6Setup*)object); + break; +#endif //DLMS_IGNORE_IP6_SETUP +#ifndef DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP + case DLMS_OBJECT_TYPE_MBUS_SLAVE_PORT_SETUP: + ret = ser_loadMbusSlavePortSetup(serializeSettings, (gxMbusSlavePortSetup*)object); + break; +#endif //DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP +#ifndef DLMS_IGNORE_IMAGE_TRANSFER + case DLMS_OBJECT_TYPE_IMAGE_TRANSFER: + ret = ser_loadImageTransfer(serializeSettings, (gxImageTransfer*)object); + break; +#endif //DLMS_IGNORE_IMAGE_TRANSFER +#ifndef DLMS_IGNORE_DISCONNECT_CONTROL + case DLMS_OBJECT_TYPE_DISCONNECT_CONTROL: + ret = ser_loadDisconnectControl(serializeSettings, (gxDisconnectControl*)object); + break; +#endif //DLMS_IGNORE_DISCONNECT_CONTROL +#ifndef DLMS_IGNORE_LIMITER + case DLMS_OBJECT_TYPE_LIMITER: + ret = ser_loadLimiter(serializeSettings, settings, (gxLimiter*)object); + break; +#endif //DLMS_IGNORE_LIMITER +#ifndef DLMS_IGNORE_MBUS_DIAGNOSTIC + case DLMS_OBJECT_TYPE_MBUS_DIAGNOSTIC: + ret = ser_loadMBusDiagnostic(serializeSettings, settings, (gxMbusDiagnostic*)object); + break; +#endif //DLMS_IGNORE_MBUS_DIAGNOSTIC +#ifndef DLMS_IGNORE_MBUS_PORT_SETUP + case DLMS_OBJECT_TYPE_MBUS_PORT_SETUP: + ret = ser_loadMBusPortSetup(serializeSettings, settings, (gxMBusPortSetup*)object); + break; +#endif //DLMS_IGNORE_MBUS_PORT_SETUP +#ifndef DLMS_IGNORE_MBUS_CLIENT + case DLMS_OBJECT_TYPE_MBUS_CLIENT: + ret = ser_loadMBusClient(serializeSettings, settings, (gxMBusClient*)object); + break; +#endif //DLMS_IGNORE_MBUS_CLIENT +#ifndef DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS + case DLMS_OBJECT_TYPE_G3_PLC_MAC_LAYER_COUNTERS: + ret = ser_loadG3PlcMacLayerCounters(serializeSettings, settings, (gxG3PlcMacLayerCounters*)object); + break; +#endif //DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS +#ifndef DLMS_IGNORE_G3_PLC_MAC_SETUP + case DLMS_OBJECT_TYPE_G3_PLC_MAC_SETUP: + ret = ser_loadG3PlcMacSetup(serializeSettings, settings, (gxG3PlcMacSetup*)object); + break; +#endif //DLMS_IGNORE_G3_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_G3_PLC_6LO_WPAN + case DLMS_OBJECT_TYPE_G3_PLC_6LO_WPAN: + ret = ser_loadG3Plc6LoWPAN(serializeSettings, settings, (gxG3Plc6LoWPAN*)object); + break; +#endif //DLMS_IGNORE_G3_PLC_6LO_WPAN +#ifndef DLMS_IGNORE_FUNCTION_CONTROL + case DLMS_OBJECT_TYPE_FUNCTION_CONTROL: + ret = ser_loadFunctionControl(serializeSettings, settings, (gxFunctionControl*)object); + break; +#endif //DLMS_IGNORE_FUNCTION_CONTROL +#ifndef DLMS_IGNORE_ARRAY_MANAGER + case DLMS_OBJECT_TYPE_ARRAY_MANAGER: + ret = ser_loadArrayManager(serializeSettings, settings, (gxArrayManager*)object); + break; +#endif //DLMS_IGNORE_ARRAY_MANAGER +#ifndef DLMS_IGNORE_MODEM_CONFIGURATION + case DLMS_OBJECT_TYPE_MODEM_CONFIGURATION: + ret = ser_loadModemConfiguration(serializeSettings, (gxModemConfiguration*)object); + break; +#endif //DLMS_IGNORE_MODEM_CONFIGURATION +#ifndef DLMS_IGNORE_PPP_SETUP + case DLMS_OBJECT_TYPE_PPP_SETUP: + ret = ser_loadPppSetup(serializeSettings, settings, (gxPppSetup*)object); + break; +#endif //DLMS_IGNORE_PPP_SETUP +#ifndef DLMS_IGNORE_PROFILE_GENERIC + case DLMS_OBJECT_TYPE_PROFILE_GENERIC: + ret = ser_loadProfileGeneric(serializeSettings, settings, (gxProfileGeneric*)object); + break; +#endif //DLMS_IGNORE_PROFILE_GENERIC +#ifndef DLMS_IGNORE_REGISTER_ACTIVATION + case DLMS_OBJECT_TYPE_REGISTER_ACTIVATION: + ret = ser_loadRegisterActivation(serializeSettings, settings, (gxRegisterActivation*)object); + break; +#endif //DLMS_IGNORE_REGISTER_ACTIVATION +#ifndef DLMS_IGNORE_REGISTER_MONITOR + case DLMS_OBJECT_TYPE_REGISTER_MONITOR: + ret = ser_loadRegisterMonitor(serializeSettings, settings, (gxRegisterMonitor*)object); + break; +#endif //DLMS_IGNORE_REGISTER_MONITOR +#ifndef DLMS_IGNORE_REGISTER_TABLE + case DLMS_OBJECT_TYPE_REGISTER_TABLE: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_REGISTER_TABLE +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_STARTUP + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_STARTUP: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_ZIG_BEE_SAS_STARTUP +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_JOIN + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_JOIN: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_ZIG_BEE_SAS_JOIN +#ifndef DLMS_IGNORE_ZIG_BEE_SAS_APS_FRAGMENTATION + case DLMS_OBJECT_TYPE_ZIG_BEE_SAS_APS_FRAGMENTATION: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_ZIG_BEE_SAS_APS_FRAGMENTATION +#ifndef DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL + case DLMS_OBJECT_TYPE_ZIG_BEE_NETWORK_CONTROL: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_ZIG_BEE_NETWORK_CONTROL +#ifndef DLMS_IGNORE_SAP_ASSIGNMENT + case DLMS_OBJECT_TYPE_SAP_ASSIGNMENT: + ret = ser_loadSapAssignment(serializeSettings, (gxSapAssignment*)object); + break; +#endif //DLMS_IGNORE_SAP_ASSIGNMENT +#ifndef DLMS_IGNORE_SCHEDULE + case DLMS_OBJECT_TYPE_SCHEDULE: + ret = ser_loadSchedule(serializeSettings, (gxSchedule*)object); + break; +#endif //DLMS_IGNORE_SCHEDULE +#ifndef DLMS_IGNORE_SCRIPT_TABLE + case DLMS_OBJECT_TYPE_SCRIPT_TABLE: + ret = ser_loadScriptTable(serializeSettings, settings, (gxScriptTable*)object); + break; +#endif //DLMS_IGNORE_SCRIPT_TABLE +#ifndef DLMS_IGNORE_SMTP_SETUP + case DLMS_OBJECT_TYPE_SMTP_SETUP: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_SMTP_SETUP +#ifndef DLMS_IGNORE_SPECIAL_DAYS_TABLE + case DLMS_OBJECT_TYPE_SPECIAL_DAYS_TABLE: + ret = ser_loadSpecialDaysTable(serializeSettings, (gxSpecialDaysTable*)object); + break; +#endif //DLMS_IGNORE_SPECIAL_DAYS_TABLE +#ifndef DLMS_IGNORE_STATUS_MAPPING + case DLMS_OBJECT_TYPE_STATUS_MAPPING: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_STATUS_MAPPING +#ifndef DLMS_IGNORE_TCP_UDP_SETUP + case DLMS_OBJECT_TYPE_TCP_UDP_SETUP: + ret = ser_loadTcpUdpSetup(serializeSettings, settings, (gxTcpUdpSetup*)object); + break; +#endif //DLMS_IGNORE_TCP_UDP_SETUP +#ifndef DLMS_IGNORE_UTILITY_TABLES + case DLMS_OBJECT_TYPE_UTILITY_TABLES: + ret = ser_loadUtilityTables(serializeSettings, (gxUtilityTables*)object); + break; +#endif //DLMS_IGNORE_UTILITY_TABLES +#ifndef DLMS_IGNORE_MBUS_MASTER_PORT_SETUP + case DLMS_OBJECT_TYPE_MBUS_MASTER_PORT_SETUP: + ret = ser_loadMBusMasterPortSetup(serializeSettings, (gxMBusMasterPortSetup*)object); + break; +#endif //DLMS_IGNORE_MBUS_MASTER_PORT_SETUP +#ifndef DLMS_IGNORE_PUSH_SETUP + case DLMS_OBJECT_TYPE_PUSH_SETUP: + ret = ser_loadPushSetup(serializeSettings, settings, (gxPushSetup*)object); + break; +#endif //DLMS_IGNORE_PUSH_SETUP +#ifndef DLMS_IGNORE_DATA_PROTECTION + case DLMS_OBJECT_TYPE_DATA_PROTECTION: +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) + assert(0); +#endif + break; +#endif //DLMS_IGNORE_DATA_PROTECTION +#ifndef DLMS_IGNORE_ACCOUNT + case DLMS_OBJECT_TYPE_ACCOUNT: + ret = ser_loadAccount(serializeSettings, (gxAccount*)object); + break; +#endif //DLMS_IGNORE_ACCOUNT +#ifndef DLMS_IGNORE_CREDIT + case DLMS_OBJECT_TYPE_CREDIT: + ret = ser_loadCredit(serializeSettings, (gxCredit*)object); + break; +#endif //DLMS_IGNORE_CREDIT +#ifndef DLMS_IGNORE_CHARGE + case DLMS_OBJECT_TYPE_CHARGE: + ret = ser_loadCharge(serializeSettings, settings, (gxCharge*)object); + break; +#endif //DLMS_IGNORE_CHARGE +#ifndef DLMS_IGNORE_TOKEN_GATEWAY + case DLMS_OBJECT_TYPE_TOKEN_GATEWAY: + ret = ser_loadTokenGateway(serializeSettings, (gxTokenGateway*)object); + break; +#endif //DLMS_IGNORE_TOKEN_GATEWAY +#ifndef DLMS_IGNORE_GSM_DIAGNOSTIC + case DLMS_OBJECT_TYPE_GSM_DIAGNOSTIC: + ret = ser_loadGsmDiagnostic(serializeSettings, (gxGsmDiagnostic*)object); + break; +#endif //DLMS_IGNORE_GSM_DIAGNOSTIC +#ifndef DLMS_IGNORE_COMPACT_DATA + case DLMS_OBJECT_TYPE_COMPACT_DATA: + ret = ser_loadCompactData(serializeSettings, settings, (gxCompactData*)object); + break; +#endif //DLMS_IGNORE_COMPACT_DATA +#ifndef DLMS_IGNORE_LLC_SSCS_SETUP + case DLMS_OBJECT_TYPE_LLC_SSCS_SETUP: + ret = ser_loadLlcSscsSetup(serializeSettings, (gxLlcSscsSetup*)object); + break; +#endif //DLMS_IGNORE_LLC_SSCS_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS: + ret = ser_loadPrimeNbOfdmPlcPhysicalLayerCounters(serializeSettings, (gxPrimeNbOfdmPlcPhysicalLayerCounters*)object); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_SETUP: + ret = ser_loadPrimeNbOfdmPlcMacSetup(serializeSettings, (gxPrimeNbOfdmPlcMacSetup*)object); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS: + ret = ser_loadPrimeNbOfdmPlcMacFunctionalParameters(serializeSettings, (gxPrimeNbOfdmPlcMacFunctionalParameters*)object); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_COUNTERS: + ret = ser_loadPrimeNbOfdmPlcMacCounters(serializeSettings, (gxPrimeNbOfdmPlcMacCounters*)object); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA: + ret = ser_loadPrimeNbOfdmPlcMacNetworkAdministrationData(serializeSettings, (gxPrimeNbOfdmPlcMacNetworkAdministrationData*)object); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION + case DLMS_OBJECT_TYPE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION: + ret = ser_loadPrimeNbOfdmPlcApplicationsIdentification(serializeSettings, (gxPrimeNbOfdmPlcApplicationsIdentification*)object); + break; +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION + case DLMS_OBJECT_TYPE_PARAMETER_MONITOR: + break; +#ifndef DLMS_IGNORE_ARBITRATOR + case DLMS_OBJECT_TYPE_ARBITRATOR: + ret = ser_loadArbitrator(serializeSettings, (gxArbitrator*)object); + break; +#endif //DLMS_IGNORE_ARBITRATOR +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE1_SETUP: + ret = ser_loadIec8802LlcType1Setup(serializeSettings, (gxIec8802LlcType1Setup*)object); + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE2_SETUP: + ser_loadIec8802LlcType2Setup(serializeSettings, (gxIec8802LlcType2Setup*)object); + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP + case DLMS_OBJECT_TYPE_IEC_8802_LLC_TYPE3_SETUP: + ser_loadIec8802LlcType3Setup(serializeSettings, (gxIec8802LlcType3Setup*)object); + break; +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP +#ifndef DLMS_IGNORE_SFSK_ACTIVE_INITIATOR + case DLMS_OBJECT_TYPE_SFSK_ACTIVE_INITIATOR: + ser_loadSFSKActiveInitiator(serializeSettings, (gxSFSKActiveInitiator*)object); + break; +#endif //DLMS_IGNORE_SFSK_ACTIVE_INITIATOR +#ifndef DLMS_IGNORE_SFSK_MAC_COUNTERS + case DLMS_OBJECT_TYPE_SFSK_MAC_COUNTERS: + ser_loadFSKMacCounters(serializeSettings, (gxFSKMacCounters*)object); + break; +#endif //DLMS_IGNORE_SFSK_MAC_COUNTERS +#ifndef DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS + case DLMS_OBJECT_TYPE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS: + ser_loadSFSKMacSynchronizationTimeouts(serializeSettings, (gxSFSKMacSynchronizationTimeouts*)object); + break; +#endif //DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS +#ifndef DLMS_IGNORE_SFSK_PHY_MAC_SETUP + case DLMS_OBJECT_TYPE_SFSK_PHY_MAC_SETUP: + ser_loadSFSKPhyMacSetUp(serializeSettings, (gxSFSKPhyMacSetUp*)object); + break; +#endif //DLMS_IGNORE_SFSK_PHY_MAC_SETUP +#ifndef DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST + case DLMS_OBJECT_TYPE_SFSK_REPORTING_SYSTEM_LIST: + ser_loadSFSKReportingSystemList(serializeSettings, (gxSFSKReportingSystemList*)object); + break; +#endif //DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST +#ifdef DLMS_ITALIAN_STANDARD + case DLMS_OBJECT_TYPE_TARIFF_PLAN: + ret = ser_loadTariffPlan(serializeSettings, (gxTariffPlan*)object); + break; +#endif //DLMS_ITALIAN_STANDARD + default: //Unknown type. + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} + +int ser_getDataSize(gxSerializerSettings * serializeSettings, void* size) +{ + int ret; + //Serializer version number. + unsigned char version; +#if !(!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + ResetPosition(serializeSettings); +#endif //!(!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + if ((ret = ser_loadUInt8(serializeSettings, &version)) == 0) + { + if (version == 0 || version > SERIALIZATION_VERSION) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("ser_loadObject failed. Invalid version,"), version); +#endif //DLMS_DEBUG + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + ret = ser_loadUInt32(serializeSettings, size); + } + return ret; +} + +//Serialize objects to bytebuffer. +int ser_loadObjects( + dlmsSettings * settings, + gxSerializerSettings * serializeSettings, + gxObject * *object, + uint16_t count) +{ + uint16_t pos; + int ret = 0; + uint32_t size; + //Serializer version number. + if ((ret = ser_getDataSize(serializeSettings, &size)) == 0 && size != 0) + { + for (pos = 0; pos != count; ++pos) + { + //If all data is read. + if (ser_isEof(serializeSettings)) + { + break; + } +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("ser_loadObject"), pos); +#endif //DLMS_DEBUG + if ((ret = ser_loadObject(settings, serializeSettings, object[pos])) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("ser_loadObject failed"), pos); +#endif //DLMS_DEBUG + //If all data is read. + if (ser_isEof(serializeSettings)) + { + ret = 0; + } + break; + } + } +#if !(!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + if (ret == 0 && serializeSettings->position - 5 != size) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } +#endif //!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + } + return ret; +} + +//Serialize objects to bytebuffer. +int ser_loadObjects2( + dlmsSettings * settings, + gxSerializerSettings * serializeSettings, + objectArray * objects) +{ + gxObject* obj; + uint32_t size; + uint16_t pos; + int ret = 0; + //Serializer version number. + if ((ret = ser_getDataSize(serializeSettings, &size)) == 0) + { + for (pos = 0; pos != objects->size; ++pos) + { + //If all data is read. + if (ser_isEof(serializeSettings)) + { + break; + } +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("ser_loadObject"), pos); +#endif //DLMS_DEBUG + if ((ret = oa_getByIndex(objects, pos, &obj)) != DLMS_ERROR_CODE_OK || + (ret = ser_loadObject(settings, serializeSettings, obj)) != 0) + { +#ifdef DLMS_DEBUG + svr_notifyTrace(GET_STR_FROM_EEPROM("ser_loadObject failed"), pos); +#endif //DLMS_DEBUG + break; + } + } +#if !(!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + if (serializeSettings->position - 5 != size) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } +#endif //!(!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) +} + return ret; +} +#endif //DLMS_IGNORE_SERIALIZER diff --git a/components/xt211/unused/gxserializer.h b/components/xt211/unused/gxserializer.h new file mode 100644 index 0000000..4d0f109 --- /dev/null +++ b/components/xt211/unused/gxserializer.h @@ -0,0 +1,179 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef GXSERIALIZER_H +#define GXSERIALIZER_H + +#include "gxignore.h" +#ifndef DLMS_IGNORE_SERIALIZER + +#include "gxobjects.h" +#include "dlmssettings.h" + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if !(!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__))) + /*Return EEPROM or Flash size.*/ + extern uint32_t SERIALIZER_SIZE(); + //Read bytes from. + extern int SERIALIZER_LOAD(uint32_t index, uint32_t count, void* value); + //Write byte + extern int SERIALIZER_SAVE(uint32_t index, uint32_t count, const void* value); +#endif //#if !defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + + //This attribute is not serialized. +#define IGNORE_ATTRIBUTE(OBJECT, INDEX) {OBJECT, INDEX, 0} + +//This attribute is not serialized by object type. +#define IGNORE_ATTRIBUTE_BY_TYPE(TYPE, INDEX) {0, INDEX, TYPE} + +#define ___COSEM_ATTRIBUTES(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16,...) _16 +//Visual Studio reguires this. +#define ___EXPAND(x) x +#define ___COUNT_ATTRIBUTES(...) ___EXPAND(___COSEM_ATTRIBUTES(__VA_ARGS__,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)) + +#define GET_ALL_ATTRIBUTES() -1 +#define GET_ATTRIBUTE1(A) 1 << (A - 1) +#define GET_ATTRIBUTE2(A, B) GET_ATTRIBUTE1(A) | GET_ATTRIBUTE1(B) +#define GET_ATTRIBUTE3(A, B, C) GET_ATTRIBUTE2(A, B) | GET_ATTRIBUTE1(C) +#define GET_ATTRIBUTE4(A, B, C, D) GET_ATTRIBUTE3(A, B, C) | GET_ATTRIBUTE1(D) +#define GET_ATTRIBUTE5(A, B, C, D, E) GET_ATTRIBUTE4(A, B, C, D) | GET_ATTRIBUTE1(E) +#define GET_ATTRIBUTE6(A, B, C, D, E, F) GET_ATTRIBUTE5(A, B, C, D, E) | GET_ATTRIBUTE1(F) +#define GET_ATTRIBUTE7(A, B, C, D, E, F, G) GET_ATTRIBUTE6(A, B, C, D, E, F) | GET_ATTRIBUTE1(G) +#define GET_ATTRIBUTE8(A, B, C, D, E, F, G, H) GET_ATTRIBUTE7(A, B, C, D, E, F, G) | GET_ATTRIBUTE1(H) +#define GET_ATTRIBUTE9(A, B, C, D, E, F, G, H, I) GET_ATTRIBUTE8(A, B, C, D, E, F, G, H) | GET_ATTRIBUTE1(I) +#define GET_ATTRIBUTE10(A, B, C, D, E, F, G, H, I, J)GET_ATTRIBUTE9(A, B, C, D, E, F, G, H, I) | GET_ATTRIBUTE1(J) +#define GET_ATTRIBUTE11(A, B, C, D, E, F, G, H, I, J, K) GET_ATTRIBUTE10(A, B, C, D, E, F, G, H, I, J) | GET_ATTRIBUTE1(K) +#define GET_ATTRIBUTE12(A, B, C, D, E, F, G, H, I, J, K, L) GET_ATTRIBUTE11(A, B, C, D, E, F, G, H, I, J, K) | GET_ATTRIBUTE1(L) +#define GET_ATTRIBUTE13(A, B, C, D, E, F, G, H, I, J, K, L, M) GET_ATTRIBUTE12(A, B, C, D, E, F, G, H, I, J, K, L) | GET_ATTRIBUTE1(M) +#define GET_ATTRIBUTE14(A, B, C, D, E, F, G, H, I, J, K, L, M, N) GET_ATTRIBUTE13(A, B, C, D, E, F, G, H, I, J, K, L, M) | GET_ATTRIBUTE1(N) +#define GET_ATTRIBUTE15(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) GET_ATTRIBUTE14(A, B, C, D, E, F, G, H, I, J, K, L, M, N) | GET_ATTRIBUTE1(O) +#define GET_ATTRIBUTE16(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) GET_ATTRIBUTE15(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) | GET_ATTRIBUTE1(P) +#define CONC(A, B) CONC_(A, B) +#define CONC_(A, B) A##B +#define GET_ATTRIBUTE(...) CONC(GET_ATTRIBUTE, ___COUNT_ATTRIBUTES(__VA_ARGS__))(__VA_ARGS__) +#define GET_ATTRIBUTE_EXCEPT(...) (uint16_t)~(GET_ATTRIBUTE(__VA_ARGS__)) +#define GET_ATTRIBUTE_ALL() 0xFFFF + + typedef struct + { + /*Target to ignore*/ + gxObject* target; + /*Bit enumerated attribute list from attributes that are not serialized.*/ + uint16_t attributes; + /*Object type to ignore*/ + uint16_t objectType; + } gxSerializerIgnore; + + typedef struct + { + //List of attributes that are not serialized. + gxSerializerIgnore* ignoredAttributes; + //Count of ignored objects. + uint16_t count; + + +#if !defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) + FILE* stream; +#else + //Serialization position is used to save serialization index. + uint32_t position; + //Index of where changed data starts. This is used for debugging. + uint32_t updateStart; + //Index of where changed data ends. This is used for debugging. + uint32_t updateEnd; +#endif //!defined(GX_DLMS_SERIALIZER) && (defined(_WIN32) || defined(_WIN64) || defined(__linux__)) +#ifdef DLMS_IGNORE_MALLOC + //Only this object is saved if it is set. + gxObject* savedObject; + //Only attributes saved when savedObject is used. + uint32_t savedAttributes; + //This is for internal use. + //Whether to save the object. This is needed if only changed object is used. + gxObject* currentObject; + //This is for internal use. + uint16_t currentIndex; +#endif //DLMS_IGNORE_MALLOC + } gxSerializerSettings; + + void ser_init(gxSerializerSettings* settings); + + //Serialize object to bytebuffer. + int ser_saveObject( + gxSerializerSettings* serializeSettings, + gxObject* object); + + //Serialize objects to flash. + int ser_saveObjects( + gxSerializerSettings* serializeSettings, + gxObject** objects, + uint16_t count); + + //Serialize objects to flash. + int ser_saveObjects2( + gxSerializerSettings* serializeSettings, + objectArray* objects); + + //Serialize object from flash. + int ser_loadObject( + dlmsSettings* settings, + gxSerializerSettings* serializeSettings, + gxObject* object); + + //Serialize objects from the flash. + int ser_loadObjects( + dlmsSettings* settings, + gxSerializerSettings* serializeSettings, + gxObject** object, + uint16_t count); + + //Serialize objects from the flash. + int ser_loadObjects2( + dlmsSettings* settings, + gxSerializerSettings* serializeSettings, + objectArray* object); + + //Get data size in bytes. + int ser_getDataSize( + gxSerializerSettings* serializeSettings, + void* size); + +#ifdef __cplusplus +} +#endif +#endif //DLMS_IGNORE_SERIALIZER +#endif //GXSERIALIZER_H diff --git a/components/xt211/unused/gxsetignoremalloc.c b/components/xt211/unused/gxsetignoremalloc.c new file mode 100644 index 0000000..59a2251 --- /dev/null +++ b/components/xt211/unused/gxsetignoremalloc.c @@ -0,0 +1,5837 @@ +// +// -------------------------------------------------------------------------- +// 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(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) +#include +#endif + +#include "gxmem.h" +#if _MSC_VER > 1400 +#include +#endif +#include +#include + +#include "gxset.h" +#include "dlms.h" +#include "gxkey.h" +#include "cosem.h" +#include "gxget.h" +#include "server.h" + +// Get item from the buffer if DLMS_IGNORE_MALLOC is defined. +// Otherwice create the object dynamically. +int cosem_getArrayItem(gxArray* arr, uint16_t index, void** value, uint16_t itemSize) +{ +#ifdef DLMS_IGNORE_MALLOC + return arr_getByIndex2(arr, index, value, itemSize); +#else + unsigned char* it = gxcalloc(1, itemSize); + *value = it; + return arr_push(arr, it); +#endif //DLMS_COSEM_EXACT_DATA_TYPES +} + +int cosem_verifyArray(gxByteBuffer* bb, gxArray* arr, uint16_t* count) +{ +#ifdef DLMS_IGNORE_MALLOC + * count = arr_getCapacity(arr); + int ret = cosem_checkArray(bb, count); + if (ret == 0) + { + arr->size = *count; + } + return ret; +#else + * count = 0xFFFF; + int ret = cosem_checkArray(bb, count); + if (ret == 0) + { + arr_capacity(arr, *count); + } + return ret; +#endif //DLMS_COSEM_EXACT_DATA_TYPES +} + +int cosem_getVariantArrayItem(variantArray* arr, uint16_t index, dlmsVARIANT** value) +{ +#ifdef DLMS_IGNORE_MALLOC + return va_getByIndex(arr, index, value); +#else + dlmsVARIANT* it = gxmalloc(sizeof(dlmsVARIANT)); + var_init(it); + *value = it; + return va_push(arr, it); +#endif //DLMS_COSEM_EXACT_DATA_TYPES +} + +int cosem_verifyVariantArray(gxByteBuffer* bb, variantArray* arr, uint16_t* count) +{ +#ifdef DLMS_IGNORE_MALLOC + * count = va_getCapacity(arr); + int ret = cosem_checkArray(bb, count); + if (ret == 0) + { + arr->size = *count; + } + return ret; +#else + * count = 0xFFFF; + int ret = cosem_checkArray(bb, count); + if (ret == 0) + { + va_capacity(arr, *count); + } + return ret; +#endif //DLMS_COSEM_EXACT_DATA_TYPES +} + +int cosem_verifyObjectArray(gxByteBuffer* bb, objectArray* arr, uint16_t* count) +{ +#ifdef DLMS_IGNORE_MALLOC + * count = oa_getCapacity(arr); + int ret = cosem_checkArray(bb, count); + if (ret == 0) + { + arr->size = *count; + } + return ret; +#else + * count = 0xFFFF; + int ret = cosem_checkArray(bb, count); + if (ret == 0) + { + oa_capacity(arr, *count); + } + return ret; +#endif //DLMS_COSEM_EXACT_DATA_TYPES +} + +int cosem_updateVariant(dlmsVARIANT* target, gxValueEventArg* e) +{ + int ret; + //If data is coming in action it's plain value. + if (e->action) + { + if (e->value.vt == (DLMS_DATA_TYPE_OCTET_STRING | DLMS_DATA_TYPE_BYREF) || + e->value.vt == (DLMS_DATA_TYPE_STRING | DLMS_DATA_TYPE_BYREF) || + e->value.vt == (DLMS_DATA_TYPE_STRING_UTF8 | DLMS_DATA_TYPE_BYREF)) + { + if ((target->vt & e->value.vt) == 0) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + else + { + gxByteBuffer tmp; + bb_attach(&tmp, target->pVal, target->size, target->capacity); + bb_clear(&tmp); + if ((ret = bb_set(&tmp, e->value.pVal, e->value.size)) == 0) + { + target->size = e->value.size; + } + } + } + else + { + *target = e->value; + ret = 0; + } + } + else + { + ret = cosem_getVariant(e->value.byteArr, target); + } + return ret; +} + +#ifndef DLMS_IGNORE_DATA +int cosem_setData(gxValueEventArg* e) +{ + int ret; + if (e->index == 2) + { + ret = cosem_updateVariant(&((gxData*)e->target)->value, e); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_DATA + +#ifndef DLMS_IGNORE_REGISTER +int cosem_setRegister(gxRegister* object, unsigned char index, dlmsVARIANT* value) +{ + int ret; + if (index == 2) + { + ret = cosem_getVariant(value->byteArr, &object->value); + } + else if (index == 3) + { + if ((ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getInt8(value->byteArr, &object->scaler)) != 0 || + (ret = cosem_getEnum(value->byteArr, &object->unit)) != 0) + { + //Error code is returned at the end of the function. + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_REGISTER + +#ifndef DLMS_IGNORE_REGISTER_TABLE +int cosem_setRegistertable(gxRegisterTable* object, unsigned char index, dlmsVARIANT* value) +{ + int pos, ret; + dlmsVARIANT* tmp; + if (index == 2) + { + uint16_t count; + if ((ret = cosem_verifyVariantArray(value->byteArr, &object->tableCellValues, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getVariantArrayItem(&object->tableCellValues, pos, &tmp)) != 0 || + (ret = cosem_getVariant(value->byteArr, tmp)) != 0) + { + break; + } + } + } + } + else if (index == 4) + { + if ((ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getInt8(value->byteArr, &object->scaler)) != 0 || + (ret = cosem_getEnum(value->byteArr, &object->unit)) != 0) + { + //Error code is returned at the end of the function. + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_REGISTER_TABLE + +#ifndef DLMS_IGNORE_CLOCK +int cosem_setClock(dlmsSettings* settings, gxClock* object, unsigned char index, dlmsVARIANT* value) +{ + unsigned char ch; + int ret; + switch (index) + { + case 2: + ret = cosem_getDateTimeFromOctetString(value->byteArr, &object->time); +#ifndef DLMS_IGNORE_SERVER + if (ret == 0) + { + //If user set's new time transform it to the same time zone as the server is. + if (settings->server) + { + //Convert time to UCT if time zone is given. + time_toUTC(&object->time); + clock_updateDST(object, &object->time); + } + } +#endif// DLMS_IGNORE_SERVER + break; + case 3: + ret = cosem_getInt16(value->byteArr, &object->timeZone); + break; + case 4: + if ((ret = cosem_getUInt8(value->byteArr, &ch)) == 0) + { + object->status = (DLMS_CLOCK_STATUS)ch; + } + break; + case 5: + ret = cosem_getDateTimeFromOctetString(value->byteArr, &object->begin); +#ifndef DLMS_IGNORE_SERVER + if (ret == 0) + { + //If user set's new time transform it to the same time zone as the server is. + if (settings->server) + { + //Convert time to UCT if time zone is given. + time_toUTC(&object->time); + clock_updateDST(object, &object->time); + } + } +#endif// DLMS_IGNORE_SERVER + break; + case 6: + ret = cosem_getDateTimeFromOctetString(value->byteArr, &object->end); +#ifndef DLMS_IGNORE_SERVER + if (ret == 0) + { + //If user set's new time transform it to the same time zone as the server is. + if (settings->server) + { + //Convert time to UCT if time zone is given. + time_toUTC(&object->time); + clock_updateDST(object, &object->time); + } + } +#endif// DLMS_IGNORE_SERVER + break; + case 7: + ret = cosem_getInt8(value->byteArr, &object->deviation); +#ifndef DLMS_IGNORE_SERVER + if (settings->server) + { + clock_updateDST(object, &object->time); + } +#endif// DLMS_IGNORE_SERVER + break; + case 8: + ret = cosem_getBoolean(value->byteArr, &object->enabled); +#ifndef DLMS_IGNORE_SERVER + if (settings->server) + { + clock_updateDST(object, &object->time); + } +#endif //DLMS_IGNORE_SERVER + break; + case 9: + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->clockBase = (DLMS_CLOCK_BASE)ch; + } + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} + +#endif //DLMS_IGNORE_CLOCK + +#ifndef DLMS_IGNORE_ACTIVITY_CALENDAR + +// The season profiles list is sorted according to season_start (in increasing order). +int cosem_orderSeasonProfile(gxArray* profile) +{ + int ret = 0; + uint16_t pos, pos2, minPos; + gxSeasonProfile* sp, * sp2; + uint32_t tmp, next1, next2; + for (pos = 0; pos < profile->size - 1; ++pos) + { + if ((ret = cosem_getArrayItem(profile, pos, (void**)&sp, sizeof(gxSeasonProfile))) != 0) + { + break; + } + next1 = time_toUnixTime2(&sp->start); + next2 = 0xFFFFFFFF; + for (pos2 = pos + 1; pos2 < profile->size; ++pos2) + { + if ((ret = cosem_getArrayItem(profile, pos2, (void**)&sp2, sizeof(gxSeasonProfile))) != 0) + { + break; + } + tmp = time_toUnixTime2(&sp2->start); + if (tmp < next2) + { + next2 = tmp; + minPos = pos2; + } + } + if (ret != 0) + { + break; + } + if (next2 < next1) + { + gxSeasonProfile tmp; + if ((ret = arr_swap(profile, pos, minPos, sizeof(gxSeasonProfile), (void*)&tmp)) != 0) + { + break; + } + } + } + return ret; +} + +int updateSeasonProfile(gxArray* profile, dlmsVARIANT* data) +{ + int ret, pos; + gxSeasonProfile* sp = NULL; + obj_clearSeasonProfile(profile); + uint16_t count; + if ((ret = cosem_verifyArray(data->byteArr, profile, &count)) == 0) { + for (pos = 0; pos != count; ++pos) + { +#ifdef DLMS_COSEM_EXACT_DATA_TYPES + if ((ret = cosem_getArrayItem(profile, pos, (void**)&sp, sizeof(gxSeasonProfile))) != 0 || + (ret = cosem_checkStructure(data->byteArr, 3)) != 0 || + (ret = cosem_getOctetString(data->byteArr, &sp->name)) != 0 || + (ret = cosem_getDateTimeFromOctetString(data->byteArr, &sp->start)) != 0 || + (ret = cosem_getOctetString(data->byteArr, &sp->weekName)) != 0) + { + break; + } +#else + if ((ret = cosem_getArrayItem(profile, pos, (void**)&sp, sizeof(gxSeasonProfile))) != 0 || + (ret = cosem_checkStructure(data->byteArr, 3)) != 0 || + (ret = cosem_getOctetString2(data->byteArr, sp->name.value, sizeof(sp->name.value), &sp->name.size)) != 0 || + (ret = cosem_getDateTimeFromOctetString(data->byteArr, &sp->start)) != 0 || + (ret = cosem_getOctetString2(data->byteArr, sp->weekName.value, sizeof(sp->weekName.value), &sp->weekName.size)) != 0) + { + break; + } +#endif //DLMS_COSEM_EXACT_DATA_TYPES + } + } + if (ret == 0) + { + ret = cosem_orderSeasonProfile(profile); + } + return ret; +} + +int updateWeekProfileTable(gxArray* profile, dlmsVARIANT* data) +{ + int ret, pos; + gxWeekProfile* wp = NULL; + obj_clearWeekProfileTable(profile); + uint16_t count; + if ((ret = cosem_verifyArray(data->byteArr, profile, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(profile, pos, (void**)&wp, sizeof(gxWeekProfile))) != 0 || + (ret = cosem_checkStructure(data->byteArr, 8)) != 0 || +#ifdef DLMS_COSEM_EXACT_DATA_TYPES + (ret = cosem_getOctetString(data->byteArr, &wp->name)) != 0 || +#else + (ret = cosem_getOctetString2(data->byteArr, wp->name.value, sizeof(wp->name.value), &wp->name.size)) != 0 || +#endif //DLMS_COSEM_EXACT_DATA_TYPES + (ret = cosem_getUInt8(data->byteArr, &wp->monday)) != 0 || + (ret = cosem_getUInt8(data->byteArr, &wp->tuesday)) != 0 || + (ret = cosem_getUInt8(data->byteArr, &wp->wednesday)) != 0 || + (ret = cosem_getUInt8(data->byteArr, &wp->thursday)) != 0 || + (ret = cosem_getUInt8(data->byteArr, &wp->friday)) != 0 || + (ret = cosem_getUInt8(data->byteArr, &wp->saturday)) != 0 || + (ret = cosem_getUInt8(data->byteArr, &wp->sunday)) != 0) + { + break; + } + } + } + return ret; +} + +int updateDayProfileTable(dlmsSettings* settings, gxArray* profile, dlmsVARIANT* data) +{ + int ret, pos, pos2; + gxDayProfile* dp = NULL; + gxDayProfileAction* ac = NULL; + obj_clearDayProfileTable(profile); + uint16_t count; + uint16_t count2; + if ((ret = cosem_verifyArray(data->byteArr, profile, &count)) == 0) { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(profile, pos, (void**)&dp, sizeof(gxDayProfile))) != 0) + { + break; + } + count2 = arr_getCapacity(&dp->daySchedules); + if ((ret = cosem_checkStructure(data->byteArr, 2)) != 0 || + (ret = cosem_getUInt8(data->byteArr, &dp->dayId)) != 0 || + (ret = cosem_verifyArray(data->byteArr, &dp->daySchedules, &count2)) != 0) + { + break; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + for (pos2 = 0; pos2 != count2; ++pos2) + { + if ((ret = cosem_getArrayItem(&dp->daySchedules, pos2, (void**)&ac, sizeof(gxDayProfileAction))) != 0 || + (ret = cosem_checkStructure(data->byteArr, 3)) != 0 || + (ret = cosem_getTimeFromOctetString(data->byteArr, &ac->startTime)) != 0 || +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getOctetString2(data->byteArr, ln, 6, NULL)) != 0 || +#else + (ret = cosem_getOctetString2(data->byteArr, ac->scriptLogicalName, 6, NULL)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getUInt16(data->byteArr, &ac->scriptSelector)) != 0) + { + break; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_SCRIPT_TABLE, ln, &ac->script)) != 0) + { + break; + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + } + } + return ret; +} + +int cosem_setActivityCalendar(dlmsSettings* settings, gxActivityCalendar* object, unsigned char index, dlmsVARIANT* value) +{ + int ret; + if (index == 2) + { + ret = cosem_getOctetString(value->byteArr, &object->calendarNameActive); + } + else if (index == 3) + { + ret = updateSeasonProfile(&object->seasonProfileActive, value); + } + else if (index == 4) + { + ret = updateWeekProfileTable(&object->weekProfileTableActive, value); + } + else if (index == 5) + { + ret = updateDayProfileTable(settings, &object->dayProfileTableActive, value); + } + else if (index == 6) + { + ret = cosem_getOctetString(value->byteArr, &object->calendarNamePassive); + } + else if (index == 7) + { + ret = updateSeasonProfile(&object->seasonProfilePassive, value); + } + else if (index == 8) + { + ret = updateWeekProfileTable(&object->weekProfileTablePassive, value); + } + else if (index == 9) + { + ret = updateDayProfileTable(settings, &object->dayProfileTablePassive, value); + } + else if (index == 10) + { + ret = cosem_getDateTimeFromOctetString(value->byteArr, &object->time); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif // DLMS_IGNORE_ACTIVITY_CALENDAR + +#ifndef DLMS_IGNORE_ACTION_SCHEDULE +int cosem_setActionSchedule( + dlmsSettings* settings, + gxActionSchedule* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret, pos; + gxtime* tm; + unsigned char ch; + if (index == 2) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + if ((ret = cosem_checkStructure(value->byteArr, 2)) != 0 || +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getOctetString2(value->byteArr, ln, 6, NULL)) != 0 || +#else + (ret = cosem_getOctetString2(value->byteArr, object->executedScriptLogicalName, 6, NULL)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getUInt16(value->byteArr, &object->executedScriptSelector)) != 0) + { + //Error code is returned at the end of the function. + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if (ret == 0) + { + if ((ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_SCRIPT_TABLE, ln, (gxObject**)&object->executedScript)) != 0) + { + //Error code is returned at the end of the function. + } + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + else if (index == 3) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->type = (DLMS_SINGLE_ACTION_SCHEDULE_TYPE)ch; + } + } + else if (index == 4) + { + arr_clear(&object->executionTime); + gxtime t; + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->executionTime, &count)) == 0) { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->executionTime, pos, (void**)&tm, sizeof(gxtime))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getTimeFromOctetString(value->byteArr, &t)) != 0 || + (ret = cosem_getDateFromOctetString(value->byteArr, tm)) != 0) + { + break; + } +#ifdef DLMS_USE_EPOCH_TIME + time_clearTime(tm); + time_clearDate(&t); + time_addHours(tm, time_getHours(&t)); + time_addMinutes(tm, time_getMinutes(&t)); + time_addSeconds(tm, time_getSeconds(&t)); + tm->skip |= t.skip; +#else + time_clearTime(tm); + time_clearDate(&t); + tm->value.tm_hour = t.value.tm_hour; + tm->value.tm_min = t.value.tm_min; + tm->value.tm_sec = t.value.tm_sec; + tm->skip |= t.skip; +#endif // DLMS_USE_EPOCH_TIME + tm->deviation = (short)0x8000; + tm->skip |= DATETIME_SKIPS_DEVITATION; + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_ACTION_SCHEDULE + +int cosem_updateAttributeAccessModes(gxObject* object, gxByteBuffer* data) +{ + signed char id; + unsigned char value, selector; + int ret; + uint16_t pos, cnt, pos2, cnt2; + if ((ret = cosem_getStructure(data, &cnt)) != 0 || + //If accessmodes are not returned. Some meters do not return them. + cnt != 2) + { + return ret; + } + //If access modes are not retrieved yet. + if (object->access == NULL || object->access->attributeAccessModes.size == 0) + { +#ifndef DLMS_IGNORE_MALLOC + if (object->access == NULL) + { + object->access = (gxAccess*)gxmalloc(sizeof(gxAccess)); + } + BYTE_BUFFER_INIT(&object->access->attributeAccessModes); + BYTE_BUFFER_INIT(&object->access->methodAccessModes); + cnt = obj_methodCount(object); + bb_capacity(&object->access->methodAccessModes, cnt); + object->access->methodAccessModes.size = object->access->methodAccessModes.capacity; + cnt = obj_attributeCount(object); + bb_capacity(&object->access->attributeAccessModes, cnt); + object->access->attributeAccessModes.size = object->access->attributeAccessModes.capacity; +#else + return DLMS_ERROR_CODE_INVALID_PARAMETER; +#endif //DLMS_IGNORE_MALLOC + } + //Get attribute access list. + if ((ret = cosem_checkArray(data, &cnt)) != 0) + { + return ret; + } + for (pos = 0; pos != cnt; ++pos) + { + if ((ret = cosem_checkStructure(data, 3)) != 0 || + (ret = cosem_getInt8(data, &id)) != 0 || + (ret = cosem_getEnum(data, &value)) != 0) + { + break; + } + if (!(id > (char)object->access->attributeAccessModes.size)) + { + if ((ret = bb_setUInt8ByIndex(&object->access->attributeAccessModes, (unsigned char)(id - 1), value)) != 0) + { + break; + } + } + //Get selector(s) + if ((ret = bb_getUInt8(data, &selector)) != 0) + { + break; + } + if (selector != DLMS_DATA_TYPE_NONE) + { + //Skip selector. + --data->position; + //Selectors are not saved nowhere. + if ((ret = cosem_checkArray(data, &cnt2)) != 0) + { + break; + } + for (pos2 = 0; pos2 != cnt2; ++pos2) + { + if ((ret = cosem_getInt8(data, &id)) != 0) + { + break; + } + } + } + } + //Get method access list. + cnt = (uint16_t)object->access->methodAccessModes.size; + if ((ret = cosem_checkArray(data, &cnt)) != 0) + { + return ret; + } + for (pos = 0; pos != cnt; ++pos) + { + if ((ret = cosem_checkStructure(data, 2)) != 0 || + (ret = cosem_getInt8(data, &id)) != 0) + { + break; + } + if ((ret = cosem_getEnum(data, &value)) != 0) + { + //Version 0 returns method access as boolean. + if ((ret = cosem_getBoolean(data, &value)) != 0) + { + break; + } + } + if (!(id > (char)object->access->methodAccessModes.size)) + { + if ((ret = bb_setUInt8ByIndex(&object->access->methodAccessModes, (unsigned char)(id - 1), value)) != 0) + { + break; + } + } + } + return ret; +} + +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME +int cosem_parseLNObjects(dlmsSettings* settings, gxByteBuffer* data, objectArray* objects) +{ +#ifdef DLMS_IGNORE_MALLOC + return DLMS_ERROR_CODE_INVALID_PARAMETER; +#else + gxObject* object; + int ret; + uint16_t pos, count = objects->capacity; + unsigned char version; + uint16_t class_id; + unsigned char ln[6]; + if ((ret = cosem_checkArray(data, &count)) == 0) + { + oa_capacity(objects, count); + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_checkStructure(data, 4)) != 0 || + (ret = cosem_getUInt16(data, &class_id)) != 0 || + (ret = cosem_getUInt8(data, &version)) != 0 || + (ret = cosem_getOctetString2(data, ln, sizeof(ln), NULL)) != 0) + { + break; + } + object = NULL; + ret = cosem_createObject(class_id, &object); + //If known object. + if (object != NULL && ret == 0) + { + object->version = version; + ret = cosem_updateAttributeAccessModes(object, data); + if (ret != 0) + { + break; + } + cosem_setLogicalName(object, ln); + oa_push(objects, object); + oa_push(&settings->releasedObjects, object); + } + else + { + if (ret != DLMS_ERROR_CODE_UNAVAILABLE_OBJECT) + { + break; + } + ret = 0; + gxfree(object); + } + } + } + return ret; +#endif //DLMS_IGNORE_MALLOC +} + +int cosem_setAssociationLogicalName( + dlmsSettings* settings, + gxAssociationLogicalName* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret, pos = 0; + unsigned char ch; + if (index == 2) + { + oa_empty(&object->objectList); + ret = cosem_parseLNObjects(settings, value->byteArr, &object->objectList); + } + else if (index == 3) + { + if ((ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getInt8(value->byteArr, &object->clientSAP)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &object->serverSAP)) != 0) + { + //Error code is returned at the end of the function. + } + } + else if (index == 4) + { + //Value of the object identifier encoded in BER + if ((ret = bb_getUInt8(value->byteArr, &ch)) == 0) + { + if (ch == 0x60) + { + object->applicationContextName.jointIsoCtt = 0; + object->applicationContextName.country = 0; + object->applicationContextName.countryName = 0; + if ((ret = bb_getUInt8ByIndex(value->byteArr, 3, &object->applicationContextName.identifiedOrganization)) == 0 && + (ret = bb_getUInt8ByIndex(value->byteArr, 4, &object->applicationContextName.dlmsUA)) == 0 && + (ret = bb_getUInt8ByIndex(value->byteArr, 5, &object->applicationContextName.applicationContext)) == 0 && + (ret = bb_getUInt8ByIndex(value->byteArr, 6, &object->applicationContextName.contextId)) == 0) + { + } + } + else + { + //Get Tag. + if (ch != 2 || + //Get Len. + (ret = bb_getUInt8(value->byteArr, &ch)) != 0 || + ch != 7 || + //Get tag + (ret = bb_getUInt8(value->byteArr, &ch)) != 0 || + ch != 0x11 || + (ret = bb_getUInt8(value->byteArr, &object->applicationContextName.jointIsoCtt)) != 0 || + //Get tag + (ret = bb_getUInt8(value->byteArr, &ch)) != 0 || + ch != 0x11 || + (ret = bb_getUInt8(value->byteArr, &object->applicationContextName.country)) != 0 || + //Get tag + (ret = bb_getUInt8(value->byteArr, &ch)) != 0 || + ch != 0x12 || + (ret = bb_getUInt16(value->byteArr, &object->applicationContextName.countryName)) != 0 || + //Get tag + (ret = bb_getUInt8(value->byteArr, &ch)) != 0 || + ch != 0x11 || + (ret = bb_getUInt8(value->byteArr, &object->applicationContextName.identifiedOrganization)) != 0 || + //Get tag + (ret = bb_getUInt8(value->byteArr, &ch)) != 0 || + ch != 0x11 || + (ret = bb_getUInt8(value->byteArr, &object->applicationContextName.dlmsUA)) != 0 || + //Get tag + (ret = bb_getUInt8(value->byteArr, &ch)) != 0 || + ch != 0x11 || + (ret = bb_getUInt8(value->byteArr, &object->applicationContextName.applicationContext)) != 0 || + //Get tag + (ret = bb_getUInt8(value->byteArr, &ch)) != 0 || + ch != 0x11 || + (ret = bb_getUInt8(value->byteArr, &object->applicationContextName.contextId)) != 0) + { + if (ret == 0) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + } + } + } + } + else if (index == 5) + { + uint32_t conformance; + //Get structure count. + if ((ret = cosem_checkStructure(value->byteArr, 6)) != 0 || + (ret = cosem_getIntegerFromBitString(value->byteArr, &conformance)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &object->xDLMSContextInfo.maxReceivePduSize)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &object->xDLMSContextInfo.maxSendPduSize)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &object->xDLMSContextInfo.dlmsVersionNumber)) != 0 || + (ret = cosem_getInt8(value->byteArr, &object->xDLMSContextInfo.qualityOfService)) != 0 || + (ret = cosem_getOctetString(value->byteArr, &object->xDLMSContextInfo.cypheringInfo)) != 0) + { + return ret; + } + object->xDLMSContextInfo.conformance = (DLMS_CONFORMANCE)conformance; + } + else if (index == 6) + { + //Value of the object identifier encoded in BER + if ((ret = bb_getUInt8(value->byteArr, &ch)) == 0) + { + if (ch == 0x60) + { + object->authenticationMechanismName.jointIsoCtt = 0; + object->authenticationMechanismName.country = 0; + object->authenticationMechanismName.countryName = 0; + if ((ret = bb_getUInt8ByIndex(value->byteArr, 3, &object->authenticationMechanismName.identifiedOrganization)) == 0 && + (ret = bb_getUInt8ByIndex(value->byteArr, 4, &object->authenticationMechanismName.dlmsUA)) == 0 && + (ret = bb_getUInt8ByIndex(value->byteArr, 5, &object->authenticationMechanismName.authenticationMechanismName)) == 0 && + (ret = bb_getUInt8ByIndex(value->byteArr, 6, &ch)) == 0) + { + object->authenticationMechanismName.mechanismId = (DLMS_AUTHENTICATION)ch; + } + } + else + { + //Get Tag. + if (ch != 2 || + //Get Len. + (ret = bb_getUInt8(value->byteArr, &ch)) != 0 || + ch != 7 || + //Get tag + (ret = bb_getUInt8(value->byteArr, &ch)) != 0 || + ch != 0x11 || + (ret = bb_getUInt8(value->byteArr, &object->authenticationMechanismName.jointIsoCtt)) != 0 || + //Get tag + (ret = bb_getUInt8(value->byteArr, &ch)) != 0 || + ch != 0x11 || + (ret = bb_getUInt8(value->byteArr, &object->authenticationMechanismName.country)) != 0 || + //Get tag + (ret = bb_getUInt8(value->byteArr, &ch)) != 0 || + ch != 0x12 || + (ret = bb_getUInt16(value->byteArr, &object->authenticationMechanismName.countryName)) != 0 || + //Get tag + (ret = bb_getUInt8(value->byteArr, &ch)) != 0 || + ch != 0x11 || + (ret = bb_getUInt8(value->byteArr, &object->authenticationMechanismName.identifiedOrganization)) != 0 || + //Get tag + (ret = bb_getUInt8(value->byteArr, &ch)) != 0 || + ch != 0x11 || + (ret = bb_getUInt8(value->byteArr, &object->authenticationMechanismName.dlmsUA)) != 0 || + //Get tag + (ret = bb_getUInt8(value->byteArr, &ch)) != 0 || + ch != 0x11 || + (ret = bb_getUInt8(value->byteArr, &object->authenticationMechanismName.authenticationMechanismName)) != 0 || + //Get tag + (ret = bb_getUInt8(value->byteArr, &ch)) != 0 || + ch != 0x11 || + (ret = bb_getUInt8(value->byteArr, &ch)) != 0) + { + if (ret == 0) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + } + else + { + object->authenticationMechanismName.mechanismId = (DLMS_AUTHENTICATION)ch; + } + } + } + } + else if (index == 7) + { + ret = cosem_getOctetString(value->byteArr, &object->secret); + } + else if (index == 8) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->associationStatus = (DLMS_ASSOCIATION_STATUS)ch; + } + } + else if (index == 9) + { +#if !(defined(DLMS_IGNORE_OBJECT_POINTERS) || defined(DLMS_IGNORE_SECURITY_SETUP)) + unsigned char ln[6]; + if ((ret = cosem_getOctetString2(value->byteArr, ln, 6, NULL)) == 0) + { + ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_SECURITY_SETUP, ln, (gxObject**)&object->securitySetup); + } +#else + ret = cosem_getOctetString2(value->byteArr, object->securitySetupReference, 6, NULL); +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + else if (index == 10) + { + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->userList, &count)) == 0) + { +#ifndef DLMS_COSEM_EXACT_DATA_TYPES + gxUser* it; + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->userList, pos, (void**)&it, sizeof(gxUser))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->id)) != 0 || + (ret = cosem_getString2(value->byteArr, it->name, sizeof(it->name))) != 0) + { + break; + } + } +#else + gxKey2* it; + for (pos = 0; pos != count; ++pos) + { + it = (gxKey2*)gxmalloc(sizeof(gxKey2)); + if ((ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->key)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &ch)) != 0) + { + break; + } + if (ch != DLMS_DATA_TYPE_OCTET_STRING) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + else + { + //Get length. + if ((ret = cosem_getUInt8(value->byteArr, &ch)) == 0) + { + it->value = gxmalloc(ch + 1); + if ((ret = cosem_getString2(value->byteArr, it->value, ch)) != 0) + { + gxfree(it->value); + gxfree(it); + break; + } + arr_push(&object->userList, it); + } + } + } +#endif //DLMS_COSEM_EXACT_DATA_TYPES + } + } + else if (index == 11) + { +#ifdef DLMS_COSEM_EXACT_DATA_TYPES + unsigned char ch; + if (object->currentUser.value != NULL) + { + gxfree(object->currentUser.value); + } + if ((ret = cosem_checkStructure(value->byteArr, 2)) == 0 && + (ret = cosem_getUInt8(value->byteArr, &object->currentUser.key)) == 0 && + (ret = bb_getUInt8(value->byteArr, &ch)) == 0) + { + if (ch != DLMS_DATA_TYPE_STRING) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + else + { + //Get length. + if ((ret = bb_getUInt8(value->byteArr, &ch)) == 0) + { + object->currentUser.value = gxmalloc(ch + 1); + if ((ret = bb_get(value->byteArr, object->currentUser.value, ch)) != 0) + { + gxfree(object->currentUser.value); + } + } + } + } +#else + if ((ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &object->currentUser.id)) != 0 || + (ret = cosem_getString2(value->byteArr, object->currentUser.name, sizeof(object->currentUser.name))) != 0) + { + //Error code is returned at the end of the function. + } +#endif //DLMS_COSEM_EXACT_DATA_TYPES + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME +int updateSNAccessRights( + objectArray* objectList, + variantArray* data) +{ + uint16_t sn; + int pos, ret; + dlmsVARIANT* it, * tmp; + gxObject* obj = NULL; + for (pos = 0; pos != data->size; ++pos) + { + ret = va_getByIndex(data, pos, &it); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + ret = va_getByIndex(it->Arr, 0, &tmp); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + sn = (uint16_t)var_toInteger(tmp); + + ret = oa_findBySN(objectList, sn, &obj); + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + if (obj != NULL) + { + if (ret != DLMS_ERROR_CODE_OK) + { + return ret; + } + } + } + return DLMS_ERROR_CODE_OK; +} + +int cosem_parseSNObjects(dlmsSettings* settings, gxByteBuffer* data, objectArray* objects) +{ +#ifdef DLMS_IGNORE_MALLOC + return DLMS_ERROR_CODE_INVALID_PARAMETER; +#else + gxDataInfo info; + short sn; + DLMS_OBJECT_TYPE class_id; + dlmsVARIANT value; + dlmsVARIANT* it1 = NULL, * it2 = NULL, * it3 = NULL, * ln = NULL; + gxObject* object; + int ret; + uint16_t count, pos; + unsigned char size, version; + var_init(&value); + //Get array tag. + if ((ret = bb_getUInt8(data, &size)) != DLMS_ERROR_CODE_OK) + { + return 0; + } + //Check that data is in the array + if (size != 0x01) + { + return DLMS_ERROR_CODE_INVALID_RESPONSE; + } + //get object count + if ((ret = hlp_getObjectCount2(data, &count)) != 0) + { + return ret; + } + oa_capacity(objects, (uint16_t)count); + for (pos = 0; pos != count; ++pos) + { + var_clear(&value); + object = NULL; + di_init(&info); + if ((ret = dlms_getData(data, &info, &value)) != 0) + { + break; + } + if (value.vt != DLMS_DATA_TYPE_STRUCTURE || value.Arr->size != 4) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + if ((ret = va_getByIndex(value.Arr, 0, &it1)) != 0 || + (ret = va_getByIndex(value.Arr, 1, &it2)) != 0 || + (ret = va_getByIndex(value.Arr, 2, &it3)) != 0 || + (ret = va_getByIndex(value.Arr, 3, &ln)) != 0) + { + break; + } + if (it1->vt != DLMS_DATA_TYPE_INT16 || + it2->vt != DLMS_DATA_TYPE_UINT16 || + it3->vt != DLMS_DATA_TYPE_UINT8 || + ln->vt != DLMS_DATA_TYPE_OCTET_STRING) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + sn = (short)var_toInteger(it1); + class_id = (DLMS_OBJECT_TYPE)var_toInteger(it2); + version = (unsigned char)var_toInteger(it3); + ret = cosem_createObject(class_id, &object); + //If known object. + if (ret == 0) + { + object->shortName = sn; + object->version = version; + cosem_setLogicalName(object, ln->byteArr->data); + oa_push(objects, object); + oa_push(&settings->releasedObjects, object); + } + else + { + if (ret != DLMS_ERROR_CODE_UNAVAILABLE_OBJECT) + { + break; + } + ret = 0; + } + } + var_clear(&value); + return ret; +#endif //DLMS_IGNORE_MALLOC +} + +int cosem_setAssociationShortName( + dlmsSettings* settings, + gxAssociationShortName* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret; + if (index == 2) + { + } + else if (index == 3) + { + return updateSNAccessRights(&object->objectList, value->Arr); + } + else if (index == 4) + { +#if !(defined(DLMS_IGNORE_OBJECT_POINTERS) || defined(DLMS_IGNORE_SECURITY_SETUP)) + unsigned char ln[6]; + if ((ret = cosem_getOctetString2(value->byteArr, ln, 6, NULL)) == 0) + { + ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_SECURITY_SETUP, ln, (gxObject**)&object->securitySetup); + } +#else + ret = cosem_getOctetString2(value->byteArr, object->securitySetupReference, 6, NULL); +#endif //!(defined(DLMS_IGNORE_OBJECT_POINTERS) || defined(DLMS_IGNORE_SECURITY_SETUP)) + } + else + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return DLMS_ERROR_CODE_OK; +} +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + +#ifndef DLMS_IGNORE_AUTO_ANSWER +int cosem_setAutoAnswer(gxAutoAnswer* object, unsigned char index, dlmsVARIANT* value) +{ + unsigned char ch; + int ret, pos; + if (index == 2) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->mode = (DLMS_AUTO_ANSWER_MODE)ch; + } + } + else if (index == 3) + { + arr_clearKeyValuePair(&object->listeningWindow); + gxTimePair* it; + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->listeningWindow, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->listeningWindow, pos, (void**)&it, sizeof(gxTimePair))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getDateTimeFromOctetString(value->byteArr, &it->first)) != 0 || + (ret = cosem_getDateTimeFromOctetString(value->byteArr, &it->second)) != 0) + { + break; + } + } + } + } + else if (index == 4) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->status = (DLMS_AUTO_ANSWER_STATUS)ch; + } + } + else if (index == 5) + { + ret = cosem_getUInt8(value->byteArr, &object->numberOfCalls); + } + else if (index == 6) + { + if ((ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &object->numberOfRingsInListeningWindow)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &object->numberOfRingsOutListeningWindow)) != 0) + { + //Error code is returned at the end of the function. + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_AUTO_ANSWER + +#ifndef DLMS_IGNORE_AUTO_CONNECT +int cosem_setAutoConnect(gxAutoConnect* object, unsigned char index, dlmsVARIANT* value) +{ + unsigned char ch; + int ret, pos; + if (index == 2) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->mode = (DLMS_AUTO_CONNECT_MODE)ch; + } + } + else if (index == 3) + { + ret = cosem_getUInt8(value->byteArr, &object->repetitions); + } + else if (index == 4) + { + ret = cosem_getUInt16(value->byteArr, &object->repetitionDelay); + } + else if (index == 5) + { + gxTimePair* k; + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->callingWindow, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->callingWindow, pos, (void**)&k, sizeof(gxTimePair)) != 0) || + (ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getDateTimeFromOctetString(value->byteArr, &k->first)) != 0 || + (ret = cosem_getDateTimeFromOctetString(value->byteArr, &k->second)) != 0) + { + break; + } + } + } + } + else if (index == 6) + { + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->destinations, &count)) == 0) + { +#ifndef DLMS_COSEM_EXACT_DATA_TYPES + gxDestination* d; + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->destinations, pos, (void**)&d, sizeof(gxDestination)) != 0) || + (ret = cosem_getOctetString2(value->byteArr, d->value, sizeof(d->value), &d->size)) != 0) + { + break; + } + } +#else + gxByteBuffer* it; + for (pos = 0; pos != count; ++pos) + { + it = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + BYTE_BUFFER_INIT(it); + if ((ret = cosem_getOctetString(value->byteArr, it)) != 0 || + (ret = arr_push(&object->destinations, it)) != 0) + { + break; + } + } +#endif //DLMS_COSEM_EXACT_DATA_TYPES + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_AUTO_CONNECT + +#ifndef DLMS_IGNORE_DEMAND_REGISTER +int cosem_setDemandRegister(gxDemandRegister* object, unsigned char index, dlmsVARIANT* value) +{ + int ret; + if (index == 2) + { + ret = cosem_getVariant(value->byteArr, &object->currentAverageValue); + } + else if (index == 3) + { + ret = cosem_getVariant(value->byteArr, &object->lastAverageValue); + } + else if (index == 4) + { + if ((ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getInt8(value->byteArr, &object->scaler)) != 0 || + (ret = cosem_getEnum(value->byteArr, &object->unit)) != 0) + { + //Error code is returned at the end of the function. + } + } + else if (index == 5) + { + ret = cosem_getVariant(value->byteArr, &object->status); + } + else if (index == 6) + { + ret = cosem_getDateTimeFromOctetString(value->byteArr, &object->captureTime); + } + else if (index == 7) + { + ret = cosem_getDateTimeFromOctetString(value->byteArr, &object->startTimeCurrent); + } + else if (index == 8) + { + ret = cosem_getUInt32(value->byteArr, &object->period); + } + else if (index == 9) + { + ret = cosem_getUInt16(value->byteArr, &object->numberOfPeriods); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_DEMAND_REGISTER + +#ifndef DLMS_IGNORE_MAC_ADDRESS_SETUP +int cosem_setMacAddressSetup(gxMacAddressSetup* object, unsigned char index, dlmsVARIANT* value) +{ + int ret; + if (index == 2) + { + ret = cosem_getOctetString3(value->byteArr, &object->macAddress, 0); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_MAC_ADDRESS_SETUP + +#ifndef DLMS_IGNORE_EXTENDED_REGISTER +int cosem_setExtendedRegister(gxExtendedRegister* object, unsigned char index, dlmsVARIANT* value) +{ + int ret; + if (index == 2) + { + ret = cosem_getVariant(value->byteArr, &object->value); + } + else if (index == 3) + { + if ((ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getInt8(value->byteArr, &object->scaler)) != 0 || + (ret = cosem_getEnum(value->byteArr, &object->unit)) != 0) + { + //Error code is returned at the end of the function. + } + } + else if (index == 4) + { + ret = cosem_getVariant(value->byteArr, &object->status); + } + else if (index == 5) + { + ret = cosem_getDateTimeFromOctetString(value->byteArr, &object->captureTime); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_EXTENDED_REGISTER + +#ifndef DLMS_IGNORE_GPRS_SETUP +int cosem_setGprsSetup(gxGPRSSetup* object, unsigned char index, dlmsVARIANT* value) +{ + int ret; + if (index == 2) + { + ret = cosem_getOctetString(value->byteArr, &object->apn); + } + else if (index == 3) + { + ret = cosem_getUInt16(value->byteArr, &object->pinCode); + } + else if (index == 4) + { + if ((ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_checkStructure(value->byteArr, 5)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &object->defaultQualityOfService.precedence)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &object->defaultQualityOfService.delay)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &object->defaultQualityOfService.reliability)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &object->defaultQualityOfService.peakThroughput)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &object->defaultQualityOfService.meanThroughput)) != 0 || + (ret = cosem_checkStructure(value->byteArr, 5)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &object->requestedQualityOfService.precedence)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &object->requestedQualityOfService.delay)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &object->requestedQualityOfService.reliability)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &object->requestedQualityOfService.peakThroughput)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &object->requestedQualityOfService.meanThroughput)) != 0) + { + return ret; + } + } + else + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return DLMS_ERROR_CODE_OK; +} +#endif //DLMS_IGNORE_GPRS_SETUP + +#ifndef DLMS_IGNORE_SECURITY_SETUP +int cosem_setSecuritySetup(dlmsSettings* settings, gxSecuritySetup* object, unsigned char index, dlmsVARIANT* value) +{ + unsigned char ch; + int pos, ret; + gxCertificateInfo* it = NULL; + switch (index) + { + case 2: + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->securityPolicy = (DLMS_SECURITY_POLICY)ch; + } + break; + case 3: + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->securitySuite = (DLMS_SECURITY_SUITE)ch; + } + break; + case 4: + ret = cosem_getOctetString(value->byteArr, &object->clientSystemTitle); + break; + case 5: + ret = cosem_getOctetString(value->byteArr, &object->serverSystemTitle); + break; + case 6: + obj_clearCertificateInfo(&object->certificates); + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->certificates, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->certificates, pos, (void**)&it, sizeof(gxCertificateInfo))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 6)) != 0 || + (ret = cosem_getUInt8(value->byteArr, (unsigned char*)&it->entity)) != 0 || + (ret = cosem_getUInt8(value->byteArr, (unsigned char*)&it->type)) != 0 || + (ret = cosem_getString2(value->byteArr, it->serialNumber, sizeof(it->serialNumber))) != 0 || + (ret = cosem_getString2(value->byteArr, it->issuer, sizeof(it->issuer))) != 0 || + (ret = cosem_getString2(value->byteArr, it->subject, sizeof(it->subject))) != 0 || + (ret = cosem_getString2(value->byteArr, it->subject, sizeof(it->subjectAltName))) != 0) + { + break; + } + } + } + break; + default: + ret = DLMS_ERROR_CODE_READ_WRITE_DENIED; + } + return ret; +} +#endif //DLMS_IGNORE_SECURITY_SETUP + +#ifndef DLMS_IGNORE_IEC_HDLC_SETUP +int cosem_setIecHdlcSetup(gxIecHdlcSetup* object, unsigned char index, dlmsVARIANT* value) +{ + unsigned char ch; + int ret; + if (index == 2) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->communicationSpeed = (DLMS_BAUD_RATE)ch; + } + } + else if (index == 3) + { + ret = cosem_getUInt8(value->byteArr, &object->windowSizeTransmit); + } + else if (index == 4) + { + ret = cosem_getUInt8(value->byteArr, &object->windowSizeReceive); + } + else if (index == 5) + { + ret = cosem_getUInt16(value->byteArr, &object->maximumInfoLengthTransmit); + } + else if (index == 6) + { + ret = cosem_getUInt16(value->byteArr, &object->maximumInfoLengthReceive); + } + else if (index == 7) + { + ret = cosem_getUInt16(value->byteArr, &object->interCharachterTimeout); + } + else if (index == 8) + { + ret = cosem_getUInt16(value->byteArr, &object->inactivityTimeout); + } + else if (index == 9) + { + ret = cosem_getUInt16(value->byteArr, &object->deviceAddress); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_IEC_HDLC_SETUP +#ifndef DLMS_IGNORE_IEC_LOCAL_PORT_SETUP +int cosem_setIecLocalPortSetup(gxLocalPortSetup* object, unsigned char index, dlmsVARIANT* value) +{ + int ret; + unsigned char ch; + if (index == 2) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->defaultMode = (DLMS_OPTICAL_PROTOCOL_MODE)ch; + } + } + else if (index == 3) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->defaultBaudrate = (DLMS_BAUD_RATE)ch; + } + } + else if (index == 4) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->proposedBaudrate = (DLMS_BAUD_RATE)ch; + } + } + else if (index == 5) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->responseTime = (DLMS_LOCAL_PORT_RESPONSE_TIME)ch; + } + } + else if (index == 6) + { + ret = cosem_getOctetString(value->byteArr, &object->deviceAddress); + } + else if (index == 7) + { + ret = cosem_getOctetString(value->byteArr, &object->password1); + } + else if (index == 8) + { + ret = cosem_getOctetString(value->byteArr, &object->password2); + } + else if (index == 9) + { + ret = cosem_getOctetString(value->byteArr, &object->password5); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_IEC_LOCAL_PORT_SETUP +#ifndef DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP +int cosem_setIecTwistedPairSetup(gxIecTwistedPairSetup* object, unsigned char index, dlmsVARIANT* value) +{ + int ret; + uint16_t count, pos; + unsigned char ch; + signed char it; + if (index == 2) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->mode = (DLMS_IEC_TWISTED_PAIR_SETUP_MODE)ch; + } + } + else if (index == 3) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->speed = (DLMS_BAUD_RATE)ch; + } + } + else if (index == 4) + { + bb_clear(&object->primaryAddresses); + if ((ret = cosem_checkArray(value->byteArr, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getUInt8(value->byteArr, &ch)) != 0 || + (ret = bb_setUInt8(&object->primaryAddresses, ch)) != 0) + { + break; + } + } + } + } + else if (index == 5) + { + bb_clear(&object->tabis); + if ((ret = cosem_checkArray(value->byteArr, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getInt8(value->byteArr, &it)) != 0 || + (ret = bb_setUInt8(&object->tabis, it)) != 0) + { + break; + } + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP + +#ifndef DLMS_IGNORE_IP4_SETUP +int cosem_setIP4Setup(dlmsSettings* settings, gxIp4Setup* object, unsigned char index, dlmsVARIANT* value) +{ + int ret, pos; + gxip4SetupIpOption* ipItem; + if (index == 2) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; + if ((ret = cosem_getOctetString2(value->byteArr, ln, 6, NULL)) == 0) + { + if ((ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_NONE, ln, &object->dataLinkLayer)) != 0) + { + return ret; + } + } +#else + ret = cosem_getOctetString2(value->byteArr, object->dataLinkLayerReference, 6, NULL); +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + else if (index == 3) + { + ret = cosem_getUInt32(value->byteArr, &object->ipAddress); + } + else if (index == 4) + { + uint32_t* v; + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->multicastIPAddress, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->multicastIPAddress, pos, (void**)&v, sizeof(uint32_t))) != 0 || + (ret = cosem_getUInt32(value->byteArr, v)) != 0) + { + break; + } + } + } + } + else if (index == 5) + { + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->ipOptions, &count)) == 0) + { +#ifdef DLMS_COSEM_EXACT_DATA_TYPES + for (pos = 0; pos != count; ++pos) + { + ipItem = (gxip4SetupIpOption*)gxmalloc(sizeof(gxip4SetupIpOption)); + BYTE_BUFFER_INIT(&ipItem->data); + if ((ret = cosem_checkStructure(value->byteArr, 3)) != 0 || + (ret = cosem_getUInt8(value->byteArr, (unsigned char*)&ipItem->type)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &ipItem->length)) != 0 || + (ret = cosem_getOctetString(value->byteArr, &ipItem->data)) != 0 || + (ret = arr_push(&object->multicastIPAddress, ipItem)) != 0) + { + break; + } + } +#else + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->ipOptions, pos, (void**)&ipItem, sizeof(gxip4SetupIpOption))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 3)) != 0 || + (ret = cosem_getUInt8(value->byteArr, (unsigned char*)&ipItem->type)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &ipItem->length)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, ipItem->data.value, sizeof(ipItem->data.value), &ipItem->data.size)) != 0) + { + break; + } + } +#endif //DLMS_COSEM_EXACT_DATA_TYPES + } + } + else if (index == 6) + { + ret = cosem_getUInt32(value->byteArr, &object->subnetMask); + } + else if (index == 7) + { + ret = cosem_getUInt32(value->byteArr, &object->gatewayIPAddress); + } + else if (index == 8) + { + ret = cosem_getBoolean(value->byteArr, &object->useDHCP); + } + else if (index == 9) + { + ret = cosem_getUInt32(value->byteArr, &object->primaryDNSAddress); + } + else if (index == 10) + { + ret = cosem_getUInt32(value->byteArr, &object->secondaryDNSAddress); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_IP4_SETUP + +#ifndef DLMS_IGNORE_IP6_SETUP +int cosem_setIP6Setup(dlmsSettings* settings, gxIp6Setup* object, unsigned char index, dlmsVARIANT* value) +{ + unsigned char ch; + int ret, pos; + IN6_ADDR* v; + if (index == 2) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; + if ((ret = cosem_getOctetString2(value->byteArr, ln, 6, NULL)) == 0) + { + if ((ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_NONE, ln, &object->dataLinkLayer)) != 0) + { + return ret; + } + } +#else + ret = cosem_getOctetString2(value->byteArr, object->dataLinkLayerReference, 6, NULL); +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + else if (index == 3) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->addressConfigMode = (DLMS_IP6_ADDRESS_CONFIG_MODE)ch; + } + } + else if (index == 4) + { + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->unicastIPAddress, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->unicastIPAddress, pos, (void**)&v, sizeof(IN6_ADDR))) != 0 || + (ret = cosem_getOctetString2(value->byteArr, (unsigned char*)v, sizeof(IN6_ADDR), NULL)) != 0) + { + break; + } + } + } + } + else if (index == 5) + { + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->multicastIPAddress, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->multicastIPAddress, pos, (void**)&v, sizeof(IN6_ADDR))) != 0 || + (ret = cosem_getOctetString2(value->byteArr, (unsigned char*)v, sizeof(IN6_ADDR), NULL)) != 0) + { + break; + } + } + } + } + else if (index == 6) + { + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->gatewayIPAddress, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->gatewayIPAddress, pos, (void**)&v, sizeof(IN6_ADDR))) != 0 || + (ret = cosem_getOctetString2(value->byteArr, (unsigned char*)v, sizeof(IN6_ADDR), NULL)) != 0) + { + break; + } + } + } + } + else if (index == 7) + { + ret = cosem_getOctetString2(value->byteArr, (unsigned char*)&object->primaryDNSAddress, sizeof(IN6_ADDR), NULL); + } + else if (index == 8) + { + ret = cosem_getOctetString2(value->byteArr, (unsigned char*)&object->secondaryDNSAddress, sizeof(IN6_ADDR), NULL); + } + else if (index == 9) + { + ret = cosem_getUInt8(value->byteArr, &object->trafficClass); + } + else if (index == 10) + { + uint16_t count; + gxNeighborDiscoverySetup* it; + if ((ret = cosem_verifyArray(value->byteArr, &object->neighborDiscoverySetup, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->neighborDiscoverySetup, pos, (void**)&it, sizeof(gxNeighborDiscoverySetup))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 3)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->maxRetry)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &it->retryWaitTime)) != 0 || + (ret = cosem_getUInt32(value->byteArr, &it->sendPeriod)) != 0) + { + break; + } + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_IP6_SETUP +#ifndef DLMS_IGNORE_UTILITY_TABLES +int cosem_setUtilityTables(gxUtilityTables* object, unsigned char index, dlmsVARIANT* value) +{ + int ret; + if (index == 2) + { + ret = cosem_getUInt16(value->byteArr, &object->tableId); + } + else if (index == 3) + { + //Skip length. + ret = 0; + } + else if (index == 4) + { + ret = cosem_getOctetString(value->byteArr, &object->buffer); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_UTILITY_TABLES + +#ifndef DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP +int cosem_setMbusSlavePortSetup(gxMbusSlavePortSetup* object, unsigned char index, dlmsVARIANT* value) +{ + int ret; + unsigned char ch; + if (index == 2) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->defaultBaud = (DLMS_BAUD_RATE)ch; + } + } + else if (index == 3) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->availableBaud = (DLMS_BAUD_RATE)ch; + } + } + else if (index == 4) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->addressState = (DLMS_ADDRESS_STATE)ch; + } + } + else if (index == 5) + { + ret = cosem_getUInt8(value->byteArr, &object->busAddress); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP +#ifndef DLMS_IGNORE_DISCONNECT_CONTROL +int cosem_setDisconnectControl(gxDisconnectControl* object, unsigned char index, dlmsVARIANT* value) +{ + unsigned char ch; + int ret; + if (index == 2) + { + ret = cosem_getBoolean(value->byteArr, &object->outputState); + } + else if (index == 3) + { + if (value->vt == DLMS_DATA_TYPE_ENUM) + { + object->controlState = (DLMS_CONTROL_STATE)value->bVal; + ret = 0; + } + else if (value->vt == DLMS_DATA_TYPE_OCTET_STRING) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->controlState = (DLMS_CONTROL_STATE)ch; + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + } + else if (index == 4) + { + if (value->vt == DLMS_DATA_TYPE_ENUM) + { + object->controlMode = (DLMS_CONTROL_MODE)value->bVal; + ret = 0; + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_DISCONNECT_CONTROL +#ifndef DLMS_IGNORE_LIMITER +int cosem_setLimiter(dlmsSettings* settings, gxLimiter* object, unsigned char index, dlmsVARIANT* value) +{ + DLMS_OBJECT_TYPE ot = DLMS_OBJECT_TYPE_NONE; + int ret, pos; + uint16_t* it; + if (index == 2) + { + unsigned char ln[6]; + ot = 0; + if ((ret = cosem_checkStructure(value->byteArr, 3)) == 0 && + (ret = cosem_getUInt16(value->byteArr, (uint16_t*)&ot)) == 0 && + (ret = cosem_getOctetString2(value->byteArr, ln, 6, NULL)) == 0 && + (ret = cosem_getInt8(value->byteArr, &object->selectedAttributeIndex)) == 0) + { + ret = cosem_findObjectByLN(settings, ot, ln, &object->monitoredValue); + } + } + else if (index == 3) + { + ret = cosem_getVariant(value->byteArr, &object->thresholdActive); + } + else if (index == 4) + { + ret = cosem_getVariant(value->byteArr, &object->thresholdNormal); + } + else if (index == 5) + { + ret = cosem_getVariant(value->byteArr, &object->thresholdEmergency); + } + else if (index == 6) + { + ret = cosem_getUInt32(value->byteArr, &object->minOverThresholdDuration); + } + else if (index == 7) + { + ret = cosem_getUInt32(value->byteArr, &object->minUnderThresholdDuration); + } + else if (index == 8) + { + if ((ret = cosem_checkStructure(value->byteArr, 3)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &object->emergencyProfile.id)) != 0 || + (ret = cosem_getDateTimeFromOctetString(value->byteArr, &object->emergencyProfile.activationTime)) != 0 || + (ret = cosem_getUInt32(value->byteArr, &object->emergencyProfile.duration)) != 0) + { + //Error code is returned at the end of the function. + } + } + else if (index == 9) + { + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->emergencyProfileGroupIDs, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->emergencyProfileGroupIDs, pos, (void**)&it, sizeof(uint16_t))) != 0 || + (ret = bb_getUInt16(value->byteArr, it)) != 0) + { + break; + } + } + } + } + else if (index == 10) + { + ret = cosem_getBoolean(value->byteArr, &object->emergencyProfileActive); + } + else if (index == 11) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char lnOver[6]; + unsigned char lnUnder[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + if ((ret = cosem_checkStructure(value->byteArr, 2)) == 0 && + (ret = cosem_checkStructure(value->byteArr, 2)) == 0 && +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getOctetString2(value->byteArr, lnOver, 6, NULL)) == 0 && +#else + (ret = cosem_getOctetString2(value->byteArr, object->actionOverThreshold.logicalName, 6, NULL)) == 0 && +#endif //DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getUInt16(value->byteArr, &object->actionOverThreshold.scriptSelector)) == 0 && + (ret = cosem_checkStructure(value->byteArr, 2)) == 0 && +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getOctetString2(value->byteArr, lnUnder, 6, NULL)) == 0 && +#else + (ret = cosem_getOctetString2(value->byteArr, object->actionUnderThreshold.logicalName, 6, NULL)) == 0 && +#endif //DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getUInt16(value->byteArr, &object->actionUnderThreshold.scriptSelector)) == 0) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_SCRIPT_TABLE, lnOver, (gxObject**)&object->actionOverThreshold.script)) == 0 && + (ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_SCRIPT_TABLE, lnUnder, (gxObject**)&object->actionUnderThreshold.script)) == 0) + { + + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + //Error code is returned at the end of the function. + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_LIMITER +#ifndef DLMS_IGNORE_MBUS_CLIENT +int cosem_setmMbusClient(dlmsSettings* settings, gxMBusClient* object, unsigned char index, dlmsVARIANT* value) +{ + unsigned char ch; + int ret, pos; + if (index == 2) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; + if ((ret = cosem_getOctetString2(value->byteArr, ln, 6, NULL)) == 0) + { + if ((ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_MBUS_MASTER_PORT_SETUP, ln, &object->mBusPort)) != 0) + { + return ret; + } + } +#else + ret = cosem_getOctetString2(value->byteArr, object->mBusPortReference, 6, NULL); +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + else if (index == 3) + { +#if defined(DLMS_COSEM_EXACT_DATA_TYPES) + arr_clearKeyValuePair(&object->captureDefinition); + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->captureDefinition, &count)) == 0) + { + gxByteBuffer* start, * end; + for (pos = 0; pos != count; ++pos) + { + start = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + end = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + BYTE_BUFFER_INIT(start); + BYTE_BUFFER_INIT(end); + if ((ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getOctetString(value->byteArr, start)) != 0 || + (ret = cosem_getOctetString(value->byteArr, end)) != 0 || + (ret = arr_push(&object->captureDefinition, key_init(start, end))) != 0) + { + break; + } + } + } +#else + gxCaptureDefinition* it; + uint16_t count = arr_getCapacity(&object->captureDefinition); + if ((ret = cosem_verifyArray(value->byteArr, &object->captureDefinition, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->captureDefinition, pos, (void**)&it, sizeof(gxCaptureDefinition))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, it->data.value, sizeof(it->data.value), &it->data.size)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, it->value.value, sizeof(it->value.value), &it->value.size)) != 0) + { + break; + } + } + } +#endif //defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + } + else if (index == 4) + { + ret = cosem_getUInt32(value->byteArr, &object->capturePeriod); + } + else if (index == 5) + { + ret = cosem_getUInt8(value->byteArr, &object->primaryAddress); + } + else if (index == 6) + { + ret = cosem_getUInt32(value->byteArr, &object->identificationNumber); + } + else if (index == 7) + { + ret = cosem_getUInt16(value->byteArr, &object->manufacturerID); + } + else if (index == 8) + { + ret = cosem_getUInt8(value->byteArr, &object->dataHeaderVersion); + } + else if (index == 9) + { + ret = cosem_getUInt8(value->byteArr, &object->deviceType); + } + else if (index == 10) + { + ret = cosem_getUInt8(value->byteArr, &object->accessNumber); + } + else if (index == 11) + { + ret = cosem_getUInt8(value->byteArr, &object->status); + } + else if (index == 12) + { + ret = cosem_getUInt8(value->byteArr, &object->alarm); + } + else if (index == 13 && object->base.version != 0) + { + ret = cosem_getUInt16(value->byteArr, &object->configuration); + } + else if (index == 14 && object->base.version != 0) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->encryptionKeyStatus = (DLMS_MBUS_ENCRYPTION_KEY_STATUS)ch; + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} + +#endif //DLMS_IGNORE_MBUS_CLIENT +#ifndef DLMS_IGNORE_MODEM_CONFIGURATION +int cosem_setModemConfiguration(gxModemConfiguration* object, unsigned char index, dlmsVARIANT* value) +{ + unsigned char ch; + int ret, pos; + gxModemInitialisation* modemInit; +#if !defined(DLMS_COSEM_EXACT_DATA_TYPES) + gxModemProfile* mp; +#endif //!defined(DLMS_COSEM_EXACT_DATA_TYPES) + if (index == 2) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->communicationSpeed = (DLMS_BAUD_RATE)ch; + } + } + else if (index == 3) + { + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->initialisationStrings, &count)) == 0) + { + unsigned cnt = object->base.version != 0 ? 3 : 2; + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->initialisationStrings, pos, (void**)&modemInit, sizeof(gxModemInitialisation))) != 0 || + (ret = cosem_checkStructure(value->byteArr, cnt)) != 0 || +#ifdef DLMS_COSEM_EXACT_DATA_TYPES + (ret = cosem_getOctetString(value->byteArr, &modemInit->request)) != 0 || + (ret = cosem_getOctetString(value->byteArr, &modemInit->response)) != 0) +#else + (ret = cosem_getOctetString2(value->byteArr, modemInit->request.value, sizeof(modemInit->request.value), &modemInit->request.size)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, modemInit->response.value, sizeof(modemInit->response.value), &modemInit->response.size)) != 0) +#endif //DLMS_COSEM_EXACT_DATA_TYPES + { + break; + } + if (object->base.version != 0) + { + if ((ret = cosem_getUInt16(value->byteArr, &modemInit->delay)) != 0) + { + break; + } + } + } + } + } + else if (index == 4) + { + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->modemProfile, &count)) == 0) + { +#ifdef DLMS_COSEM_EXACT_DATA_TYPES + gxByteBuffer* it; + for (pos = 0; pos != count; ++pos) + { + it = (gxByteBuffer*)gxmalloc(sizeof(gxByteBuffer)); + BYTE_BUFFER_INIT(it); + if ((ret = cosem_getOctetString(value->byteArr, it)) != 0 || + (ret = arr_push(&object->modemProfile, it)) != 0) + { + break; + } + } +#else + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->modemProfile, pos, (void**)&mp, sizeof(gxModemProfile))) != 0 || + (ret = cosem_getOctetString2(value->byteArr, mp->value, sizeof(mp->value), &mp->size)) != 0) + { + break; + } + } +#endif //DLMS_COSEM_EXACT_DATA_TYPES + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_MODEM_CONFIGURATION +#ifndef DLMS_IGNORE_PPP_SETUP +int cosem_setPppSetup(dlmsSettings* settings, gxPppSetup* object, unsigned char index, dlmsVARIANT* value) +{ + unsigned char ch; + int ret, pos; + gxpppSetupLcpOption* lcpItem; + gxpppSetupIPCPOption* ipcpItem; + if (index == 2) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; + if ((ret = cosem_getOctetString2(value->byteArr, ln, 6, NULL)) == 0) + { + if ((ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_NONE, ln, &object->phy)) != 0) + { + return ret; + } + } +#else + ret = cosem_getOctetString2(value->byteArr, object->PHYReference, 6, NULL); +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + else if (index == 3) + { + arr_clear(&object->lcpOptions); + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->lcpOptions, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->lcpOptions, pos, (void**)&lcpItem, sizeof(gxpppSetupLcpOption))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 3)) != 0 || + (ret = cosem_getUInt8(value->byteArr, (unsigned char*)&lcpItem->type)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &lcpItem->length)) != 0 || + (ret = cosem_getVariant(value->byteArr, &lcpItem->data)) != 0) + { + break; + } + } + } + } + else if (index == 4) + { + arr_clear(&object->ipcpOptions); + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->ipcpOptions, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->ipcpOptions, pos, (void**)&ipcpItem, sizeof(gxpppSetupIPCPOption))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 3)) != 0 || + (ret = cosem_getUInt8(value->byteArr, (unsigned char*)&ipcpItem->type)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &ipcpItem->length)) != 0 || + (ret = cosem_getVariant(value->byteArr, &ipcpItem->data)) != 0) + { + break; + } + } + } + } + else if (index == 5) + { + if ((ret = bb_getUInt8(value->byteArr, &ch)) == 0) + { + bb_clear(&object->userName); + bb_clear(&object->password); + if (ch == 2) + { + --value->byteArr->position; + if ((ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getOctetString(value->byteArr, &object->userName)) != 0 || + (ret = cosem_getOctetString(value->byteArr, &object->password)) != 0) + { + //Error code is returned at the end of the function. + } + } + else if (ch != 0) + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_PPP_SETUP +#ifndef DLMS_IGNORE_REGISTER_ACTIVATION +int cosem_setRegisterActivation( + dlmsSettings* settings, + gxValueEventArg* e) +{ + int ret, pos, pos2; + gxRegisterActivation* object = (gxRegisterActivation*)e->target; + unsigned char index = e->index; + dlmsVARIANT* value = &e->value; +#ifdef DLMS_IGNORE_OBJECT_POINTERS + gxObjectDefinition* objectDefinition; +#else + gxObject* objectDefinition; +#endif //DLMS_IGNORE_OBJECT_POINTERS + if (index == 2) + { +#ifdef DLMS_IGNORE_OBJECT_POINTERS + uint16_t count = 0xFFFF; +#else + uint16_t count; + uint16_t ot; + unsigned char ln[6]; + obj_clearRegisterActivationAssignment(&object->registerAssignment); +#endif //DLMS_IGNORE_OBJECT_POINTERS + if ((ret = cosem_verifyArray(value->byteArr, &object->registerAssignment, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_checkStructure(value->byteArr, 2)) != 0 || +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getUInt16(value->byteArr, &ot)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, ln, 6, NULL)) != 0) + { + break; + } +#ifndef DLMS_COSEM_EXACT_DATA_TYPES + if ((ret = arr_getByIndexRef(&object->registerAssignment, pos, (void**)&objectDefinition)) != 0) + { + break; + } +#endif //DLMS_COSEM_EXACT_DATA_TYPES + if ((ret = cosem_findObjectByLN(settings, (DLMS_OBJECT_TYPE)ot, ln, &objectDefinition)) != 0) + { + break; + } +#ifdef DLMS_COSEM_EXACT_DATA_TYPES + if ((ret = arr_push(&object->registerAssignment, objectDefinition)) != 0) + { + break; + } +#endif //DLMS_COSEM_EXACT_DATA_TYPES +#else + (ret = cosem_getArrayItem(&object->registerAssignment, pos, (void**)&objectDefinition, sizeof(gxObjectDefinition))) != 0 || + (ret = cosem_getUInt16(value->byteArr, (uint16_t*)&objectDefinition->objectType)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, objectDefinition->logicalName, 6, NULL)) != 0) + { + break; + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + } + } + else if (index == 3) + { + obj_clearRegisterActivationMaskList(&object->maskList); + gxRegisterActivationMask* k; + uint16_t size; + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->maskList, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getArrayItem(&object->maskList, pos, (void**)&k, sizeof(gxRegisterActivationMask))) != 0 || +#ifndef DLMS_COSEM_EXACT_DATA_TYPES + (ret = cosem_getOctetString2(value->byteArr, k->name, sizeof(k->name), &size)) != 0) +#else + (ret = cosem_getOctetString(value->byteArr, &k->name)) != 0) +#endif //DLMS_COSEM_EXACT_DATA_TYPES + { + break; + } +#ifndef DLMS_COSEM_EXACT_DATA_TYPES + k->length = (unsigned char)size; +#endif //DLMS_COSEM_EXACT_DATA_TYPES + size = sizeof(k->indexes); + if ((ret = cosem_checkArray(value->byteArr, &size)) == 0) + { +#ifdef DLMS_COSEM_EXACT_DATA_TYPES + unsigned char ch; + for (pos2 = 0; pos2 != size; ++pos2) + { + if ((ret = cosem_getUInt8(value->byteArr, &ch)) != 0 || + (ret = bb_setUInt8(&k->indexes, ch)) != 0) + { + break; + } + } +#else + k->count = (unsigned char)size; + for (pos2 = 0; pos2 != size; ++pos2) + { + if ((ret = cosem_getUInt8(value->byteArr, &k->indexes[pos2])) != 0) + { + break; + } + } +#endif //DLMS_COSEM_EXACT_DATA_TYPES + } + } + } + } + else if (index == 4 && (value->vt & DLMS_DATA_TYPE_OCTET_STRING) != 0) + { + //If data is coming in action it's plain value. + if (e->action && value->vt == (DLMS_DATA_TYPE_OCTET_STRING | DLMS_DATA_TYPE_BYREF)) + { + bb_clear(&object->activeMask); + ret = bb_set(&object->activeMask, value->pVal, value->size); + } + else + { + ret = cosem_getOctetString(value->byteArr, &object->activeMask); + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_REGISTER_ACTIVATION +#ifndef DLMS_IGNORE_REGISTER_MONITOR +int cosem_setRegisterMonitor(dlmsSettings* settings, gxRegisterMonitor* object, unsigned char index, dlmsVARIANT* value) +{ + int ret, pos; + gxActionSet* actionSet; + dlmsVARIANT* tmp; + if (index == 2) + { + va_clear(&object->thresholds); + uint16_t count; + if ((ret = cosem_verifyVariantArray(value->byteArr, &object->thresholds, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getVariantArrayItem(&object->thresholds, pos, &tmp)) != 0 || + (ret = cosem_getVariant(value->byteArr, tmp)) != 0) + { + break; + } + } + } + } + else if (index == 3) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + uint16_t type; +#endif //DLMS_IGNORE_OBJECT_POINTERS +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + if ((ret = cosem_checkStructure(value->byteArr, 3)) == 0 && +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getUInt16(value->byteArr, &type)) == 0 && + (ret = cosem_getOctetString2(value->byteArr, ln, 6, NULL)) == 0 && +#else + (ret = cosem_getUInt16(value->byteArr, (short*)&object->monitoredValue.objectType)) == 0 && + (ret = cosem_getOctetString2(value->byteArr, object->monitoredValue.logicalName, 6, NULL)) == 0 && +#endif //DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getInt8(value->byteArr, &object->monitoredValue.attributeIndex)) == 0) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + ret = cosem_findObjectByLN(settings, type, ln, &object->monitoredValue.target); +#endif //DLMS_IGNORE_OBJECT_POINTERS + //Error code is returned at the end of the function. + } + } + else if (index == 4) + { + obj_clearRegisterMonitorActions(&object->actions); +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char lnUp[6]; + unsigned char lnDown[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->actions, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->actions, pos, (void**)&actionSet, sizeof(gxActionSet))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + //Update action up. + (ret = cosem_checkStructure(value->byteArr, 2)) != 0 || +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getOctetString2(value->byteArr, lnUp, 6, NULL)) != 0 || +#else + (ret = cosem_getOctetString2(value->byteArr, actionSet->actionUp.logicalName, 6, NULL)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getUInt16(value->byteArr, &actionSet->actionUp.scriptSelector)) != 0 || + //Update action down. + (ret = cosem_checkStructure(value->byteArr, 2)) != 0 || +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getOctetString2(value->byteArr, lnDown, 6, NULL)) != 0 || +#else + (ret = cosem_getOctetString2(value->byteArr, actionSet->actionDown.logicalName, 6, NULL)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getUInt16(value->byteArr, &actionSet->actionDown.scriptSelector)) != 0) + { + break; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_SCRIPT_TABLE, lnUp, (gxObject**)&actionSet->actionUp.script)) != 0 || + (ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_SCRIPT_TABLE, lnDown, (gxObject**)&actionSet->actionDown.script)) != 0) + { + break; + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} + +#endif //DLMS_IGNORE_REGISTER_MONITOR +#ifndef DLMS_IGNORE_SAP_ASSIGNMENT +int cosem_setSapAssignment(gxSapAssignment* object, unsigned char index, dlmsVARIANT* value) +{ + int ret, pos; + gxSapItem* it = NULL; + if (index == 2) + { + obj_clearSapList(&object->sapAssignmentList); + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->sapAssignmentList, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->sapAssignmentList, pos, (void**)&it, sizeof(gxSapItem))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &it->id)) != 0 || +#ifdef DLMS_IGNORE_MALLOC + (ret = cosem_getOctetString2(value->byteArr, it->name.value, sizeof(it->name.value), &it->name.size)) != 0) +#else + (ret = cosem_getOctetString(value->byteArr, &it->name)) != 0) +#endif //DLMS_IGNORE_MALLOC + { + break; + } + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SAP_ASSIGNMENT +#ifndef DLMS_IGNORE_SCHEDULE +int cosem_setSchedule(dlmsSettings* settings, gxSchedule* object, unsigned char index, dlmsVARIANT* value) +{ + gxScheduleEntry* se; + int ret, pos; + if (index == 2) + { + obj_clearScheduleEntries(&object->entries); +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->entries, &count)) == 0) + { + uint32_t execWeekdays; + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->entries, pos, (void**)&se, sizeof(gxScheduleEntry))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 10)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &se->index)) != 0 || + (ret = cosem_getBoolean(value->byteArr, &se->enable)) != 0 || +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getOctetString2(value->byteArr, ln, 6, NULL)) != 0 || +#else + (ret = cosem_getOctetString2(value->byteArr, se->logicalName, 6, NULL)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getUInt16(value->byteArr, &se->scriptSelector)) != 0 || + (ret = cosem_getTimeFromOctetString(value->byteArr, &se->switchTime)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &se->validityWindow)) != 0 || + (ret = cosem_getIntegerFromBitString(value->byteArr, &execWeekdays)) != 0 || + (ret = cosem_getBitString(value->byteArr, &se->execSpecDays)) != 0 || + (ret = cosem_getDateFromOctetString(value->byteArr, &se->beginDate)) != 0 || + (ret = cosem_getDateFromOctetString(value->byteArr, &se->endDate)) != 0) + { + break; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_SCRIPT_TABLE, ln, (gxObject**)&se->scriptTable)) != 0) + { + break; + } +#else +#endif //DLMS_IGNORE_OBJECT_POINTERS + se->execWeekdays = execWeekdays; + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SCHEDULE + +#ifndef DLMS_IGNORE_SCRIPT_TABLE +int cosem_setScriptTable(dlmsSettings* settings, gxScriptTable* object, unsigned char index, dlmsVARIANT* value) +{ + int ret, pos, pos2; + gxScriptAction* scriptAction; + gxScript* script; + if (index == 2) + { + obj_clearScriptTable(&object->scripts); +#ifndef DLMS_IGNORE_OBJECT_POINTERS + uint16_t type; +#endif //DLMS_IGNORE_OBJECT_POINTERS +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + uint16_t count, count2; + if ((ret = cosem_verifyArray(value->byteArr, &object->scripts, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->scripts, pos, (void**)&script, sizeof(gxScript))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &script->id)) != 0) + { + break; + } + if ((ret = cosem_verifyArray(value->byteArr, &script->actions, &count2)) != 0) + { + break; + } + for (pos2 = 0; pos2 != count2; ++pos2) + { + if ((ret = cosem_getArrayItem(&script->actions, pos2, (void**)&scriptAction, sizeof(gxScriptAction))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 5)) != 0 || + (ret = cosem_getEnum(value->byteArr, (unsigned char*)&scriptAction->type)) != 0 || +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getUInt16(value->byteArr, &type)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, ln, 6, NULL)) != 0 || +#else + (ret = cosem_getUInt16(value->byteArr, (uint16_t*)&scriptAction->objectType)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, scriptAction->logicalName, 6, NULL)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getInt8(value->byteArr, &scriptAction->index)) != 0 || + (ret = cosem_getVariant(value->byteArr, &scriptAction->parameter)) != 0) + { + break; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = cosem_findObjectByLN(settings, type, ln, &scriptAction->target)) != 0) + { + break; + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SCRIPT_TABLE +#ifndef DLMS_IGNORE_SPECIAL_DAYS_TABLE +int cosem_setSpecialDaysTable(gxSpecialDaysTable* object, unsigned char index, dlmsVARIANT* value) +{ + int ret, pos; + gxSpecialDay* specialDay; + if (index == 2) + { + arr_clear(&object->entries); + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->entries, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->entries, pos, (void**)&specialDay, sizeof(gxSpecialDay))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 3)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &specialDay->index)) != 0 || + (ret = cosem_getDateFromOctetString(value->byteArr, &specialDay->date)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &specialDay->dayId)) != 0) + { + break; + } + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SPECIAL_DAYS_TABLE +#ifndef DLMS_IGNORE_TCP_UDP_SETUP +int cosem_setTcpUdpSetup(dlmsSettings* settings, gxTcpUdpSetup* object, unsigned char index, dlmsVARIANT* value) +{ + int ret; + if (index == 2) + { + ret = cosem_getUInt16(value->byteArr, &object->port); + } + else if (index == 3) + { + if (value->vt == DLMS_DATA_TYPE_NONE) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + object->ipSetup = NULL; +#else + memset(object->ipReference, 0, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + ret = 0; + } + else + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; + if ((ret = cosem_getOctetString2(value->byteArr, ln, 6, NULL)) == 0) + { + ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_IP4_SETUP, ln, &object->ipSetup); + } +#else + ret = bb_get(value->byteArr, object->ipReference, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + } + else if (index == 4) + { + ret = cosem_getUInt16(value->byteArr, &object->maximumSegmentSize); + } + else if (index == 5) + { + ret = cosem_getUInt8(value->byteArr, &object->maximumSimultaneousConnections); + } + else if (index == 6) + { + ret = cosem_getUInt16(value->byteArr, &object->inactivityTimeout); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_TCP_UDP_SETUP + +#ifndef DLMS_IGNORE_MBUS_DIAGNOSTIC +int cosem_setMbusDiagnostic(gxMbusDiagnostic* object, unsigned char index, dlmsVARIANT* value) +{ + int ret; + gxBroadcastFrameCounter* it; + if (index == 2) + { + ret = cosem_getUInt8(value->byteArr, &object->receivedSignalStrength); + } + else if (index == 3) + { + ret = cosem_getUInt8(value->byteArr, &object->channelId); + } + else if (index == 4) + { + unsigned char ch; + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->linkStatus = (DLMS_MBUS_LINK_STATUS)ch; + } + } + else if (index == 5) + { + uint16_t pos, count; + if ((ret = cosem_verifyArray(value->byteArr, &object->broadcastFrames, &count)) == 0) { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->broadcastFrames, pos, (void**)&it, sizeof(gxBroadcastFrameCounter))) == 0) + { + if ((ret = cosem_checkStructure(value->byteArr, 3)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->clientId)) != 0 || + (ret = cosem_getUInt32(value->byteArr, &it->counter)) != 0 || + (ret = cosem_getDateTime(value->byteArr, &it->timeStamp)) != 0) + { + break; + } + } + } + } + } + else if (index == 6) + { + ret = cosem_getUInt32(value->byteArr, &object->transmissions); + } + else if (index == 7) + { + ret = cosem_getUInt32(value->byteArr, &object->receivedFrames); + } + else if (index == 8) + { + ret = cosem_getUInt32(value->byteArr, &object->failedReceivedFrames); + } + else if (index == 9) + { + if ((ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &object->captureTime.attributeId)) != 0 || + (ret = cosem_getDateTime(value->byteArr, &object->captureTime.timeStamp)) != 0) + { + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_MBUS_DIAGNOSTIC + + +#ifndef DLMS_IGNORE_MBUS_PORT_SETUP +int cosem_setMbusPortSetup(gxMBusPortSetup* object, unsigned char index, dlmsVARIANT* value) +{ + int ret; + unsigned char ch; + if (index == 2) + { + ret = cosem_getOctetString2(value->byteArr, object->profileSelection, 6, NULL); + } + else if (index == 3) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->portCommunicationStatus = ch; + } + } + else if (index == 4) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->dataHeaderType = ch; + } + } + else if (index == 5) + { + ret = cosem_getUInt8(value->byteArr, &object->primaryAddress); + } + else if (index == 6) + { + ret = cosem_getUInt32(value->byteArr, &object->identificationNumber); + } + else if (index == 7) + { + ret = cosem_getUInt16(value->byteArr, &object->manufacturerId); + } + else if (index == 8) + { + ret = cosem_getUInt8(value->byteArr, &object->mBusVersion); + } + else if (index == 9) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->deviceType = ch; + } + } + else if (index == 10) + { + ret = cosem_getUInt16(value->byteArr, &object->maxPduSize); + } + else if (index == 11) + { + gxTimePair* it; + uint16_t count; + int pos; + arr_clearKeyValuePair(&object->listeningWindow); + if ((ret = cosem_verifyArray(value->byteArr, &object->listeningWindow, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->listeningWindow, pos, (void**)&it, sizeof(gxTimePair))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getDateTimeFromOctetString(value->byteArr, &it->first)) != 0 || + (ret = cosem_getDateTimeFromOctetString(value->byteArr, &it->second)) != 0) + { + break; + } + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_MBUS_PORT_SETUP + +#ifndef DLMS_IGNORE_MBUS_MASTER_PORT_SETUP +int cosem_setMbusMasterPortSetup(gxMBusMasterPortSetup* object, unsigned char index, dlmsVARIANT* value) +{ + int ret; + unsigned char ch; + if (index == 2) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->commSpeed = (DLMS_BAUD_RATE)ch; + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_MBUS_MASTER_PORT_SETUP + +#ifndef DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS +int cosem_setG3PlcMacLayerCounters(gxG3PlcMacLayerCounters* object, unsigned char index, dlmsVARIANT* value) +{ + int ret = 0; + if (index == 2) + { + ret = cosem_getUInt32(value->byteArr, &object->txDataPacketCount); + } + else if (index == 3) + { + ret = cosem_getUInt32(value->byteArr, &object->rxDataPacketCount); + } + else if (index == 4) + { + ret = cosem_getUInt32(value->byteArr, &object->txCmdPacketCount); + } + else if (index == 5) + { + ret = cosem_getUInt32(value->byteArr, &object->rxCmdPacketCount); + } + else if (index == 6) + { + ret = cosem_getUInt32(value->byteArr, &object->cSMAFailCount); + } + else if (index == 7) + { + ret = cosem_getUInt32(value->byteArr, &object->cSMANoAckCount); + } + else if (index == 8) + { + ret = cosem_getUInt32(value->byteArr, &object->badCrcCount); + } + else if (index == 9) + { + ret = cosem_getUInt32(value->byteArr, &object->txDataBroadcastCount); + } + else if (index == 10) + { + ret = cosem_getUInt32(value->byteArr, &object->rxDataBroadcastCount); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS + +#ifndef DLMS_IGNORE_G3_PLC_MAC_SETUP +int cosem_setG3PlcMacSetup(gxG3PlcMacSetup* object, unsigned char index, dlmsVARIANT* value) +{ + uint16_t count; + int pos, ret = 0; + if (index == 2) + { + ret = cosem_getUInt16(value->byteArr, &object->shortAddress); + } + else if (index == 3) + { + ret = cosem_getUInt16(value->byteArr, &object->rcCoord); + } + else if (index == 4) + { + ret = cosem_getUInt16(value->byteArr, &object->panId); + } + else if (index == 5) + { + arr_clear(&object->keyTable); + gxG3MacKeyTable* it; + if (value->Arr != NULL) + { + if ((ret = cosem_verifyArray(value->byteArr, &object->keyTable, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->keyTable, pos, (void**)&it, sizeof(gxG3MacKeyTable))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->id)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, it->key, MAX_G3_MAC_KEY_TABLE_KEY_SIZE, NULL)) != 0) + { + break; + } + } + } + } + } + else if (index == 6) + { + ret = cosem_getUInt32(value->byteArr, &object->frameCounter); + } + else if (index == 7) + { + ba_clear(&object->toneMask); + ret = cosem_getBitString(value->byteArr, &object->toneMask); + } + else if (index == 8) + { + ret = cosem_getUInt8(value->byteArr, &object->tmrTtl); + } + else if (index == 9) + { + ret = cosem_getUInt8(value->byteArr, &object->maxFrameRetries); + } + else if (index == 10) + { + ret = cosem_getUInt8(value->byteArr, &object->neighbourTableEntryTtl); + } + else if (index == 11) + { + gxNeighbourTable* it; + unsigned char txRes, modulation; + obj_clearNeighbourTable(&object->neighbourTable); + if ((ret = cosem_verifyArray(value->byteArr, &object->neighbourTable, &count)) == 0) + { + uint16_t toneMapSize, txCoeffSize; + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->neighbourTable, pos, (void**)&it, sizeof(gxNeighbourTable))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 11)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &it->shortAddress)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->payloadModulationScheme)) != 0 || + (ret = cosem_getBitString2(value->byteArr, it->toneMap[pos].value, MAX_G3_MAC_NEIGHBOUR_TABLE_TONE_MAP_ITEM_SIZE, &toneMapSize)) != 0 || + (ret = cosem_getEnum(value->byteArr, &modulation)) != 0 || + (ret = cosem_getInt8(value->byteArr, &it->txGain)) != 0 || + (ret = cosem_getEnum(value->byteArr, &txRes)) != 0 || + (ret = cosem_getBitString2(value->byteArr, it->txCoeff[pos].value, MAX_G3_MAC_NEIGHBOUR_TABLE_GAIN_ITEM_SIZE, &txCoeffSize)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->lqi)) != 0 || + (ret = cosem_getInt8(value->byteArr, &it->phaseDifferential)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->tmrValidTime)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->noData)) != 0) + { + break; + } + it->modulation = modulation; + it->txRes = txRes; + it->toneMap[pos].size = (unsigned char)toneMapSize; + it->txCoeff[pos].size = (unsigned char)txCoeffSize; + } + } + } + else if (index == 12) + { + ret = cosem_getUInt8(value->byteArr, &object->highPriorityWindowSize); + } + else if (index == 13) + { + ret = cosem_getUInt8(value->byteArr, &object->cscmFairnessLimit); + } + else if (index == 14) + { + ret = cosem_getUInt8(value->byteArr, &object->beaconRandomizationWindowLength); + } + else if (index == 15) + { + ret = cosem_getUInt8(value->byteArr, &object->macA); + } + else if (index == 16) + { + ret = cosem_getUInt8(value->byteArr, &object->macK); + } + else if (index == 17) + { + ret = cosem_getUInt8(value->byteArr, &object->minCwAttempts); + } + else if (index == 18) + { + ret = cosem_getUInt8(value->byteArr, &object->cenelecLegacyMode); + } + else if (index == 19) + { + ret = cosem_getUInt8(value->byteArr, &object->fccLegacyMode); + } + else if (index == 20) + { + ret = cosem_getUInt8(value->byteArr, &object->maxBe); + } + else if (index == 21) + { + ret = cosem_getUInt8(value->byteArr, &object->maxCsmaBackoffs); + } + else if (index == 22) + { + ret = cosem_getUInt8(value->byteArr, &object->minBe); + } + else if (index == 23) + { + ret = cosem_getUInt8(value->byteArr, &object->macBroadcastMaxCwEnabled); + } + else if (index == 24) + { + ret = cosem_getUInt8(value->byteArr, &object->macTransmitAtten); + } + else if (index == 25) + { + gxMacPosTable* it; + arr_clear(&object->macPosTable); + if ((ret = cosem_verifyArray(value->byteArr, &object->macPosTable, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->macPosTable, pos, (void**)&it, sizeof(gxMacPosTable))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 3)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &it->shortAddress)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->lqi)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->validTime)) != 0) + { + break; + } + } + } + } + else if (object->base.version > 2 && index == 26) + { + ret = cosem_getUInt8(value->byteArr, &object->macDuplicateDetectionTTL); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_G3_PLC_MAC_SETUP + + +#ifndef DLMS_IGNORE_G3_PLC_6LO_WPAN + +int cosem_getUint16Array(gxArray* arr, dlmsVARIANT* value) +{ + int pos, ret; + uint16_t count; + uint16_t* it; + arr_clear(arr); + if ((ret = cosem_verifyArray(value->byteArr, arr, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(arr, pos, (void**)&it, sizeof(uint16_t))) != 0 || + (ret = cosem_getUInt16(value->byteArr, it)) != 0) + { + break; + } + } + } + return ret; +} + +int cosem_setG3Plc6LoWPAN(gxG3Plc6LoWPAN* object, unsigned char index, dlmsVARIANT* value) +{ + uint16_t count; + int pos, ret = 0; + if (index == 2) + { + ret = cosem_getUInt8(value->byteArr, &object->maxHops); + } + else if (index == 3) + { + ret = cosem_getUInt8(value->byteArr, &object->weakLqiValue); + } + else if (index == 4) + { + ret = cosem_getUInt8(value->byteArr, &object->securityLevel); + } + else if (index == 5) + { + unsigned char ch; + bb_clear(&object->prefixTable); + int ret = cosem_checkArray(value->byteArr, &count); + if (ret == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getUInt8(value->byteArr, &ch)) != 0 || + (ret = bb_setUInt8(&object->prefixTable, ch)) != 0) + { + break; + } + } + } + } + else if (index == 6) + { + arr_clear(&object->routingConfiguration); + gxRoutingConfiguration* it; + if ((ret = cosem_verifyArray(value->byteArr, &object->routingConfiguration, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->routingConfiguration, pos, (void**)&it, sizeof(gxRoutingConfiguration))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 14)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->netTraversalTime)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &it->routingTableEntryTtl)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->kr)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->km)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->kc)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->kq)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->kh)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->krt)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->rReqRetries)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->rReqReqWait)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &it->blacklistTableEntryTtl)) != 0 || + (ret = cosem_getBoolean(value->byteArr, &it->unicastRreqGenEnable)) != 0 || + (ret = cosem_getBoolean(value->byteArr, &it->rlcEnabled)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->addRevLinkCost)) != 0) + { + break; + } + } + } + } + else if (index == 7) + { + ret = cosem_getUInt16(value->byteArr, &object->broadcastLogTableEntryTtl); + } + else if (index == 8) + { + arr_clear(&object->routingTable); + gxRoutingTable* it; + if ((ret = cosem_verifyArray(value->byteArr, &object->routingTable, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->routingTable, pos, (void**)&it, sizeof(gxRoutingTable))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 6)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &it->destinationAddress)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &it->nextHopAddress)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &it->routeCost)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->hopCount)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->weakLinkCount)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &it->validTime)) != 0) + { + break; + } + } + } + } + else if (index == 9) + { + arr_clear(&object->contextInformationTable); + gxContextInformationTable* it; + unsigned char tmp[2]; + bitArray ba; + uint32_t v; + ba_attach(&ba, tmp, 0, 8 * sizeof(tmp)); + if ((ret = cosem_verifyArray(value->byteArr, &object->contextInformationTable, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + ba_clear(&ba); + if ((ret = cosem_getArrayItem(&object->contextInformationTable, pos, (void**)&it, sizeof(gxContextInformationTable))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 5)) != 0 || + (ret = cosem_getBitString(value->byteArr, &ba)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->contextLength)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, it->context, 16, NULL)) != 0 || + (ret = cosem_getBoolean(value->byteArr, &it->compression)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &it->validLifetime)) != 0) + { + break; + } + ba_toInteger(&ba, &v); + it->cid = (unsigned char)v; + } + } + } + else if (index == 10) + { + arr_clear(&object->blacklistTable); + gxBlacklistTable* it; + if ((ret = cosem_verifyArray(value->byteArr, &object->blacklistTable, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->blacklistTable, pos, (void**)&it, sizeof(gxBlacklistTable))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &it->neighbourAddress)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &it->validTime)) != 0) + { + break; + } + } + } + } + else if (index == 11) + { + arr_clear(&object->broadcastLogTable); + gxBroadcastLogTable* it; + if ((ret = cosem_verifyArray(value->byteArr, &object->broadcastLogTable, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->broadcastLogTable, pos, (void**)&it, sizeof(gxBroadcastLogTable))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 3)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &it->sourceAddress)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->sequenceNumber)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &it->validTime)) != 0) + { + break; + } + } + } + } + else if (index == 12) + { + ret = cosem_getUint16Array(&object->groupTable, value); + } + else if (index == 13) + { + ret = cosem_getUInt16(value->byteArr, &object->maxJoinWaitTime); + } + else if (index == 14) + { + ret = cosem_getUInt8(value->byteArr, &object->pathDiscoveryTime); + } + else if (index == 15) + { + ret = cosem_getUInt8(value->byteArr, &object->activeKeyIndex); + } + else if (index == 16) + { + ret = cosem_getUInt8(value->byteArr, &object->metricType); + } + else if (index == 17) + { + ret = cosem_getUInt16(value->byteArr, &object->coordShortAddress); + } + else if (index == 18) + { + ret = cosem_getUInt8(value->byteArr, &object->disableDefaultRouting); + } + else if (index == 19) + { + unsigned char ch; + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->deviceType = (DLMS_PAN_DEVICE_TYPE)ch; + } + } + else if (index == 20) + { + ret = cosem_getBoolean(value->byteArr, &object->defaultCoordRouteEnabled); + } + else if (index == 21) + { + ret = cosem_getUint16Array(&object->destinationAddress, value); + } + else if (index == 22) + { + ret = cosem_getUInt8(value->byteArr, &object->lowLQI); + } + else if (index == 23) + { + ret = cosem_getUInt8(value->byteArr, &object->highLQI); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_G3_PLC_6LO_WPAN + +#ifndef DLMS_IGNORE_FUNCTION_CONTROL +int cosem_setFunctionControl( + dlmsSettings* settings, + gxFunctionControl* object, + unsigned char index, + dlmsVARIANT* value) +{ + int pos, ret = 0; +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + if (index == 2) + { + functionStatus* it; + obj_clearActivationStatus(&object->activationStatus); + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->activationStatus, &count)) == 0) { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->activationStatus, pos, (void**)&it, sizeof(functionStatus))) == 0) + { + if ((ret = cosem_checkStructure(value->byteArr, 2)) != 0) + { + break; + } +#ifdef DLMS_IGNORE_MALLOC + if ((ret = cosem_getOctetString2(value->byteArr, it->name, sizeof(it->name), &it->size)) != 0) + { + break; + } +#else + if ((ret = cosem_getOctetString(value->byteArr, &it->name)) != 0) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + if ((ret = cosem_getUInt8(value->byteArr, &it->status)) != 0) + { + break; + } + + } + } + } + } + else if (index == 3) + { + functionalBlock* it; + gxObject* obj; + obj_clearFunctionList(&object->functions); + uint16_t ot, count; + if ((ret = cosem_verifyArray(value->byteArr, &object->functions, &count)) == 0) { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->functions, pos, (void**)&it, sizeof(functionalBlock))) == 0) + { + if ((ret = cosem_checkStructure(value->byteArr, 2)) != 0) + { + break; + } + if ((ret = cosem_getOctetString2(value->byteArr, it->name, sizeof(it->name), &it->nameSize)) != 0) + { + break; + } + if ((ret = cosem_checkArray(value->byteArr, &count)) == 0) + { + if (MAX_FUNCTION_TARGET_LENGTH < count) + { + return DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &ot)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, ln, 6, NULL)) != 0) + { + break; + } + obj = NULL; + if ((ret = cosem_findObjectByLN(settings, ot, ln, &obj)) != 0) + { + break; + } + if (obj == NULL) + { + ret = DLMS_ERROR_CODE_INCONSISTENT_CLASS_OR_OBJECT; + } + it->functionSpecifications[pos] = obj; + } + } + } + if (ret != 0) + { + break; + } + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_FUNCTION_CONTROL + +#ifndef DLMS_IGNORE_ARRAY_MANAGER + +int cosem_setArrayManager(dlmsSettings* settings, gxArrayManager* object, unsigned char index, dlmsVARIANT* value) +{ + int pos, ret = 0; + gxArrayManagerItem* it; +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + if (index == 2) + { + arr_clear(&object->elements); + uint16_t ot, count; + if ((ret = cosem_verifyArray(value->byteArr, &object->elements, &count)) == 0) { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->elements, pos, (void**)&it, sizeof(gxArrayManagerItem))) == 0) + { + if ((ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &it->id)) != 0 || + (ret = cosem_checkStructure(value->byteArr, 3)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &ot)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, ln, 6, NULL)) != 0 || + (ret = cosem_getInt8(value->byteArr, &it->element.attributeIndex)) != 0) + { + break; + } + it->element.target = NULL; + if ((ret = cosem_findObjectByLN(settings, ot, ln, &it->element.target)) != 0) + { + break; + } + if (it->element.target == NULL) + { + object->elements.size = pos; + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + } + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_ARRAY_MANAGER + +#ifndef DLMS_IGNORE_PUSH_SETUP +int cosem_setPushSetup(dlmsSettings* settings, gxPushSetup* object, unsigned char index, dlmsVARIANT* value) +{ + int ret, pos; + gxTarget* it; + if (index == 2) + { + DLMS_OBJECT_TYPE type = DLMS_OBJECT_TYPE_NONE; + obj_clearPushObjectList(&object->pushObjectList); +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->pushObjectList, &count)) == 0) { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->pushObjectList, pos, (void**)&it, sizeof(gxTarget))) == 0) + { + if ((ret = cosem_checkStructure(value->byteArr, 4)) != 0 || +#ifdef DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getUInt16(value->byteArr, &it->objectType)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, it->logicalName, 6, NULL)) != 0 || +#else + (ret = cosem_getUInt16(value->byteArr, (uint16_t*)&type)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, ln, 6, NULL)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getInt8(value->byteArr, &it->attributeIndex)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &it->dataIndex)) != 0) + { + break; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = cosem_findObjectByLN(settings, type, ln, &it->target)) != 0) + { + break; + } + if (it->target == NULL) + { +#ifdef DLMS_DEBUG + svr_notifyTrace2("Invalid object", type, ln, -1); +#endif //DLMS_DEBUG + object->pushObjectList.size = pos; + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } +#ifdef DLMS_DEBUG + svr_notifyTrace2("Adding object ", type, ln, 0); +#endif //DLMS_DEBUG +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + } + } + } + else if (index == 3) + { + if ((ret = bb_clear(&object->destination)) != 0 || + (ret = cosem_checkStructure(value->byteArr, 3)) != 0 || + (ret = cosem_getEnum(value->byteArr, (unsigned char*)&object->service)) != 0 || + (ret = cosem_getOctetString(value->byteArr, &object->destination)) != 0 || + (ret = cosem_getEnum(value->byteArr, (unsigned char*)&object->message)) != 0) + { + //Error code is returned at the end of the function. + } + } + else if (index == 4) + { + gxTimePair* it; + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->communicationWindow, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->communicationWindow, pos, (void**)&it, sizeof(gxTimePair))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getDateTimeFromOctetString(value->byteArr, &it->first)) != 0 || + (ret = cosem_getDateTimeFromOctetString(value->byteArr, &it->second)) != 0) + { + break; + } + } + } + } + else if (index == 5) + { + ret = cosem_getUInt16(value->byteArr, &object->randomisationStartInterval); + } + else if (index == 6) + { + ret = cosem_getUInt8(value->byteArr, &object->numberOfRetries); + } + else if (index == 7) + { + ret = cosem_getUInt16(value->byteArr, &object->repetitionDelay); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_PUSH_SETUP + +#ifndef DLMS_IGNORE_CHARGE +int setUnitCharge(dlmsSettings* settings, gxUnitCharge* target, dlmsVARIANT* value) +{ + gxChargeTable* ct; + int ret, pos; + ret = obj_clearChargeTables(&target->chargeTables); + if (ret != 0) + { + return ret; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + uint16_t type; +#endif //DLMS_IGNORE_OBJECT_POINTERS +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + uint16_t count; + if ((ret = cosem_checkStructure(value->byteArr, 3)) != 0 || + //charge per unit scaling + (ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getInt8(value->byteArr, &target->chargePerUnitScaling.commodityScale)) != 0 || + (ret = cosem_getInt8(value->byteArr, &target->chargePerUnitScaling.priceScale)) != 0 || + //commodity + (ret = cosem_checkStructure(value->byteArr, 3)) != 0 || +#ifndef DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getUInt16(value->byteArr, &type)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, ln, 6, NULL)) != 0 || +#else + (ret = cosem_getInt16(value->byteArr, (short*)&target->commodity.type)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, target->commodity.logicalName, 6, NULL)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getInt8(value->byteArr, &target->commodity.attributeIndex)) != 0 || + (ret = cosem_verifyArray(value->byteArr, &target->chargeTables, &count)) != 0) + { + return ret; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = cosem_findObjectByLN(settings, type, ln, &target->commodity.target)) != 0) + { + return ret; + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getArrayItem(&target->chargeTables, pos, (void**)&ct, sizeof(gxChargeTable))) != 0 || +#ifdef DLMS_IGNORE_MALLOC + (ret = cosem_getOctetString2(value->byteArr, ct->index.data, sizeof(ct->index.data), &ct->index.size)) != 0 || +#else + (ret = cosem_getOctetString(value->byteArr, &ct->index)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = cosem_getInt16(value->byteArr, &ct->chargePerUnit)) != 0) + { + break; + } + } + return ret; +} + +int cosem_setCharge(dlmsSettings* settings, gxCharge* object, unsigned char index, dlmsVARIANT* value) +{ + int ret; + unsigned char ch; + if (index == 2) + { + ret = cosem_getInt32(value->byteArr, &object->totalAmountPaid); + } + else if (index == 3) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->chargeType = (DLMS_CHARGE_TYPE)ch; + } + } + else if (index == 4) + { + ret = cosem_getUInt8(value->byteArr, &object->priority); + } + else if (index == 5) + { + ret = setUnitCharge(settings, &object->unitChargeActive, value); + } + else if (index == 6) + { + ret = setUnitCharge(settings, &object->unitChargePassive, value); + } + else if (index == 7) + { + ret = cosem_getDateTimeFromOctetString(value->byteArr, &object->unitChargeActivationTime); + } + else if (index == 8) + { + ret = cosem_getUInt32(value->byteArr, &object->period); + } + else if (index == 9) + { + uint32_t val; + if ((ret = cosem_getIntegerFromBitString(value->byteArr, &val)) == 0) + { + object->chargeConfiguration = val; + } + } + else if (index == 10) + { + ret = cosem_getDateTime(value->byteArr, &object->lastCollectionTime); + } + else if (index == 11) + { + ret = cosem_getInt32(value->byteArr, &object->lastCollectionAmount); + } + else if (index == 12) + { + ret = cosem_getInt32(value->byteArr, &object->totalAmountRemaining); + } + else if (index == 13) + { + ret = cosem_getUInt16(value->byteArr, &object->proportion); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_CHARGE +#ifndef DLMS_IGNORE_CREDIT +int cosem_setCredit(gxCredit* object, unsigned char index, dlmsVARIANT* value) +{ + unsigned char ch; + int ret; + if (index == 2) + { + ret = cosem_getInt32(value->byteArr, &object->currentCreditAmount); + } + else if (index == 3) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->type = (DLMS_CREDIT_TYPE)ch; + } + } + else if (index == 4) + { + ret = cosem_getUInt8(value->byteArr, &object->priority); + } + else if (index == 5) + { + ret = cosem_getInt32(value->byteArr, &object->warningThreshold); + } + else if (index == 6) + { + ret = cosem_getInt32(value->byteArr, &object->limit); + } + else if (index == 7) + { + uint32_t val; + if ((ret = cosem_getIntegerFromBitString(value->byteArr, &val)) == 0) + { + object->creditConfiguration = (DLMS_CREDIT_CONFIGURATION)val; + } + } + else if (index == 8) + { + ret = cosem_getEnum(value->byteArr, &object->status); + } + else if (index == 9) + { + ret = cosem_getInt32(value->byteArr, &object->presetCreditAmount); + } + else if (index == 10) + { + ret = cosem_getInt32(value->byteArr, &object->creditAvailableThreshold); + } + else if (index == 11) + { + ret = cosem_getDateTimeFromOctetString(value->byteArr, &object->period); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_CREDIT +#ifndef DLMS_IGNORE_ACCOUNT +int cosem_setAccount(gxAccount* object, unsigned char index, dlmsVARIANT* value) +{ + int ret, pos; + unsigned char m, s; + unsigned char* ba; + gxCreditChargeConfiguration* ccc; + gxTokenGatewayConfiguration* gwc; + if (index == 2) + { + if ((ret = cosem_checkStructure(value->byteArr, 2)) == 0 && + (ret = cosem_getEnum(value->byteArr, &m)) == 0 && + (ret = cosem_getEnum(value->byteArr, &s)) == 0) + { + object->paymentMode = (DLMS_ACCOUNT_PAYMENT_MODE)m; + object->accountStatus = (DLMS_ACCOUNT_STATUS)s; + //Error is returned at the end of the function. + } + } + else if (index == 3) + { + ret = cosem_getUInt8(value->byteArr, &object->currentCreditInUse); + } + else if (index == 4) + { + uint32_t v; + if ((ret = cosem_getIntegerFromBitString(value->byteArr, &v)) == 0) + { + object->currentCreditStatus = (DLMS_ACCOUNT_CREDIT_STATUS)v; + } + } + else if (index == 5) + { + ret = cosem_getInt32(value->byteArr, &object->availableCredit); + } + else if (index == 6) + { + ret = cosem_getInt32(value->byteArr, &object->amountToClear); + } + else if (index == 7) + { + ret = cosem_getInt32(value->byteArr, &object->clearanceThreshold); + } + else if (index == 8) + { + ret = cosem_getInt32(value->byteArr, &object->aggregatedDebt); + } + else if (index == 9) + { + arr_clear(&object->creditReferences); + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->creditReferences, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->creditReferences, pos, (void**)&ba, 6)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, ba, 6, NULL)) != 0) + { + break; + } + } + } + } + else if (index == 10) + { + arr_clear(&object->chargeReferences); + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->chargeReferences, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->chargeReferences, pos, (void**)&ba, 6)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, ba, 6, NULL)) != 0) + { + break; + } + } + } + } + else if (index == 11) + { + obj_clearCreditChargeConfigurations(&object->creditChargeConfigurations); + uint32_t v; + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->creditChargeConfigurations, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->creditChargeConfigurations, pos, (void**)&ccc, sizeof(gxCreditChargeConfiguration))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 3)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, ccc->creditReference, 6, NULL)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, ccc->chargeReference, 6, NULL)) != 0 || + (ret = cosem_getIntegerFromBitString(value->byteArr, &v)) != 0) + { + break; + } + ccc->collectionConfiguration = (DLMS_CREDIT_COLLECTION_CONFIGURATION)v; + } + } + } + else if (index == 12) + { + obj_clearTokenGatewayConfigurations(&object->tokenGatewayConfigurations); + gwc = NULL; + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->tokenGatewayConfigurations, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->tokenGatewayConfigurations, pos, (void**)&gwc, sizeof(gxTokenGatewayConfiguration))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, gwc->creditReference, 6, NULL)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &gwc->tokenProportion)) != 0) + { + break; + } + } + } + } + else if (index == 13) + { + ret = cosem_getDateTimeFromOctetString(value->byteArr, &object->accountActivationTime); + } + else if (index == 14) + { + ret = cosem_getDateTimeFromOctetString(value->byteArr, &object->accountClosureTime); + } + else if (index == 15) + { + if ((ret = cosem_checkStructure(value->byteArr, 3)) != 0 || +#ifdef DLMS_IGNORE_MALLOC + (ret = cosem_getUtf8String2(value->byteArr, object->currency.name.value, sizeof(object->currency.name.value), &object->currency.name.size)) != 0 || +#else + (ret = cosem_getUtf8String(value->byteArr, &object->currency.name)) != 0 || +#endif //DLMS_IGNORE_MALLOC + (ret = cosem_getInt8(value->byteArr, &object->currency.scale)) != 0 || + (ret = cosem_getEnum(value->byteArr, (unsigned char*)&object->currency.unit)) != 0) + { + //Error code is returned at the end of the function. + } + } + else if (index == 16) + { + ret = cosem_getInt32(value->byteArr, &object->lowCreditThreshold); + } + else if (index == 17) + { + ret = cosem_getInt32(value->byteArr, &object->nextCreditAvailableThreshold); + } + else if (index == 18) + { + ret = cosem_getUInt16(value->byteArr, &object->maxProvision); + } + else if (index == 19) + { + ret = cosem_getInt32(value->byteArr, &object->maxProvisionPeriod); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_ACCOUNT +#ifndef DLMS_IGNORE_IMAGE_TRANSFER +int cosem_setImageTransfer(gxImageTransfer* object, unsigned char index, dlmsVARIANT* value) +{ + int pos, ret; + unsigned char ch; + gxImageActivateInfo* item; + if (index == 2) + { + ret = cosem_getUInt32(value->byteArr, &object->imageBlockSize); + } + else if (index == 3) + { + ret = cosem_getBitString(value->byteArr, &object->imageTransferredBlocksStatus); + } + else if (index == 4) + { + ret = cosem_getUInt32(value->byteArr, &object->imageFirstNotTransferredBlockNumber); + } + else if (index == 5) + { + ret = cosem_getBoolean(value->byteArr, &object->imageTransferEnabled); + } + else if (index == 6) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->imageTransferStatus = (DLMS_IMAGE_TRANSFER_STATUS)ch; + } + } + else if (index == 7) + { + arr_clear(&object->imageActivateInfo); + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->imageActivateInfo, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->imageActivateInfo, pos, (void**)&item, sizeof(gxImageActivateInfo))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 3)) != 0 || + (ret = cosem_getUInt32(value->byteArr, &item->size)) != 0 || +#ifdef DLMS_IGNORE_MALLOC + (ret = cosem_getOctetString2(value->byteArr, item->identification.data, sizeof(item->identification.data), &item->identification.size)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, item->signature.data, sizeof(item->signature.data), &item->signature.size)) != 0) +#else + (ret = cosem_getOctetString(value->byteArr, &item->identification)) != 0 || + (ret = cosem_getOctetString(value->byteArr, &item->signature)) != 0) +#endif //DLMS_IGNORE_MALLOC + { + break; + } + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_IMAGE_TRANSFER + +#if !(defined(DLMS_IGNORE_PROFILE_GENERIC) && defined(DLMS_IGNORE_COMPACT_DATA)) +int setCaptureObjects( + dlmsSettings* settings, + gxArray* objects, + dlmsVARIANT* value) +{ + gxTarget* co; + int pos, ret; + if ((ret = obj_clearProfileGenericCaptureObjects(objects)) != DLMS_ERROR_CODE_OK) + { + return ret; + } + uint16_t type; + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, objects, &count)) == 0) + { + unsigned char ln[6]; + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(objects, pos, (void**)&co, sizeof(gxTarget))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 4)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &type)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, ln, 6, NULL)) != 0 || + (ret = cosem_getInt8(value->byteArr, &co->attributeIndex)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &co->dataIndex)) != 0) + { + obj_clearProfileGenericCaptureObjects(objects); + break; + } + ret = cosem_findObjectByLN(settings, type, ln, &co->target); + if (ret != DLMS_ERROR_CODE_OK) + { + obj_clearProfileGenericCaptureObjects(objects); + break; + } + } + } + return ret; +} +#endif //!(defined(DLMS_IGNORE_PROFILE_GENERIC) && defined(DLMS_IGNORE_CONPACT_DATA)) + +#ifndef DLMS_IGNORE_PROFILE_GENERIC +int cosem_setProfileGeneric( + dlmsSettings* settings, + gxProfileGeneric* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret; + unsigned char ch; + DLMS_OBJECT_TYPE type; + if (index == 2) + { + return DLMS_ERROR_CODE_INVALID_PARAMETER; + } + else if (index == 3) + { + object->entriesInUse = 0; + ret = setCaptureObjects(settings, &object->captureObjects, value); + } + else if (index == 4) + { + ret = cosem_getUInt32(value->byteArr, &object->capturePeriod); + } + else if (index == 5) + { + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->sortMethod = (DLMS_SORT_METHOD)ch; + } + } + else if (index == 6) + { + if ((ret = cosem_checkStructure(value->byteArr, 4)) != 0) + { + unsigned char ln[6]; + type = 0; + object->sortObject = NULL; + if ((ret = cosem_getInt16(value->byteArr, (signed short*)&type)) == 0 && + (ret = cosem_getOctetString2(value->byteArr, ln, 6, NULL)) == 0 && + (ret = cosem_findObjectByLN(settings, type, ln, &object->sortObject)) == 0 && + (ret = cosem_getInt8(value->byteArr, &object->sortObjectAttributeIndex)) == 0 && + (ret = cosem_getUInt16(value->byteArr, &object->sortObjectDataIndex)) == 0) + { + } + } + } + else if (index == 7) + { + ret = cosem_getUInt32(value->byteArr, &object->entriesInUse); + } + else if (index == 8) + { + ret = cosem_getUInt32(value->byteArr, &object->profileEntries); + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_PROFILE_GENERIC +#ifndef DLMS_IGNORE_GSM_DIAGNOSTIC +int cosem_setGsmDiagnostic(gxGsmDiagnostic* object, unsigned char index, dlmsVARIANT* value) +{ + unsigned char ch; + int ret, pos; + gxAdjacentCell* ac; + switch (index) + { + case 2: + ret = cosem_getString(value->byteArr, &object->operatorName); + break; + case 3: + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->status = (DLMS_GSM_STATUS)ch; + } + break; + case 4: + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->circuitSwitchStatus = (DLMS_GSM_CIRCUIT_SWITCH_STATUS)ch; + } + break; + case 5: + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->packetSwitchStatus = (DLMS_GSM_PACKET_SWITCH_STATUS)ch; + } + break; + case 6: + { + unsigned char count; + if (object->base.version != 0) + { + count = 7; + } + else + { + count = 4; + } + if ((ret = cosem_checkStructure(value->byteArr, count)) == 0) + { + if ((ret = cosem_getUInt32(value->byteArr, &object->cellInfo.cellId)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &object->cellInfo.locationId)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &object->cellInfo.signalQuality)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &object->cellInfo.ber)) != 0) + { + break; + } + if (object->base.version != 0) + { + if ((ret = cosem_getUInt16(value->byteArr, &object->cellInfo.mobileCountryCode)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &object->cellInfo.mobileNetworkCode)) != 0 || + (ret = cosem_getUInt32(value->byteArr, &object->cellInfo.channelNumber)) != 0) + { + break; + } + } + } + } + break; + case 7: + arr_clear(&object->adjacentCells); + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->adjacentCells, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->adjacentCells, pos, (void**)&ac, sizeof(gxAdjacentCell))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getUInt32(value->byteArr, &ac->cellId)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &ac->signalQuality)) != 0) + { + break; + } + } + } + break; + case 8: + ret = cosem_getDateTime(value->byteArr, &object->captureTime); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_GSM_DIAGNOSTIC +#ifndef DLMS_IGNORE_TOKEN_GATEWAY +int cosem_setTokenGateway(gxTokenGateway* object, unsigned char index, dlmsVARIANT* value) +{ + int ret, pos; + unsigned char ch; + uint16_t count; +#ifdef DLMS_IGNORE_MALLOC + gxTokenGatewayDescription* it; +#else + gxByteBuffer* it; +#endif //DLMS_IGNORE_MALLOC + switch (index) + { + case 2: + ret = cosem_getOctetString(value->byteArr, &object->token); + break; + case 3: + ret = cosem_getDateTimeFromOctetString(value->byteArr, &object->time); + break; + case 4: + obj_clearByteBufferList(&object->descriptions); + if ((ret = cosem_verifyArray(value->byteArr, &object->descriptions, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->descriptions, pos, (void**)&it, sizeof(gxTokenGatewayDescription))) != 0 || + (ret = cosem_getOctetString2(value->byteArr, it->value, sizeof(it->value), &it->size)) != 0) + { + break; + } + } + } + break; + case 5: + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->deliveryMethod = (DLMS_TOKEN_DELIVERY)ch; + } + break; + case 6: + if ((ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getEnum(value->byteArr, (unsigned char*)&object->status)) != 0 || + (ret = cosem_getBitString(value->byteArr, &object->dataValue)) != 0) + { + //Result code is returned at the end of the method. + } + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_TOKEN_GATEWAY + +#ifndef DLMS_IGNORE_COMPACT_DATA + +int compactData_updateTemplateDescription( + dlmsSettings* settings, + gxCompactData* object) +{ + int ret, pos; + gxByteBuffer tmp; + gxValueEventCollection args; + gxValueEventArg e; + ve_init(&e); +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + gxTarget* kv; +#else + gxKey* kv; +#endif //DLMS_IGNORE_MALLOC + unsigned char tmp2[100]; + gxByteBuffer bb; + bb_attach(&bb, tmp2, 0, sizeof(tmp2)); + bb_clear(&object->buffer); + bb_clear(&object->templateDescription); + e.action = 1; + e.target = &object->base; + e.index = 2; + vec_init(&args); + BYTE_BUFFER_INIT(&tmp); + unsigned char tmp3[100]; + bb_attach(&tmp, tmp3, 0, sizeof(tmp3)); + if (!e.handled) + { + if ((ret = bb_setUInt8(&object->templateDescription, DLMS_DATA_TYPE_STRUCTURE)) != DLMS_ERROR_CODE_OK) + { + bb_clear(&object->buffer); + return ret; + } + hlp_setObjectCount(object->captureObjects.size, &object->templateDescription); + for (pos = 0; pos != object->captureObjects.size; ++pos) + { +#ifdef DLMS_IGNORE_MALLOC + if ((ret = arr_getByIndex2(&object->captureObjects, pos, (void**)&kv, sizeof(gxTarget))) != DLMS_ERROR_CODE_OK) + { + break; + } +#else + if ((ret = arr_getByIndex(&object->captureObjects, pos, (void**)&kv)) != DLMS_ERROR_CODE_OK) + { + break; + } +#endif //DLMS_IGNORE_MALLOC + e.value.byteArr = &bb; + e.value.vt = DLMS_DATA_TYPE_OCTET_STRING; + e.target = kv->target; + e.index = kv->attributeIndex; + if ((ret = cosem_getValue(settings, &e)) != 0) + { + break; + } + if (e.byteArray) + { + if (bb_size(e.value.byteArr) == 0) + { + bb_setUInt8(&object->templateDescription, 0); + } + else + { + unsigned char ch; + if ((ret = bb_getUInt8(e.value.byteArr, &ch)) != 0) + { + break; + } + if (ch == DLMS_DATA_TYPE_ARRAY || + ch == DLMS_DATA_TYPE_STRUCTURE) + { + gxDataInfo info; + dlmsVARIANT value; + uint16_t count; + di_init(&info); + var_init(&value); + if ((ret = hlp_getObjectCount2(e.value.byteArr, &count)) != 0 || + kv->dataIndex > count) + { + break; + } + //If all data is captured. + if (kv->dataIndex == 0) + { + uint16_t count2; + if ((ret = bb_setUInt8(&object->templateDescription, ch)) != 0) + { + break; + } + if (ch == DLMS_DATA_TYPE_ARRAY) + { + if ((ret = bb_setUInt16(&object->templateDescription, count)) != 0) + { + break; + } + } + else + { + if ((ret = bb_setUInt8(&object->templateDescription, (unsigned char)count)) != 0) + { + break; + } + } + for (unsigned char pos = 0; pos < count; ++pos) + { + di_init(&info); + var_clear(&value); + if ((ret = dlms_getData(e.value.byteArr, &info, &value)) != 0) + { + break; + } + if (info.type == DLMS_DATA_TYPE_STRUCTURE || info.type == DLMS_DATA_TYPE_ARRAY) + { + bb_setUInt8(&object->templateDescription, info.type); + ++value.byteArr->position; + if ((ret = hlp_getObjectCount2(value.byteArr, &count2)) != 0 || + (ret = hlp_setObjectCount(count2, &object->templateDescription)) != 0) + { + break; + } + for (uint16_t pos = 0; pos < count2; ++pos) + { + var_clear(&value); + if ((ret = dlms_getData(e.value.byteArr, &info, &value)) != 0 || + (ret = bb_setUInt8(&object->templateDescription, value.vt)) != 0) + { + var_clear(&value); + var_clear(&e.value); + bb_clear(&object->buffer); + return ret; + } + } + } + else + { + bb_setUInt8(&object->templateDescription, info.type); + } + if (e.value.byteArr->data[0] == DLMS_DATA_TYPE_ARRAY) + { + break; + } + } + } + else + { + for (unsigned char pos = 0; pos < kv->dataIndex; ++pos) + { + var_clear(&value); + di_init(&info); + if ((ret = dlms_getData(e.value.byteArr, &info, &value)) != 0) + { + var_clear(&value); + var_clear(&e.value); + bb_clear(&object->buffer); + return ret; + } + if (!info.complete) + { + return DLMS_ERROR_CODE_READ_WRITE_DENIED; + } + } + if (info.type == DLMS_DATA_TYPE_STRUCTURE) + { + dlmsVARIANT* value2; + bb_setUInt8(&object->templateDescription, DLMS_DATA_TYPE_STRUCTURE); + bb_setUInt8(&object->templateDescription, (unsigned char)value.Arr->size); + for (uint16_t pos = 0; pos < value.Arr->size; ++pos) + { + if ((ret = va_getByIndex(value.Arr, pos, &value2)) != 0) + { + var_clear(&value); + var_clear(&e.value); + bb_clear(&object->buffer); + return ret; + } + bb_setUInt8(&object->templateDescription, value2->vt); + } + } + else + { + bb_setUInt8(&object->templateDescription, info.type); + } + } + var_clear(&value); + } + else + { + bb_setUInt8(&object->templateDescription, ch); + } + } + } + else + { + if ((ret = dlms_setData(&tmp, e.value.vt, &e.value)) != 0) + { + var_clear(&e.value); + bb_clear(&tmp); + bb_clear(&object->buffer); + return ret; + } + bb_setUInt8(&object->templateDescription, tmp.data[0]); + bb_clear(&tmp); + } + var_clear(&e.value); + ve_clear(&e); + } + } + bb_clear(&tmp); + //svr_postGet(settings, &args); + vec_empty(&args); + return 0; +} + +int cosem_setCompactData( + dlmsSettings* settings, + gxCompactData* object, + unsigned char index, + dlmsVARIANT* value) +{ + unsigned char ch; + int ret; + switch (index) + { + case 2: + ret = cosem_getOctetString(value->byteArr, &object->buffer); + break; + case 3: + ret = setCaptureObjects(settings, &object->captureObjects, value); + if (ret == 0 && settings->server) + { + ret = compactData_updateTemplateDescription(settings, object); + } + break; + case 4: + ret = cosem_getUInt8(value->byteArr, &object->templateId); + break; + case 5: + ret = cosem_getOctetString(value->byteArr, &object->templateDescription); + break; + case 6: + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->captureMethod = (DLMS_CAPTURE_METHOD)ch; + } + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_COMPACT_DATA + +#ifndef DLMS_IGNORE_PARAMETER_MONITOR +int cosem_setParameterMonitor( + dlmsSettings* settings, + gxParameterMonitor* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret, pos; + switch (index) + { + case 2: + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + object->changedParameter.target = NULL; +#else + object->changedParameter.type = DLMS_OBJECT_TYPE_NONE; + memset(object->changedParameter.logicalName, 0, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; + uint16_t type; + if ((ret = cosem_checkStructure(value->byteArr, 4)) == 0 && + (ret = cosem_getUInt16(value->byteArr, &type)) == 0 && + (ret = cosem_getOctetString2(value->byteArr, ln, 6, NULL)) == 0 && + (ret = cosem_getInt8(value->byteArr, &object->changedParameter.attributeIndex)) == 0 && + (ret = cosem_getVariant(value->byteArr, &object->changedParameter.value)) == 0) + { +#ifndef DLMS_IGNORE_OBJECT_POINTERS + ret = cosem_findObjectByLN(settings, type, ln, &object->changedParameter.target); +#else + object->changedParameter.type = type; + memcpy(object->changedParameter.logicalName, ln, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + break; + } + case 3: + { + ret = cosem_getDateTimeFromOctetString(value->byteArr, &object->captureTime); + } + break; + case 4: + { + uint16_t type; +#ifndef DLMS_IGNORE_OBJECT_POINTERS + unsigned char ln[6]; +#endif //DLMS_IGNORE_OBJECT_POINTERS + gxTarget* it; + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->parameters, &count)) == 0) { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->parameters, pos, (void**)&it, sizeof(gxTarget))) != 0) + { + break; + } + if ((ret = cosem_checkStructure(value->byteArr, 3)) != 0 || + (ret = cosem_getUInt16(value->byteArr, (uint16_t*)&type)) != 0 || +#ifdef DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getOctetString2(value->byteArr, it->logicalName, 6, NULL)) != 0 || +#else + (ret = cosem_getOctetString2(value->byteArr, ln, 6, NULL)) != 0 || +#endif //DLMS_IGNORE_OBJECT_POINTERS + (ret = cosem_getInt8(value->byteArr, &it->attributeIndex)) != 0) + { + break; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = cosem_findObjectByLN(settings, type, ln, &it->target)) != 0) + { + break; + } +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + } + break; + } + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_PARAMETER_MONITOR + +#ifndef DLMS_IGNORE_LLC_SSCS_SETUP +int cosem_setLlcSscsSetup( + dlmsSettings* settings, + gxLlcSscsSetup* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret; + switch (index) + { + case 2: + ret = cosem_getUInt16(value->byteArr, &object->serviceNodeAddress); + break; + case 3: + ret = cosem_getUInt16(value->byteArr, &object->baseNodeAddress); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_LLC_SSCS_SETUP + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS +int cosem_setPrimeNbOfdmPlcPhysicalLayerCounters( + dlmsSettings* settings, + gxPrimeNbOfdmPlcPhysicalLayerCounters* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret; + switch (index) + { + case 2: + ret = cosem_getUInt16(value->byteArr, &object->crcIncorrectCount); + break; + case 3: + ret = cosem_getUInt16(value->byteArr, &object->crcFailedCount); + break; + case 4: + ret = cosem_getUInt16(value->byteArr, &object->txDropCount); + break; + case 5: + ret = cosem_getUInt16(value->byteArr, &object->rxDropCount); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} + +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +int cosem_setPrimeNbOfdmPlcMacSetup( + dlmsSettings* settings, + gxPrimeNbOfdmPlcMacSetup* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret; + switch (index) + { + case 2: + ret = cosem_getUInt8(value->byteArr, &object->macMinSwitchSearchTime); + break; + case 3: + ret = cosem_getUInt8(value->byteArr, &object->macMaxPromotionPdu); + break; + case 4: + ret = cosem_getUInt8(value->byteArr, &object->macPromotionPduTxPeriod); + break; + case 5: + ret = cosem_getUInt8(value->byteArr, &object->macBeaconsPerFrame); + break; + case 6: + ret = cosem_getUInt8(value->byteArr, &object->macScpMaxTxAttempts); + break; + case 7: + ret = cosem_getUInt8(value->byteArr, &object->macCtlReTxTimer); + break; + case 8: + ret = cosem_getUInt8(value->byteArr, &object->macMaxCtlReTx); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} + +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +int cosem_setPrimeNbOfdmPlcMacFunctionalParameters( + dlmsSettings* settings, + gxPrimeNbOfdmPlcMacFunctionalParameters* object, + unsigned char index, + dlmsVARIANT* value) +{ + unsigned char ch; + uint16_t v; + int ret; + switch (index) + { + case 2: + ret = cosem_getInt16(value->byteArr, &object->lnId); + break; + case 3: + ret = cosem_getUInt8(value->byteArr, &object->lsId); + break; + case 4: + ret = cosem_getUInt8(value->byteArr, &object->sId); + break; + case 5: + ret = cosem_getOctetString(value->byteArr, &object->sna); + break; + case 6: + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->state = (DLMS_MAC_STATE)ch; + } + break; + case 7: + ret = cosem_getInt16(value->byteArr, &object->scpLength); + break; + case 8: + ret = cosem_getUInt8(value->byteArr, &object->nodeHierarchyLevel); + break; + case 9: + ret = cosem_getUInt8(value->byteArr, &object->beaconSlotCount); + break; + case 10: + ret = cosem_getUInt8(value->byteArr, &object->beaconRxSlot); + break; + case 11: + ret = cosem_getUInt8(value->byteArr, &object->beaconTxSlot); + break; + case 12: + ret = cosem_getUInt8(value->byteArr, &object->beaconRxFrequency); + break; + case 13: + ret = cosem_getUInt8(value->byteArr, &object->beaconTxFrequency); + break; + case 14: + if ((ret = cosem_getUInt16(value->byteArr, &v)) == 0) + { + object->capabilities = (DLMS_MAC_CAPABILITIES)v; + } + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +int cosem_setPrimeNbOfdmPlcMacCounters( + dlmsSettings* settings, + gxPrimeNbOfdmPlcMacCounters* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret; + switch (index) + { + case 2: + ret = cosem_getUInt32(value->byteArr, &object->txDataPktCount); + break; + case 3: + ret = cosem_getUInt32(value->byteArr, &object->rxDataPktCount); + break; + case 4: + ret = cosem_getUInt32(value->byteArr, &object->txCtrlPktCount); + break; + case 5: + ret = cosem_getUInt32(value->byteArr, &object->rxCtrlPktCount); + break; + case 6: + ret = cosem_getUInt32(value->byteArr, &object->csmaFailCount); + break; + case 7: + ret = cosem_getUInt32(value->byteArr, &object->csmaChBusyCount); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + +int cosem_setMulticastEntries(gxPrimeNbOfdmPlcMacNetworkAdministrationData* object, dlmsVARIANT* value) +{ + int ret; + int pos; + gxMacMulticastEntry* it; + arr_clear(&object->multicastEntries); + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->multicastEntries, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->multicastEntries, pos, (void**)&it, sizeof(gxMacMulticastEntry))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getInt8(value->byteArr, &it->id)) != 0 || + (ret = cosem_getInt16(value->byteArr, &it->members)) != 0) + { + break; + } + } + } + return 0; +} + + +int cosem_setSwitchTable(gxPrimeNbOfdmPlcMacNetworkAdministrationData* object, dlmsVARIANT* value) +{ + int ret; + int pos; + arr_empty(&object->switchTable); + short* it; + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->switchTable, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->switchTable, pos, (void**)&it, sizeof(short))) != 0 || + (ret = cosem_getInt16(value->byteArr, it)) != 0) + { + break; + } + } + } + return 0; +} + +int cosem_setDirectTable(gxPrimeNbOfdmPlcMacNetworkAdministrationData* object, dlmsVARIANT* value) +{ + int ret; + int pos; + gxMacDirectTable* it; + arr_clear(&object->directTable); + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->directTable, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->directTable, pos, (void**)&it, sizeof(gxMacDirectTable))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 7)) != 0 || + (ret = cosem_getInt16(value->byteArr, &it->sourceSId)) != 0 || + (ret = cosem_getInt16(value->byteArr, &it->sourceLnId)) != 0 || + (ret = cosem_getInt16(value->byteArr, &it->sourceLcId)) != 0 || + (ret = cosem_getInt16(value->byteArr, &it->destinationSId)) != 0 || + (ret = cosem_getInt16(value->byteArr, &it->destinationLnId)) != 0 || + (ret = cosem_getInt16(value->byteArr, &it->destinationLcId)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, it->did, sizeof(it->did), NULL)) != 0) + { + break; + } + } + } + return 0; +} + +int cosem_setAvailableSwitches(gxPrimeNbOfdmPlcMacNetworkAdministrationData* object, dlmsVARIANT* value) +{ + int ret; + int pos; + gxMacAvailableSwitch* it; + obj_clearAvailableSwitches(&object->availableSwitches); + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->availableSwitches, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->availableSwitches, pos, (void**)&it, sizeof(gxMacAvailableSwitch))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 5)) != 0 || + (ret = cosem_getOctetString(value->byteArr, &it->sna)) != 0 || + (ret = cosem_getInt16(value->byteArr, &it->lsId)) != 0 || + (ret = cosem_getInt8(value->byteArr, &it->level)) != 0 || + (ret = cosem_getInt8(value->byteArr, &it->rxLevel)) != 0 || + (ret = cosem_getInt8(value->byteArr, &it->rxSnr)) != 0) + { + break; + } + } + } + return 0; +} + +int cosem_setCommunications(gxPrimeNbOfdmPlcMacNetworkAdministrationData* object, dlmsVARIANT* value) +{ + int ret; + int pos; + gxMacPhyCommunication* it; + arr_clear(&object->communications); + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->communications, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->communications, pos, (void**)&it, sizeof(gxMacPhyCommunication))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 9)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, it->eui, sizeof(it->eui), NULL)) != 0 || + (ret = cosem_getInt8(value->byteArr, &it->txPower)) != 0 || + (ret = cosem_getInt8(value->byteArr, &it->txCoding)) != 0 || + (ret = cosem_getInt8(value->byteArr, &it->rxCoding)) != 0 || + (ret = cosem_getInt8(value->byteArr, &it->rxLvl)) != 0 || + (ret = cosem_getInt8(value->byteArr, &it->snr)) != 0 || + (ret = cosem_getInt8(value->byteArr, &it->txPowerModified)) != 0 || + (ret = cosem_getInt8(value->byteArr, &it->txCodingModified)) != 0 || + (ret = cosem_getInt8(value->byteArr, &it->rxCodingModified)) != 0) + { + break; + } + } + } + return 0; +} + +int cosem_setPrimeNbOfdmPlcMacNetworkAdministrationData( + dlmsSettings* settings, + gxPrimeNbOfdmPlcMacNetworkAdministrationData* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret; + switch (index) + { + case 2: + ret = cosem_setMulticastEntries(object, value); + break; + case 3: + ret = cosem_setSwitchTable(object, value); + break; + case 4: + ret = cosem_setDirectTable(object, value); + break; + case 5: + ret = cosem_setAvailableSwitches(object, value); + break; + case 6: + ret = cosem_setCommunications(object, value); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} + +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION +int cosem_setPrimeNbOfdmPlcApplicationsIdentification( + dlmsSettings* settings, + gxPrimeNbOfdmPlcApplicationsIdentification* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret; + switch (index) + { + case 2: + ret = cosem_getOctetString(value->byteArr, &object->firmwareVersion); + break; + case 3: + ret = cosem_getUInt16(value->byteArr, &object->vendorId); + break; + case 4: + ret = cosem_getUInt16(value->byteArr, &object->productId); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION + +#ifndef DLMS_IGNORE_ARBITRATOR +int cosem_setArbitrator( + dlmsSettings* settings, + gxArbitrator* object, + unsigned char index, + dlmsVARIANT* value) +{ + int pos, ret; + gxActionItem* it; + bitArray* ba; + switch (index) + { + case 2: + { + arr_clear(&object->actions); + unsigned char ln[6]; + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->actions, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->actions, pos, (void**)&it, sizeof(gxActionItem))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getOctetString2(value->byteArr, ln, 6, NULL)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &it->scriptSelector)) != 0) + { + break; + } +#ifndef DLMS_IGNORE_OBJECT_POINTERS + if ((ret = cosem_findObjectByLN(settings, DLMS_OBJECT_TYPE_SCRIPT_TABLE, ln, (gxObject**)&it->script)) != 0) + { + break; + } +#else + memcpy(it->scriptLogicalName, ln, 6); +#endif //DLMS_IGNORE_OBJECT_POINTERS + } + } + } + break; + case 3: + { + obj_clearBitArrayList(&object->permissionsTable); + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->permissionsTable, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->permissionsTable, pos, (void**)&ba, sizeof(bitArray))) != 0 || + (ret = cosem_getBitString(value->byteArr, ba)) != 0) + { + break; + } + } + } + } + break; + case 4: + { + ret = 0; + arr_clear(&object->weightingsTable); + } + break; + case 5: + { + obj_clearBitArrayList(&object->mostRecentRequestsTable); + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->mostRecentRequestsTable, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->mostRecentRequestsTable, pos, (void**)&it, sizeof(bitArray))) != 0 || + (ret = cosem_getBitString(value->byteArr, ba)) != 0) + { + break; + } + } + } + } + break; + case 6: + ret = cosem_getUInt8(value->byteArr, &object->lastOutcome); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; + } +#endif //DLMS_IGNORE_ARBITRATOR +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +int cosem_setIec8802LlcType1Setup( + dlmsSettings* settings, + gxIec8802LlcType1Setup* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret; + switch (index) + { + case 2: + ret = cosem_getUInt16(value->byteArr, &object->maximumOctetsUiPdu); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP +int cosem_setIec8802LlcType2Setup( + dlmsSettings* settings, + gxIec8802LlcType2Setup* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret; + switch (index) + { + case 2: + ret = cosem_getUInt8(value->byteArr, &object->transmitWindowSizeK); + break; + case 3: + ret = cosem_getUInt8(value->byteArr, &object->transmitWindowSizeRW); + break; + case 4: + ret = cosem_getUInt16(value->byteArr, &object->maximumOctetsPdu); + break; + case 5: + ret = cosem_getUInt8(value->byteArr, &object->maximumNumberTransmissions); + break; + case 6: + ret = cosem_getUInt16(value->byteArr, &object->acknowledgementTimer); + break; + case 7: + ret = cosem_getUInt16(value->byteArr, &object->bitTimer); + break; + case 8: + ret = cosem_getUInt16(value->byteArr, &object->rejectTimer); + break; + case 9: + ret = cosem_getUInt16(value->byteArr, &object->busyStateTimer); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP +int cosem_setIec8802LlcType3Setup( + dlmsSettings* settings, + gxIec8802LlcType3Setup* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret; + switch (index) + { + case 2: + ret = cosem_getUInt16(value->byteArr, &object->maximumOctetsACnPdu); + break; + case 3: + ret = cosem_getUInt8(value->byteArr, &object->maximumTransmissions); + break; + case 4: + ret = cosem_getUInt16(value->byteArr, &object->acknowledgementTime); + break; + case 5: + ret = cosem_getUInt16(value->byteArr, &object->receiveLifetime); + break; + case 6: + ret = cosem_getUInt16(value->byteArr, &object->transmitLifetime); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP +#ifndef DLMS_IGNORE_SFSK_ACTIVE_INITIATOR +int cosem_setSFSKActiveInitiator( + dlmsSettings* settings, + gxSFSKActiveInitiator* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret; + switch (index) + { + case 2: + if ((ret = cosem_checkStructure(value->byteArr, 3)) != 0 || + (ret = cosem_getOctetString(value->byteArr, &object->systemTitle)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &object->macAddress)) != 0 || + (ret = cosem_getUInt8(value->byteArr, &object->lSapSelector)) != 0) + { + } + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SFSK_ACTIVE_INITIATOR +#ifndef DLMS_IGNORE_SFSK_MAC_COUNTERS +int cosem_setFSKMacCounters( + dlmsSettings* settings, + gxFSKMacCounters* object, + unsigned char index, + dlmsVARIANT* value) +{ + int pos, ret; + gxUint16PairUint32* it; + switch (index) + { + case 2: + { + arr_clear(&object->synchronizationRegister); + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->synchronizationRegister, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->synchronizationRegister, pos, (void**)&it, sizeof(gxUint16PairUint32))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &it->first)) != 0 || + (ret = cosem_getUInt32(value->byteArr, &it->second)) != 0) + { + break; + } + } + } + } + break; + case 3: + { + if ((ret = cosem_checkStructure(value->byteArr, 5)) != 0 || + (ret = cosem_getUInt32(value->byteArr, &object->physicalLayerDesynchronization)) != 0 || + (ret = cosem_getUInt32(value->byteArr, &object->timeOutNotAddressedDesynchronization)) != 0 || + (ret = cosem_getUInt32(value->byteArr, &object->timeOutFrameNotOkDesynchronization)) != 0 || + (ret = cosem_getUInt32(value->byteArr, &object->writeRequestDesynchronization)) != 0 || + (ret = cosem_getUInt32(value->byteArr, &object->wrongInitiatorDesynchronization)) != 0) + { + object->physicalLayerDesynchronization = 0; + object->timeOutNotAddressedDesynchronization = 0; + object->timeOutFrameNotOkDesynchronization = 0; + object->writeRequestDesynchronization = 0; + object->wrongInitiatorDesynchronization = 0; + break; + } + } + break; + case 4: + { + arr_clear(&object->broadcastFramesCounter); + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->broadcastFramesCounter, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->broadcastFramesCounter, pos, (void**)&it, sizeof(gxUint16PairUint32))) != 0 || + (ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getUInt16(value->byteArr, &it->first)) != 0 || + (ret = cosem_getUInt32(value->byteArr, &it->second)) != 0) + { + break; + } + } + } + } + break; + case 5: + ret = cosem_getUInt32(value->byteArr, &object->repetitionsCounter); + break; + case 6: + ret = cosem_getUInt32(value->byteArr, &object->transmissionsCounter); + break; + case 7: + ret = cosem_getUInt32(value->byteArr, &object->crcOkFramesCounter); + break; + case 8: + ret = cosem_getUInt32(value->byteArr, &object->crcNOkFramesCounter); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_SFSK_MAC_COUNTERS +#ifndef DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS +int cosem_setSFSKMacSynchronizationTimeouts( + dlmsSettings* settings, + gxSFSKMacSynchronizationTimeouts* object, + unsigned char index, + dlmsVARIANT* value) +{ + int ret; + switch (index) + { + case 2: + ret = cosem_getUInt16(value->byteArr, &object->searchInitiatorTimeout); + break; + case 3: + ret = cosem_getUInt16(value->byteArr, &object->synchronizationConfirmationTimeout); + break; + case 4: + ret = cosem_getUInt16(value->byteArr, &object->timeOutNotAddressed); + break; + case 5: + ret = cosem_getUInt16(value->byteArr, &object->timeOutFrameNotOK); + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS +#ifndef DLMS_IGNORE_SFSK_PHY_MAC_SETUP +int cosem_setSFSKPhyMacSetUp( + dlmsSettings* settings, + gxSFSKPhyMacSetUp* object, + unsigned char index, + dlmsVARIANT* value) +{ + unsigned char ch; + int pos, ret; + switch (index) + { + case 2: + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->initiatorElectricalPhase = (DLMS_INITIATOR_ELECTRICAL_PHASE)ch; + } + break; + case 3: + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->deltaElectricalPhase = (DLMS_DELTA_ELECTRICAL_PHASE)ch; + } + break; + case 4: + ret = cosem_getUInt8(value->byteArr, &object->maxReceivingGain); + break; + case 5: + ret = cosem_getUInt8(value->byteArr, &object->maxTransmittingGain); + break; + case 6: + ret = cosem_getUInt8(value->byteArr, &object->searchInitiatorThreshold); + break; + case 7: + { + if ((ret = cosem_checkStructure(value->byteArr, 2)) != 0 || + (ret = cosem_getUInt32(value->byteArr, &object->markFrequency)) != 0 || + (ret = cosem_getUInt32(value->byteArr, &object->spaceFrequency)) != 0) + { + object->markFrequency = 0; + object->spaceFrequency = 0; + } + break; + } + case 8: + ret = cosem_getUInt16(value->byteArr, &object->macAddress); + break; + case 9: + { + arr_clear(&object->macGroupAddresses); + uint16_t* v; + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->macGroupAddresses, &count)) == 0) + { + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->macGroupAddresses, pos, (void**)&v, sizeof(uint16_t))) != 0 || + (ret = cosem_getUInt16(value->byteArr, v)) != 0) + { + break; + } + } + } + break; + } + case 10: + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->repeater = (DLMS_REPEATER)ch; + } + break; + case 11: + ret = cosem_getBoolean(value->byteArr, &object->repeaterStatus); + break; + case 12: + ret = cosem_getUInt8(value->byteArr, &object->minDeltaCredit); + break; + case 13: + ret = cosem_getUInt16(value->byteArr, &object->initiatorMacAddress); + break; + case 14: + ret = cosem_getBoolean(value->byteArr, &object->synchronizationLocked); + break; + case 15: + if ((ret = cosem_getEnum(value->byteArr, &ch)) == 0) + { + object->transmissionSpeed = (DLMS_BAUD_RATE)ch; + } + break; + default: + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + break; + } + return ret; +} +#endif //DLMS_IGNORE_SFSK_PHY_MAC_SETUP + +#ifndef DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST +int cosem_setSFSKReportingSystemList( + dlmsSettings* settings, + gxSFSKReportingSystemList* object, + unsigned char index, + dlmsVARIANT* value) +{ + int pos, ret; + if (index == 2) + { + obj_clearByteBufferList(&object->reportingSystemList); + uint16_t count; + if ((ret = cosem_verifyArray(value->byteArr, &object->reportingSystemList, &count)) == 0) + { + gxReportingSystemItem* v; + for (pos = 0; pos != count; ++pos) + { + if ((ret = cosem_getArrayItem(&object->reportingSystemList, pos, (void**)&v, sizeof(gxReportingSystemItem))) != 0 || + (ret = cosem_getOctetString2(value->byteArr, v->name, sizeof(v->name), &v->size)) != 0) + { + break; + } + } + } + } + else + { + ret = DLMS_ERROR_CODE_INVALID_PARAMETER; + } + return ret; +} +#endif //DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST + +#ifdef DLMS_ITALIAN_STANDARD +int updateIntervals(gxInterval* interval, gxByteBuffer* value) +{ + int ret; + unsigned char b; + if ((ret = bb_getUInt8(value, &b)) != 0) + { + return ret; + } + interval[0].startHour = (unsigned char)(b >> 3); + interval[0].intervalTariff = (DLMS_DEFAULT_TARIFF_BAND)((b >> 1) & 0x3); + interval[0].useInterval = (b & 0x1) != 0; + if ((ret = bb_getUInt8(value, &b)) != 0) + { + return ret; + } + interval[1].startHour = (unsigned char)(b >> 3); + interval[1].intervalTariff = (DLMS_DEFAULT_TARIFF_BAND)((b >> 1) & 0x3); + interval[1].useInterval = (b & 0x1) != 0; + if ((ret = bb_getUInt8(value, &b)) != 0) + { + return ret; + } + interval[2].startHour = (unsigned char)(b >> 3); + interval[2].intervalTariff = (DLMS_DEFAULT_TARIFF_BAND)((b >> 1) & 0x3); + interval[2].useInterval = (b & 0x1) != 0; + if ((ret = bb_getUInt8(value, &b)) != 0) + { + return ret; + } + interval[3].startHour = (unsigned char)(b >> 3); + interval[3].intervalTariff = (DLMS_DEFAULT_TARIFF_BAND)((b >> 1) & 0x3); + interval[3].useInterval = (b & 0x1) != 0; + if ((ret = bb_getUInt8(value, &b)) != 0) + { + return ret; + } + interval[4].startHour = (unsigned char)(b >> 3); + interval[4].intervalTariff = (DLMS_DEFAULT_TARIFF_BAND)((b >> 1) & 0x3); + interval[4].useInterval = (b & 0x1) != 0; + return 0; +} + +int updateSeason(gxBandDescriptor* season, variantArray* value) +{ + int ret; + dlmsVARIANT* tmp; + if (value->size == 5) + { + if ((ret = va_getByIndex(value, 0, &tmp)) != 0) + { + return ret; + } + season->dayOfMonth = tmp->bVal; + if ((ret = va_getByIndex(value, 1, &tmp)) != 0) + { + return ret; + } + season->month = tmp->bVal; + if ((ret = va_getByIndex(value, 2, &tmp)) != 0 || + (ret = updateIntervals(season->workingDayIntervals, tmp->byteArr)) != 0 || + (ret = va_getByIndex(value, 3, &tmp)) != 0 || + (ret = updateIntervals(season->saturdayIntervals, tmp->byteArr)) != 0 || + (ret = va_getByIndex(value, 4, &tmp)) != 0 || + (ret = updateIntervals(season->holidayIntervals, tmp->byteArr)) != 0) + { + return ret; + } + } + else + { + ret = DLMS_ERROR_CODE_UNMATCH_TYPE; + } + return ret; +} + +int cosem_setTariffPlan(gxTariffPlan* object, unsigned char index, dlmsVARIANT* value) +{ + dlmsVARIANT tmp3; + dlmsVARIANT* tmp, * tmp2; + int ret, pos, h, m, s; + switch (index) + { + case 2: + if (value->vt == DLMS_DATA_TYPE_OCTET_STRING) + { + object->calendarName = (char*)gxmalloc(value->byteArr->size); + memcpy(object->calendarName, value->byteArr->data, value->byteArr->size); + object->calendarName[value->byteArr->size] = 0; + } + else + { + object->calendarName = (char*)gxmalloc(value->strVal->size + 1); + memcpy(object->calendarName, value->strVal->data, value->strVal->size); + object->calendarName[value->strVal->size] = 0; + } + break; + case 3: + object->enabled = value->boolVal; + break; + case 4: + { + if (value->Arr->size == 4) + { + if ((ret = va_getByIndex(value->Arr, 0, &tmp)) != 0) + { + return ret; + } + object->plan.defaultTariffBand = tmp->bVal; + if ((ret = va_getByIndex(value->Arr, 1, &tmp)) != 0) + { + return ret; + } + if ((ret = va_getByIndex(tmp->Arr, 0, &tmp2)) != 0 || + (ret = updateSeason(&object->plan.winterSeason, tmp2->Arr)) != 0 || + (ret = va_getByIndex(tmp->Arr, 1, &tmp2)) != 0 || + (ret = updateSeason(&object->plan.summerSeason, tmp2->Arr)) != 0) + { + return ret; + } + ba_clear(&object->plan.weeklyActivation); + if ((ret = va_getByIndex(value->Arr, 2, &tmp)) != 0 || + (ret = ba_copy(&object->plan.weeklyActivation, tmp->bitArr->data, tmp->bitArr->size)) != 0) + { + return ret; + } + if ((ret = va_getByIndex(value->Arr, 3, &tmp)) != 0) + { + return ret; + } + arr_clear(&object->plan.specialDays); + arr_capacity(&object->plan.specialDays, tmp->Arr->size); + for (pos = 0; pos != tmp->Arr->size; ++pos) + { + if ((ret = va_getByIndex(tmp->Arr, pos, &tmp2)) != 0) + { + return ret; + } + arr_push(&object->plan.specialDays, (void*)tmp2->ulVal); + } + } + break; + } + case 5: + { + if ((ret = va_getByIndex(value->Arr, 0, &tmp)) != 0) + { + return ret; + } + var_init(&tmp3); + if ((ret = dlms_changeType2(tmp, DLMS_DATA_TYPE_TIME, &tmp3)) != 0) + { + return ret; + } + if ((tmp3.dateTime->skip & DATETIME_SKIPS_HOUR) == 0) + { + h = time_getHours(tmp3.dateTime); + } + else + { + h = 0; + } + if ((tmp3.dateTime->skip & DATETIME_SKIPS_MINUTE) == 0) + { + m = time_getMinutes(tmp3.dateTime); + } + else + { + m = 0; + } + if ((tmp3.dateTime->skip & DATETIME_SKIPS_SECOND) == 0) + { + s = time_getSeconds(tmp3.dateTime); + } + else + { + s = 0; + } + if ((ret = va_getByIndex(value->Arr, 1, &tmp2)) != 0) + { + return ret; + } + var_clear(&tmp3); + if ((ret = dlms_changeType2(tmp2, DLMS_DATA_TYPE_DATE, &tmp3)) != 0) + { + return ret; + } + time_copy(&object->activationTime, tmp3.dateTime); + object->activationTime.skip &= ~(DATETIME_SKIPS_HOUR | DATETIME_SKIPS_MINUTE | DATETIME_SKIPS_SECOND | DATETIME_SKIPS_MS); + time_addHours(&object->activationTime, h); + time_addMinutes(&object->activationTime, m); + time_addSeconds(&object->activationTime, s); + } + break; + default: + return DLMS_ERROR_CODE_READ_WRITE_DENIED; + } + return DLMS_ERROR_CODE_OK; +} +#endif //DLMS_ITALIAN_STANDARD + +#endif //defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) diff --git a/components/xt211/unused/gxsetignoremalloc.h b/components/xt211/unused/gxsetignoremalloc.h new file mode 100644 index 0000000..0293cce --- /dev/null +++ b/components/xt211/unused/gxsetignoremalloc.h @@ -0,0 +1,388 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef COSEM_SET_IGNORE_MALLOC_H +#define COSEM_SET_IGNORE_MALLOC_H + +#include "gxignore.h" +#if defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) + +#ifdef __cplusplus +extern "C" { +#endif + +#include "gxobjects.h" +#include "dlmssettings.h" + +#ifndef DLMS_IGNORE_DATA + int cosem_setData(gxValueEventArg* e); +#endif //DLMS_IGNORE_DATA + +#ifndef DLMS_IGNORE_REGISTER + int cosem_setRegister(gxRegister* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_REGISTER + +#ifndef DLMS_IGNORE_CLOCK + int cosem_setClock(dlmsSettings* settings, gxClock* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_CLOCK + +#ifndef DLMS_IGNORE_ACTION_SCHEDULE + int cosem_setActionSchedule(dlmsSettings* settings, gxActionSchedule* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_ACTION_SCHEDULE + +#ifndef DLMS_IGNORE_ACTIVITY_CALENDAR + int cosem_setActivityCalendar(dlmsSettings* settings, gxActivityCalendar* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_ACTIVITY_CALENDAR + +#ifndef DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + int cosem_parseLNObjects(dlmsSettings* settings, gxByteBuffer* data, objectArray* objects); + int cosem_setAssociationLogicalName(dlmsSettings* settings, gxAssociationLogicalName* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_ASSOCIATION_LOGICAL_NAME + +#ifndef DLMS_IGNORE_ASSOCIATION_SHORT_NAME + int cosem_parseSNObjects(dlmsSettings* settings, gxByteBuffer* data, objectArray* objects); + int cosem_setAssociationShortName(dlmsSettings* settings, gxAssociationShortName* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_ASSOCIATION_SHORT_NAME + +#ifndef DLMS_IGNORE_AUTO_ANSWER + int cosem_setAutoAnswer(gxAutoAnswer* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_AUTO_ANSWER + +#ifndef DLMS_IGNORE_AUTO_CONNECT + int cosem_setAutoConnect(gxAutoConnect* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_AUTO_CONNECT + +#ifndef DLMS_IGNORE_DEMAND_REGISTER + int cosem_setDemandRegister(gxDemandRegister* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_DEMAND_REGISTER + +#ifndef DLMS_IGNORE_MAC_ADDRESS_SETUP + int cosem_setMacAddressSetup(gxMacAddressSetup* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_MAC_ADDRESS_SETUP + +#ifndef DLMS_IGNORE_EXTENDED_REGISTER + int cosem_setExtendedRegister(gxExtendedRegister* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_EXTENDED_REGISTER + +#ifndef DLMS_IGNORE_GPRS_SETUP + int cosem_setGprsSetup(gxGPRSSetup* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_GPRS_SETUP + +#ifndef DLMS_IGNORE_SECURITY_SETUP + int cosem_setSecuritySetup(dlmsSettings* settings, gxSecuritySetup* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_SECURITY_SETUP + +#ifndef DLMS_IGNORE_IEC_HDLC_SETUP + int cosem_setIecHdlcSetup(gxIecHdlcSetup* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_IEC_HDLC_SETUP + +#ifndef DLMS_IGNORE_IEC_LOCAL_PORT_SETUP + int cosem_setIecLocalPortSetup(gxLocalPortSetup* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_IEC_LOCAL_PORT_SETUP + +#ifndef DLMS_IGNORE_IP4_SETUP + int cosem_setIP4Setup(dlmsSettings* settings, gxIp4Setup* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_IP4_SETUP + +#ifndef DLMS_IGNORE_PROFILE_GENERIC + int cosem_setProfileGeneric(dlmsSettings* settings, gxProfileGeneric* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_PROFILE_GENERIC + +#ifndef DLMS_IGNORE_UTILITY_TABLES + int cosem_setUtilityTables(gxUtilityTables* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_UTILITY_TABLES + +#ifndef DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP + int cosem_setMbusSlavePortSetup(gxMbusSlavePortSetup* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_MBUS_SLAVE_PORT_SETUP + +#ifndef DLMS_IGNORE_DISCONNECT_CONTROL + int cosem_setDisconnectControl(gxDisconnectControl* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_DISCONNECT_CONTROL + +#ifndef DLMS_IGNORE_LIMITER + int cosem_setLimiter(dlmsSettings* settings, gxLimiter* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_LIMITER + +#ifndef DLMS_IGNORE_MBUS_CLIENT + int cosem_setmMbusClient(dlmsSettings* settings, gxMBusClient* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_MBUS_CLIENT + +#ifndef DLMS_IGNORE_MODEM_CONFIGURATION + int cosem_setModemConfiguration(gxModemConfiguration* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_MODEM_CONFIGURATION + +#ifndef DLMS_IGNORE_PPP_SETUP + int cosem_setPppSetup(dlmsSettings* settings, gxPppSetup* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_PPP_SETUP + +#ifndef DLMS_IGNORE_REGISTER_ACTIVATION + int cosem_setRegisterActivation(dlmsSettings* settings, gxValueEventArg* e); +#endif //DLMS_IGNORE_REGISTER_ACTIVATION + +#ifndef DLMS_IGNORE_REGISTER_MONITOR + int cosem_setRegisterMonitor(dlmsSettings* settings, gxRegisterMonitor* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_REGISTER_MONITOR + +#ifndef DLMS_IGNORE_SAP_ASSIGNMENT + int cosem_setSapAssignment(gxSapAssignment* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_SAP_ASSIGNMENT + +#ifndef DLMS_IGNORE_SCHEDULE + int cosem_setSchedule(dlmsSettings* settings, gxSchedule* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_SCHEDULE + +#ifndef DLMS_IGNORE_SCRIPT_TABLE + int cosem_setScriptTable(dlmsSettings* settings, gxScriptTable* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_SCRIPT_TABLE + +#ifndef DLMS_IGNORE_SPECIAL_DAYS_TABLE + int cosem_setSpecialDaysTable(gxSpecialDaysTable* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_SPECIAL_DAYS_TABLE + +#ifndef DLMS_IGNORE_TCP_UDP_SETUP + int cosem_setTcpUdpSetup(dlmsSettings* settings, gxTcpUdpSetup* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_TCP_UDP_SETUP +#ifndef DLMS_IGNORE_MBUS_DIAGNOSTIC + int cosem_setMbusDiagnostic(gxMbusDiagnostic* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_MBUS_DIAGNOSTIC +#ifndef DLMS_IGNORE_MBUS_PORT_SETUP + int cosem_setMbusPortSetup(gxMBusPortSetup* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_MBUS_PORT_SETUP +#ifndef DLMS_IGNORE_MBUS_MASTER_PORT_SETUP + int cosem_setMbusMasterPortSetup(gxMBusMasterPortSetup* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_MBUS_MASTER_PORT_SETUP + +#ifndef DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS + int cosem_setG3PlcMacLayerCounters(gxG3PlcMacLayerCounters* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_G3_PLC_MAC_LAYER_COUNTERS +#ifndef DLMS_IGNORE_G3_PLC_MAC_SETUP + int cosem_setG3PlcMacSetup(gxG3PlcMacSetup* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_G3_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_G3_PLC_6LO_WPAN + int cosem_setG3Plc6LoWPAN(gxG3Plc6LoWPAN* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_G3_PLC_6LO_WPAN +#ifndef DLMS_IGNORE_FUNCTION_CONTROL + int cosem_setFunctionControl( + dlmsSettings* settings, + gxFunctionControl* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_FUNCTION_CONTROL +#ifndef DLMS_IGNORE_ARRAY_MANAGER + int cosem_setArrayManager(dlmsSettings* settings, gxArrayManager* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_ARRAY_MANAGER +#ifndef DLMS_IGNORE_PUSH_SETUP + int cosem_setPushSetup(dlmsSettings* settings, gxPushSetup* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_PUSH_SETUP + +#ifndef DLMS_IGNORE_GSM_DIAGNOSTIC + int cosem_setGsmDiagnostic(gxGsmDiagnostic* object, unsigned char index, dlmsVARIANT *value); +#endif //DLMS_IGNORE_GSM_DIAGNOSTIC + +#ifndef DLMS_IGNORE_COMPACT_DATA + int compactData_updateTemplateDescription( + dlmsSettings* settings, + gxCompactData* object); +#endif //DLMS_IGNORE_COMPACT_DATA + +#ifndef DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP + int cosem_setIecTwistedPairSetup(gxIecTwistedPairSetup* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_IEC_TWISTED_PAIR_SETUP + +#ifndef DLMS_IGNORE_IP6_SETUP + int cosem_setIP6Setup(dlmsSettings* settings, gxIp6Setup* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_IP6_SETUP + +#ifndef DLMS_IGNORE_IMAGE_TRANSFER + int cosem_setImageTransfer(gxImageTransfer* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_IMAGE_TRANSFER +#ifndef DLMS_IGNORE_REGISTER_TABLE + int cosem_setRegistertable(gxRegisterTable* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_REGISTER_TABLE +#ifndef DLMS_IGNORE_ACCOUNT + int cosem_setAccount(gxAccount* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_ACCOUNT +#ifndef DLMS_IGNORE_CREDIT + int cosem_setCredit(gxCredit* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_CREDIT +#ifndef DLMS_IGNORE_CHARGE + int cosem_setCharge(dlmsSettings* settings, gxCharge* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_CHARGE +#ifndef DLMS_IGNORE_TOKEN_GATEWAY + int cosem_setTokenGateway(gxTokenGateway* object, unsigned char index, dlmsVARIANT* value); +#endif //DLMS_IGNORE_TOKEN_GATEWAY + +#ifndef DLMS_IGNORE_COMPACT_DATA + int cosem_setCompactData( + dlmsSettings* settings, + gxCompactData* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_COMPACT_DATA + +#ifndef DLMS_IGNORE_PARAMETER_MONITOR + int cosem_setParameterMonitor( + dlmsSettings* settings, + gxParameterMonitor* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_PARAMETER_MONITOR + +#ifndef DLMS_IGNORE_LLC_SSCS_SETUP + int cosem_setLlcSscsSetup( + dlmsSettings* settings, + gxLlcSscsSetup* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_LLC_SSCS_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS + int cosem_setPrimeNbOfdmPlcPhysicalLayerCounters( + dlmsSettings* settings, + gxPrimeNbOfdmPlcPhysicalLayerCounters* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_PHYSICAL_LAYER_COUNTERS + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP + int cosem_setPrimeNbOfdmPlcMacSetup( + dlmsSettings* settings, + gxPrimeNbOfdmPlcMacSetup* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_SETUP +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS + int cosem_setPrimeNbOfdmPlcMacFunctionalParameters( + dlmsSettings* settings, + gxPrimeNbOfdmPlcMacFunctionalParameters* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_FUNCTIONAL_PARAMETERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS + int cosem_setPrimeNbOfdmPlcMacCounters( + dlmsSettings* settings, + gxPrimeNbOfdmPlcMacCounters* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_COUNTERS +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + int cosem_setPrimeNbOfdmPlcMacNetworkAdministrationData( + dlmsSettings* settings, + gxPrimeNbOfdmPlcMacNetworkAdministrationData* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_MAC_NETWORK_ADMINISTRATION_DATA + +#ifndef DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION + int cosem_setPrimeNbOfdmPlcApplicationsIdentification( + dlmsSettings* settings, + gxPrimeNbOfdmPlcApplicationsIdentification* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_PRIME_NB_OFDM_PLC_APPLICATIONS_IDENTIFICATION +#ifndef DLMS_IGNORE_ARBITRATOR + int cosem_setArbitrator( + dlmsSettings* settings, + gxArbitrator* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_ARBITRATOR + +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP + int cosem_setIec8802LlcType1Setup( + dlmsSettings* settings, + gxIec8802LlcType1Setup* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE1_SETUP + +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP + int cosem_setIec8802LlcType2Setup( + dlmsSettings* settings, + gxIec8802LlcType2Setup* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE2_SETUP + +#ifndef DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP + int cosem_setIec8802LlcType3Setup( + dlmsSettings* settings, + gxIec8802LlcType3Setup* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_IEC_8802_LLC_TYPE3_SETUP + +#ifndef DLMS_IGNORE_SFSK_ACTIVE_INITIATOR + int cosem_setSFSKActiveInitiator( + dlmsSettings* settings, + gxSFSKActiveInitiator* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_SFSK_ACTIVE_INITIATOR + +#ifndef DLMS_IGNORE_SFSK_MAC_COUNTERS + int cosem_setFSKMacCounters( + dlmsSettings* settings, + gxFSKMacCounters* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_SFSK_MAC_COUNTERS +#ifndef DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS + int cosem_setSFSKMacSynchronizationTimeouts( + dlmsSettings* settings, + gxSFSKMacSynchronizationTimeouts* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_SFSK_MAC_SYNCHRONIZATION_TIMEOUTS + +#ifndef DLMS_IGNORE_SFSK_PHY_MAC_SETUP + int cosem_setSFSKPhyMacSetUp( + dlmsSettings* settings, + gxSFSKPhyMacSetUp* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_SFSK_PHY_MAC_SETUP + +#ifndef DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST + int cosem_setSFSKReportingSystemList( + dlmsSettings* settings, + gxSFSKReportingSystemList* object, + unsigned char index, + dlmsVARIANT* value); +#endif //DLMS_IGNORE_SFSK_REPORTING_SYSTEM_LIST + +#ifdef __cplusplus +} +#endif + +#endif //defined(DLMS_IGNORE_MALLOC) || defined(DLMS_COSEM_EXACT_DATA_TYPES) +#endif//COSEM_SET_IGNORE_MALLOC_H diff --git a/components/xt211/unused/gxsha1.c b/components/xt211/unused/gxsha1.c new file mode 100644 index 0000000..5e31615 --- /dev/null +++ b/components/xt211/unused/gxsha1.c @@ -0,0 +1,209 @@ +// +// -------------------------------------------------------------------------- +// 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" +#ifndef DLMS_IGNORE_HIGH_SHA1 +#include +#include "gxsha1.h" + +#define SHA1_ROL(value, bits) (((value) << (bits)) | (((value) & 0xffffffff) >> (32 - (bits)))) +#define SHA1_BLK(i) (block[i&15] = SHA1_ROL(block[(i+13)&15] ^ block[(i+8)&15] ^ block[(i+2)&15] ^ block[i&15],1)) + +#define SHA1_R0(v,w,x,y,z,i) z += ((w & (x ^ y)) ^ y) + block[i] + 0x5a827999 + SHA1_ROL(v,5); w=SHA1_ROL(w,30); +#define SHA1_R1(v,w,x,y,z,i) z += ((w & (x ^ y)) ^ y) + SHA1_BLK(i) + 0x5a827999 + SHA1_ROL(v,5); w=SHA1_ROL(w,30); +#define SHA1_R2(v,w,x,y,z,i) z += (w ^ x ^ y) + SHA1_BLK(i) + 0x6ed9eba1 + SHA1_ROL(v,5); w=SHA1_ROL(w,30); +#define SHA1_R3(v,w,x,y,z,i) z += (((w | x) & y) | ( w & x)) + SHA1_BLK(i) + 0x8f1bbcdc + SHA1_ROL(v,5); w=SHA1_ROL(w,30); +#define SHA1_R4(v,w,x,y,z,i) z += (w ^ x ^ y) + SHA1_BLK(i) + 0xca62c1d6 + SHA1_ROL(v,5); w=SHA1_ROL(w,30); + +/* +* Hash block is a single 512-bit block. +*/ +void gxsha1_transform(uint32_t* block, uint32_t* digest, uint32_t* transforms) +{ + uint32_t a = digest[0]; + uint32_t b = digest[1]; + uint32_t c = digest[2]; + uint32_t d = digest[3]; + uint32_t e = digest[4]; + + SHA1_R0(a, b, c, d, e, 0); + SHA1_R0(e, a, b, c, d, 1); + SHA1_R0(d, e, a, b, c, 2); + SHA1_R0(c, d, e, a, b, 3); + SHA1_R0(b, c, d, e, a, 4); + SHA1_R0(a, b, c, d, e, 5); + SHA1_R0(e, a, b, c, d, 6); + SHA1_R0(d, e, a, b, c, 7); + SHA1_R0(c, d, e, a, b, 8); + SHA1_R0(b, c, d, e, a, 9); + SHA1_R0(a, b, c, d, e, 10); + SHA1_R0(e, a, b, c, d, 11); + SHA1_R0(d, e, a, b, c, 12); + SHA1_R0(c, d, e, a, b, 13); + SHA1_R0(b, c, d, e, a, 14); + SHA1_R0(a, b, c, d, e, 15); + SHA1_R1(e, a, b, c, d, 16); + SHA1_R1(d, e, a, b, c, 17); + SHA1_R1(c, d, e, a, b, 18); + SHA1_R1(b, c, d, e, a, 19); + SHA1_R2(a, b, c, d, e, 20); + SHA1_R2(e, a, b, c, d, 21); + SHA1_R2(d, e, a, b, c, 22); + SHA1_R2(c, d, e, a, b, 23); + SHA1_R2(b, c, d, e, a, 24); + SHA1_R2(a, b, c, d, e, 25); + SHA1_R2(e, a, b, c, d, 26); + SHA1_R2(d, e, a, b, c, 27); + SHA1_R2(c, d, e, a, b, 28); + SHA1_R2(b, c, d, e, a, 29); + SHA1_R2(a, b, c, d, e, 30); + SHA1_R2(e, a, b, c, d, 31); + SHA1_R2(d, e, a, b, c, 32); + SHA1_R2(c, d, e, a, b, 33); + SHA1_R2(b, c, d, e, a, 34); + SHA1_R2(a, b, c, d, e, 35); + SHA1_R2(e, a, b, c, d, 36); + SHA1_R2(d, e, a, b, c, 37); + SHA1_R2(c, d, e, a, b, 38); + SHA1_R2(b, c, d, e, a, 39); + SHA1_R3(a, b, c, d, e, 40); + SHA1_R3(e, a, b, c, d, 41); + SHA1_R3(d, e, a, b, c, 42); + SHA1_R3(c, d, e, a, b, 43); + SHA1_R3(b, c, d, e, a, 44); + SHA1_R3(a, b, c, d, e, 45); + SHA1_R3(e, a, b, c, d, 46); + SHA1_R3(d, e, a, b, c, 47); + SHA1_R3(c, d, e, a, b, 48); + SHA1_R3(b, c, d, e, a, 49); + SHA1_R3(a, b, c, d, e, 50); + SHA1_R3(e, a, b, c, d, 51); + SHA1_R3(d, e, a, b, c, 52); + SHA1_R3(c, d, e, a, b, 53); + SHA1_R3(b, c, d, e, a, 54); + SHA1_R3(a, b, c, d, e, 55); + SHA1_R3(e, a, b, c, d, 56); + SHA1_R3(d, e, a, b, c, 57); + SHA1_R3(c, d, e, a, b, 58); + SHA1_R3(b, c, d, e, a, 59); + SHA1_R4(a, b, c, d, e, 60); + SHA1_R4(e, a, b, c, d, 61); + SHA1_R4(d, e, a, b, c, 62); + SHA1_R4(c, d, e, a, b, 63); + SHA1_R4(b, c, d, e, a, 64); + SHA1_R4(a, b, c, d, e, 65); + SHA1_R4(e, a, b, c, d, 66); + SHA1_R4(d, e, a, b, c, 67); + SHA1_R4(c, d, e, a, b, 68); + SHA1_R4(b, c, d, e, a, 69); + SHA1_R4(a, b, c, d, e, 70); + SHA1_R4(e, a, b, c, d, 71); + SHA1_R4(d, e, a, b, c, 72); + SHA1_R4(c, d, e, a, b, 73); + SHA1_R4(b, c, d, e, a, 74); + SHA1_R4(a, b, c, d, e, 75); + SHA1_R4(e, a, b, c, d, 76); + SHA1_R4(d, e, a, b, c, 77); + SHA1_R4(c, d, e, a, b, 78); + SHA1_R4(b, c, d, e, a, 79); + + digest[0] += a; + digest[1] += b; + digest[2] += c; + digest[3] += d; + digest[4] += e; + + ++* transforms; +} + +void gxsha1_update(gxByteBuffer* data, uint32_t* digest, uint32_t* transforms) +{ + unsigned int pos; + uint32_t block[16]; + while (data->size - data->position > 64) + { + for (pos = 0; pos != 16; ++pos) + { + bb_getUInt32(data, &block[pos]); + } + gxsha1_transform(block, digest, transforms); + } +} + +int gxsha1_final(gxByteBuffer* data, uint32_t* digest, uint32_t* transforms, gxByteBuffer* reply) +{ + int pos; + bb_capacity(reply, (uint16_t) *transforms * 64); + bb_set(reply, data->data, data->size); + /* Total number of hashed bits */ + uint64_t total_bits = (*transforms * 64 + data->size) * 8; + + /* Padding */ + bb_setUInt8(reply, 0x80); + uint32_t orig_size = reply->size; + bb_zero(reply, reply->size, 64 - reply->size); + uint32_t block[16]; + for (pos = 0; pos != 16; ++pos) + { + bb_getUInt32(reply, &block[pos]); + } + if (orig_size > 64 - 8) + { + gxsha1_transform(block, digest, transforms); + for (pos = 0; pos < 16 - 2; ++pos) + { + block[pos] = 0; + } + } + + /* Append total_bits, split this uint64 into two uint32 */ + block[16 - 1] = (uint32_t)total_bits; + block[16 - 2] = (uint32_t)(total_bits >> 32); + gxsha1_transform(block, digest, transforms); + bb_capacity(reply, 20); + reply->position = reply->size = 0; + for (pos = 0; pos < 5; ++pos) + { + bb_setUInt32(reply, digest[pos]); + } + return 0; +} + +int gxsha1_encrypt(gxByteBuffer* data, gxByteBuffer* result) +{ + uint32_t digest[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 }; + uint32_t transforms = 0; + gxsha1_update(data, digest, &transforms); + return gxsha1_final(data, digest, &transforms, result); +} + +#endif //DLMS_IGNORE_HIGH_SHA1 diff --git a/components/xt211/unused/gxsha1.h b/components/xt211/unused/gxsha1.h new file mode 100644 index 0000000..27e884d --- /dev/null +++ b/components/xt211/unused/gxsha1.h @@ -0,0 +1,52 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef GXSHA1 +#define GXSHA1 + +#ifdef __cplusplus +extern "C" { +#endif +#include "gxignore.h" +#ifndef DLMS_IGNORE_HIGH_SHA1 + +#include "bytebuffer.h" + + int gxsha1_encrypt(gxByteBuffer* data, gxByteBuffer* digest); + +#endif //DLMS_IGNORE_HIGH_SHA1 + +#ifdef __cplusplus +} +#endif + +#endif //GXSHA_256 diff --git a/components/xt211/unused/gxsha256.c b/components/xt211/unused/gxsha256.c new file mode 100644 index 0000000..991ba54 --- /dev/null +++ b/components/xt211/unused/gxsha256.c @@ -0,0 +1,180 @@ +// +// -------------------------------------------------------------------------- +// 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" +#ifndef DLMS_IGNORE_HIGH_SHA256 +#include +#include "gxsha256.h" + +const uint32_t sha256_k[64] = +{ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, +0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, +0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, +0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, +0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, +0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, +0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, +0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, +0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, +0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, +0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, +0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, +0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, +0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, +0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, +0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; + +#define SHA2_SHFR(x, n) (x >> n) +#define SHA2_ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n))) +#define SHA2_ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n))) +#define SHA2_CH(x, y, z) ((x & y) ^ (~x & z)) +#define SHA2_MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) +#define SHA256_F1(x) (SHA2_ROTR(x, 2) ^ SHA2_ROTR(x, 13) ^ SHA2_ROTR(x, 22)) +#define SHA256_F2(x) (SHA2_ROTR(x, 6) ^ SHA2_ROTR(x, 11) ^ SHA2_ROTR(x, 25)) +#define SHA256_F3(x) (SHA2_ROTR(x, 7) ^ SHA2_ROTR(x, 18) ^ SHA2_SHFR(x, 3)) +#define SHA256_F4(x) (SHA2_ROTR(x, 17) ^ SHA2_ROTR(x, 19) ^ SHA2_SHFR(x, 10)) +#define SHA2_UNPACK32(x, str) \ +{ \ + *((str) + 3) = (unsigned char) ((x) ); \ + *((str) + 2) = (unsigned char) ((x) >> 8); \ + *((str) + 1) = (unsigned char) ((x) >> 16); \ + *((str) + 0) = (unsigned char) ((x) >> 24); \ +} +#define SHA2_PACK32(str, x) \ +{ \ + *(x) = ((uint32_t) *((str) + 3) ) \ + | ((uint32_t) *((str) + 2) << 8) \ + | ((uint32_t) *((str) + 1) << 16) \ + | ((uint32_t) *((str) + 0) << 24); \ +} + + +void gxsha256_transform(uint32_t *h, const unsigned char *message, unsigned int block_nb) +{ + uint32_t w[64]; + uint32_t wv[8]; + uint32_t t1, t2; + const unsigned char *sub_block; + unsigned int i; + int j; + for (i = 0; i < block_nb; i++) + { + sub_block = message + (i << 6); + for (j = 0; j < 16; j++) + { + SHA2_PACK32(&sub_block[j << 2], &w[j]); + } + for (j = 16; j < 64; j++) + { + w[j] = SHA256_F4(w[j - 2]) + w[j - 7] + SHA256_F3(w[j - 15]) + w[j - 16]; + } + for (j = 0; j < 8; j++) + { + wv[j] = h[j]; + } + for (j = 0; j < 64; j++) { + t1 = wv[7] + SHA256_F2(wv[4]) + SHA2_CH(wv[4], wv[5], wv[6]) + + sha256_k[j] + w[j]; + t2 = SHA256_F1(wv[0]) + SHA2_MAJ(wv[0], wv[1], wv[2]); + wv[7] = wv[6]; + wv[6] = wv[5]; + wv[5] = wv[4]; + wv[4] = wv[3] + t1; + wv[3] = wv[2]; + wv[2] = wv[1]; + wv[1] = wv[0]; + wv[0] = t1 + t2; + } + for (j = 0; j < 8; j++) + { + h[j] += wv[j]; + } + } +} + +int gxsha256_update(uint32_t *h, unsigned char *block, gxByteBuffer* data, unsigned int *len, unsigned int *totalLen) +{ + unsigned int block_nb; + unsigned int new_len, rem_len, tmp_len; + const unsigned char *shifted_message; + tmp_len = 64 - (data->size - data->position); + rem_len = data->size < tmp_len ? data->size : tmp_len; + memcpy(&block[data->position], data->data, rem_len); + if (data->size - data->position < 64) + { + data->position = data->size; + return 0; + } + new_len = *len - rem_len; + block_nb = new_len / 64; + shifted_message = data->data + rem_len; + gxsha256_transform(h, block, 1); + gxsha256_transform(h, shifted_message, block_nb); + rem_len = new_len % 64; + memcpy(block, &shifted_message[block_nb << 6], rem_len); + *len = rem_len; + *totalLen += (block_nb + 1) << 6; + return 0; +} + +int gxsha256_final(uint32_t *h, unsigned char *block, unsigned char *digest, unsigned int len, unsigned int totalLen) +{ + unsigned int block_nb; + unsigned int pm_len; + uint32_t len_b; + int i; + block_nb = (1 + ((64 - 9) < (len % 64))); + len_b = (totalLen + len) << 3; + pm_len = block_nb << 6; + memset(block + len, 0, pm_len - len); + block[len] = 0x80; + SHA2_UNPACK32(len_b, block + pm_len - 4); + gxsha256_transform(h, block, block_nb); + for (i = 0; i < 8; i++) + { + SHA2_UNPACK32(h[i], &digest[i << 2]); + } + return 0; +} + +int gxsha256_encrypt(gxByteBuffer* data, gxByteBuffer* digest) +{ + unsigned int len = data->size, totalLen = 0; + uint32_t h[8] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 }; + unsigned char block[128]; + bb_capacity(digest, 32); + digest->size = 32; + gxsha256_update((uint32_t*)&h, block, data, &len, &totalLen); + return gxsha256_final(h, block, digest->data, len, totalLen); +} + +#endif //DLMS_IGNORE_HIGH_SHA256 diff --git a/components/xt211/unused/gxsha256.h b/components/xt211/unused/gxsha256.h new file mode 100644 index 0000000..ba08279 --- /dev/null +++ b/components/xt211/unused/gxsha256.h @@ -0,0 +1,52 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef GXSHA_256 +#define GXSHA_256 + +#include "gxignore.h" +#ifndef DLMS_IGNORE_HIGH_SHA256 +#ifdef __cplusplus +extern "C" { +#endif + + +#include "bytebuffer.h" + + int gxsha256_encrypt(gxByteBuffer* data, gxByteBuffer* digest); + +#ifdef __cplusplus +} +#endif +#endif //DLMS_IGNORE_HIGH_SHA256 + +#endif //GXSHA_256 diff --git a/components/xt211/unused/gxvalueeventargs.c b/components/xt211/unused/gxvalueeventargs.c new file mode 100644 index 0000000..3badf00 --- /dev/null +++ b/components/xt211/unused/gxvalueeventargs.c @@ -0,0 +1,233 @@ +// +// -------------------------------------------------------------------------- +// 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 _MSC_VER > 1400 +#include +#endif +#include "gxvalueeventargs.h" +#include "objectarray.h" + +void vec_init(gxValueEventCollection* arr) +{ + arr->capacity = 0; + arr->data = NULL; + arr->position = 0; + arr->size = 0; +} + +char vec_isAttached(gxValueEventCollection* arr) +{ + return (arr->capacity & 0x80) == 0x80; +} + +unsigned char vec_getCapacity(gxValueEventCollection* arr) +{ + return arr->capacity & 0x7F; +} + +#ifdef DLMS_IGNORE_MALLOC +void vec_attach( + gxValueEventCollection* arr, + gxValueEventArg* value, + unsigned char count, + unsigned char capacity) +{ + arr->data = value; + arr->capacity = (uint16_t)(0x80 | capacity); + arr->size = count; + arr->position = 0; +} +#endif //DLMS_IGNORE_MALLOC + +//Allocate new size for the array in bytes. +int vec_capacity(gxValueEventCollection* arr, unsigned char capacity) +{ +#ifndef DLMS_IGNORE_MALLOC + if (!vec_isAttached(arr)) + { + arr->capacity = capacity; + if (arr->data == NULL) + { + arr->data = (gxValueEventArg * *)gxmalloc(arr->capacity * sizeof(gxValueEventArg*)); + } + else + { +#ifdef gxrealloc + //If compiler supports realloc. + arr->data = (gxValueEventArg * *)gxrealloc(arr->data, arr->capacity * sizeof(gxValueEventArg*)); +#else + //If compiler doesn't supports realloc. + gxValueEventArg ** old = arr->data; + arr->data = (gxValueEventArg * *)gxmalloc(arr->capacity * sizeof(gxValueEventArg*)); + //If not enought memory available. + if (arr->data == NULL) + { + arr->data = old; + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + memcpy(arr->data, old, sizeof(gxValueEventArg*) * arr->size); + gxfree(old); +#endif //gxrealloc + } + } +#endif //DLMS_IGNORE_MALLOC + if (vec_getCapacity(arr) < capacity) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } + return 0; +} + +#ifndef DLMS_IGNORE_MALLOC +//Push new data to the gxValueEventCollection. +int vec_push(gxValueEventCollection * arr, gxValueEventArg* item) +{ + int ret = 0; + if (!vec_isAttached(arr)) + { + if (arr->size >= vec_getCapacity(arr)) + { + if ((ret = vec_capacity(arr, arr->capacity + 2)) != 0) + { + return ret; + } + } + } + if (vec_getCapacity(arr) <= arr->size) + { + ret = DLMS_ERROR_CODE_OUTOFMEMORY; + } + else + { + arr->data[arr->size] = item; + ++arr->size; + } + return ret; +} +#endif //DLMS_IGNORE_MALLOC + +void vec_empty( + gxValueEventCollection* arr) +{ +#ifndef DLMS_IGNORE_MALLOC + if (!vec_isAttached(arr)) + { + if (arr->size != 0) + { + gxfree(arr->data); + arr->data = NULL; + } + arr->capacity = 0; +} +#endif //DLMS_IGNORE_MALLOC + arr->size = 0; + arr->position = 0; +} + +void vec_clear( + gxValueEventCollection* arr) +{ +#ifndef DLMS_IGNORE_MALLOC + if (!vec_isAttached(arr)) + { + int pos; + if (arr->size != 0) + { + for (pos = 0; pos != arr->size; ++pos) + { + ve_clear(arr->data[pos]); + gxfree(arr->data[pos]); + } + gxfree(arr->data); + arr->data = NULL; + } + arr->capacity = 0; + } +#endif //DLMS_IGNORE_MALLOC + arr->size = 0; + arr->position = 0; +} + +int vec_getByIndex(gxValueEventCollection* arr, int index, gxValueEventArg** value) +{ + if (index >= arr->size) + { + return DLMS_ERROR_CODE_OUTOFMEMORY; + } +#ifdef DLMS_IGNORE_MALLOC + *value = &arr->data[index]; +#else + * value = arr->data[index]; +#endif //DLMS_IGNORE_MALLOC + return 0; +} + +void ve_init(gxValueEventArg * ve) +{ + var_init(&ve->value); + ve->handled = 0; + ve->target = NULL; + ve->index = 0; +#if !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + ve->dataType = DLMS_DATA_TYPE_NONE; +#endif //!defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + ve->selector = 0; + var_init(&ve->parameters); + ve->error = DLMS_ERROR_CODE_OK; + ve->action = 0; + ve->byteArray = 0; + ve->skipMaxPduSize = 0; + ve->transactionStartIndex = 0; + ve->transactionEndIndex = 0; + ve->transaction = 0; +} + +void ve_clear(gxValueEventArg * ve) +{ + var_clear(&ve->value); + ve->handled = 0; + ve->target = NULL; + ve->index = 0; +#if !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + ve->dataType = DLMS_DATA_TYPE_NONE; +#endif //!defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + ve->selector = 0; + var_clear(&ve->parameters); + ve->error = DLMS_ERROR_CODE_OK; + ve->action = 0; + ve->byteArray = 0; + ve->skipMaxPduSize = 0; + ve->transactionStartIndex = 0; + ve->transactionEndIndex = 0; + ve->transaction = 0; +} diff --git a/components/xt211/unused/notify.c b/components/xt211/unused/notify.c new file mode 100644 index 0000000..0980216 --- /dev/null +++ b/components/xt211/unused/notify.c @@ -0,0 +1,514 @@ +// +// -------------------------------------------------------------------------- +// 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 +#endif +#include "gxmem.h" +#if _MSC_VER > 1400 +#include +#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 diff --git a/components/xt211/unused/notify.h b/components/xt211/unused/notify.h new file mode 100644 index 0000000..a9cd537 --- /dev/null +++ b/components/xt211/unused/notify.h @@ -0,0 +1,188 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef NOTIFY_H +#define NOTIFY_H +#include "gxignore.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include "dlms.h" +#include "gxget.h" +#include "gxkey.h" + +/** + * Removes the HDLC frame from the packet, and returns COSEM data only. + * + * @param reply + * The received data from the device. + * @param data + * Information from the received data. + * @return Is frame complete. + */ +int notify_getData( + dlmsSettings* settings, + gxByteBuffer* reply, + gxReplyData *data); + +/** + * Add value of COSEM object to byte buffer. AddData method can be used with + * GetDataNotificationMessage -method. DLMS specification do not specify the + * structure of Data-Notification body. So each manufacture can sent + * different data. + * + * @param obj + * COSEM object. + * @param index + * Attribute index. + * @param buff + * Byte buffer. + */ +int notify_addData( + dlmsSettings* settings, + gxObject* obj, + unsigned char index, + gxByteBuffer* buff); + +/** + * Generates data notification message. + * + * @param date + * Date time. Set to null or Date(0) if not used + * @param data + * Notification body. + * @return Generated data notification message(s). + */ +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); + +/** + * Generates data notification message. + * + * @param date + * Date time. Set To Min or Max if not added. + * @param objects + * List of objects and attribute indexes to notify. + * @return Generated data notification message(s). + */ +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); + +#ifndef DLMS_IGNORE_PUSH_SETUP +/** + * Generates push setup message. + * + * @param date + * Date time. Set to null or Date(0) if not used. + * @param push + * Target Push object. + * @return Generated data notification message(s). + */ +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); + +/** + * Returns collection of push objects. If this method is used Push object + * must be set for first object on push object list. + * + * @param data + * Received value. + * @return Array of objects and called indexes. + */ +int notify_parsePush( + dlmsSettings* settings, + variantArray* data, + gxArray* items); + +#if !defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) +int notify_getPushValues( + dlmsSettings* settings, + gxPushSetup* pushSetup, + variantArray* data, + gxArray* items); +#endif //!defined(DLMS_IGNORE_MALLOC) && !defined(DLMS_COSEM_EXACT_DATA_TYPES) + +//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); + +//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); + +#endif //DLMS_IGNORE_PUSH_SETUP + +#ifdef __cplusplus +} +#endif +#endif //NOTIFY_H diff --git a/components/xt211/variant.c b/components/xt211/variant.c new file mode 100644 index 0000000..64be97d --- /dev/null +++ b/components/xt211/variant.c @@ -0,0 +1,2615 @@ +// +// -------------------------------------------------------------------------- +// 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) diff --git a/components/xt211/variant.h b/components/xt211/variant.h new file mode 100644 index 0000000..6bda0e0 --- /dev/null +++ b/components/xt211/variant.h @@ -0,0 +1,534 @@ +// +// -------------------------------------------------------------------------- +// 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 +//--------------------------------------------------------------------------- + +#ifndef VARIANT_H +#define VARIANT_H + +#ifdef __cplusplus +extern "C" { +#endif +#include "gxignore.h" +#include "date.h" +#include "enums.h" +#include "errorcodes.h" +#include "bytebuffer.h" +#include "bitarray.h" +#if _MSC_VER > 1400 +#pragma warning(disable : 4201) +#endif +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) +#include +#endif + +#define GX_SWAP_UINT16(a)(((a & 0xFF) << 8) | ((a & 0xFF00) >> 8)) +#define GX_SWAP_UINT32(a)(GX_SWAP_UINT16(a & 0xFFFF) << 16) | (GX_SWAP_UINT16(a >> 16) ) + +#define VARIANT_ARRAY_CAPACITY 10 + +#if defined(_WIN32) || defined(_WIN64) || defined(__linux__) +#define VERIFY(X, TYPE) (assert(X.vt == TYPE)) +#else +#define VERIFY(X, TYPE) +#endif + +#define V_VT(X) ((X)->vt) +#define GX_UNION(X, Y, Z) V_VT(X)=Z;(X)->Y +#ifdef DLMS_IGNORE_MALLOC +#define GX_UNION2(X, Y, Z, S, C) (X)->size=S;(X)->capacity=C;V_VT(X)=Z;(X)->Y +#endif //DLMS_IGNORE_MALLOC +#define GX_UINT8(X) GX_UNION(&X, bVal, DLMS_DATA_TYPE_UINT8) +#define GX_UINT16(X) GX_UNION(&X, uiVal, DLMS_DATA_TYPE_UINT16) +#define GX_UINT32(X) GX_UNION(&X, ulVal, DLMS_DATA_TYPE_UINT32) +#define GX_UINT64(X) GX_UNION(&X, ullVal, DLMS_DATA_TYPE_UINT64) +#define GX_INT8(X) GX_UNION(&X, cVal, DLMS_DATA_TYPE_INT8) +#define GX_INT16(X) GX_UNION(&X, iVal, DLMS_DATA_TYPE_INT16) +#define GX_INT32(X) GX_UNION(&X, lVal, DLMS_DATA_TYPE_INT32) +#define GX_INT64(X) GX_UNION(&X, llVal, DLMS_DATA_TYPE_INT64) +#define GX_FLOAT(X) GX_UNION(&X, fltVal, DLMS_DATA_TYPE_FLOAT32) +#define GX_DOUBLE(X) GX_UNION(&X, dblVal, DLMS_DATA_TYPE_FLOAT64) +#define GX_BOOL(X) GX_UNION(&X, bVal, DLMS_DATA_TYPE_BOOLEAN) +#ifdef DLMS_IGNORE_MALLOC +#define GX_DATETIME(X) X.size = 12; GX_UNION(&X, pVal, (DLMS_DATA_TYPE)(DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_DATETIME)) +#else +#define GX_DATETIME(X) GX_UNION(&X, pVal, (DLMS_DATA_TYPE)(DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_DATETIME)) +#endif //DLMS_IGNORE_MALLOC +#define GX_DATE(X) GX_UNION(&X, pVal, (DLMS_DATA_TYPE)(DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_DATE)) +#define GX_TIME(X) GX_UNION(&X, pVal, (DLMS_DATA_TYPE)(DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_TIME)) +#define GX_UINT8_BYREF(X, VALUE_) GX_UNION(&X, pbVal = &VALUE_, (DLMS_DATA_TYPE)(DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_UINT8)) +#define GX_UINT16_BYREF(X, VALUE_) GX_UNION(&X, puiVal = &VALUE_, (DLMS_DATA_TYPE)(DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_UINT16)) +#define GX_UINT32_BYREF(X, VALUE_) GX_UNION(&X, pulVal = &VALUE_, (DLMS_DATA_TYPE)(DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_UINT32)) +#define GX_UINT64_BYREF(X, VALUE_) GX_UNION(&X, pullVal = &VALUE_, (DLMS_DATA_TYPE)(DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_UINT64)) +#define GX_INT8_BYREF(X, VALUE_) GX_UNION(&X, pcVal = &VALUE_, (DLMS_DATA_TYPE)(DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_INT8)) +#define GX_INT16_BYREF(X, VALUE_) GX_UNION(&X, piVal = &VALUE_, (DLMS_DATA_TYPE)(DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_INT16)) +#define GX_INT32_BYREF(X, VALUE_) GX_UNION(&X, plVal = &VALUE_, (DLMS_DATA_TYPE)(DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_INT32)) +#define GX_INT64_BYREF(X, VALUE_) GX_UNION(&X, pllVal = &VALUE_, (DLMS_DATA_TYPE)(DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_INT64)) +#define GX_FLOAT_BYREF(X, VALUE_) GX_UNION(&X, pfltVal = &VALUE_, (DLMS_DATA_TYPE)(DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_FLOAT32)) +#define GX_DOUBLE_BYREF(X, VALUE_) GX_UNION(&X, pdblVal = &VALUE_, (DLMS_DATA_TYPE)(DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_FLOAT64)) + +#ifdef DLMS_IGNORE_MALLOC +#define GX_OCTET_STRING(X, VALUE_, SIZE_) GX_UNION2(&X, pVal = VALUE_, (DLMS_DATA_TYPE) (DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_OCTET_STRING), SIZE_, sizeof(VALUE_)) +#define GX_BIT_STRING(X, VALUE_, SIZE_) GX_UNION2(&X, pVal = VALUE_, (DLMS_DATA_TYPE) (DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_BIT_STRING), SIZE_, 8 * sizeof(VALUE_)/sizeof(VALUE_[0])) +#define GX_STRING(X, VALUE_, SIZE_) GX_UNION2(&X, pVal = VALUE_, (DLMS_DATA_TYPE)(DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_STRING), SIZE_, sizeof(VALUE_)) +#define GX_ARRAY(X, VALUE_) GX_UNION2(&X, pVal = &VALUE_, (DLMS_DATA_TYPE)(DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_ARRAY), 0, 0) +#define GX_STRUCT(X, VALUE_) GX_UNION2(&X, pVal = &VALUE_, (DLMS_DATA_TYPE)(DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_STRUCTURE), 0, 0) +#endif //DLMS_IGNORE_MALLOC + +#define GX_BOOL_BYREF(X, VALUE_) GX_UNION(&X, pcVal = &VALUE_, (DLMS_DATA_TYPE)(DLMS_DATA_TYPE_BYREF | DLMS_DATA_TYPE_BOOLEAN)) + +/*Get UInt8 value from variant.*/ +#define GX_GET_UINT8(X) (X.vt & DLMS_DATA_TYPE_BYREF) == 0 ? X.bVal : *X.pbVal + +/*Get UInt16 value from variant.*/ +#define GX_GET_UINT16(X) (X.vt & DLMS_DATA_TYPE_BYREF) == 0 ? X.uiVal : *X.puiVal + +/*Get UInt32 value from variant.*/ +#define GX_GET_UINT32(X) (X.vt & DLMS_DATA_TYPE_BYREF) == 0 ? X.culVal : *X.pulVal + +/*Get UInt64 value from variant.*/ +#define GX_GET_UINT64(X) (X.vt & DLMS_DATA_TYPE_BYREF) == 0 ? X.cullVal : *X.pullVal + +/*Get Int8 value from variant.*/ +#define GX_GET_INT8(X) (X.vt & DLMS_DATA_TYPE_BYREF) == 0 ? X.cVal : *X.pcVal +/*Get Int16 value from variant.*/ +#define GX_GET_INT16(X)(X.vt & DLMS_DATA_TYPE_BYREF) == 0 ? X.iVal : *X.piVal +/*Get Int32 value from variant.*/ +#define GX_GET_INT32(X)(X.vt & DLMS_DATA_TYPE_BYREF) == 0 ? X.lVal : *X.plVal +/*Get Int64 value from variant.*/ +#define GX_GET_INT64(X)(X.vt & DLMS_DATA_TYPE_BYREF) == 0 ? X.llVal : *X.pllVal +/*Get float value from variant.*/ +#define GX_GET_FLOAT(X) (X.vt & DLMS_DATA_TYPE_BYREF) == 0 ? X.fltVal : *X.pfltVal +/*Get double value from variant.*/ +#define GX_GET_DOUBLE(X) (X.vt & DLMS_DATA_TYPE_BYREF) == 0 ? X.dblVal : *X.pdblVal +/*Get boolean value from variant.*/ +#define GX_GET_BOOL(X) (X.vt & DLMS_DATA_TYPE_BYREF) == 0 ? (X.bVal != 0) : (*X.pbVal != 0) + + typedef struct + { +#ifdef DLMS_IGNORE_MALLOC + void* data; +#else + void** data; +#endif //DLMS_IGNORE_MALLOC + uint16_t capacity; + uint16_t size; + } variantArray; + + typedef struct tagdlmsVARIANT + { + DLMS_DATA_TYPE vt; + union + { + unsigned char bVal; + signed char cVal; + int16_t iVal; + int32_t lVal; + int64_t llVal; +#ifndef DLMS_IGNORE_FLOAT32 + float fltVal; +#endif //DLMS_IGNORE_FLOAT32 +#ifndef DLMS_IGNORE_FLOAT64 + double dblVal; +#endif //DLMS_IGNORE_FLOAT64 + unsigned char boolVal; + uint16_t uiVal; + uint32_t ulVal; + uint64_t ullVal; +#ifndef DLMS_IGNORE_MALLOC + gxtime* dateTime; + gxByteBuffer* strVal; + gxByteBuffer* strUtfVal; + bitArray* bitArr; +#endif //DLMS_IGNORE_MALLOC + variantArray* Arr; + gxByteBuffer* byteArr; + unsigned char* pbVal; + signed char* pcVal; + short* piVal; + int32_t* plVal; + int64_t* pllVal; +#ifndef DLMS_IGNORE_FLOAT32 + float* pfltVal; +#endif //DLMS_IGNORE_FLOAT32 +#ifndef DLMS_IGNORE_FLOAT64 + double* pdblVal; +#endif //DLMS_IGNORE_FLOAT64 + unsigned char* pboolVal; + uint16_t* puiVal; + uint32_t* pulVal; + uint64_t* pullVal; + void* pVal; + }; +#ifdef DLMS_IGNORE_MALLOC + uint16_t size; + uint16_t capacity; +#endif //DLMS_IGNORE_MALLOC + } dlmsVARIANT; + + +#ifdef DLMS_IGNORE_MALLOC + typedef dlmsVARIANT* dlmsVARIANT_PTR; +#else + typedef dlmsVARIANT* dlmsVARIANT_PTR; +#endif //DLMS_IGNORE_MALLOC + + //Initialize variantArray. + void va_init( + variantArray* arr); + +#ifdef DLMS_IGNORE_MALLOC + void va_attach( + variantArray* trg, + dlmsVARIANT* src, + uint16_t size, + uint16_t capacity); +#endif //DLMS_IGNORE_MALLOC + + void va_attach2( + variantArray* trg, + variantArray* src); + + //Is variant array attached. + char va_isAttached(variantArray* arr); + + //Get variant array capacity. + uint16_t va_size( + variantArray* arr); + + //Get variant array capacity. + uint16_t va_getCapacity( + variantArray* arr); + + + //Allocate new size for the array in bytes. + int va_capacity( + variantArray* arr, + uint16_t capacity); + + //Push new data to the variantArray. + int va_push( + variantArray* arr, + dlmsVARIANT* item); + + void va_clear( + variantArray* arr); + + //Set byte value to variant. + int var_setUInt8( + dlmsVARIANT* data, + unsigned char value); + + //Set UInt16 value to variant. + int var_setUInt16( + dlmsVARIANT* data, + uint16_t value); + + //Set UInt32 value to variant. + int var_setUInt32(dlmsVARIANT + * data, + uint32_t value); + + //Set UInt64 value to variant. + int var_setUInt64( + dlmsVARIANT* data, + uint64_t value); + + //Set signed byte value to variant. + int var_setInt8( + dlmsVARIANT* data, + char value); + + //Set Int16 value to variant. + int var_setInt16( + dlmsVARIANT* data, + short value); + + //Set Int32 value to variant. + int var_setInt32( + dlmsVARIANT* data, + int32_t value); + + //Set Int64 value to variant. + int var_setInt64( + dlmsVARIANT* data, + int64_t value); + +#ifndef DLMS_IGNORE_FLOAT64 + int var_setDouble( + dlmsVARIANT* data, + double value); +#endif //DLMS_IGNORE_FLOAT64 + +#ifndef DLMS_IGNORE_MALLOC + int var_setDateTime( + dlmsVARIANT* target, + gxtime* value); + + int var_setDate( + dlmsVARIANT* target, + gxtime* value); + + int var_setTime( + dlmsVARIANT* target, + gxtime* value); + +#endif //DLMS_IGNORE_MALLOC + int var_setBoolean( + dlmsVARIANT* target, + char value); + + int var_getDateTime( + dlmsVARIANT* target, + gxtime* value); + + int var_getDateTime2( + gxtime* dateTime, + gxByteBuffer* ba); + + int var_getDate( + gxtime* date, + gxByteBuffer* ba); + + int var_getTime( + gxtime* date, + gxByteBuffer* ba); + + int var_setDateTimeAsOctetString( + dlmsVARIANT* target, + gxtime* value); + + int var_setDateAsOctetString( + dlmsVARIANT* target, + gxtime* value); + + int var_setTimeAsOctetString( + dlmsVARIANT* target, + gxtime* value); + + //Get byte value from variant. + int var_getUInt8( + dlmsVARIANT* data, + unsigned char* value); + + //Get UInt16 value from variant. + int var_getUInt16( + dlmsVARIANT* data, + uint16_t* value); + + //Get UInt32 value from variant. + int var_getUInt32( + dlmsVARIANT* data, + uint32_t* value); + + //Get UInt64 value from variant. + int var_getUInt64( + dlmsVARIANT* data, + uint64_t* value); + + //Get signed byte value from variant. + int var_getInt8( + dlmsVARIANT* data, + char* value); + + //Get Int16 value from variant. + int var_getInt16( + dlmsVARIANT* data, + short* value); + + //Get Int32 value from variant. + int var_getInt32( + dlmsVARIANT* data, + int32_t* value); + + //Get Int64 value from variant. + int var_getInt64( + dlmsVARIANT* data, + int64_t* value); + +#ifndef DLMS_IGNORE_MALLOC + int var_addBytes( + dlmsVARIANT* data, + const unsigned char* value, + uint16_t count); +#endif //DLMS_IGNORE_MALLOC + +#ifndef DLMS_IGNORE_MALLOC + int var_setString( + dlmsVARIANT* data, + const char* value, + uint16_t count); +#endif //DLMS_IGNORE_MALLOC + +#ifndef DLMS_IGNORE_MALLOC + void var_attach( + dlmsVARIANT* target, + gxByteBuffer* source); +#endif //DLMS_IGNORE_MALLOC + + int var_addOctetString( + dlmsVARIANT* data, + gxByteBuffer* ba); + + int var_setEnum(dlmsVARIANT* data, + unsigned char value); + + int var_addByteArray( + dlmsVARIANT* data, + gxByteBuffer* ba, + uint16_t index, + uint16_t count); + + //Initialize variant. + int var_init( + dlmsVARIANT* data); + +#ifndef DLMS_IGNORE_MALLOC + //attach static array. + void var_attachArray( + dlmsVARIANT* data, + const variantArray* arr, + const uint16_t count); +#endif //DLMS_IGNORE_MALLOC + +#ifndef DLMS_IGNORE_MALLOC + //attach static structure. + void var_attachStructure( + dlmsVARIANT* data, + const dlmsVARIANT** arr, + const uint16_t count); +#endif //DLMS_IGNORE_MALLOC + + //copy variant. + int var_copy( + dlmsVARIANT* value, + dlmsVARIANT* copy); + + //Clear variant. + int var_clear( + dlmsVARIANT* data); + + //Get bytes from variant value. + int var_getBytes( + dlmsVARIANT* data, + gxByteBuffer* ba); + + //Get bytes from variant value. + int var_getBytes2( + dlmsVARIANT* data, + DLMS_DATA_TYPE type, + gxByteBuffer* ba); + + //Get bytes from variant value without data type. + int var_getBytes3( + dlmsVARIANT* data, + DLMS_DATA_TYPE type, + gxByteBuffer* ba, + unsigned char addType); + + //Get size in bytes. + int var_getSize( + DLMS_DATA_TYPE vt); + + //Convert variant value to integer. + int var_toInteger( + dlmsVARIANT* data); + + //Get item from variant array by index. + int va_getByIndex( + variantArray* arr, + int index, + dlmsVARIANT_PTR* item); + +#ifndef DLMS_IGNORE_MALLOC + //copy variant array. + int va_copyArray( + variantArray* target, + variantArray* source); + + //Add given value to the array N times. + int va_addValue( + variantArray* target, + dlmsVARIANT* value, + uint16_t count); +#endif //DLMS_IGNORE_MALLOC + +#ifndef DLMS_IGNORE_MALLOC + int var_changeType( + dlmsVARIANT* value, + DLMS_DATA_TYPE newType); +#endif //DLMS_IGNORE_MALLOC + +#ifndef DLMS_IGNORE_MALLOC + //Convert variant to string. + //Note! toString do not clear existing byte array. + int var_toString( + dlmsVARIANT* item, + gxByteBuffer* value); + + //Convert variant array to string. + //Note! toString do not clear existing byte array. + int va_toString( + variantArray* items, + gxByteBuffer* ba); + +#endif //DLMS_IGNORE_MALLOC + //Convert variant to double. + double var_toDouble( + dlmsVARIANT* target); + +#ifdef DLMS_IGNORE_MALLOC + //Attach value by ref. + int var_byRef( + dlmsVARIANT* target, + DLMS_DATA_TYPE type, + void* value); +#endif //DLMS_IGNORE_MALLOC + +#ifndef GX_DLMS_MICROCONTROLLER + //Print content of the variant to cout. + int var_print( + //Format. + const char* format, + dlmsVARIANT* target); + + //Print content of the variant array to cout. + int va_print( + variantArray* target); + +#endif //GX_DLMS_MICROCONTROLLER + +#define VA_ATTACH(X, V, S) va_attach(&X, V, S, sizeof(V)/sizeof(V[0])) + +#ifdef __cplusplus +} +#endif + +#endif //VARIANT_H diff --git a/components/xt211/xt211.cpp b/components/xt211/xt211.cpp new file mode 100644 index 0000000..ccec133 --- /dev/null +++ b/components/xt211/xt211.cpp @@ -0,0 +1,494 @@ +#include "xt211.h" +#include "xt211_axdr_parser.h" +#include "esphome/core/application.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" +#include + +namespace esphome { + namespace xt211 { + + static const char *TAG0 = "xt211_"; + +#define TAG (this->tag_.c_str()) + + static constexpr uint8_t + BOOT_WAIT_S = 10; + + void XT211Component::setup() { + ESP_LOGD(TAG, "setup (PUSH mode only)"); + + this->buffers_.init(DEFAULT_IN_BUF_SIZE_PUSH); + +#ifdef USE_ESP32 + iuart_ = make_unique(*static_cast(this->parent_)); +#endif + +#if USE_ESP8266 + iuart_ = make_unique(*static_cast(this->parent_)); +#endif + + this->set_baud_rate_(this->baud_rate_); + + CosemObjectFoundCallback fn = [this](auto... args) { (void) this->set_sensor_value(args...); }; + + this->axdr_parser_ = new AxdrStreamParser(&this->buffers_.in, fn, this->push_show_log_); + + // default patterns + this->axdr_parser_->register_pattern_dsl("T1", "TC,TO,TS,TV"); + this->axdr_parser_->register_pattern_dsl("T2", "TO,TV,TSU"); + this->axdr_parser_->register_pattern_dsl("T3", "TV,TC,TSU,TO"); + this->axdr_parser_->register_pattern_dsl("U.ZPA", "F,C,O,A,TV"); + + // user-provided pattern + if (this->push_custom_pattern_dsl_.length() > 0) { + this->axdr_parser_->register_pattern_dsl("CUSTOM", this->push_custom_pattern_dsl_, 0); + } + + bool locked = false; + for (int i = 0; i < 3; i++) + if (this->try_lock_uart_session_()) { + locked = true; + break; + } + + if (!locked) { + ESP_LOGE(TAG, "Failed to lock UART session. Aborting setup."); + this->mark_failed(); + return; + } + + this->set_timeout(BOOT_WAIT_S * 1000, [this]() { + ESP_LOGD(TAG, "Boot timeout, component is ready to use"); + this->clear_rx_buffers_(); + this->set_next_state_(State::IDLE); + }); + } + + void XT211Component::dump_config() { + ESP_LOGCONFIG(TAG, "XT211 (PUSH Mode Read-Only):"); + ESP_LOGCONFIG(TAG, " Receive Timeout: %ums", this->receive_timeout_ms_); + ESP_LOGCONFIG(TAG, " Mode: PUSH Data Reception"); + ESP_LOGCONFIG(TAG, " Sensors:"); + for (const auto &sensors: sensors_) { + auto &s = sensors.second; + ESP_LOGCONFIG(TAG, " OBIS code: %s, Name: %s", s->get_obis_code().c_str(), s->get_sensor_name().c_str()); + } + } + + void XT211Component::register_sensor(XT211SensorBase *sensor) { + this->sensors_.insert({sensor->get_obis_code(), sensor}); + } + + void XT211Component::abort_mission_() { + ESP_LOGV(TAG, "Push mode error, returning to listening"); + this->clear_rx_buffers_(); + this->set_next_state_(State::IDLE); + } + + void XT211Component::report_failure(bool failure) { + if (!failure) { + this->stats_.failures_ = 0; + return; + } + + this->stats_.failures_++; + ESP_LOGE(TAG, "Failure reported. Count: %u", this->stats_.failures_); + } + + void XT211Component::loop() { + if (!this->is_ready() || this->state_ == State::NOT_INITIALIZED) + return; + + switch (this->state_) { + case State::IDLE: { + this->update_last_rx_time_(); + this->indicate_transmission(false); + this->indicate_session(false); + + // Push mode listening logic + if (this->available() > 0) { + // Set up for receiving push data + memset(this->buffers_.in.data, 0, buffers_.in.capacity); + this->buffers_.in.size = 0; + // read what we can then move forward to avoid buffer overflow + this->receive_frame_raw_(); + + ESP_LOGV(TAG, "Push mode: incoming data detected"); + this->stats_.connections_tried_++; + this->loop_state_.session_started_ms = millis(); + + this->indicate_transmission(true); + this->set_next_state_(State::COMMS_RX); + } + } + break; + + case State::WAIT: + if (this->check_wait_timeout_()) { + this->set_next_state_(this->wait_.next_state); + this->update_last_rx_time_(); + } + break; + + case State::COMMS_RX: { + this->handle_comms_rx_(); + } + break; + + case State::MISSION_FAILED: { + this->set_next_state_(State::IDLE); + this->report_failure(true); + this->stats_dump(); + } + break; + + case State::PUSH_DATA_PROCESS: { + this->handle_push_data_process_(); + } + break; + + case State::PUBLISH: { + this->handle_publish_(); + } + break; + + default: + // Should not happen + ESP_LOGW(TAG, "Unhandled state: %s", state_to_string(this->state_)); + this->set_next_state_(State::IDLE); + break; + } + } + + void XT211Component::handle_comms_rx_() { + this->log_state_(); + + if (this->check_rx_timeout_()) { + ESP_LOGI(TAG, "Push data reception completed (timeout reached)"); + + this->indicate_connection(false); + this->indicate_transmission(false); + + // check if we received any data at all + this->indicate_connection(true); + if (this->buffers_.in.size > 0) { + ESP_LOGV(TAG, "Push mode RX data avail, len=%d", this->buffers_.in.size); + this->set_next_state_(State::PUSH_DATA_PROCESS); + } else { + ESP_LOGV(TAG, "Push mode RX timeout, no data, idling"); + this->set_next_state_(State::IDLE); + } + return; + } + + received_frame_size_ = this->receive_frame_raw_(); + // keep reading until timeout + } + + void XT211Component::handle_push_data_process_() { + this->log_state_(); + ESP_LOGD(TAG, "Processing received push data"); + this->loop_state_.sensor_iter = this->sensors_.begin(); + this->set_next_state_(State::PUBLISH); + this->process_push_data(); + this->clear_rx_buffers_(); + } + + void XT211Component::handle_publish_() { + this->log_state_(); + ESP_LOGD(TAG, "Publishing data"); + this->update_last_rx_time_(); + + if (this->loop_state_.sensor_iter != this->sensors_.end()) { + if (this->loop_state_.sensor_iter->second->shall_we_publish()) { + this->loop_state_.sensor_iter->second->publish(); + } + this->loop_state_.sensor_iter++; + } else { + this->stats_dump(); + if (this->crc_errors_per_session_sensor_ != nullptr) { + this->crc_errors_per_session_sensor_->publish_state(this->stats_.crc_errors_per_session()); + } + this->report_failure(false); + this->set_next_state_(State::IDLE); + ESP_LOGD(TAG, "Total time: %u ms", millis() - this->loop_state_.session_started_ms); + } + } + +// This is the entry point for PollingComponent, which is now unused. + void XT211Component::update() {} + + void XT211Component::set_next_state_delayed_(uint32_t ms, State next_state) { + if (ms == 0) { + set_next_state_(next_state); + } else { + ESP_LOGV(TAG, "Short delay for %u ms", ms); + set_next_state_(State::WAIT); + wait_.start_time = millis(); + wait_.delay_ms = ms; + wait_.next_state = next_state; + } + } + + void XT211Component::PushBuffers::init(size_t default_in_buf_size) { + BYTE_BUFFER_INIT(&in); + bb_capacity(&in, default_in_buf_size); + this->reset(); + } + + void XT211Component::PushBuffers::reset() { + in.size = 0; + in.position = 0; + } + + void XT211Component::PushBuffers::check_and_grow_input(uint16_t + more_data) { + const uint16_t GROW_EPSILON = 20; + if (in.size + more_data > in.capacity) { + ESP_LOGVV(TAG0, + "Growing input buffer from %d to %d", in.capacity, in.size + more_data + GROW_EPSILON); + bb_capacity(&in, in + .size + more_data + GROW_EPSILON); + } +} + +void XT211Component::process_push_data() { + ESP_LOGD(TAG, "Processing PUSH data frame with AXDR parser"); + + // Ensure we parse from the beginning of the collected frame + this->buffers_.in.position = 0; + const auto total_size = this->buffers_.in.size; + ESP_LOGD(TAG, "PUSH frame size: %u bytes", static_cast(total_size)); + + size_t total_objects = 0; + size_t iterations = 0; + + while (this->buffers_.in.position < this->buffers_.in.size) { + auto before = this->buffers_.in.position; + auto parsed_now = this->axdr_parser_->parse(); + auto after = this->buffers_.in.position; + iterations++; + + if (parsed_now == 0 && after == before) { + // No progress, avoid potential infinite loop on malformed frames + ESP_LOGW(TAG, "AXDR parser made no progress at pos=%u/%u, aborting", static_cast(after), + static_cast(this->buffers_.in.size)); + break; + } + total_objects += parsed_now; + ESP_LOGV(TAG, "AXDR iteration %u: parsed=%u, pos=%u/%u, objects_total=%u", static_cast(iterations), + static_cast(parsed_now), static_cast(after), + static_cast(this->buffers_.in.size), static_cast(total_objects)); + } + + ESP_LOGD(TAG, "PUSH data parsing complete: %u objects, bytes consumed %u/%u", static_cast(total_objects), + static_cast(this->buffers_.in.position), static_cast(total_size)); +} + +int XT211Component::set_sensor_value(uint16_t class_id, const uint8_t *obis_code, DLMS_DATA_TYPE value_type, + const uint8_t *value_buffer_ptr, uint8_t value_length, const int8_t *scaler, + const uint8_t *unit) { + static char obis_buf[32]; + auto er = hlp_getLogicalNameToString(obis_code, obis_buf); + + std::string obis_str(obis_buf); + + auto range = this->sensors_.equal_range(obis_str); + int found_count = 0; + for (auto it = range.first; it != range.second; ++it) { + XT211SensorBase *sensor = it->second; + if (!sensor->shall_we_publish()) { + continue; + } + ESP_LOGD(TAG, "Found sensor for OBIS code %s: '%s' ", obis_buf, sensor->get_sensor_name().c_str()); + found_count++; + +#ifdef USE_SENSOR + if (sensor->get_type() == SensorType::SENSOR) { + float val = dlms_data_as_float(value_type, value_buffer_ptr, value_length); + if (scaler != nullptr) { + float scale = pow(10, *scaler); + val *= scale; + } + static_cast(sensor)->set_value(val); +} +#endif + +#ifdef USE_TEXT_SENSOR + if (sensor->get_type() == SensorType::TEXT_SENSOR) { + auto val = dlms_data_as_string(value_type, value_buffer_ptr, value_length); + static_cast(sensor)->set_value(val.c_str()); +} +#endif + +#ifdef USE_BINARY_SENSOR + if (sensor->get_type() == SensorType::BINARY_SENSOR) { + bool val = dlms_data_as_float(value_type, value_buffer_ptr, value_length) != 0.0f; + static_cast(sensor)->set_value(val); +} +#endif + + } + + if (found_count == 0) { + ESP_LOGVV(TAG, "No sensor found for OBIS code: '%s'", (char *) obis_buf); + } else { + ESP_LOGVV(TAG, "Updated %d sensors for OBIS code: '%s'", found_count, (char *) obis_buf); + } + + return DLMS_ERROR_CODE_OK; +} + +void XT211Component::indicate_transmission(bool transmission_on) { +#ifdef USE_BINARY_SENSOR + if (this->transmission_binary_sensor_) { + this->transmission_binary_sensor_->publish_state(transmission_on); +} +#endif +} + +void XT211Component::indicate_session(bool session_on) { +#ifdef USE_BINARY_SENSOR + if (this->session_binary_sensor_) { + this->session_binary_sensor_->publish_state(session_on); +} +#endif +} + +void XT211Component::indicate_connection(bool connection_on) { +#ifdef USE_BINARY_SENSOR + if (this->connection_binary_sensor_) { + this->connection_binary_sensor_->publish_state(connection_on); +} +#endif +} + +size_t XT211Component::receive_frame_(FrameStopFunction stop_fn) { + const uint32_t read_time_limit_ms = 45; + size_t ret_val; + + auto count_available = this->available(); + if (count_available <= 0) + return 0; + + uint32_t read_start = millis(); + uint8_t * p; + + // ESP_LOGVV(TAG, "avail RX: %d", count_available); + buffers_.check_and_grow_input(count_available); + + while (count_available-- > 0) { + if (millis() - read_start > read_time_limit_ms) { + return 0; + } + + p = &this->buffers_.in.data[this->buffers_.in.size]; + if (!iuart_->read_one_byte(p)) { + return 0; + } + this->buffers_.in.size++; + + if (stop_fn(this->buffers_.in.data, this->buffers_.in.size)) { + ESP_LOGVV(TAG, "RX: %s", format_hex_pretty(this->buffers_.in.data, this->buffers_.in.size).c_str()); + ret_val = this->buffers_.in.size; + + this->update_last_rx_time_(); + return ret_val; + } + + yield(); + App.feed_wdt(); + } + return 0; +} + +size_t XT211Component::receive_frame_raw_() { + auto frame_end_check_timeout = [](uint8_t *b, size_t s) { + return false; // never stop by content, only by timeout + }; + return receive_frame_(frame_end_check_timeout); +} + +void XT211Component::clear_rx_buffers_() { + int available = this->available(); + if (available > 0) { + ESP_LOGVV(TAG, "Cleaning garbage from UART input buffer: %d bytes", available); + } + + int len; + while (available > 0) { + len = std::min(available, (int) buffers_.in.capacity); + this->read_array(this->buffers_.in.data, len); + available -= len; + } + memset(this->buffers_.in.data, 0, buffers_.in.capacity); + this->buffers_.in.size = 0; + this->buffers_.in.position = 0; +} + +const char *XT211Component::state_to_string(State state) { + switch (state) { + case State::NOT_INITIALIZED: + return "NOT_INITIALIZED"; + case State::IDLE: + return "IDLE"; + case State::WAIT: + return "WAIT"; + case State::COMMS_RX: + return "COMMS_RX"; + case State::MISSION_FAILED: + return "MISSION_FAILED"; + case State::PUBLISH: + return "PUBLISH"; + case State::PUSH_DATA_PROCESS: + return "PUSH_DATA_PROCESS"; + default: + return "UNKNOWN"; + } +} + +void XT211Component::log_state_(State *next_state) { + if (this->state_ != this->last_reported_state_) { + if (next_state == nullptr) { + ESP_LOGV(TAG, "State::%s", state_to_string(this->state_)); + } else { + ESP_LOGV(TAG, "State::%s -> %s", state_to_string(this->state_), state_to_string(*next_state)); + } + this->last_reported_state_ = this->state_; + } +} + +void XT211Component::stats_dump() { + ESP_LOGV(TAG, "============================================"); + ESP_LOGV(TAG, "Data collection and publishing finished."); + ESP_LOGV(TAG, "Total number of sessions ............. %u", this->stats_.connections_tried_); + ESP_LOGV(TAG, "Total number of invalid frames ....... %u", this->stats_.invalid_frames_); + ESP_LOGV(TAG, "Total number of CRC errors ........... %u", this->stats_.crc_errors_); + ESP_LOGV(TAG, "Total number of CRC errors recovered . %u", this->stats_.crc_errors_recovered_); + ESP_LOGV(TAG, "CRC errors per session ............... %f", this->stats_.crc_errors_per_session()); + ESP_LOGV(TAG, "Number of failures ................... %u", this->stats_.failures_); + ESP_LOGV(TAG, "============================================"); +} + +bool XT211Component::try_lock_uart_session_() { + if (AnyObjectLocker::try_lock(this->parent_)) { + ESP_LOGV(TAG, "UART bus %p locked by %s", this->parent_, this->tag_.c_str()); + return true; + } + ESP_LOGV(TAG, "UART bus %p busy", this->parent_); + return false; +} + +void XT211Component::set_baud_rate_(uint32_t baud_rate) { + if (this->iuart_ != nullptr) { + this->iuart_->update_baudrate(baud_rate); + } +} + +uint8_t XT211Component::next_obj_id_ = 0; + +std::string XT211Component::generateTag() { return str_sprintf("%s%03d", TAG0, ++next_obj_id_); } + +} // namespace xt211 +} // namespace esphome \ No newline at end of file diff --git a/components/xt211/xt211.h b/components/xt211/xt211.h new file mode 100644 index 0000000..55601ed --- /dev/null +++ b/components/xt211/xt211.h @@ -0,0 +1,206 @@ +#pragma once + +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/uart/uart.h" +#include "esphome/core/component.h" + +#ifdef USE_BINARY_SENSOR +#include "esphome/components/binary_sensor/binary_sensor.h" +#endif + +#include +#include +#include +#include +#include + +#include "xt211_sensor.h" +#include "xt211_uart.h" +#include "object_locker.h" + +#include "client.h" +#include "converters.h" +#include "cosem.h" +#include "dlmssettings.h" + +namespace esphome { + namespace xt211 { + static const size_t DEFAULT_IN_BUF_SIZE_PUSH = 2048; + + using SensorMap = std::multimap; + + using FrameStopFunction = std::function< + bool(uint8_t + *buf, + size_t size + )>; + + class AxdrStreamParser; + + class XT211Component : public PollingComponent, public uart::UARTDevice { + public: + XT211Component() : tag_(generateTag()) {}; + + void setup() override; + + void dump_config() override; + + void loop() override; + + void update() override; // Kept for PollingComponent, but will be empty + float get_setup_priority() const override { return setup_priority::DATA; }; + + void set_baud_rate(uint32_t baud_rate) { this->baud_rate_ = baud_rate; }; + + void set_receive_timeout_ms(uint32_t timeout) { this->receive_timeout_ms_ = timeout; }; + + void register_sensor(XT211SensorBase *sensor); + + void set_reboot_after_failure(uint16_t number_of_failures) { this->failures_before_reboot_ = number_of_failures; } + + // PUSH mode is now default, these are for configuring it + void set_push_show_log(bool show_log) { this->push_show_log_ = show_log; } + + void set_push_custom_pattern_dsl(const std::string &dsl) { this->push_custom_pattern_dsl_ = dsl; } + + bool has_error{true}; + +#ifdef USE_BINARY_SENSOR + SUB_BINARY_SENSOR(transmission) +SUB_BINARY_SENSOR(session) +SUB_BINARY_SENSOR(connection) +#endif + +#ifdef USE_TEXT_SENSOR + SUB_TEXT_SENSOR(last_scan) +#endif + + protected: + bool push_show_log_{false}; + std::string push_custom_pattern_dsl_{""}; + + uint32_t receive_timeout_ms_{2000}; + + std::unique_ptr iuart_; + + SensorMap sensors_; + + sensor::Sensor *crc_errors_per_session_sensor_{}; + + enum class State : uint8_t { + NOT_INITIALIZED, + IDLE, + WAIT, + COMMS_RX, + MISSION_FAILED, + PUSH_DATA_PROCESS, // Process received push data + PUBLISH, + } state_{State::NOT_INITIALIZED}; + State last_reported_state_{State::NOT_INITIALIZED}; + + struct { + uint32_t start_time{0}; + uint32_t delay_ms{0}; + State next_state{State::IDLE}; + } wait_; + + bool is_idling() const { return this->state_ == State::WAIT || this->state_ == State::IDLE; }; + + void set_next_state_(State next_state) { state_ = next_state; }; + + void set_next_state_delayed_(uint32_t ms, State next_state); + + void process_push_data(); + + // State handler methods extracted from loop() + void handle_comms_rx_(); + + void handle_push_data_process_(); + + void handle_publish_(); + + int set_sensor_value(uint16_t class_id, const uint8_t *obis_code, DLMS_DATA_TYPE value_type, + const uint8_t *value_buffer_ptr, uint8_t value_length, const int8_t *scaler, + const uint8_t *unit); + + void indicate_transmission(bool transmission_on); + + void indicate_session(bool session_on); + + void indicate_connection(bool connection_on); + + AxdrStreamParser *axdr_parser_{nullptr}; + + size_t received_frame_size_{0}; + + uint32_t baud_rate_{9600}; + + uint32_t last_rx_time_{0}; + + struct LoopState { + uint32_t session_started_ms{0}; // start of session + SensorMap::iterator sensor_iter{nullptr}; // publishing sensor values + + } loop_state_; + + struct PushBuffers { + gxByteBuffer in; + + void init(size_t default_in_buf_size); + + void reset(); + + void check_and_grow_input(uint16_t more_data); + + } buffers_; + + protected: + void clear_rx_buffers_(); + + void set_baud_rate_(uint32_t baud_rate); + + size_t receive_frame_(FrameStopFunction stop_fn); + + size_t receive_frame_raw_(); + + inline void update_last_rx_time_() { this->last_rx_time_ = millis(); } + + bool check_wait_timeout_() { return millis() - wait_.start_time >= wait_.delay_ms; } + + bool check_rx_timeout_() { return millis() - this->last_rx_time_ >= receive_timeout_ms_; } + + void report_failure(bool failure); + + void abort_mission_(); + + const char *state_to_string(State state); + + void log_state_(State *next_state = nullptr); + + struct Stats { + uint32_t connections_tried_{0}; + uint32_t crc_errors_{0}; + uint32_t crc_errors_recovered_{0}; + uint32_t invalid_frames_{0}; + uint8_t failures_{0}; + + float crc_errors_per_session() const { return (float) crc_errors_ / connections_tried_; } + } stats_; + + void stats_dump(); + + uint8_t failures_before_reboot_{0}; + + bool try_lock_uart_session_(); + // unlock_uart_session_() has been removed + + public: + private: + static uint8_t next_obj_id_; + std::string tag_; + + static std::string generateTag(); + }; + + } // namespace xt211 +} // namespace esphome \ No newline at end of file diff --git a/components/xt211/xt211_axdr_parser.cpp b/components/xt211/xt211_axdr_parser.cpp new file mode 100644 index 0000000..cef433f --- /dev/null +++ b/components/xt211/xt211_axdr_parser.cpp @@ -0,0 +1,877 @@ +#include "xt211_axdr_parser.h" +#include "esphome/core/log.h" +#include "esphome/core/helpers.h" +#include +#include +#include + +namespace esphome { +namespace xt211 { + +constexpr const char *TAG = "xt211.axdr"; + +const char *dlms_error_to_string(int error) { + switch (error) { + case DLMS_ERROR_CODE_OK: + return "DLMS_ERROR_CODE_OK"; + case DLMS_ERROR_CODE_HARDWARE_FAULT: + return "DLMS_ERROR_CODE_HARDWARE_FAULT"; + case DLMS_ERROR_CODE_TEMPORARY_FAILURE: + return "DLMS_ERROR_CODE_TEMPORARY_FAILURE"; + case DLMS_ERROR_CODE_READ_WRITE_DENIED: + return "DLMS_ERROR_CODE_READ_WRITE_DENIED"; + case DLMS_ERROR_CODE_UNDEFINED_OBJECT: + return "DLMS_ERROR_CODE_UNDEFINED_OBJECT"; + case DLMS_ERROR_CODE_ACCESS_VIOLATED: + return "DLMS_ERROR_CODE_ACCESS_VIOLATED"; + default: + return ""; + } +} + +const char *dlms_data_type_to_string(DLMS_DATA_TYPE vt) { + switch (vt) { + case DLMS_DATA_TYPE_NONE: + return "DLMS_DATA_TYPE_NONE"; + case DLMS_DATA_TYPE_BOOLEAN: + return "DLMS_DATA_TYPE_BOOLEAN"; + case DLMS_DATA_TYPE_BIT_STRING: + return "DLMS_DATA_TYPE_BIT_STRING"; + case DLMS_DATA_TYPE_INT32: + return "DLMS_DATA_TYPE_INT32"; + case DLMS_DATA_TYPE_UINT32: + return "DLMS_DATA_TYPE_UINT32"; + case DLMS_DATA_TYPE_OCTET_STRING: + return "DLMS_DATA_TYPE_OCTET_STRING"; + case DLMS_DATA_TYPE_STRING: + return "DLMS_DATA_TYPE_STRING"; + case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL: + return "DLMS_DATA_TYPE_BINARY_CODED_DESIMAL"; + case DLMS_DATA_TYPE_STRING_UTF8: + return "DLMS_DATA_TYPE_STRING_UTF8"; + case DLMS_DATA_TYPE_INT8: + return "DLMS_DATA_TYPE_INT8"; + case DLMS_DATA_TYPE_INT16: + return "DLMS_DATA_TYPE_INT16"; + case DLMS_DATA_TYPE_UINT8: + return "DLMS_DATA_TYPE_UINT8"; + case DLMS_DATA_TYPE_UINT16: + return "DLMS_DATA_TYPE_UINT16"; + case DLMS_DATA_TYPE_INT64: + return "DLMS_DATA_TYPE_INT64"; + case DLMS_DATA_TYPE_UINT64: + return "DLMS_DATA_TYPE_UINT64"; + case DLMS_DATA_TYPE_ENUM: + return "DLMS_DATA_TYPE_ENUM"; + case DLMS_DATA_TYPE_FLOAT32: + return "DLMS_DATA_TYPE_FLOAT32"; + case DLMS_DATA_TYPE_FLOAT64: + return "DLMS_DATA_TYPE_FLOAT64"; + case DLMS_DATA_TYPE_DATETIME: + return "DLMS_DATA_TYPE_DATETIME"; + case DLMS_DATA_TYPE_DATE: + return "DLMS_DATA_TYPE_DATE"; + case DLMS_DATA_TYPE_TIME: + return "DLMS_DATA_TYPE_TIME"; + case DLMS_DATA_TYPE_ARRAY: + return "DLMS_DATA_TYPE_ARRAY"; + case DLMS_DATA_TYPE_STRUCTURE: + return "DLMS_DATA_TYPE_STRUCTURE"; + case DLMS_DATA_TYPE_COMPACT_ARRAY: + return "DLMS_DATA_TYPE_COMPACT_ARRAY"; + case DLMS_DATA_TYPE_BYREF: + return "DLMS_DATA_TYPE_BYREF"; + default: + return "DMS_DATA_TYPE UNKNOWN"; + } +} + +bool hlp_isValueDataType(DLMS_DATA_TYPE type) { + switch (type) { + // Complex/Container types - NOT value types + case DLMS_DATA_TYPE_ARRAY: + case DLMS_DATA_TYPE_STRUCTURE: + case DLMS_DATA_TYPE_COMPACT_ARRAY: + return false; + + // All other types are value types + case DLMS_DATA_TYPE_NONE: + case DLMS_DATA_TYPE_BOOLEAN: + case DLMS_DATA_TYPE_BIT_STRING: + case DLMS_DATA_TYPE_INT32: + case DLMS_DATA_TYPE_UINT32: + case DLMS_DATA_TYPE_OCTET_STRING: + case DLMS_DATA_TYPE_STRING: + case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL: + case DLMS_DATA_TYPE_STRING_UTF8: + 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: + case DLMS_DATA_TYPE_FLOAT32: + case DLMS_DATA_TYPE_FLOAT64: + case DLMS_DATA_TYPE_DATETIME: + case DLMS_DATA_TYPE_DATE: + case DLMS_DATA_TYPE_TIME: + return true; + + default: + + return false; + } +} +float dlms_data_as_float(DLMS_DATA_TYPE value_type, const uint8_t *value_buffer_ptr, uint8_t value_length) { + if (value_buffer_ptr == nullptr || value_length == 0) + return 0.0f; + + auto be16 = [](const uint8_t *p) -> uint16_t { return (uint16_t) ((p[0] << 8) | p[1]); }; + auto be32 = [](const uint8_t *p) -> uint32_t { + return ((uint32_t) p[0] << 24) | ((uint32_t) p[1] << 16) | ((uint32_t) p[2] << 8) | (uint32_t) p[3]; + }; + auto be64 = [](const uint8_t *p) -> uint64_t { + uint64_t v = 0; + for (int i = 0; i < 8; i++) + v = (v << 8) | p[i]; + return v; + }; + + switch (value_type) { + case DLMS_DATA_TYPE_BOOLEAN: + case DLMS_DATA_TYPE_ENUM: + case DLMS_DATA_TYPE_UINT8: + return static_cast(value_buffer_ptr[0]); + case DLMS_DATA_TYPE_INT8: + return static_cast(static_cast(value_buffer_ptr[0])); + case DLMS_DATA_TYPE_UINT16: + if (value_length >= 2) + return static_cast(be16(value_buffer_ptr)); + return 0.0f; + case DLMS_DATA_TYPE_INT16: + if (value_length >= 2) { + int16_t v = static_cast(be16(value_buffer_ptr)); + return static_cast(v); + } + return 0.0f; + case DLMS_DATA_TYPE_UINT32: + if (value_length >= 4) + return static_cast(be32(value_buffer_ptr)); + return 0.0f; + case DLMS_DATA_TYPE_INT32: + if (value_length >= 4) { + int32_t v = static_cast(be32(value_buffer_ptr)); + return static_cast(v); + } + return 0.0f; + case DLMS_DATA_TYPE_UINT64: + if (value_length >= 8) + return static_cast(be64(value_buffer_ptr)); + return 0.0f; + case DLMS_DATA_TYPE_INT64: + if (value_length >= 8) { + uint64_t u = be64(value_buffer_ptr); + int64_t v = static_cast(u); + return static_cast(v); + } + return 0.0f; + case DLMS_DATA_TYPE_FLOAT32: + if (value_length >= 4) { + uint32_t u = be32(value_buffer_ptr); + float f{}; + std::memcpy(&f, &u, sizeof(f)); + return f; + } + return 0.0f; + case DLMS_DATA_TYPE_FLOAT64: + if (value_length >= 8) { + uint8_t b[8]; + for (int i = 0; i < 8; i++) + b[i] = value_buffer_ptr[i]; + + double d{}; + std::memcpy(&d, b, sizeof(d)); + return static_cast(d); + } + return 0.0f; + default: + return 0.0f; + } +} +std::string dlms_data_as_string(DLMS_DATA_TYPE value_type, const uint8_t *value_buffer_ptr, uint8_t value_length) { + if (value_buffer_ptr == nullptr && value_length == 0) + return std::string(); + + auto hex_of = [](const uint8_t *p, uint8_t len) -> std::string { + std::ostringstream ss; + ss << std::hex << std::setfill('0'); + for (uint8_t i = 0; i < len; i++) { + ss << std::setw(2) << static_cast(p[i]); + if (i + 1 < len) + ss << ""; // compact + } + return ss.str(); + }; + + switch (value_type) { + case DLMS_DATA_TYPE_OCTET_STRING: + case DLMS_DATA_TYPE_STRING: + case DLMS_DATA_TYPE_STRING_UTF8: { + return std::string(reinterpret_cast(value_buffer_ptr), + reinterpret_cast(value_buffer_ptr) + value_length); + } + case DLMS_DATA_TYPE_BIT_STRING: + case DLMS_DATA_TYPE_BINARY_CODED_DESIMAL: + return hex_of(value_buffer_ptr, value_length); + + case DLMS_DATA_TYPE_BOOLEAN: + case DLMS_DATA_TYPE_ENUM: + case DLMS_DATA_TYPE_UINT8: { + return std::to_string(static_cast(value_buffer_ptr ? value_buffer_ptr[0] : 0)); + } + case DLMS_DATA_TYPE_INT8: { + return std::to_string(static_cast(static_cast(value_buffer_ptr ? value_buffer_ptr[0] : 0))); + } + case DLMS_DATA_TYPE_UINT16: { + if (value_length >= 2) { + uint16_t v = (uint16_t) ((value_buffer_ptr[0] << 8) | value_buffer_ptr[1]); + return std::to_string(v); + } + return std::string(); + } + case DLMS_DATA_TYPE_INT16: { + if (value_length >= 2) { + int16_t v = (int16_t) ((value_buffer_ptr[0] << 8) | value_buffer_ptr[1]); + return std::to_string(v); + } + return std::string(); + } + case DLMS_DATA_TYPE_UINT32: { + if (value_length >= 4) { + uint32_t v = ((uint32_t) value_buffer_ptr[0] << 24) | ((uint32_t) value_buffer_ptr[1] << 16) | + ((uint32_t) value_buffer_ptr[2] << 8) | (uint32_t) value_buffer_ptr[3]; + return std::to_string(v); + } + return std::string(); + } + case DLMS_DATA_TYPE_INT32: { + if (value_length >= 4) { + int32_t v = ((int32_t) value_buffer_ptr[0] << 24) | ((int32_t) value_buffer_ptr[1] << 16) | + ((int32_t) value_buffer_ptr[2] << 8) | (int32_t) value_buffer_ptr[3]; + return std::to_string(v); + } + return std::string(); + } + case DLMS_DATA_TYPE_UINT64: { + if (value_length >= 8) { + uint64_t v = 0; + for (int i = 0; i < 8; i++) + v = (v << 8) | value_buffer_ptr[i]; + return std::to_string(v); + } + return std::string(); + } + case DLMS_DATA_TYPE_INT64: { + if (value_length >= 8) { + uint64_t u = 0; + for (int i = 0; i < 8; i++) + u = (u << 8) | value_buffer_ptr[i]; + int64_t v = static_cast(u); + return std::to_string(v); + } + return std::string(); + } + case DLMS_DATA_TYPE_FLOAT32: + case DLMS_DATA_TYPE_FLOAT64: { + float f = dlms_data_as_float(value_type, value_buffer_ptr, value_length); + // Use minimal formatting + std::ostringstream ss; + ss << f; + return ss.str(); + } + case DLMS_DATA_TYPE_DATETIME: + case DLMS_DATA_TYPE_DATE: + case DLMS_DATA_TYPE_TIME: + // For now, return hex. Higher-level layers may decode properly. + return hex_of(value_buffer_ptr, value_length); + + case DLMS_DATA_TYPE_NONE: + default: + return std::string(); + } +} + +void AxdrPatternRegistry::add_pattern(const AxdrDescriptorPattern &p) { + auto it = std::upper_bound( + patterns_.begin(), patterns_.end(), p, + [](const AxdrDescriptorPattern &a, const AxdrDescriptorPattern &b) { return a.priority < b.priority; }); + patterns_.insert(it, p); +} + +uint8_t AxdrStreamParser::peek_byte_() { + if (this->buffer_->position + 1 > this->buffer_->size) { + return 0xFF; + } + return this->buffer_->data[this->buffer_->position]; +} + +uint8_t AxdrStreamParser::read_byte_() { + if (this->buffer_->position + 1 > this->buffer_->size) { + return 0xFF; + } + return this->buffer_->data[this->buffer_->position++]; +} + +uint16_t AxdrStreamParser::read_u16_() { + if (this->buffer_->position + 2 > this->buffer_->size) { + return 0xFFFF; + } + uint16_t value = + (this->buffer_->data[this->buffer_->position] << 8) | this->buffer_->data[this->buffer_->position + 1]; + this->buffer_->position += 2; + return value; +} + +uint32_t AxdrStreamParser::read_u32_() { + if (this->buffer_->position + 4 > this->buffer_->size) { + return 0xFFFFFFFF; + } + uint32_t value = + (this->buffer_->data[this->buffer_->position] << 24) | (this->buffer_->data[this->buffer_->position + 1] << 16) | + (this->buffer_->data[this->buffer_->position + 2] << 8) | this->buffer_->data[this->buffer_->position + 3]; + this->buffer_->position += 4; + return value; +} + +bool AxdrStreamParser::test_if_date_time_12b_() { + if (this->buffer_->position + 12 > this->buffer_->size) { + return 0; + } + + const uint8_t *buf = this->buffer_->data + this->buffer_->position; + if (!buf) + return false; + + // Year + uint16_t year = (buf[0] << 8) | buf[1]; + if (!(year == 0x0000 || (year >= 1970 && year <= 2100))) + return false; + + // Month + uint8_t month = buf[2]; + if (!(month == 0xFF || (month >= 1 && month <= 12))) + return false; + + // Day of month + uint8_t day = buf[3]; + if (!(day == 0xFF || (day >= 1 && day <= 31))) + return false; + + // Day of week + uint8_t dow = buf[4]; + if (!(dow == 0xFF || (dow >= 1 && dow <= 7))) + return false; + + // Hour + uint8_t hour = buf[5]; + if (!(hour == 0xFF || hour <= 23)) + return false; + + // Minute + uint8_t minute = buf[6]; + if (!(minute == 0xFF || minute <= 59)) + return false; + + // Second + uint8_t second = buf[7]; + if (!(second == 0xFF || second <= 59)) + return false; + + // Hundredths of second + uint8_t ms = buf[8]; + if (!(ms == 0xFF || ms <= 99)) + return false; + + // some makers mix up the order + // Deviation (timezone offset, signed, 2 bytes) + uint16_t u_dev = (buf[9] << 8) | buf[10]; + int16_t s_dev = (int16_t) (u_dev); + if (!((s_dev == (int16_t) 0x8000 || (s_dev >= -720 && s_dev <= 720)))) + return false; + + uint8_t clock_status = buf[11]; + + return true; +} + +constexpr uint16_t MAX_CLASS_ID = 0x00FF; +constexpr uint8_t MAX_ATTRIBUTE_ID = 0x20; +constexpr size_t MIN_UNTAGGED_ATTRIBUTE_DESCRIPTOR_SIZE = 9; +constexpr size_t MIN_TAGGED_ATTRIBUTE_DESCRIPTOR_SIZE = 14; + +bool AxdrStreamParser::skip_data_(uint8_t type) { + int data_size = hlp_getDataTypeSize((DLMS_DATA_TYPE) type); + + if (data_size == 0) // Zero-length data (NONE type) - nothing to skip + return true; + + if (data_size > 0) { // Fixed size data + if (this->buffer_->position + data_size > this->buffer_->size) { + return false; + } + this->buffer_->position += data_size; + } else { // Variable size data + uint8_t length = read_byte_(); + if (length == 0xFF) { + return false; + } + if (this->buffer_->position + length > this->buffer_->size) { + return false; + } + this->buffer_->position += length; + } + + return true; +} + +bool AxdrStreamParser::skip_sequence_(uint8_t type) { + uint8_t elements_count = read_byte_(); + if (elements_count == 0xFF) { + ESP_LOGV(TAG, "Invalid sequence length when skipping at position %d", this->buffer_->position - 1); + return false; + } + + ESP_LOGD(TAG, "Skipping %s with %d elements at position %d", + (type == DLMS_DATA_TYPE_STRUCTURE) ? "STRUCTURE" : "ARRAY", elements_count, this->buffer_->position - 1); + + for (uint8_t i = 0; i < elements_count; i++) { + uint8_t elem_type = read_byte_(); + if (!parse_element_(elem_type)) { + ESP_LOGV(TAG, "Failed to skip element %d of %s at position %d", i + 1, + (type == DLMS_DATA_TYPE_STRUCTURE) ? "STRUCTURE" : "ARRAY", this->buffer_->position - 1); + return false; + } + } + + return true; +} + +bool AxdrStreamParser::parse_data_(uint8_t type, uint8_t depth) { return skip_data_(type); } + +bool AxdrStreamParser::parse_sequence_(uint8_t type, uint8_t depth) { + uint8_t elements_count = read_byte_(); + if (elements_count == 0xFF) { + ESP_LOGVV(TAG, "Invalid sequence length at position %d", this->buffer_->position - 1); + return false; + } + + uint8_t elements_consumed = 0; + + while (elements_consumed < elements_count) { + uint32_t original_position = this->buffer_->position; + + if (try_match_patterns_(elements_consumed)) { + uint8_t used = this->last_pattern_elements_consumed_ ? this->last_pattern_elements_consumed_ : 1; + elements_consumed += used; + this->last_pattern_elements_consumed_ = 0; + continue; + } + + if (this->buffer_->position >= this->buffer_->size) { + ESP_LOGV(TAG, "Unexpected end while reading element %d of %s", elements_consumed + 1, + (type == DLMS_DATA_TYPE_STRUCTURE) ? "STRUCTURE" : "ARRAY"); + return false; + } + uint8_t elem_type = read_byte_(); + if (!parse_element_(elem_type, depth + 1)) { + return false; + } + elements_consumed++; + + if (this->buffer_->position == original_position) { + ESP_LOGV(TAG, "No progress parsing element %d at position %d, aborting to avoid infinite loop", elements_consumed, + original_position); + return false; + } + } + + return true; +} + +bool AxdrStreamParser::parse_element_(uint8_t type, uint8_t depth) { + if (type == DLMS_DATA_TYPE_STRUCTURE || type == DLMS_DATA_TYPE_ARRAY) { + return parse_sequence_(type, depth); + } else { + return parse_data_(type, depth); + } +} + +size_t AxdrStreamParser::parse() { + if (this->buffer_ == nullptr || this->buffer_->size == 0) { + ESP_LOGV(TAG, "Buffer is null or empty"); + return 0; + } + // Skip to notification flag 0x0F + while (this->buffer_->position < this->buffer_->size) { + uint8_t flag = read_byte_(); + if (flag == 0x0F) { + ESP_LOGD(TAG, "Found notification flag at position %d", this->buffer_->position - 1); + break; + } + } + + // Skip 5 bytes (invoke id and priority) + for (int i = 0; i < 5; i++) { + uint8_t priority = read_byte_(); + } + + // Check for datetime object before the data + bool is_date_time = test_if_date_time_12b_(); + if (is_date_time) { + ESP_LOGV(TAG, "Skipping datetime at position %d", this->buffer_->position); + this->buffer_->position += 12; + } + + // First byte after flag should be the data type + uint8_t start_type = read_byte_(); + if (start_type != (uint8_t) DLMS_DATA_TYPE_STRUCTURE && start_type != (uint8_t) DLMS_DATA_TYPE_ARRAY) { + ESP_LOGV(TAG, "Expected structure or array after notification flag, found type %02X at position %d", start_type, + this->buffer_->position); + return 0; + } + + // Parse the data, looking for attribute descriptors + bool success = parse_element_(start_type, 0); + if (!success) { + ESP_LOGV(TAG, "Some errors occurred parsing AXDR data"); + } + + ESP_LOGD(TAG, "Fast parsing completed, processed %d bytes", this->buffer_->position); + return this->objects_found_; +} + +bool AxdrStreamParser::capture_generic_value_(AxdrCaptures &c) { + uint8_t vt = read_byte_(); + if (!hlp_isValueDataType((DLMS_DATA_TYPE) vt)) { + return false; + } + int ds = hlp_getDataTypeSize((DLMS_DATA_TYPE) vt); + const uint8_t *ptr = nullptr; + uint8_t len = 0; + if (ds > 0) { + if (this->buffer_->position + ds > this->buffer_->size) + return false; + ptr = &this->buffer_->data[this->buffer_->position]; + len = (uint8_t) ds; + this->buffer_->position += ds; + } else if (ds == 0) { + ptr = nullptr; + len = 0; + } else { + uint8_t L = read_byte_(); + if (L == 0xFF || this->buffer_->position + L > this->buffer_->size) + return false; + ptr = &this->buffer_->data[this->buffer_->position]; + len = L; + this->buffer_->position += L; + } + c.value_type = (DLMS_DATA_TYPE) vt; + c.value_ptr = ptr; + c.value_len = len; + return true; +} + +void AxdrStreamParser::emit_object_(const AxdrDescriptorPattern &pat, const AxdrCaptures &c) { + if (!c.obis) + return; + uint16_t cid = c.class_id ? c.class_id : pat.default_class_id; + + if (this->show_log_) { + ESP_LOGD(TAG, "Pattern match '%s' at idx %d ===============", pat.name, c.elem_idx); + + auto val_f = dlms_data_as_float((DLMS_DATA_TYPE) c.value_type, c.value_ptr, c.value_len); + auto val_s = dlms_data_as_string((DLMS_DATA_TYPE) c.value_type, c.value_ptr, c.value_len); + ESP_LOGI(TAG, "Found attribute descriptor: class_id=%d, obis=%d.%d.%d.%d.%d.%d", cid, c.obis[0], c.obis[1], + c.obis[2], c.obis[3], c.obis[4], c.obis[5], c.value_type); + if (c.has_scaler_unit) { + ESP_LOGI(TAG, "Value type: %s, len %d, scaler %d, unit %d (%s)", + dlms_data_type_to_string((DLMS_DATA_TYPE) c.value_type), c.value_len, c.scaler, c.unit_enum, + obj_getUnitAsString(c.unit_enum)); + } else { + ESP_LOGI(TAG, "Value type: %s, len %d", dlms_data_type_to_string((DLMS_DATA_TYPE) c.value_type), c.value_len); + } + ESP_LOGI(TAG, " as hex dump : %s", esphome::format_hex_pretty(c.value_ptr, c.value_len).c_str()); + ESP_LOGI(TAG, " as string :'%s'", val_s.c_str()); + ESP_LOGI(TAG, " as number : %f", val_f); + if (c.has_scaler_unit) { + ESP_LOGI(TAG, " as number * scaler : %f", val_f * std::pow(10, c.scaler)); + } + } + + if (callback_) { + if (c.has_scaler_unit) { + callback_(cid, c.obis, c.value_type, c.value_ptr, c.value_len, &c.scaler, &c.unit_enum); + } else { + callback_(cid, c.obis, c.value_type, c.value_ptr, c.value_len, nullptr, nullptr); + } + } + this->objects_found_++; +} + +bool AxdrStreamParser::match_pattern_(uint8_t elem_idx, const AxdrDescriptorPattern &pat, + uint8_t &elements_consumed_at_level0) { + AxdrCaptures cap{}; + elements_consumed_at_level0 = 0; + uint8_t level = 0; + auto consume_one = [&]() { + if (level == 0) + elements_consumed_at_level0++; + }; + auto initial_position = this->buffer_->position; + + for (const auto &step : pat.steps) { + switch (step.type) { + case AxdrTokenType::EXPECT_TO_BE_FIRST: { + if (elem_idx != 0) + return false; + break; + } + case AxdrTokenType::EXPECT_TYPE_EXACT: { + uint8_t t = read_byte_(); + if (t != step.param_u8_a) + return false; + consume_one(); + break; + } + case AxdrTokenType::EXPECT_TYPE_U_I_8: { + uint8_t t = read_byte_(); + if (!(t == DLMS_DATA_TYPE_INT8 || t == DLMS_DATA_TYPE_UINT8)) + return false; + consume_one(); + break; + } + case AxdrTokenType::EXPECT_CLASS_ID_UNTAGGED: { + uint16_t v = read_u16_(); + if ( + // v == 0 || + v > MAX_CLASS_ID) + return false; + cap.class_id = v; + break; + } + case AxdrTokenType::EXPECT_OBIS6_TAGGED: { + uint8_t t = read_byte_(); + if (t != DLMS_DATA_TYPE_OCTET_STRING) + return false; + uint8_t len = read_byte_(); + if (len != 6) + return false; + if (this->buffer_->position + 6 > this->buffer_->size) + return false; + cap.obis = &this->buffer_->data[this->buffer_->position]; + this->buffer_->position += 6; + consume_one(); + break; + } + case AxdrTokenType::EXPECT_OBIS6_UNTAGGED: { + if (this->buffer_->position + 6 > this->buffer_->size) + return false; + cap.obis = &this->buffer_->data[this->buffer_->position]; + this->buffer_->position += 6; + break; + } + case AxdrTokenType::EXPECT_ATTR8_UNTAGGED: { + uint8_t a = read_byte_(); + if (a == 0) + return false; + // cap.attr_id = a; + break; + } + case AxdrTokenType::EXPECT_VALUE_GENERIC: { + if (!capture_generic_value_(cap)) + return false; + consume_one(); + break; + } + case AxdrTokenType::EXPECT_STRUCTURE_N: { + uint8_t t = read_byte_(); + if (t != DLMS_DATA_TYPE_STRUCTURE) + return false; + uint8_t cnt = read_byte_(); + if (cnt != step.param_u8_a) + return false; + consume_one(); + break; + } + case AxdrTokenType::EXPECT_SCALER_TAGGED: { + uint8_t t = read_byte_(); + if (t != DLMS_DATA_TYPE_INT8) + return false; + uint8_t b = read_byte_(); + cap.scaler = (int8_t) b; + cap.has_scaler_unit = true; + consume_one(); + break; + } + case AxdrTokenType::EXPECT_UNIT_ENUM_TAGGED: { + uint8_t t = read_byte_(); + if (t != DLMS_DATA_TYPE_ENUM) + return false; + uint8_t b = read_byte_(); + cap.unit_enum = b; + cap.has_scaler_unit = true; + consume_one(); + break; + } + case AxdrTokenType::GOING_DOWN: { + level++; + break; + } + case AxdrTokenType::GOING_UP: { + level--; + break; + } + default: + return false; + } + } + if (elements_consumed_at_level0 == 0) { + elements_consumed_at_level0 = 1; // Fallback: one element to move forward + } + cap.elem_idx = initial_position; + emit_object_(pat, cap); + return true; +} + +bool AxdrStreamParser::try_match_patterns_(uint8_t elem_idx) { + const auto &pats = registry_.patterns(); + for (const auto &p : pats) { + uint8_t consumed = 0; + uint32_t saved_position = buffer_->position; + if (match_pattern_(elem_idx, p, consumed)) { + this->last_pattern_elements_consumed_ = consumed; + return true; + } else { + buffer_->position = saved_position; + } + } + return false; +} + +void AxdrStreamParser::register_pattern_dsl(const char *name, const std::string &dsl, int priority) { + AxdrDescriptorPattern pat{name, priority, {}, 0}; + // DSL tokens separated by commas, optional spaces. Supported atoms: + // F : must be first element in sequence + // C : raw class_id (uint16 payload, no type tag) + // TC : tagged class_id (type tag UINT16 + uint16 payload) + // O : raw OBIS (6 bytes payload, no type tag) + // TO : tagged OBIS (type tag OCTET_STRING + length=6 + 6 bytes) + // A : raw attribute id (uint8 payload, no type tag) + // TA : tagged attribute (type tag INT8/UINT8 + 1 byte) + // TV : tagged value (type tag + payload for any value type) + // TSU : tagged scaler+unit structure (STRUCTURE tag + count 2 + TS + TU) + // Additionally supported: + // TS : tagged scaler (type tag INT8 + int8 payload) + // TU : tagged unit (type tag ENUM + uint8 payload) + // S(...) : structure with N elements, expands inner tokens + // Examples: "TC,TO,TA,TV", "TO,TV,TSU", "F,C,O,A,TV" + + // For simplicity we parse left-to-right and translate to steps. + + auto trim = [](const std::string &s) { + size_t b = s.find_first_not_of(" \t\r\n"); + size_t e = s.find_last_not_of(" \t\r\n"); + if (b == std::string::npos) + return std::string(); + return s.substr(b, e - b + 1); + }; + + std::list tokens; + std::string current; + int paren = 0; + for (char c : dsl) { + if (c == '(') { + paren++; + current.push_back(c); + } else if (c == ')') { + paren--; + current.push_back(c); + } else if (c == ',' && paren == 0) { + tokens.push_back(trim(current)); + current.clear(); + } else + current.push_back(c); + } + if (!current.empty()) + tokens.push_back(trim(current)); + + for (auto it = tokens.begin(); it != tokens.end(); ++it) { + auto &tok = *it; + if (tok.empty()) + continue; + if (tok == "F") { + pat.steps.push_back({AxdrTokenType::EXPECT_TO_BE_FIRST}); + } else if (tok == "C") { + pat.steps.push_back({AxdrTokenType::EXPECT_CLASS_ID_UNTAGGED}); + } else if (tok == "TC") { + pat.steps.push_back({AxdrTokenType::EXPECT_TYPE_EXACT, (uint8_t) DLMS_DATA_TYPE_UINT16}); + pat.steps.push_back({AxdrTokenType::EXPECT_CLASS_ID_UNTAGGED}); + } else if (tok == "O") { + pat.steps.push_back({AxdrTokenType::EXPECT_OBIS6_UNTAGGED}); + } else if (tok == "TO") { + pat.steps.push_back({AxdrTokenType::EXPECT_OBIS6_TAGGED}); + } else if (tok == "A") { + pat.steps.push_back({AxdrTokenType::EXPECT_ATTR8_UNTAGGED}); + } else if (tok == "TA") { + pat.steps.push_back({AxdrTokenType::EXPECT_TYPE_U_I_8}); + pat.steps.push_back({AxdrTokenType::EXPECT_ATTR8_UNTAGGED}); + } else if (tok == "TS") { + pat.steps.push_back({AxdrTokenType::EXPECT_SCALER_TAGGED}); + } else if (tok == "TU") { + pat.steps.push_back({AxdrTokenType::EXPECT_UNIT_ENUM_TAGGED}); + } else if (tok == "TSU") { + pat.steps.push_back({AxdrTokenType::EXPECT_STRUCTURE_N, 2}); + pat.steps.push_back({AxdrTokenType::GOING_DOWN}); + pat.steps.push_back({AxdrTokenType::EXPECT_SCALER_TAGGED}); + pat.steps.push_back({AxdrTokenType::EXPECT_UNIT_ENUM_TAGGED}); + pat.steps.push_back({AxdrTokenType::GOING_UP}); + } else if (tok == "V" || tok == "TV") { + pat.steps.push_back({AxdrTokenType::EXPECT_VALUE_GENERIC}); + } else if (tok.rfind("S", 0) == 0) { + size_t l = tok.find('('); + size_t r = tok.rfind(')'); + std::list inner_tokens; + if (l != std::string::npos && r != std::string::npos && r > l + 1) { + std::string inner = tok.substr(l + 1, r - l - 1); + std::vector innerT; + std::string cur; + for (char c2 : inner) { + if (c2 == ',') { + inner_tokens.push_back(trim(cur)); + cur.clear(); + } else + cur.push_back(c2); + } + if (!cur.empty()) + inner_tokens.push_back(trim(cur)); + } + if (!inner_tokens.empty()) { + pat.steps.push_back({AxdrTokenType::EXPECT_STRUCTURE_N, static_cast(inner_tokens.size())}); + inner_tokens.push_front("DN"); + inner_tokens.push_back("UP"); + tokens.insert(std::next(it), inner_tokens.begin(), inner_tokens.end()); + } + + } else if (tok == "DN") { + pat.steps.push_back({AxdrTokenType::GOING_DOWN}); + } else if (tok == "UP") { + pat.steps.push_back({AxdrTokenType::GOING_UP}); + } + } + + registry_.add_pattern(pat); +} + +} // namespace xt211 +} // namespace esphome \ No newline at end of file diff --git a/components/xt211/xt211_axdr_parser.h b/components/xt211/xt211_axdr_parser.h new file mode 100644 index 0000000..61ffc37 --- /dev/null +++ b/components/xt211/xt211_axdr_parser.h @@ -0,0 +1,118 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "client.h" +#include "converters.h" +#include "cosem.h" +#include "dlmssettings.h" + +namespace esphome { + namespace xt211 { + + const char *dlms_data_type_to_string(DLMS_DATA_TYPE vt); + const char *dlms_error_to_string(int error); + float dlms_data_as_float(DLMS_DATA_TYPE value_type, const uint8_t *value_buffer_ptr, uint8_t value_length); + std::string dlms_data_as_string(DLMS_DATA_TYPE value_type, const uint8_t *value_buffer_ptr, uint8_t value_length); + + bool hlp_isValueDataType(DLMS_DATA_TYPE type); + + using CosemObjectFoundCallback = + std::function; + + enum class AxdrTokenType : uint8_t { + EXPECT_TO_BE_FIRST, + EXPECT_TYPE_EXACT, // param_u8_a = required DLMS type tag + EXPECT_TYPE_U_I_8, // param_u8_a = required DLMS type tag; accept UINT8 or INT8 + EXPECT_CLASS_ID_UNTAGGED, // capture class_id (big endian) + EXPECT_OBIS6_TAGGED, // capture 6-byte tagged OBIS + EXPECT_OBIS6_UNTAGGED, // capture 6-byte OBIS + EXPECT_ATTR8_UNTAGGED, // capture attribute id (accept INT8/UINT8 depending on flags) + EXPECT_VALUE_GENERIC, // capture value: first byte is type tag; supports fixed/variable lengths + EXPECT_STRUCTURE_N, // expect a structure with element count = param_u8_a + EXPECT_SCALER_TAGGED, // capture scaler (INT8 or UINT8) + EXPECT_UNIT_ENUM_TAGGED, // capture unit enum (ENUM base + 1 byte value) + GOING_DOWN, // capture going down + GOING_UP, // capture going up + }; + + struct AxdrPatternStep { + AxdrTokenType type; + uint8_t param_u8_a{0}; + }; + + struct AxdrDescriptorPattern { + const char *name; + int priority{0}; + std::vector steps; + + uint16_t default_class_id{0}; + uint8_t value_attr_id{2}; + uint8_t scaler_unit_attr_id{3}; + }; + + struct AxdrCaptures { + uint32_t elem_idx{0}; + uint16_t class_id{0}; + const uint8_t *obis{nullptr}; + DLMS_DATA_TYPE value_type{DLMS_DATA_TYPE_NONE}; + const uint8_t *value_ptr{nullptr}; + uint8_t value_len{0}; + + bool has_scaler_unit{false}; + int8_t scaler{0}; + uint8_t unit_enum{DLMS_UNIT_NO_UNIT}; + }; + + class AxdrPatternRegistry { + public: + void add_pattern(const AxdrDescriptorPattern &p); + const std::vector &patterns() const { return patterns_; } + void clear() { patterns_.clear(); } + + private: + std::vector patterns_{}; + }; + + class AxdrStreamParser { + gxByteBuffer *buffer_; + CosemObjectFoundCallback callback_; + size_t objects_found_ = 0; + bool show_log_ = false; + + AxdrPatternRegistry registry_{}; + uint8_t last_pattern_elements_consumed_{0}; + + uint8_t peek_byte_(); + uint8_t read_byte_(); + uint16_t read_u16_(); + uint32_t read_u32_(); + + bool test_if_date_time_12b_(); + + bool parse_element_(uint8_t type, uint8_t depth = 0); + bool parse_sequence_(uint8_t type, uint8_t depth = 0); + bool parse_data_(uint8_t type, uint8_t depth = 0); + bool skip_data_(uint8_t type); + bool skip_sequence_(uint8_t type); + + bool try_match_patterns_(uint8_t elem_idx); + bool match_pattern_(uint8_t elem_idx, const AxdrDescriptorPattern &pat, uint8_t &elements_consumed_at_level); + bool capture_generic_value_(AxdrCaptures &c); + void emit_object_(const AxdrDescriptorPattern &pat, const AxdrCaptures &c); + + public: + AxdrStreamParser(gxByteBuffer *buf, CosemObjectFoundCallback callback, bool show_log) + : buffer_(buf), callback_(callback), show_log_(show_log) {} + size_t parse(); + void register_pattern_dsl(const char *name, const std::string &dsl, int priority = 10); + void clear_patterns() { registry_.clear(); } + }; + + } // namespace xt211 +} // namespace esphome \ No newline at end of file diff --git a/components/xt211/xt211_sensor.h b/components/xt211/xt211_sensor.h new file mode 100644 index 0000000..37d65f9 --- /dev/null +++ b/components/xt211/xt211_sensor.h @@ -0,0 +1,110 @@ +#pragma once + +#include "esphome/components/sensor/sensor.h" +#ifdef USE_TEXT_SENSOR +#include "esphome/components/text_sensor/text_sensor.h" +#endif +#ifdef USE_BINARY_SENSOR +#include "esphome/components/binary_sensor/binary_sensor.h" +#endif +#include // for std::pow + +namespace esphome { + namespace xt211 { + + enum SensorType { SENSOR, TEXT_SENSOR, BINARY_SENSOR }; + +// const char * UNIT_STR_UNKNOWN = "Unknown unit"; +#define UNIT_STR_UNKNOWN_NOT_YET "Unknown unit / not yet known" +#define UNIT_STR_UNKNOWN "Unknown unit" + + class XT211SensorBase { + public: + static const uint8_t MAX_REQUEST_SIZE = 15; + + virtual SensorType get_type() const = 0; + virtual const StringRef &get_sensor_name() = 0; + virtual EntityBase *get_base() = 0; + virtual void publish() = 0; + + void set_obis_code(const char *obis_code) { this->obis_code_ = obis_code; } + const std::string &get_obis_code() const { return this->obis_code_; } + + void set_dont_publish(bool dont_publish) { this->we_shall_publish_ = !dont_publish; } + bool shall_we_publish() const { return this->we_shall_publish_; } + + void set_obis_class(int obis_class) { this->obis_class_ = obis_class; } + int get_obis_class() { return this->obis_class_; } + + virtual bool has_got_scale_and_unit() { return false; } // PULL mode logic removed + + protected: + std::string obis_code_; + int obis_class_{3 /*DLMS_OBJECT_TYPE_REGISTER*/}; + bool we_shall_publish_{true}; + // Removed has_value_, tries_ + }; + + class XT211Sensor : public XT211SensorBase, public sensor::Sensor { + public: + SensorType get_type() const override { return SENSOR; } + const StringRef &get_sensor_name() { return this->get_name(); } + EntityBase *get_base() { return this; } + void publish() override { publish_state(this->value_); } + + bool has_got_scale_and_unit() override { return true; } // PULL mode logic removed + + void set_multiplier(float multiplier) { this->multiplier_ = multiplier; } + + void set_value(float value) { + // Scale is applied in XT211Component::set_sensor_value before calling this + this->value_ = value * multiplier_; + } + + protected: + float value_{NAN}; + float multiplier_{1.0f}; + // Removed scaler_, scale_f_, unit_, unit_s_, scale_and_unit_detected_ + }; + +#ifdef USE_TEXT_SENSOR + class XT211TextSensor : public XT211SensorBase, public text_sensor::TextSensor { + public: + SensorType get_type() const override { return TEXT_SENSOR; } + const StringRef &get_sensor_name() { return this->get_name(); } + EntityBase *get_base() { return this; } + void publish() override { publish_state(value_); } + + bool has_got_scale_and_unit() override { return true; } + + void set_value(const char *value) { + value_ = std::string(value); + } + + protected: + std::string value_; + +}; +#endif +#ifdef USE_BINARY_SENSOR + class XT211BinarySensor : public XT211SensorBase, public binary_sensor::BinarySensor { + public: + SensorType get_type() const override { return BINARY_SENSOR; } + const StringRef &get_sensor_name() { return this->get_name(); } + EntityBase *get_base() { return this; } + void publish() override { publish_state(value_); } + + bool has_got_scale_and_unit() override { return true; } + + void set_value(bool value) { + value_ = value; + } + + protected: + bool value_; + +}; +#endif + + } // namespace xt211 +} // namespace esphome \ No newline at end of file diff --git a/components/xt211/xt211_uart.h b/components/xt211/xt211_uart.h new file mode 100644 index 0000000..591cb8c --- /dev/null +++ b/components/xt211/xt211_uart.h @@ -0,0 +1,139 @@ +#pragma once +#include + +#ifdef USE_ESP32 +#include "esphome/components/uart/uart_component_esp_idf.h" +#include "esphome/core/log.h" +#endif + +#ifdef USE_ESP8266 +#include "esphome/components/uart/uart_component_esp8266.h" +#endif + +namespace esphome { +namespace xt211 { + +static const uint32_t TIMEOUT = 20; // default value in uart implementation is 100ms + +#ifdef USE_ESP8266 + +class XSoftSerial : public uart::ESP8266SoftwareSerial { + public: + void set_bit_time(uint32_t bt) { bit_time_ = bt; } +}; + +class XT211Uart final : public uart::ESP8266UartComponent { + public: + XT211Uart(uart::ESP8266UartComponent const &uart) + : uart_(uart), hw_(uart.*(&XT211Uart::hw_serial_)), sw_(uart.*(&XT211Uart::sw_serial_)) {} + + void update_baudrate(uint32_t baudrate) { + if (this->hw_ != nullptr) { + this->hw_->updateBaudRate(baudrate); + } else if (baudrate > 0) { + ((XSoftSerial *) sw_)->set_bit_time(F_CPU / baudrate); + } + } + + bool read_one_byte(uint8_t *data) { + if (this->hw_ != nullptr) { + if (!this->check_read_timeout_quick_(1)) + return false; + this->hw_->readBytes(data, 1); + } else { + if (sw_->available() < 1) + return false; + assert(this->sw_ != nullptr); + optional b = this->sw_->read_byte(); + if (b) { + *data = *b; + } else { + return false; + } + } + return true; + } + + protected: + bool check_read_timeout_quick_(size_t len) { + if (this->hw_->available() >= int(len)) + return true; + + uint32_t start_time = millis(); + while (this->hw_->available() < int(len)) { + if (millis() - start_time > TIMEOUT) { + return false; + } + yield(); + } + return true; + } + + uart::ESP8266UartComponent const &uart_; + HardwareSerial *const hw_; // hardware Serial + uart::ESP8266SoftwareSerial *const sw_; // software serial +}; +#endif + +#ifdef USE_ESP32 + +// backward compatibility with old IDF versions +#ifndef portTICK_PERIOD_MS +#define portTICK_PERIOD_MS portTICK_RATE_MS +#endif + +class XT211Uart final : public uart::IDFUARTComponent { + public: + XT211Uart(uart::IDFUARTComponent &uart) + : uart_(uart), iuart_num_(uart.*(&XT211Uart::uart_num_)), ilock_(uart.*(&XT211Uart::lock_)) {} + + // Reconfigure baudrate + void update_baudrate(uint32_t baudrate) { + xSemaphoreTake(ilock_, portMAX_DELAY); + uart_set_baudrate(iuart_num_, baudrate); + xSemaphoreGive(ilock_); + } + + bool read_one_byte(uint8_t *data) { return read_array_quick_(data, 1); } + + protected: + bool check_read_timeout_quick_(size_t len) { + if (uart_.available() >= int(len)) + return true; + + uint32_t start_time = millis(); + while (uart_.available() < int(len)) { + if (millis() - start_time > TIMEOUT) { + return false; + } + yield(); + } + return true; + } + + bool read_array_quick_(uint8_t *data, size_t len) { + size_t length_to_read = len; + if (!this->check_read_timeout_quick_(len)) + return false; + xSemaphoreTake(this->ilock_, portMAX_DELAY); + if (this->has_peek_) { + length_to_read--; + *data = this->peek_byte_; + data++; + this->has_peek_ = false; + } + if (length_to_read > 0) + uart_read_bytes(this->iuart_num_, data, length_to_read, 20 / portTICK_PERIOD_MS); + xSemaphoreGive(this->ilock_); + + return true; + } + + uart::IDFUARTComponent &uart_; + uart_port_t iuart_num_; + SemaphoreHandle_t &ilock_; +}; +#endif + +} // namespace xt211 +} // namespace esphome diff --git a/esphome-smartmeter.yaml b/esphome-smartmeter.yaml new file mode 100644 index 0000000..d91d40b --- /dev/null +++ b/esphome-smartmeter.yaml @@ -0,0 +1,182 @@ +esphome: + name: esphome-smartmeter + friendly_name: SmartMeter + +esp32: + variant: esp32c3 + framework: + type: esp-idf + +# Enable logging +logger: + +# Enable Home Assistant API +api: + +# Allow Over-The-Air updates +ota: +- platform: esphome + +wifi: + ssid: "wifi_ssid" + password: "wifi_password" + +external_components: + - source: + type: local + path: components + +uart: + id: bus_1 + rx_pin: GPIO21 + tx_pin: GPIO20 + baud_rate: 9600 + data_bits: 8 + parity: NONE + stop_bits: 1 + +xt211: + push_show_log: true + +text_sensor: + - platform: xt211 + name: Serial number + obis_code: 0.0.96.1.1.255 + entity_category: diagnostic + - platform: xt211 + name: Disconnector state + obis_code: 0.0.96.3.10.255 + entity_category: diagnostic + - platform: xt211 + name: Limmiter + obis_code: 0.0.17.0.0.255 + entity_category: diagnostic + + - platform: xt211 + name: Current tariff + obis_code: 0.0.96.14.0.255 + entity_category: diagnostic + + - platform: xt211 + name: Relay 1 + obis_code: 0.1.96.3.10.255 + - platform: xt211 + name: Relay 2 + obis_code: 0.2.96.3.10.255 + - platform: xt211 + name: Relay 3 + obis_code: 0.3.96.3.10.255 + - platform: xt211 + name: Relay 4 + obis_code: 0.4.96.3.10.255 + +sensor: + - platform: xt211 + id: active_energy_consumed + name: Energy + obis_code: 1.0.1.8.0.255 + unit_of_measurement: kWh + accuracy_decimals: 0 + device_class: energy + state_class: total_increasing + + - platform: xt211 + id: active_energy_consumed_t1 + name: Energy T1 + obis_code: 1.0.1.8.1.255 + unit_of_measurement: kWh + accuracy_decimals: 0 + device_class: energy + state_class: total_increasing + - platform: xt211 + id: active_energy_consumed_t2 + name: Energy T2 + obis_code: 1.0.1.8.2.255 + unit_of_measurement: kWh + accuracy_decimals: 0 + device_class: energy + state_class: total_increasing + - platform: xt211 + id: active_energy_consumed_t3 + name: Energy T3 + obis_code: 1.0.1.8.3.255 + unit_of_measurement: kWh + accuracy_decimals: 0 + device_class: energy + state_class: total_increasing + - platform: xt211 + id: active_energy_consumed_t4 + name: Energy T4 + obis_code: 1.0.1.8.4.255 + unit_of_measurement: kWh + accuracy_decimals: 0 + device_class: energy + state_class: total_increasing + + - platform: xt211 + id: active_power + name: Active power consumption + obis_code: 1.0.1.7.0.255 + unit_of_measurement: W + accuracy_decimals: 0 + device_class: power + state_class: measurement + + - platform: xt211 + id: active_power_l1 + name: Active power consumption L1 + obis_code: 1.0.21.7.0.255 + unit_of_measurement: W + accuracy_decimals: 0 + device_class: power + state_class: measurement + - platform: xt211 + id: active_power_l2 + name: Active power consumption L2 + obis_code: 1.0.41.7.0.255 + unit_of_measurement: W + accuracy_decimals: 0 + device_class: power + state_class: measurement + - platform: xt211 + id: active_power_l3 + name: Active power consumption L3 + obis_code: 1.0.61.7.0.255 + unit_of_measurement: W + accuracy_decimals: 0 + device_class: power + state_class: measurement + + - platform: xt211 + id: active_power_delivery + name: Active power delivery + obis_code: 1.0.2.7.0.255 + unit_of_measurement: W + accuracy_decimals: 0 + device_class: power + state_class: measurement + + - platform: xt211 + id: active_power_l1_delivery + name: Active power L1 delivery + obis_code: 1.0.22.7.0.255 + unit_of_measurement: W + accuracy_decimals: 0 + device_class: power + state_class: measurement + - platform: xt211 + id: active_power_l2_delivery + name: Active power L2 delivery + obis_code: 1.0.42.7.0.255 + unit_of_measurement: W + accuracy_decimals: 0 + device_class: power + state_class: measurement + - platform: xt211 + id: active_power_l3_delivery + name: Active power L3 delivery + obis_code: 1.0.62.7.0.255 + unit_of_measurement: W + accuracy_decimals: 0 + device_class: power + state_class: measurement