Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ZBHCI_CMD_ZCL_ATTR_WRITE_RCV example #40

Open
jrossouw opened this issue Mar 29, 2024 · 1 comment
Open

ZBHCI_CMD_ZCL_ATTR_WRITE_RCV example #40

jrossouw opened this issue Mar 29, 2024 · 1 comment

Comments

@jrossouw
Copy link

From my home automation application I am trying to write to the BINARY OUTPUT cluster (0x0010) or a T-Zigbee device. When I write a bool value to the PresentValue attribute (0x0055), I receive a ZBHCI_CMD_ZCL_ATTR_WRITE_RCV message on the T-Zigbee, but I cannot find an example of how to parse that message. There also is no handler in the zbhciCmdHandler function for that message type.

@asat232
Copy link

asat232 commented Oct 10, 2024

Good question, and the simple answer ZBHCI_CMD_ZCL_ATTR_WRITE_RCV message not handling.
I modified the code to support ZBHCI_CMD_ZCL_ATTR_WRITE_RCV message handling for data types:

ZCL_DATA_TYPE_UINT8
ZCL_DATA_TYPE_UINT16
ZCL_DATA_TYPE_UINT32
ZCL_DATA_TYPE_UINT64
//zbhci_common.h
typedef struct ts_MsgZclAttrWriteRcvPayload
{
    uint8_t      u8SeqNum;
    uint8_t      u8Unk; // i named Unk, because i dont know purpose of it
    uint16_t     u16SrcAddr;
    uint8_t      u8DstEp;
    uint16_t     u16ClusterId;
    uint8_t      u8AttrNum;
    ts_AttrList  asAttrList[4];
} ts_MsgZclAttrWriteRcvPayload;

typedef struct ts_HciMsg
{
    uint16_t u16MsgType;
    uint16_t u16MsgLength;
    union
    {
        ...
        ts_MsgZclAttrWriteRcvPayload           sZclAttrWriteRcvPayload;// only this line should be ADDED
        ...
    } uPayload;
} ts_HciMsg;
//zbhci.c
static void zbhci_UnpackZclAttrWriteRcvPayload(ts_MsgZclAttrWriteRcvPayload *psPayload);

static void zbhciCmdHandler(uint16_t u16MsgType, uint16_t u16MsgLen, uint8_t *pu8Payload, void *psPayload)
{
       ....
       case ZBHCI_CMD_ZCL_ATTR_WRITE_RCV:{
            zbhci_UnpackZclAttrWriteRcvPayload((ts_MsgZclAttrWriteRcvPayload *)psPayload, pu8Payload);
        }
        break;
        .....
}

static void zbhci_UnpackZclAttrWriteRcvPayload(ts_MsgZclAttrWriteRcvPayload *psPayload, uint8_t *pu8Payload){
    uint16_t u16Offset = 0;

    bzero(psPayload, sizeof(ts_MsgZclAttrWriteRcvPayload));
    psPayload->u8SeqNum     = BUFFER_TO_U8_OFFSET (pu8Payload, u16Offset, u16Offset);
    psPayload->u8Unk        = BUFFER_TO_U8_OFFSET (pu8Payload, u16Offset, u16Offset);
    psPayload->u16SrcAddr   = BUFFER_TO_U16_OFFSET(pu8Payload, u16Offset, u16Offset);
    psPayload->u8DstEp      = BUFFER_TO_U8_OFFSET (pu8Payload, u16Offset, u16Offset);
    psPayload->u16ClusterId = BUFFER_TO_U16_OFFSET (pu8Payload, u16Offset, u16Offset);
    psPayload->u8AttrNum    = BUFFER_TO_U8_OFFSET (pu8Payload, u16Offset, u16Offset);
    for (size_t n = 0; n < psPayload->u8AttrNum; n++)
    {
        psPayload->asAttrList[n].u16AttrID  = BUFFER_TO_U16_OFFSET (pu8Payload, u16Offset, u16Offset);
        psPayload->asAttrList[n].u8DataType = BUFFER_TO_U8_OFFSET (pu8Payload, u16Offset, u16Offset);
        if(psPayload->asAttrList[n].u8DataType == ZCL_DATA_TYPE_UINT8){
            psPayload->asAttrList[n].uAttrData.u8AttrData = BUFFER_TO_U8_OFFSET (pu8Payload, u16Offset, u16Offset);
        }
        else if(psPayload->asAttrList[n].u8DataType == ZCL_DATA_TYPE_UINT16){
            psPayload->asAttrList[n].uAttrData.u16AttrData = BUFFER_TO_U16_OFFSET (pu8Payload, u16Offset, u16Offset);
        }
        else if(psPayload->asAttrList[n].u8DataType == ZCL_DATA_TYPE_UINT32){
            psPayload->asAttrList[n].uAttrData.u32AttrData = BUFFER_TO_U32_OFFSET (pu8Payload, u16Offset, u16Offset);
        }
        else if(psPayload->asAttrList[n].u8DataType == ZCL_DATA_TYPE_UINT64){
            psPayload->asAttrList[n].uAttrData.u64AttrData = BUFFER_TO_U64_OFFSET (pu8Payload, u16Offset, u16Offset);
        }
    }
}
// handling in your .ino
void zbhciTask(void *pvParameters)
{
     ...
               case ZBHCI_CMD_ZCL_ATTR_WRITE_RCV:
                    displayZclAttrWriteRcv(&sHciMsg.uPayload.sZclAttrWriteRcvPayload);
                break;
     ....
}
// in my code i use remote udp logger, so you can replace d functions with Serial.printf
void displayZclAttrWriteRcv(ts_MsgZclAttrWriteRcvPayload *psPayload)
{
    d("Type: %#04x", ZBHCI_CMD_ZCL_ATTR_WRITE_RCV);
    d("  (ZCL Attr Write Rcv)");
    d("  SQN:        %#02x", psPayload->u8SeqNum);
    d("  Unknown:    %#02x", psPayload->u8Unk);
    d("  Src Addr:   %#04x", psPayload->u16SrcAddr);
    d("  Dst Ep:     %#02x", psPayload->u8DstEp);
    d("  Cluster ID: %#04x", psPayload->u16ClusterId);
    d("  Attr Num:   %#02x", psPayload->u8AttrNum);
    if (psPayload->u8AttrNum)
    {
        d("  Attr List:");
        for (size_t i = 0; i < psPayload->u8AttrNum; i++)
        {
            d("    Attr %d:", i);
            d("      Attr ID: %#04x", psPayload->asAttrList[i].u16AttrID);
            d("      Data Type: %#02x", psPayload->asAttrList[i].u8DataType);
            if(psPayload->asAttrList[i].u8DataType == ZCL_DATA_TYPE_UINT8){
                d("      Attr Data: %#02x", psPayload->asAttrList[i].uAttrData.u8AttrData);
            }
            else if(psPayload->asAttrList[i].u8DataType == ZCL_DATA_TYPE_UINT16){
                d("      Attr Data: %#04x", psPayload->asAttrList[i].uAttrData.u16AttrData);
            }
            else if(psPayload->asAttrList[i].u8DataType == ZCL_DATA_TYPE_UINT32){
                d("      Attr Data: %#08lx", psPayload->asAttrList[i].uAttrData.u32AttrData);
            }
            else if(psPayload->asAttrList[i].u8DataType == ZCL_DATA_TYPE_UINT64){
                d("      Attr Data: %#016llx", psPayload->asAttrList[i].uAttrData.u64AttrData);
            }
        }
    }
}

