14.2.3.5.2 Read or write a Remote Attribute

To read or write an attribute on a remote device, the ZCL_AttribureReq() function is used. A single request can access values of several attributes from the same cluster.

The argument is of ZCL_Request_t* type. The id field of the argument shall be set to ZCL_READ_ATTRIBUTES_COMMAND_ID to read attributes’ values and to ZCL_WRITE_ATTRIBUTES_COMMAND_ID to write attributes’ values. The requestPayload and requestLength fields of the ZCL_Request_t instance shall be filled as described in following sections.

Payload for Read Attributes Command

To form the payload for the read attributes command use the ZCL_PutNextElement() function. With the help of this function attribute IDs are written one by one to the buffer in a correct way and the overall payload length is calculated. The buffer is then used as the payload for the read attribute command. See instructions below:

  1. Define variables of ZCL_NextElement_t and ZCL_ReadAttributeReq_t types. For example:
    ZCL_NextElement_t element;
    ZCL_ReadAttributeReq_t readAttrReqElement;
  2. Define a sufficiently large buffer (but note that it should include only attribute IDs). The buffer must be defined globally and may be a variable of the uint8_t* type.
  3. Configure element in the following way:
    element.payloadLength = 0;
    element.payload = buffer;
    element.id = ZCL_READ_ATTRIBUTES_COMMAND_ID;
    element.content = &readAttrReqElement;
    The buffer variable is assumed to be defined somewhere in the application to be used as the buffer.
  4. For each requested attribute repeat the following steps:
    1. Set readAttrReqElement.id to the target attributes identifier.
    2. Call ZCL_PutNextElement()(&element).
  5. Set the requestLength field of the ZCL_Request_t instance to element.payloadLength.
  6. Set the requestPayload field of the ZCL_Request_t instance in the request to buffer.

Payload for Write Attributes Command

Forming the payload for a write attributes command involves almost the same steps as for the read attributes command:

  1. Define a variable of ZCL_NextElement_t type and a request element. The latter may have the ZCL_WriteAttributeReq_t type. For example:
    ZCL_NextElement_t element;
    ZCL_WriteAttributeReq_t writeAttrReqElement;
    In this case the type field of the ZCL_WriteAttributeReq_t instance should be set to the constant specifying the attribute’s data type; for example, ZCL_U64BIT_DATA_TYPE_ID. The data type for a given attribute is defined by the ZCL specification and should coincide with the data type assigned to the attribute on the destination devices. The attribute’s value should be written to the value field. However, this field in fact has the unit8_t[1] type. A one-byte value may be assigned to value[0]. But values occupying more than one byte in memory cannot be written directly. A possible workaround is to allocate sufficiently long buffer and cast it to the ZCL_WriteAttributeReq_t* type. Another solution is to define a custom structure containing subsequent ID, type, and value fields, with the value field of the actual attribute’s size. For example, for 64-bit unsigned type the structure may be defined in the following way:
    typedef struct PACK
    {
     ZCL_AttributeId_t id;
     uint8_t type;
     uint64_t value;
    } APP_Write64BitAttributeReq_t;
    And the request element will be defined in this way:
    APP_Write64BitAttributeReq_t writeAttrReqElement;
  2. Configure element in the following way:
    element.payloadLength = 0;
    element.payload = buffer;
    element.id = ZCL_WRITE_ATTRIBUTES_COMMAND_ID;
    element.content = &writeAttrReqElement;
    
    The buffer variable is assumed to be defined somewhere in the application to be used as the buffer.
  3. For each requested attribute repeat the following steps:
    1. Set writeAttrReqElement.id to the target attribute’s ID.
    2. Write the attribute’s value to the writeAttrReqElement.value field. For a ZCL_WriteAttributeReq_t instance, cast this field to a pointer to the attribute’s data type and dereference it, for example:
      *(uint64_t*)writeAttrReqElement->value = VALUE;
    3. Call ZCL_PutNextElement()(&element). Check the returned value: ZCL_END_PAYLOAD_REACHED_STATUS will be returned when the last element fitting into the payload is written.
  4. Set the requestLength field of the ZCL_Request_t instance to element.payloadLength.
  5. Set the requestPayload field of the ZCL_Request_t instance in the request to buffer.