This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

adding an "array" attribute

Hello!
I add an attribute array (0x48) for the user cluster.
Having problems using the "array" attribute:


1. If you select the data type of 16 or 32 bits, then an alignment is added in the transmission, since the frame structure is: 8 bits for the type of array variables, then 16 bits for the length. Alignment is added after the 8 bit field for the variable type.
I use an array of 8-bit variables in the declaration, then a pointer to the desired structure and this is not a problem.


2. For some reason, 32 bytes are always transferred, regardless of the size of the specified array. Is this hardcoded or is it possible to specify the size?

#ifndef ZB_ZCL_ANALOG_SIGNAL_H__
#define ZB_ZCL_ANALOG_SIGNAL_H__

#include "zcl/zb_zcl_common.h"

/* Cluster ZB_ZCL_CLUSTER_ID_ANALOG_VALUE */

#define   ANALOG_NUMBER_OF_ARRAY_ELEMENTS     18
#define   ANALOG_DATA_TYPE                    ZB_ZCL_ATTR_TYPE_U8

typedef struct  struct_analog_data
{   
    zb_uint8_t  Element_Type;    
    zb_uint8_t  Number_Of_Elements1;
    zb_uint8_t  Number_Of_Elements2;  
    zb_uint8_t  allign;
    zb_int16_t  Analog_Signal_Array[ANALOG_NUMBER_OF_ARRAY_ELEMENTS];
} analog_data_t;

enum analog_array_element_t
{
   ANALOG_T1 = 0,
   ANALOG_T2,
   ANALOG_T3,
   ANALOG_T4,
   ANALOG_T5,
   ANALOG_T6,
   ANALOG_T7,
   ANALOG_T8,
   ANALOG_T9,
   ANALOG_T10,
   ANALOG_T11,
   ANALOG_T12,
   ANALOG_T13,
   ANALOG_T14,
   ANALOG_T15,
   ANALOG_T16,
   ANALOG_DI,
   ANALOG_DO,
};

typedef struct
{
    zb_bool_t       OutOfService;
    float           PresentValue;
    zb_uint8_t      StatusFlags;  
    analog_data_t   AnalogData;
} zb_zcl_analog_attrs_t;


enum zb_zcl_analog_measurement_attr_e
{
    ZB_ZCL_ATTR_ANALOG_SERVICE_ID = 0x0051,
    ZB_ZCL_ATTR_ANALOG_VALUE_ID   = 0x0055,
    ZB_ZCL_ATTR_ANALOG_STATUS_ID  = 0x006F,
    ZB_ZCL_ATTR_ANALOG_ARRAY_ID   = 0x0080,
};

/**@brief MeasuredValue attribute unknown value. */
#define ZB_ZCL_ATTR_ANALOG_VALUE_UNKNOWN                  ((zb_int16_t)0x8000)

/**@brief MinMeasuredValue attribute minimum value. */
#define ZB_ZCL_ATTR_ANALOG_MIN_VALUE_MIN_VALUE            ((zb_int16_t)0x8001)

/**@brief MinMeasuredValue attribute maximum value. */
#define ZB_ZCL_ATTR_ANALOG_MIN_VALUE_MAX_VALUE            0x7FFE

/**@brief MinMeasuredValue attribute invalid value. */
#define ZB_ZCL_ATTR_ANALOG_MIN_VALUE_INVALID              ((zb_int16_t)0x8000)

/**@brief MaxMeasuredValue attribute minimum value. */
#define ZB_ZCL_ATTR_ANALOG_MAX_VALUE_MIN_VALUE            ((zb_int16_t)0x8002)

/**@brief MaxMeasuredValue attribute maximum value. */
#define ZB_ZCL_ATTR_ANALOG_MAX_VALUE_MAX_VALUE            0x7FFF

/**@brief MaxMeasuredValue attribute invalid value. */
#define ZB_ZCL_ATTR_ANALOG_MAX_VALUE_INVALID              ((zb_int16_t)0x8000)

/**@brief MeasuredValue attribute unknown value. */
#define ZB_ZCL_ATTR_ANALOG_DEFAULT_STATUS_FLAG            ((zb_uint8_t)0x00)

/**@brief Default value for Value attribute. */
#define ZB_ZCL_ANALOG_VALUE_DEFAULT_VALUE ((zb_int16_t)0x0)

#define ZB_SET_ATTR_DESCR_WITH_ZB_ZCL_ATTR_ANALOG_VALUE_ID(data_ptr)              \
{                                                                                 \
    ZB_ZCL_ATTR_ANALOG_VALUE_ID,                                                  \
    ZB_ZCL_ATTR_TYPE_SINGLE,                                                      \
    ZB_ZCL_ATTR_ACCESS_READ_ONLY | ZB_ZCL_ATTR_ACCESS_WRITE_OPTIONAL,             \
    (zb_voidp_t) data_ptr                                                         \
}

#define ZB_SET_ATTR_DESCR_WITH_ZB_ZCL_ATTR_ANALOG_SERVICE_ID(data_ptr)             \
{                                                                                  \
    ZB_ZCL_ATTR_ANALOG_SERVICE_ID,                                                 \
    ZB_ZCL_ATTR_TYPE_BOOL,                                                         \
    ZB_ZCL_ATTR_ACCESS_READ_ONLY | ZB_ZCL_ATTR_ACCESS_WRITE_OPTIONAL,              \
    (zb_voidp_t) data_ptr                                                          \
}

#define ZB_SET_ATTR_DESCR_WITH_ZB_ZCL_ATTR_ANALOG_STATUS_ID(data_ptr)              \
{                                                                                  \
    ZB_ZCL_ATTR_ANALOG_STATUS_ID,                                                  \
    ZB_ZCL_ATTR_TYPE_8BITMAP,                                                      \
    ZB_ZCL_ATTR_ACCESS_READ_ONLY,                                                  \
    (zb_voidp_t) data_ptr                                                          \
}

#define ZB_SET_ATTR_DESCR_WITH_ZB_ZCL_ATTR_ANALOG_ARRAY_ID(data_ptr)               \
{                                                                                  \
    ZB_ZCL_ATTR_ANALOG_ARRAY_ID,                                                   \
    ZB_ZCL_ATTR_TYPE_ARRAY,                                                        \
    ZB_ZCL_ATTR_ACCESS_READ_ONLY,                                                  \
    (zb_voidp_t) data_ptr                                                          \
}


/**@brief Declares attribute list for the cluster on the server side.

 */
#define ZB_ZCL_DECLARE_ANALOG_ATTRIB_LIST(attr_list,                   \
    service, value, status, array)                                     \
  ZB_ZCL_START_DECLARE_ATTRIB_LIST(attr_list)                          \
  ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_ANALOG_SERVICE_ID, (service))       \
  ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_ANALOG_VALUE_ID, (value))           \
  ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_ANALOG_STATUS_ID, (status))         \
  ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_ANALOG_ARRAY_ID, (array))           \
  ZB_ZCL_FINISH_DECLARE_ATTRIB_LIST

/**@brief Function initialising the server side of Cluster. */
zb_void_t zb_zcl_analog_init_server(void);
/**@brief Function initialising the client side of Cluster. */
zb_void_t zb_zcl_analog_init_client(void);

/**@brief Defines needed for the stack to initialise the cluster correctly. */
#define ZB_ZCL_CLUSTER_ID_CUSTOM_ATTR_SERVER_ROLE_INIT zb_zcl_analog_init_server
#define ZB_ZCL_CLUSTER_ID_CUSTOM_ATTR_CLIENT_ROLE_INIT zb_zcl_analog_init_client

#endif /* ZB_ZCL_ANALOG_SIGNAL_H__ */

  • Hi,

    Are you implementing a custom cluster or are you trying to implement the "Analog Value" cluster from the ZCL specification?

    According to the ZCL specification the lenght (in octets) for the Array attribute type (0x48) shoud be 2 octets + the sum of lengths of contents.

     From the specification "The zeroth element is readable, always has type 16 bit unsigned integer, and holds the number of elements contained in the array".

    2. For some reason, 32 bytes are always transferred, regardless of the size of the specified array. Is this hardcoded or is it possible to specify the size?

    It looks like you are sending your own data type, since you have the struct 'analog_data_t' for attribute 0x0080, and I guess this is why you are having trouble. This is not encouraged by the Zigbee specification, see section 2.6.2 Data types in the ZCL specification.

    Best regards,

    Marjeris

  • Hi!

    Thanks for the answer. Zero element with 16-bit type, but one more bit is added for alignment, apparently this is done by the linker.
    now I'm making a custom attribute (I wanted an analog one right away, but more data needs to be transferred). There is an array and a string:
    ZB_ZCL_ATTR_TYPE_ARRAY,
    ZB_ZCL_ATTR_TYPE_CHAR_STRING.
    0x80 is the attribute number, during initialization I specify the correct ZB_ZCL_ATTR_TYPE_ARRAY = 0x48:

    #define ZB_SET_ATTR_DESCR_WITH_ZB_ZCL_ATTR_DATA_ARRAY_ID(data_ptr)                 \
    {                                                                                  \
        ZB_ZCL_ATTR_DATA_ARRAY_ID,                                                     \
        ZB_ZCL_ATTR_TYPE_ARRAY,                                                        \
        ZB_ZCL_ATTR_ACCESS_READ_ONLY,                                                  \
        (zb_voidp_t) data_ptr                                                          \
    }

    When requesting an array, the first element of the array (16-bit), which contains the length, is ignored, and all the time 32 bits of data are transmitted, including zero (16-bit, with the number of array elements).

    for example, I exposed 13 elements to see the extra data in the package:

    #define   CUSTOM_NUMBER_OF_ARRAY_ELEMENTS     6 //(CUSTOM_NUMBER_OF_ARRAY_ELEMENTS*2+1)

    Array data type:

    #define   CUSTOM_ARRAY_DATA_TYPE              ZB_ZCL_ATTR_TYPE_U8

    #ifndef ZB_ZCL_CUSTOM_SIGNAL_H__
    #define ZB_ZCL_CUSTOM_SIGNAL_H__
    
    #include "zcl/zb_zcl_common.h"
    
    /* Cluster  */
    #define   CUSTOM_ANALOG_STRING_SIZE           64
    #define   CUSTOM_NUMBER_OF_ARRAY_ELEMENTS     6
    #define   CUSTOM_ARRAY_DATA_TYPE              ZB_ZCL_ATTR_TYPE_U8
    
    typedef struct  struct_array_attr_data
    {   
        zb_uint8_t  Element_Type;    
        zb_uint8_t  Number_Of_Elements_1;
        zb_uint8_t  Number_Of_Elements_2;  
        zb_uint8_t  For_Allign;
        zb_int16_t  Data_Array[CUSTOM_NUMBER_OF_ARRAY_ELEMENTS];
    } array_attr_data_t;
    
    
    typedef struct
    {
        array_attr_data_t   ArrayAttrData;
        zb_char_t           StringAttrData[CUSTOM_ANALOG_STRING_SIZE];
    } zb_zcl_custom_attrs_t;
    
    
    enum zb_zcl_custom_attr_e
    {
        ZB_ZCL_ATTR_DATA_ARRAY_ID    = 0x0080,
        ZB_ZCL_ATTR_DATA_STRING_ID   = 0x0081,
    };
    
    /**@brief MeasuredValue attribute unknown value. */
    #define ZB_ZCL_ATTR_CUSTOM_DATA_VALUE_UNKNOWN              ((zb_int16_t)0x8000)
    
    
    /**@brief MinMeasuredValue attribute invalid value. */
    #define ZB_ZCL_ATTR_CUSTOM_DATA_VALUE_INVALID              ((zb_int16_t)0x8000)
    
    /**@brief Default value for Value attribute. */
    #define ZB_ZCL_CUSTOM_DATA_DEFAULT_VALUE                   ((zb_int16_t)0x0)
    
    
    #define ZB_SET_ATTR_DESCR_WITH_ZB_ZCL_ATTR_DATA_ARRAY_ID(data_ptr)                 \
    {                                                                                  \
        ZB_ZCL_ATTR_DATA_ARRAY_ID,                                                     \
        ZB_ZCL_ATTR_TYPE_ARRAY,                                                        \
        ZB_ZCL_ATTR_ACCESS_READ_ONLY,                                                  \
        (zb_voidp_t) data_ptr                                                          \
    }
    
    #define ZB_SET_ATTR_DESCR_WITH_ZB_ZCL_ATTR_DATA_STRING_ID(data_ptr)                \
    {                                                                                  \
        ZB_ZCL_ATTR_DATA_STRING_ID,                                                    \
        ZB_ZCL_ATTR_TYPE_CHAR_STRING,                                                  \
        ZB_ZCL_ATTR_ACCESS_READ_ONLY,                                                  \
        (zb_voidp_t) data_ptr                                                          \
    }
    
    /**@brief Declares attribute list for the cluster on the server side.
    
     */
    #define ZB_ZCL_DECLARE_ANALOG_ATTRIB_LIST(attr_list,                   \
        array, string)                                                     \
      ZB_ZCL_START_DECLARE_ATTRIB_LIST(attr_list)                          \
      ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_DATA_ARRAY_ID, (array))             \
      ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_DATA_STRING_ID, (string))           \
      ZB_ZCL_FINISH_DECLARE_ATTRIB_LIST
    
    /**@brief Function initialising the server side of Cluster. */
    zb_void_t zb_zcl_custom_signal_init_server(void);
    /**@brief Function initialising the client side of Cluster. */
    zb_void_t zb_zcl_custom_signal_init_client(void);
    
    /**@brief Defines needed for the stack to initialise the cluster correctly. */
    #define ZB_ZCL_CLUSTER_ID_CUSTOM_ATTR_SERVER_ROLE_INIT zb_zcl_custom_signal_init_server
    #define ZB_ZCL_CLUSTER_ID_CUSTOM_ATTR_CLIENT_ROLE_INIT zb_zcl_custom_signal_init_client
    
    #endif /* ZB_ZCL_CUSTOM_SIGNAL_H__ */
    

    there are 6 16-bit elements plus 1 alignment octet equals 13 elements in an array of 8-bit elements:

     m_dev_ctx.custom_attr.ArrayAttrData.Data_Array[0]=0x1122;
    m_dev_ctx.custom_attr.ArrayAttrData.Data_Array[1]=0x3344;
    m_dev_ctx.custom_attr.ArrayAttrData.Data_Array[2]=0x5566;
    m_dev_ctx.custom_attr.ArrayAttrData.Data_Array[3]=0x7788;
    m_dev_ctx.custom_attr.ArrayAttrData.Element_Type=CUSTOM_ARRAY_DATA_TYPE;
    m_dev_ctx.custom_attr.ArrayAttrData.Number_Of_Elements_1=CUSTOM_NUMBER_OF_ARRAY_ELEMENTS*2+1;

    In the parser, element 0 is an alignment octet (looks like a linker):

    Basically, I created an array of 15 16-bit elements + an alignment octet, then everything is transmitted exactly without extra or missing bytes.

  • pay attention "helloz" is in the next attribute "string", but it is passed along with the array, as if the length of the array is being ignored (last picture)

    m_dev_ctx.custom_attr.ArrayAttrData.Data_Array[0]=0x1122;
    m_dev_ctx.custom_attr.ArrayAttrData.Data_Array[1]=0x3344;
    m_dev_ctx.custom_attr.ArrayAttrData.Data_Array[2]=0x5566;
    m_dev_ctx.custom_attr.ArrayAttrData.Data_Array[3]=0x7788;
    m_dev_ctx.custom_attr.ArrayAttrData.Element_Type=CUSTOM_ARRAY_DATA_TYPE;
    m_dev_ctx.custom_attr.ArrayAttrData.Number_Of_Elements_1=CUSTOM_NUMBER_OF_ARRAY_ELEMENTS*2+1;
    m_dev_ctx.custom_attr.StringAttrData[0]=5;
    m_dev_ctx.custom_attr.StringAttrData[1]='h';
    m_dev_ctx.custom_attr.StringAttrData[2]='e';
    m_dev_ctx.custom_attr.StringAttrData[3]='l';
    m_dev_ctx.custom_attr.StringAttrData[4]='l';
    m_dev_ctx.custom_attr.StringAttrData[5]='o';
    m_dev_ctx.custom_attr.StringAttrData[6]='z';

  • Hi,

    I am sorry for the late reply. I was not able to reproduce your issue. Are you still struggling with this? Could you send your whole project folder so I can test this at my end?

    Best regards,

    Marjeris

  • hi and thanks.

    No more, now I am packing data into an array and transmitting it as a string. An array also works, but the entire array that was defined during initialization (CUSTOM_NUMBER_OF_ARRAY_ELEMENTS) is transmitted. And the value specified in the request (it may be less) is ignored and is still transmitted more as it was specified during initialization. The data still comes through, of course. It seems like the "sum of lengths of content" field is not used by the stack, the whole array is sent all the time.

Related