/* SPDX-License-Identifier: BSD-3-Clause */
/*
 * Copyright 2022 Raritan Inc. All rights reserved.
 */

#ifndef __PERIPHERAL_GATEWAY_SENSOR_MANAGER_IDL__
#define __PERIPHERAL_GATEWAY_SENSOR_MANAGER_IDL__

#include <Sensor.idl>
#include <NumericSensor.idl>
#include <Event.idl>
#include <ModbusCfg.idl>

/**
 * Peripheral Devices
 */
module peripheral {

    /** Gateway Sensor Configuration Interface */
    interface GatewaySensorManager_3_0_0 {

        /*
            To define a gateway sensor the following steps are required:

            1) Create a [Numeric|State|Switch]SensorClass with a unique
               *classId* and metadata.
               This specification can be used for one or more gateway sensors.

            2) Create a Remote[ModbusRTU|ModbusTCP|...]Device with a unique
               *deviceId* and all information required to connect a remote
               device that provides access to sensors and actuators to be associated
               to one or more gateway sensors.

            3) Create a ValueEncoding, e.g. ModbusValueEncoding[Bit|8|16|32|64],
               with a unique *encodingId* and all information needed to correctly
               interpret a received byte sequence.

               Besides word width, masking and encoding (bool/int/uint/float) there
               is also the possibility to define rules that interpret error codes and
               special values.

               A rule consists of a recognition feature (e.g. InterpretationRuleRAW,
               InterpretationRuleIEEE754INF) and an interpretation (e.g. IGNORE,
               NUMERIC_INVALID).

               This specification can be used for one or more gateway sensors.

            4) Create a [Modbus|...]Sensor, with references to configurations described
               above: *classId*, *deviceId* and *encodingId*. The unique *sensorId* will be
               generated if not set. Additionaly, [Modbus|...]Sensor has information necessary
               to address the sensor on the referenced RemoteDevice.

            5) Store all created classes using setConfiguration()


            Example A) PMMC-1000

                1) Create NumericSensorClass with
                        classId = "Temperature"
                        metaData = {
                            type = { NUMERIC, TEMPERATURE, DEGREE_CELSIUS },
                            decdigits = 1,
                            range = { -55, +85 },
                            accuracy = 0.1,
                            resolution = 0.1,
                            tolerance = 0,
                            noiseThreshold = -55,
                            thresholdCaps = { true, true, true, true }
                        }
                        defaultThresholds = {
                            upperCriticalActive = true,
                            upperCritical = 44.0,
                            upperWarningActive = true,
                            upperWarning = 37.0,
                            lowerWarningActive = true,
                            lowerWarning = 1.0,
                            lowerCriticalActive = true,
                            lowerCritical = -11,
                            assertionTimeout = 3,
                            deassertionHysteresis = 2.0F
                        }
                        preferCommonThresholds = false

                2) Create RemoteModbusRTUDevice with
                        deviceId = "PMMC"
                        busInterface = "REMOTE-HUB-1"
                        busSettings = {38400, NONE, 8, 1}
                        unitId = 247;
                        detectionIdentifiers = [ { VENDOR_NAME, "Raritan" },
                                                 { PRODUCT_CODE, "iPDU" }
                                                 { REVISION, "3\\.6.*"}
                                               ]

                3) Create ModbusValueEncoding32 with
                        encodingId = "IEEE754_32"
                        endianness = MODBUS_BIG_ENDIAN
                        type = IEEE754
                        interpretationRules = [
                            InterpretationRuleIEEE754NAN {
                                interpretation = INVALID
                            }
                        ]

                4) Create ModbusSensor with
                        classId = "Temperature"
                        deviceId = "PMMC"
                        encodingId = "IEEE754_32"
                        function = HOLDING_REGISTER;
                        regAddr = 0x812
                        defaultName = "Room temperature"


           Example B) Current sensor and check product code in INPUT_REGISTER 0

                1) Create NumericSensorClass with
                        classId = "Current"
                        metaData = {
                            type = { NUMERIC, CURRENT, AMPERE },
                            decdigits = 2,
                            range = { 0, 100 },
                            accuracy = 0.01,
                            resolution = 0.01,
                            tolerance = 0,
                            noiseThreshold = 0.01,
                            thresholdCaps = { true, true, true, true }
                        }

                2) Create RemoteModbusRTUDevice with
                        deviceId = "GW"
                        busInterface = "USB-2"
                        busSettings = {9600, NONE, 8, 1}
                        unitId = 1;

                3) Create ModbusValueEncoding32 with
                        encodingId = "IEEE754_32_MIXED_LE"
                        endianness = MODBUS_LITTLE_ENDIAN
                        type = IEEE754
                        interpretationRules = [
                            InterpretationRuleRAW {
                                value = 0x00800000         # FLT_MIN
                                interpretation = IGNORE
                                ignoreTimeout = 60         # unavailable after 60 seconds
                            },
                            InterpretationRuleRAW {
                                value = 0x7f7fffff         # FLT_MAX
                                interpretation = UNAVAILABLE
                            }
                        ]

                   Create ModbusValueEncoding16 with
                        encodingId = "GW_PRODUCT_UINT_16"
                        type = UINT
                        interpretationRules = [
                            InterpretationRuleRAW {
                                value = 1200                    # product code
                                invertCondition = true
                                interpretation = REJECT_DEVICE  # device detection failed
                            },
                        ]

                4) Create ModbusSensor with
                        classId = "Current"
                        deviceId = "GW"
                        encodingId = "IEEE754_32_MIXED_LE"
                        function = INPUT_REGISTER;
                        regAddr = 0xD
                        defaultName = "AC Current ch2"

                   Create ModbusSensor with
                        classId = ""                 # used for device detection only
                        deviceId = "GW"
                        encodingId = "GW_PRODUCT_UINT_16"
                        function = INPUT_REGISTER;
                        regAddr = 0


           Example C) Energy Meter

                1) Create NumericSensorClass with
                        classId = "Energy"
                        metaData = {
                            type = { NUMERIC, POWER, WATT },
                            decdigits = 1,
                            range = { 0, 9999999 },
                            accuracy = 0.1,
                            resolution = 0.1,
                            tolerance = 0,
                            noiseThreshold = 0,
                            thresholdCaps = { }
                        }

                2) Create RemoteModbusRTUDevice with
                        deviceId = "EX4"
                        busInterface = "REMOTE-HUB-1"
                        busSettings = {9600, NONE, 8, 1}
                        unitId = 4;

                3) Create ModbusValueEncoding32 with
                        encodingId = "UINT_24_MIXED_LE"
                        endianness = MODBUS_LITTLE_ENDIAN
                        mask = "0x00FFFFFF"
                        type = UINT
                        scalingFactor = 10.0;

                4) Create ModbusSensor with
                        classId = "Energy"
                        deviceId = "EX4"
                        encodingId = "UINT_24_MIXED_LE"
                        function = HOLDING_REGISTER;
                        regAddr = 0
                        defaultName = "Energy Meter"
        */


        /* ======================= SENSOR CLASSES ========================= */

        /**
         * @brief Specification of sensor class that stores sensor properties
         *
         * Before an instance of Sensor can be created,
         * an instance of SensorClass must be present.
         * The Sensor locates the corresponding SensorClass
         * using the sensor class id `classId`.
         */
        valueobject SensorClass {
            string classId;                            ///< sensor class id
        };

        /**
         * @brief Sensor class that stores numeric sensor properties
         */
        valueobject NumericSensorClass extends SensorClass {
            /**
             * numeric sensor type, ranges, etc.
             */
            sensors.NumericSensor_4_0_8.MetaData metadata;

            /**
             * threshold values may be used initially and as default threshold values,
             * depending on the value of the preferCommonThresholds field
             */
            sensors.NumericSensor_4_0_8.Thresholds defaultThresholds;

            boolean preferCommonThresholds;  ///< if true, use common default thresholds if available, otherwise use the value of the defaultThresholds field
        };

        /**
         * @brief Sensor class that stores state sensor properties
         */
        valueobject StateSensorClass extends SensorClass {
            sensors.Sensor_4_0_7.TypeSpec type;              ///< state sensor type
        };

        /**
         * @brief Sensor class that switch properties
         */
        valueobject SwitchSensorClass extends StateSensorClass { };


        /* ======================= REMOTE DEVICES ========================= */

        /**
         * @brief Specification of a remote device that provides access to sensors
         *
         * It contains all the information required to connect a remote
         * device that provides access to sensors and actuators to be connected
         * to one or more gateway sensors.
         *
         * Before an instance of Sensor can be created, an instance
         * of RemoteDevice must be present. The Sensor locates the
         * corresponding RemoteDevice using the remote device id `deviceId`.
         */
        valueobject RemoteDevice {
            string deviceId;   ///< remote device id
            boolean disabled;  ///< prevents usage of all sensor specifications which reference this device
            string name;       ///< human readable remote device name
            int timeoutMs;     ///< communication access timeout, 0 = default
            int retry;         ///< communication retry count, 0 = default
        };

        constant int MODBUS_VENDOR_NAME = 0;
        constant int MODBUS_PRODUCT_CODE = 1;
        constant int MODBUS_REVISION = 2;
        constant int MODBUS_VENDOR_URL = 3;
        constant int MODBUS_PRODUCT_NAME = 4;
        constant int MODBUS_MODEL_NAME = 5;
        constant int MODBUS_APP_NAME = 6;

        valueobject RemoteModbusDevice extends RemoteDevice {
            map<int, string> detectionIdentifiers; ///< list of expected device identifiers
            int unitId;                            ///< modbus server address
            /** @brief list of unsupported modbus function codes (FC)
              *
              * This information is used to select a supported way for communication,
              * if more than one way is available. If there is no flexibility, the list is ignored.
              * Therefore, some entries may have no effect.
              *
              * Examples:
              *  - FC 43 (Read Device Identification) is used without regard to this list,
              *    as there is no alternative way if detectionIdentifiers is to be used
              *  - FC 22 (Masked Register Write) is only used if the support is known,
              *    otherwise FC 03 + FC 06 (or FC 16 if not known as unsupported) will be used
              */
            vector<byte> unsupportedFunctionCodes;
        };

        valueobject RemoteModbusRTUDevice extends RemoteModbusDevice {
            /**
             * @brief rs485 interface used for modbus communication
             *
             * Supported values:
             *
             * (1) with SRC-080X, the REMOTE HUB interfaces are supported, possible values are:
             *   - "REMOTE-HUB-1" or "sensorhub0-rs485" (deprecated) mean port "REMOTE HUB 1"
             *   - "REMOTE-HUB-2" or "sensorhub1-rs485" (deprecated) mean port "REMOTE HUB 2"
             *
             * (2) with Raritan Modbus/RS-485 dongle "USB-MOD-DONGLE", possible values are:
             *   - "USB<topo>": where <topo> contains the USB port number and possibly the topology of USB hubs
             *       - "USB-2" means dongle connected to PDU USB port "USB A 2"
             *       - "USB-1-2-3" means dongle is connected to a first USB hub at port 3,
             *                     and the first USB hub is connected to a second USB hub at port 2,
             *                     and the second USB hub is connected to PDU USB port "USB A 1"
             *   - "<serial>": where <serial> is the serial number of USB dongle, according to the label
             */
            string busInterface;
            ModbusCfg.SerialSettings busSettings; ///< interface settings
            int interframeDelayDeciChars;         ///< (== 0) -> default, (< 0) -> no delay, (> 0) -> e.g. 35 means 3.5 chars
        };

        valueobject RemoteModbusTCPDevice extends RemoteModbusDevice {
            string          ipAddress;            ///< modbus device ip address
            int             tcpPort;              ///< modbus tcp port
        };

        valueobject RemoteSnmpDevice extends RemoteDevice {
            string          host;            ///< host
        };

        valueobject RemoteSnmpV1V2Device extends RemoteSnmpDevice {
            string          community;            ///< community string for v1/v2c
        };

        enumeration SnmpSecurityLevel {
            NO_AUTH_NO_PRIV,  ///< no authentication, no privacy
            AUTH_NO_PRIV,    ///< authentication, no privacy
            AUTH_PRIV       ///< authentication, privacy
        };

        enumeration SnmpAuthProtocol {
            MD5,       ///< MD5
            SHA1,      ///< SHA-1
            SHA224,    ///< SHA-224
            SHA256,    ///< SHA-256
            SHA384,    ///< SHA-384
            SHA512     ///< SHA-512
        };

        enumeration SnmpPrivProtocol {
            DES,          ///< DES
            AES128,       ///< AES-128
            AES192,       ///< AES-192
            AES256,       ///< AES-256
            AES192_3DES,  ///< AES-192 with key extension (3DES)
            AES256_3DES   ///< AES-256 with key extension (3DES)
        };

        valueobject RemoteSnmpV3Device extends RemoteSnmpDevice {
            string              user;               ///< security user name
            SnmpSecurityLevel   level;              ///< security level (noAuthNoPriv|authNoPriv|authPriv)
            SnmpAuthProtocol    authProtocol;       ///< authentication protocol (MD5|SHA|SHA-224|SHA-256|SHA-384|SHA-512)
            string              authPassphrase;     ///< authentication protocol passphrase
            SnmpPrivProtocol    privacyProtocol;    ///< privacy protocol (DES|AES|AES-192|AES-256)
            string              privacyPassphrase;  ///< privacy protocol pass phrase
        };

        /* ======================= VALUE ENCODING ========================= */

        /**
         * interpretation of binary values
         */
        enumeration EncodingType {
            BOOL,                          ///< boolean
            INT,                           ///< signed integer of a size specified in ValueEncoding as two's complement
            UINT,                          ///< unsigned integer of a size specified in ValueEncoding
            IEEE754,                       ///< IEEE 754 floating point of a size specified in ValueEncoding
            INT_ONES_COMPLEMENT,           ///< integer as one's complement
            INT_SIGN_MAGNITUDE,            ///< signed integer with sign in MSB
            INT_10K,                       ///< signed integer stored as 'modulo 10000' (int16[0] + 10000 * int16[1] + 10000^2 * int16[2] ...), the int16 parts are stores as two's complement
            UINT_10K,                      ///< unsigned integer stored as 'modulo 10000' (uint16[0] + 10000 * uint16[1] + 10000^2 * uint16[2] ...)
            INT_BCD,                       ///< signed integer as BCD, 10th complement
            INT_SIGN_MAGNITUDE_BCD,        ///< signed integer as BCD, with sign in MSB
            UINT_BCD,                      ///< unsigned integer as BCD
            INT_PACKED_BCD,                ///< signed integer as packed BCD, 10th complement
            INT_SIGN_MAGNITUDE_PACKED_BCD, ///< signed integer as packed BCD, with sign in MSB
            UINT_PACKED_BCD                ///< unsigned integer as packed BCD
        };

        /**
         * @brief Here you define how certain read values are to be interpreted
         *
         * The rules leading to *_IGNORE and *_UNAVAILABLE are applied to numeric values and states.
         *
         * IGNORE can be time-limited using ignoreTimeout, see InterpretationRule. After the time has expired,
         * the value is set to unavailable.
         *
         * NUMERIC_INVALID only affects NumericSensors. As DEFAULT for numeric sensors (if
         * no rule is matched, or if DEFAULT is matched) the value is converted to a floating point
         * number according to type specification.
         *
         * STATE_ON and STATE_OFF affect only StateSensors. If no such rule is specified, the state
         * becomes true if the read value is integral and not 0. If STATE_ON or STATE_OFF are present in
         * the rules, then the state is set to true or false only if a STATE_* rule matches. Otherwise
         * (DEFAULT) the state becomes unavailable.

         * REJECT_SENSOR means: do not accept this reading in any way. The sensor is treated as
         * non-existent.
         *
         * REJECT_DEVICE means: do not accept this reading in any way. Instead, this is a clear
         * indication that the device is defective, or it is a wrong device. All sensors that belong
         * to this device are treated as non-existent.
         * REJECT_DEVICE can be used in this way to detect devices. The sensor defined for this purpose
         * does not have to be imported as gateway sensor (see Sensor.classId = "").
         *
         * Default on read access for
         *   - received modbus exceptions is REJECT_SENSOR
         *   - on modbus errors (SystemError or ModbusSystemError) is REJECT_DEVICE
         *   - on value decoding/conversion is normal numeric/state decoding
         *
         * Default on write access (actuator switch) for
         *   - all modbus exceptions and errors is UNAVAILABLE
         */
        enumeration Interpretation {
            DEFAULT,                     ///< default behaviour as without rule, see above
            REJECT_DEVICE,               ///< read only: device is treated as non-existent
            REJECT_SENSOR,               ///< read only: sensor is treated as non-existent
            IGNORE,                      ///< read: ignore (use previous value) and retry  write: ignore error and retry
            UNAVAILABLE,                 ///< read: treat as unavailable (both state and numeric value)  write: give up, do not retry
            NUMERIC_INVALID,             ///< read only: treat as invalid numeric value
            STATE_ON,                    ///< read: treat as state ON   write: use for reversed rule to handle requested ON
            STATE_OFF                    ///< read: treat as state OFF  write: use for reversed rule to handle requested OFF
        };

        enumeration AccessType {
            ACCESS_READ_WRITE,           ///< use rule for both read and write access
            ACCESS_READ,                 ///< use rule for read access only
            ACCESS_WRITE                 ///< use rule for write access only
        };

        /**
         * InterpretationRule defines a rule that is applied to a reading, resulting in an Interpretation.
         * A list of InterpretationRule is applied in the given order, and stopped after the first match.
         * If no rule applies, the interpretation is Interpretation.DEFAULT.
         **/
        valueobject InterpretationRule {
            Interpretation interpretation; ///< how to interpret the applied rule
            int     ignoreTimeout;         ///< if > 0, ignoring stops after this timeout (seconds), and state changes to unavailable
            AccessType  accessType;        ///< use rule for read and/or write access
        };

        valueobject InterpretationRuleInvertable extends InterpretationRule {
            boolean invertCondition;       ///< negate rule condition
        };

        /** InterpretationRuleModbusException is applied to modbus read exceptions
         */
        valueobject InterpretationRuleModbusException extends InterpretationRuleInvertable {
            vector<int> exceptions;        ///< list of modbus exception codes
        };

        /** InterpretationRuleModbusSystemError is applied to standard system errors returned
         *  from libmodbus
         */
        valueobject InterpretationRuleModbusSystemError extends InterpretationRuleInvertable {
            vector<int> errnos;            ///< list of system error codes
        };

        /** InterpretationRuleModbusSpecificError is applied to specific errors from libmodbus
         */
        valueobject InterpretationRuleModbusSpecificError extends InterpretationRuleInvertable {
            vector<ModbusCfg.SpecificModbusErrors> errors;  ///< list of specific libmodbus error codes
        };

        /** InterpretationRuleRAW is applied after swap, but before masking (because it has it's own mask)
         */
        valueobject InterpretationRuleRAW extends InterpretationRuleInvertable {
            string value;                 ///< compare to value (unsigned 64-bit value as string, decimal or hexadecimal)
            string mask;                  ///< mask before compare (unsigned 64-bit value as string, decimal or hexadecimal; "" or "0" = not masked, the same as "0xFFFFFFFFFFFFFFFF")
        };

        /** InterpretationRuleRangeRAW is applied after swap, but before masking (because it has it's own mask)
         */
        valueobject InterpretationRuleRangeRAW extends InterpretationRuleInvertable {
            string min;                   ///< minimum accepted value (unsigned 64-bit value as string, decimal or hexadecimal)
            string max;                   ///< maximum accepted value (unsigned 64-bit value as string, decimal or hexadecimal)
            string mask;                  ///< mask before compare (unsigned 64-bit value as string, decimal or hexadecimal; "" or "0" = not masked, the same as "0xFFFFFFFFFFFFFFFF")
        };

        /** InterpretationRuleEnum is applied to a reading and maps the values to the given Interpretation
         */
        valueobject InterpretationRuleEnum extends InterpretationRuleInvertable {
            vector<string> enumValues;    ///< signed or unsigned 64-bit values as strings, decimal or hexadecimal 64-bit numbers
        };

        /** InterpretationRuleIEEE* are applied after value is wapped, masked and interpreted as float / double
         */
        valueobject InterpretationRuleIEEE754INF extends InterpretationRuleInvertable {};
        valueobject InterpretationRuleIEEE754NAN extends InterpretationRuleInvertable {};

        valueobject InterpretationRuleCatchAll extends InterpretationRule {};