But sender side having bug as well, the bytes order is wrong, so sending uint32_t 0x01020304 , you will receive 0x04030201
To fix the issue you should modify:

//zbhci.c
void zbhci_ZclAttrWrite(uint8_t     u8DstAddrMode,
                       ts_DstAddr   sDstAddr,
                       uint8_t      u8SrcEp,
                       uint8_t      u8DstEp,
                       uint8_t      u8Direction,
                       uint16_t     u16ClusterID,
                       uint8_t      u8AttrNum,
                       ts_AttrList *psAttrList)
{
    uint16_t u16MsgLength    = 0;
    /** @bug The array may be out of bounds */
    uint8_t  au8Payload[256] = { 0 };
    int32_t  i               = 0;
    uint8_t  dataLen         = 0;

    U8_TO_BUFFER (&au8Payload[u16MsgLength], u8DstAddrMode, u16MsgLength);
    if (u8DstAddrMode == 0x01 || u8DstAddrMode == 0x02)
    {
        U16_TO_BUFFER (&au8Payload[u16MsgLength], sDstAddr.u16DstAddr, u16MsgLength);
    }
    else if (u8DstAddrMode == 0x03)
    {
        U64_TO_BUFFER (&au8Payload[u16MsgLength], sDstAddr.u64DstAddr, u16MsgLength);
    }
    U8_TO_BUFFER (&au8Payload[u16MsgLength], u8SrcEp,      u16MsgLength);
    U8_TO_BUFFER (&au8Payload[u16MsgLength], u8DstEp,      u16MsgLength);
    U8_TO_BUFFER (&au8Payload[u16MsgLength], u8Direction,  u16MsgLength);
    U16_TO_BUFFER(&au8Payload[u16MsgLength], u16ClusterID, u16MsgLength);
    U8_TO_BUFFER (&au8Payload[u16MsgLength], u8AttrNum,     u16MsgLength);
    for (i = 0; i < u8AttrNum; i++)
    {
        U16_TO_BUFFER(&au8Payload[u16MsgLength], psAttrList[i].u16AttrID, u16MsgLength);
        U8_TO_BUFFER(&au8Payload[u16MsgLength], psAttrList[i].u8DataType, u16MsgLength);
        if(psAttrList[i].u8DataType == ZCL_DATA_TYPE_UINT8){
            U8_TO_BUFFER(&au8Payload[u16MsgLength], psAttrList[i].uAttrData.u8AttrData, u16MsgLength);
        }
        else if(psAttrList[i].u8DataType == ZCL_DATA_TYPE_UINT16){
            U16_TO_BUFFER(&au8Payload[u16MsgLength], psAttrList[i].uAttrData.u16AttrData, u16MsgLength);
        }
        else if(psAttrList[i].u8DataType == ZCL_DATA_TYPE_UINT32){
            U32_TO_BUFFER(&au8Payload[u16MsgLength], psAttrList[i].uAttrData.u32AttrData, u16MsgLength);
        }
        else if(psAttrList[i].u8DataType == ZCL_DATA_TYPE_UINT64){
            U64_TO_BUFFER(&au8Payload[u16MsgLength], psAttrList[i].uAttrData.u64AttrData, u16MsgLength);
        }
        else{
            dataLen = zcl_getAttrSize(psAttrList[i].u8DataType, psAttrList[i].uAttrData.au8AttrData);
            memcpy(&au8Payload[u16MsgLength], &psAttrList[i].uAttrData, dataLen);
            
            u16MsgLength += dataLen;
        }
    }

    zbhci_Tx(ZBHCI_CMD_ZCL_ATTR_WRITE, u16MsgLength, au8Payload);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants