This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

RFD Binding Table

Other Parts Discussed in Thread: CC2538, Z-STACK, PACKET-SNIFFER

Hi Everyone, 

I'm using Z-Stack Energy on CC2538.

Im developing the IPD and a Load-Control Node (LCN) base codes into a customized solution for our project at the moment. The IPD is a reduced Function Device (RFD) and the LCN is a Full Function Device (FFD). We are trying to avoid having the ESP (Coordinator) in the network for normal use.

I am trying to create an end-point to end-point link between the two, such that the *IPD* can send a command to the *LCN*. I thought of using assisted Binding. After reading all the documentation, I'm a little confused about the issue: they seem to indicate that only FFD (reflector-devices) can use ZDP_BindReq(), but others seem to say this is not true.

Can I use the command ZDP_BindReq() on the IPD which is a RFD, to create this link and thus create a binding table on this device, so that if the LCN has it's short address changed over time, the IPD message will still find its way to the LCN?

Must I use ZDP_BindReq() on BOTH devices, or just the sending device (in this case the IPD), or just on the LCN (providing its set as a reflector)? 

Thanks for your consideration.

  • As I know, only FFD (reflector-devices) can use ZDP_BindReq. You should send Binding Request from your LCN.
  • Ok thanks YiKai, so I should send the ZDP_BindReq() command from the FFD, but set the bind-table location address to the destination address (RFD address)?
  • Ok thanks, Ill try it.
  • You are welcome.
  • Hi YiKai & Others,

    In the post above I asked about the binding table, but I've not been able to send the command yet! Here's why:

    Im trying to design the firmware so that a button press or other trigger on a LCN and IPD will create a binding. I can't use end-device-bind-requesting because it requires the coordinator. So the only alternative that I know of, is to broadcast a match-descriptor-request from the IPD and capture the address info of the LCN in its match-descriptor-response, and likewise the LCN would have captured the address info of the IDP.

    The problem is that this address info on the LCN is not complete: there is no end-point address, and this is required to use the ZDP_BindReq() command. I've tried initiating a simple-descriptor-request & response in an attempt to get the end-point address across, but even though I can see the end-point address being sent on the packet-sniffer, it does not seem to be accessible once in the LCN function "..._event_loop" under "SYS_EVENT_MSG". I've also tried using the "Identify" cluster, but it does not appear at all in "..._event_loop". So I'm not sure what to do.

    Here are the steps that I've tried so far:

    1. IPD > LCN - Match-descriptor request (Broadcast).
    2. LCN > IPD - Match-descriptor response.

    3. IPD > LCN - Simple-descriptor request, containing IPD EP. (via a button press) } Problem : cannot access EP in LCN "..._event_loop".
    4. LCN > IPD - Simple-descriptor response. }

    5. LCN > IPD - ZDP_BindReq(). (Not got here yet).
    6. LCN > LCN - ZDP_BindReq(). (Not got here yet).


    I've also tried:


    1. IPD > LCN - Match-descriptor request (Broadcast).
    2. LCN > IPD - Match-descriptor response.

    3. IPD > LCN - Identify command, containing IPD EP in srcAddr (via a button press) } Problem: data not sent to LCN "..._event_loop".

    4. LCN > IPD - ZDP_BindReq(). (Not got here yet).
    5. LCN > LCN - ZDP_BindReq(). (Not got here yet).


    Sorry for the long message! Best way I can describe the problem. Im open to any suggestions.

    Thanks!
  • You can use ZDP_ActiveEPReq to request endpoint and use ZDP_SimpleDescReq to get Simple Descriptor of related endpoint.
  • Thanks YiKai, I didnt think of using ZDP_ActiveEPReq.

    My LCN now sends a bind request to the IPD with the correct address parameters, but there are 2 problems:

    1. The Bind Request as shown by the packet sniffer has an address type error. I have set it to afAddr16Bit (0x02). Not sure what else might work. afAddrNotPresent (0x00) also doesn't work. Any comments on this?

    2. The IPD sends back a bind response indicating that it does not support binding. This might be due to its role as a RFD. Is there a compile option that I need to enable to make it as least use its binding table & system? I remember seeing one somewhere that might be the one, but I've no idea where now! Would enabling "REFLECTOR" on the RFD do it, without causing other problems?

    Thanks for your help with all this!
  • Can you show me how you use ZDP_BindReq and attach sniffer log?
  • Hi YiKai, thanks, please see the posts above, they are JPG files. The one shows the decoded values, and the other shows the raw values. I tried to upload the original workspace, but the browser would not let me because of the file extension. 

  • I think I've found the issue: One must use afAddr64Bit when sending a bind request. I've just tried it and the bind-request is now showing no errors, and the bind-response also shows no errors, status OK. This is the only change I made, no changes to the compiler options.
  • Yes, SourceAddr and DestinationAddr should be IEEE address. It's good to know it works now.
  • Hi YiKai, thanks for the help.

    There are still 2 strange things happening with my code, if you could spare a few moments to read about them and comment, that would be greatly appreciated!:

    1- For the ZDP_BindReq() function, it requires the zAddrType_t for the address parameters. When I declare & use this type and attempt to set the shortAddress parameter, the 2 LSB (Least Significant Bytes) of the IEEE address are replaced with the short address! They seem to have the same address. It does this even when I edit it in debug mode with the watch window, which shows that the addresses are the same.

    The function still sends without errors, which is surprising because the address mode is set to afAddr64Bit, so I'd expected that the IEEE would have to be correct. Whats also strange is that it also sends a NWKAddrReq packet for the erroneous IEEE address.

    Im not sure whats happening here, any comments / suggestions?

    2- In the *_event_loop() function, I'm trying to read the signal strength of the incoming packet to determine the sending device's closeness to the receiving device, for ZDO commands specifically.  I attempt to read the incoming message of type afIncomingMSGPacket_t. I thought that LinkQuality / RSSI might help me.

    The parameters are all misplaced, the data is a total mess. For example, I see the source-address in the place of the groupID parameter. And so all the parameters are garbage.

    I tried to fix this by using "#pragma pack (push, 1)" and "#pragma pack (pop)" around the afIncomingMSGPacket_t definition, but nothing changed. Once again, I've no idea why it would do this. Any comments / suggestions?

    Thanks again for taking time to read this long message! 

  • 1. I don't understand your problem well. Can you elaborate with your real case?
    2. Can you specify which case you use to get LQI/RSSI in _event_loop? It is better to use your real case to explain this.
  • Sorry for the confusion: I will put two posts, one per query, to help with clarity: 

    For query 1, I have shown the function that I use, and two JPG images showing the variables in real time, before and after I change the long address:

    The function:

    /*********************************************************************
     * @fn      sendBindReq
     *
     * @brief   Sends a bind request to a remote device and to this device
     *
     * @param   (uses global dstAddr)
     *
     * @return  none
     */
    void sendBindReq( uint8 linkEP )
    {
      if ( linkMode == true )   //Set elsewhere
      {
        uint8 outCome1, outCome2;
        zAddrType_t thisDeviceAddr;
        zAddrType_t otherDeviceAddr; 
        uint8 tempExtAddr[Z_EXTADDR_LEN];
        
        AddrMgrExtAddrLookup( remoteAddr.addr.shortAddr, tempExtAddr );
        
        osal_cpyExtAddr( (void *)&thisDeviceAddr.addr.extAddr, (void *)NLME_GetExtAddr() );
        thisDeviceAddr.addr.shortAddr = NLME_GetShortAddr();    //This step overwrites the last two bytes of IEEE address!!
        thisDeviceAddr.addrMode = afAddr64Bit;
        
        osal_cpyExtAddr( (void *)&otherDeviceAddr.addr.extAddr, (void *)tempExtAddr );
        otherDeviceAddr.addr.shortAddr = remoteAddr.addr.shortAddr;     //This step overwrites the last two bytes of the IEEE address!! 
        otherDeviceAddr.addrMode = afAddr64Bit;
        
        //Make entry into dstAddr's binding table ...
        outCome1 = ZDP_BindReq( &remoteAddr, tempExtAddr, linkEP,  
                                ZCL_CLUSTER_ID_GEN_ON_OFF, &thisDeviceAddr, LOADCONTROL_EP100_ENDPOINT, 0 );          
        
        //Make entry into local binding table ... 
        outCome2 = ZDP_BindReq( &otherDeviceAddr, tempExtAddr, linkEP, 
                                ZCL_CLUSTER_ID_GEN_ON_OFF, &thisDeviceAddr, LOADCONTROL_EP100_ENDPOINT, 0 );
        
        linkMode = false;
      }
    }

    The "Watch" window in IAR debugger BEFORE I manually edit the long address:

    Notice for "thisdeviceAddr" and "otherDeviceAddr", that the last two bytes of the long address match the two bytes of the short address, making the IEEE address incorrect.

    The "Watch" window in IAR debugger AFTER I manually edit the long address:

    Notice that after I change the last two bytes of the long address for both "thisDeviceAddr" and "otherDeviceAddr" to what they should be, the short address also changes to these two bytes on its own!

    I can see that the memory addresses of the short and long addresses are the same, surely this should not be the case?

  • For Query 2, I have shown the code of the  *_event_loop() function:

    /*********************************************************************
     * @fn          loadControlEP100_event_loop
     *
     * @brief       Event Loop Processor for loadcontrol.
     *
     * @param       uint8 task id - load control task id
     * @param       uint16 events - event bitmask
     *
     * @return      none
     */
    uint16 loadControlEP100_event_loop( uint8 task_id, uint16 events )
    {
      afIncomingMSGPacket_t *MSGpkt;  
      //afDataConfirm_t *afDataConfirm;
    
      if ( events & SYS_EVENT_MSG )
      {
        while ( (MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( loadControlTaskID )) )
        {
          switch ( MSGpkt->hdr.event )
          {
            #ifdef DANIEL_PCT_CI_SE_2013
             case MT_SYS_APP_MSG:
             // Message received from MT (serial port)
             loadcontrol_ProcessAppMsg( ( (mtSysAppMsg_t *)MSGpkt)->appData );
             break;
             
             case AF_INCOMING_MSG_CMD:
              customCommsCI( MSGpkt );
              break;
              
             case AF_DATA_CONFIRM_CMD:
              // This message is received as a confirmation of a data packet sent.
              // The status is of ZStatus_t type [defined in ZComDef.h]
              // The message fields are defined in AF.h
              //afDataConfirm = (afDataConfirm_t *)MSGpkt;
              
              /*(void)sentEP;
              (void)sentTransID;
    
              // Action taken when confirmation is received.
              if ( sentStatus != ZSuccess )
              {
                // The data wasn't delivered -- Do something
              }*/
              break;
             
            #endif  //DANIEL_PCT_CI_SE_2013
    
            case ZDO_CB_MSG:
              
              if ( (MSGpkt->rssi < 90) && (MSGpkt->wasBroadcast == true) ) //To stop every single LCN responding to a IPD/Remote broadcast, 
              {   }                                                        //  but still allowing unicast ZDO messages through.                                                                
              else  {                                                     // Therefore broadcasting device must be close to LCN!                
                loadcontrol_ProcessZDOMsgs( (zdoIncomingMsg_t *)MSGpkt );  }            
              break; 
    ...

    Have a look at case "ZDO_CB_MSG": I have attempted to filter out calls to the function "loadcontrol_ProcessZDOMsgs(...)" based on the two variables "MSGpkt->wasBroadcast" and "MSGpkt->rssi". The idea here is to only allow broadcasting messages that are very close to this device, to call the function.

    This is what the "Watch" window shows when execution enters the case:

    As you can see the short address (0xE0E8) is at the groupId parameter, and the short address, endPoint (0xBD) and clusterId (0x9E21) parameters are all some unknown value, along with all the others. This tells me that all the data in the struct "afIncomingMSGPacket_t" is completely mis-aligned.

    So, when I try to test the two parameters in question, the values that they refer to are completely inconsistent: moving the calling device further or nearer to this device make absolutely no difference to the rssi value, which is simply some random number every time this code is called.

    Thanks for taking time to understand these problems!

  • I see that the reply to Query 1 came out in a very confusing way! Here it is as it should have been:

    >>>

    Sorry for the confusion: I will put two posts, one per query, to help with clarity:

    For query 1, I have shown the function that I use, and two JPG images showing the variables in real time, before and after I change the long address:

    The function:

    /*********************************************************************
     * @fn      sendBindReq
     *
     * @brief   Sends a bind request to a remote device and to this device
     *
     * @param   (uses global dstAddr)
     *
     * @return  none
     */
    void sendBindReq( uint8 linkEP )
    {
      if ( linkMode == true ) 
      {
        uint8 outCome1, outCome2;
        zAddrType_t thisDeviceAddr;
        zAddrType_t otherDeviceAddr; 
        uint8 tempExtAddr[Z_EXTADDR_LEN];
        
        AddrMgrExtAddrLookup( remoteAddr.addr.shortAddr, tempExtAddr );
        
        osal_cpyExtAddr( (void *)&thisDeviceAddr.addr.extAddr, (void *)NLME_GetExtAddr() );
        thisDeviceAddr.addr.shortAddr = NLME_GetShortAddr();  //This line changes the last two bytes of the IEEE address to its own values!!
        thisDeviceAddr.addrMode = afAddr64Bit;
        
        osal_cpyExtAddr( (void *)&otherDeviceAddr.addr.extAddr, (void *)tempExtAddr );
        otherDeviceAddr.addr.shortAddr = remoteAddr.addr.shortAddr;   //This line changes the last two bytes of the IEEE address to its own values!!
        otherDeviceAddr.addrMode = afAddr64Bit;
        
        //Make entry into dstAddr's binding table ...
        outCome1 = ZDP_BindReq( &remoteAddr, tempExtAddr, linkEP,  
                                ZCL_CLUSTER_ID_GEN_ON_OFF, &thisDeviceAddr, LOADCONTROL_EP100_ENDPOINT, 0 );          
        
        //Make entry into local binding table ... 
        outCome2 = ZDP_BindReq( &otherDeviceAddr, tempExtAddr, linkEP, 
                                ZCL_CLUSTER_ID_GEN_ON_OFF, &thisDeviceAddr, LOADCONTROL_EP100_ENDPOINT, 0 );
        
        linkMode = false;
      }
    }

    The "Watch" window in IAR debugger BEFORE I manually edit the long address:

    Notice for "thisDeviceAddr" and "otherDeviceAddr", that the last two bytes of the long address match the two bytes of the short address, making the IEEE address incorrect.

    The "Watch" window in IAR debugger AFTER I manually edit the long address:

    Notice that after I change the last two bytes of the long address for both "thisDeviceAddr" and "otherDeviceAddr" to what they should be, the short address also changes to these two bytes on its own!
    I can see that the memory addresses of the short and long addresses are the same, surely this should not be the case?

  • shortAddr and extAddr share the same memory. If you set "thisDeviceAddr.addr.shortAddr = NLME_GetShortAddr();" after you get extAddr, it will be overwrite.
  • Thanks YiKai, 

    Yes I know the memory is shared, but surely it should not be sharing the memory? If we look at the definition in ZComDef.h they are separate variables, so they should have separate addresses in memory. Or did I miss something?

    typedef struct
    {
      union
      {
        uint16      shortAddr;
        ZLongAddr_t extAddr;
      } addr;
      byte addrMode;
    } zAddrType_t;

  • It's about C union. You can refer to en.wikipedia.org/.../Union_type.
  • Wait, it seems I didn't understand what a union was!

    Definition from www.tutorialspoint.com/.../c_unions.htm :
    "A union is a special data type available in C that allows to store different data types in the same memory location. You can define a union with many members, but only one member can contain a value at any given time. Unions provide an efficient way of using the same memory location for multiple-purpose. "
  • Yes, you get it now.
  • Ok thanks YiKai, up until now I didn't realize that Z-Stack only uses one address type at a time, I thought that in some cases it needed both. Anyway we live and learn! Thanks for your patience.

    When you have a moment, could you comment on the other issue regarding loadControlEP100_event_loop() and afIncomingMSGPacket_t.

    Thanks for all you help.
  • In "case ZDO_CB_MSG:", you should use zdoIncomingMsg_t to overlook MSGpkt not afIncomingMSGPacket_t.
  • Thanks YiKai, I would have used zdoIncomingMsg_t seeing as it has the "wasBroadcast" parameter, but there is no lqi or rssi or correlation parameter, so I can't get an idea for how close the transmitting device is to the receiving device.
  • You can only get LQI in "case AF_INCOMING_MSG_CMD:".
  • Thanks YiKai. That is unfortunate.
  • You are welcome.