        /**
         * @brief Specification of value encoding
         *
         * Before an instance of Sensor can be created,
         * an instance of ValueEncoding must be present.
         * The Sensor locates the corresponding ValueEncoding
         * using the sensor class id `encodingId`.
         */
        valueobject ValueEncoding {
            string                      encodingId;          ///< encoding type id
            EncodingType                type;                ///< value coding type
            boolean                     invertState;         ///< invert when interpreting as state
            vector<InterpretationRule>  interpretationRules; ///< error/value interpretation rules
            int                         minAccessInterval;   ///< minimum time interval between two read accesses in seconds
        };

        valueobject NumericValueEncoding extends ValueEncoding {
            float                       scalingFactor;       ///< multiply with when interpreting as numeric value
            float                       offset;              ///< add value after applying scalingFactor
        };

        valueobject ModbusValueEncodingBit extends ValueEncoding {};

        valueobject ModbusValueEncoding8 extends NumericValueEncoding {
            /**
             * 16-bit modbus words should be transferred in big-endian byte order.
             * For modbus devices that do not comply with this, byteSwap = true must
             * be set. Another application is to use byteSwap to address a single byte in
             * a 16-bit modbus word in case 8-bit values are requested (ModbusValueEncoding8).
             */
            boolean byteSwap;
            /**
             * 64-bit unsigned raw mask value as decimal or hexadecimal string, applied before interpreting
             * ("" or "0" = not masked, the same as "0xFFFFFFFFFFFFFFFF")
             */
            string mask;
            /**
             * The least significant bit of the read word used in numerical interpretation.
             * If `start` is greater than 0, then one or more least significant bits remain unused.
             * 0 is the default value. For integer values a `start > 0` has mostly the same effect as
             * using a `mask = ~(2^start-1)` and a `scalingFactor = 1/2^start`.
             */
            int start;
            /**
             * Word width in bits used in numerical interpretation.
             * If `width` is smaller than the read word width, then the most significant bits remain unused.
             * 0 is the default value.
             * Example: 24 bit signed integer:
             *   `ModbusValueEncoding32` with `start = 0` and `width = 24` and 'type = INT`
             * (Only for unsigned integer the use of `mask` would be sufficient.)
             */
            int width;
        };

        valueobject ModbusValueEncoding16 extends ModbusValueEncoding8 {};

        enumeration ModbusEndianness {
            MODBUS_BIG_ENDIAN,          ///< use big endian modbus word order (default is big endian)
            MODBUS_LITTLE_ENDIAN        ///< use little endian modbus word order
        };

        valueobject ModbusValueEncoding32 extends ModbusValueEncoding16 {
            /**
             * Modbus 16-bit-words should be transmitted in big endian order. For modbus
             * devices that do not comply with this, endianness must be set to LITTLE_ENDIAN.
             */
            ModbusEndianness endianness;
        };

        valueobject ModbusValueEncoding48 extends ModbusValueEncoding32 {};

        valueobject ModbusValueEncoding64 extends ModbusValueEncoding32 {};


        /* ======================= SENSORS  ========================= */

        /**
         * Specification of a Sensor
         */
        valueobject Sensor {
            /**
             * Unique sensor id, is automatically generated if not set
             */
            string           sensorId;

            /**
             * Set disabled = true prevents any usage of the specification
             */
            boolean          disabled;

            /**
             * @brief remote device id
             *
             * deviceId is used to locate the corresponding RemoteDevice that
             * provides the physical sensor
             */
            string           deviceId;

            /**
             * @brief sensor class id
             *
             * classId is used to locate the corresponding SensorClass.
             * classId = "" prevents the sensor specification from being used
             * for an imported gateway sensor. The sensor value is read anyway, and a read
             * error or a interpretation as Interpretation.REJECT_DEVICE
             * prevents the successful detection of the device
             */
            string           classId;

            /**
             * @brief sensor encoding id
             *
             * classId is used to locate the corresponding ValueEncoding
             */
            string           encodingId;

            /**
             * @brief sensor name
             *
             * defaultName is used as default sensor slot name
             */
            string           defaultName;

            /**
             * @brief sensor description
             *
             * defaultDescription is used as default sensor slot description
             */
            string           defaultDescription;

            /**
             * @brief sensor location X coordinate
             *
             * defaultLocationX is used as default sensor slot location X coordinate
             */
            string           defaultLocationX;

            /**
             * @brief sensor location Y coordinate
             *
             * defaultLocationY is used as default sensor slot location Y coordinate
             */
            string           defaultLocationY;

            /**
             * @brief sensor location Z coordinate
             *
             * defaultLocationZ is used as default sensor slot location Z coordinate
             */
            string           defaultLocationZ;
        };

        valueobject ModbusSensor extends Sensor {
            ModbusCfg.ModbusFunction  function;      ///< Modbus function to be used
            int                       regAddr;       ///< Modbus server register address
        };

        valueobject SnmpSensor extends Sensor {
            string                    oid;           ///< sensor oid
        };

        /* ======================= FULL CONFIGURATION  ========================= */

        structure ConfigurationPackage {
            boolean disabled;              ///< prevents usage of all sensor specifications defined in this package
            string name;                   ///< package name
            vector<SensorClass> classes;
            vector<RemoteDevice> devices;
            vector<ValueEncoding> encodings;
            vector<Sensor> sensors;
        };

        /**
         * @brief Get all defined gateway sensors and required objects from config
         *
         * Read all Sensor Classes, Remote Devices, Value Encodings and Sensors
         * at once to ensure that the overall configuration is consistent
         *
         * @return all defined gateway sensor feature configuration objects
         */
        map<string, ConfigurationPackage> getConfiguration();

        constant int ERR_CONFIG_INCONSISTENT = 1;
        constant int ERR_CONFIG_STORAGE_FAILED = 2;

        /**
         * @brief Replace defined gateway sensor and/or other configuration objects in config
         *
         * Write all Sensor Classes, Remote Devices, Value Encodings and Sensors
         * at once to ensure that the overall configuration is consistent at every
         * moment.
         *
         * The uniqueness of all IDs and the availability of all referenced elements are
         * checked before the configuration is applied. Otherwise setConfiguration() returns
         * with an error.
         *
         * @param cfg all defined gateway sensor feature configuration objects
         * @return 0 if OK
         * @return ERR_CONFIG_INCONSISTENT if consistency check has failed (e.g. non-unique identifiers)
         * @return ERR_CONFIG_STORAGE_FAILED if configuration cannot be stored
         */
        int setConfiguration(in map<string, ConfigurationPackage> cfg);

        /** Event: The gateway sensor feature configuration has changed */
        valueobject ConfigurationChangedEvent extends idl.Event {
            map<string, ConfigurationPackage> configuration;   ///< the current gateway sensor feature configuration
        };


        /* ======================= FEEDBACK  ========================= */

        /**
         * @brief Feedback from gateway sensor configuration usage
         *
         * There is no knowledge of Feedback required to configure gateway sensors.
         * The following is only needed for special tools that monitor the usage
         * of the configurations above.
         */
        structure FeedbackObject {
            enumeration FeedbackState {
                UNSPECIFIED,
                INTENTIONALLY_UNUSED,
                FAILED_PRECONDITIONS_UNUSED,
                FAILED,
                GOOD
            };

            string key;                         ///< empty or free defined value name
            string value;                       ///< message or value
            FeedbackState stateTansitionTo;     ///< this FeedbackObject changes state, if not UNSPECIFIED
        };

        valueobject Feedback {
            FeedbackObject.FeedbackState currentState;  ///< Device or sensor state
            vector<FeedbackObject> infos;
        };

        valueobject DeviceFeedback extends Feedback {
            string packageId;             ///< the configuration package id
            string deviceId;              ///< the same id as in RemoteDevice
        };

        valueobject SensorFeedback extends Feedback {
            string packageId;             ///< the configuration package id
            string deviceId;              ///< the same id as in RemoteDevice
            string sensorId;              ///< the same id as in Sensor
        };

        /**
         * Get feedback from gateway sensor configuration usage
         *
         * @return Result: the full feedback
         */
        vector<Feedback> getFeedback();

        /** Event: The configuration usage feedback has changed */
        valueobject FeedbackChangedEvent extends idl.Event {
            vector<Feedback> feedback;  ///< the latest configuration usage feedback
        };
    };
}

#endif /* __PERIPHERAL_GATEWAY_SENSOR_MANAGER_IDL__ */
