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.

NLME_DirectJoinRequestWithAddr() usage

Other Parts Discussed in Thread: Z-STACK

We have a Zigbee Pro system that has roaming, Reduced Function (RFD) end devices.  These devices are low power, battery powered devices that sleep most of the time with Data Requests to the router occurring about every 15 seconds.  

To prevent filling the association table on any one router device in the system, we have a mechanism that helps us know when we haven't had a Data Request from one of these devices in a while.

When we haven't heart from one of them in a while, we use NLME_LeaveReq() to kick it out of our list of associations, silently.

Occasionally, for reasons we don't completely understand, we start hearing data requests from one that we no longer have an association with.  We'd like to make the system more robust against this sort of thing.  To do that, we attempted to use NLME_DirectJoinRequestWithAddr() to add the end device back in.

When we have one that needs to be added back in, we only have the short address.  It's not clear how this function should be called when we don't have an extended address.  We attempted to use this as below:

ZLongAddr_t extAddr={0};
ZStatus_t zStatus;

zStatus = NLME_DirectJoinRequestWithAddr(extAddr, knownShortAddr, CAPINFO_DEVICETYPE_RFD);

The problem is that this worked only for the first value of knownShortAddr.  Subsequent calls to it did not return Zsuccess.

Is this function buggy?  What is it doing in there, perhaps matching the extAddr value we passed against something in the association table?  What is the correct way to use this to force an association back into the table?

  • how can you start hearing data requests from one that we no longer have an association with? If the device is not associated properly, you can't hear data request from it..

  • We get to the point where the end device is sending DR's with the router being associated with it through NLME_LeaveReq():

    NLME_LeaveReq_t req = {0};

    req.extAddr = extAddr;

    req.silent = TRUE;

    NLME_LeaveReq( &req );

    Apparently we do this some time when we shouldn't, but the answer to why that is isn't important.  I want to restore the association when I see that it's not there anymore but probably should be.

  • Which stack version are you using? If you use ZStack-Home-1.2.x you can use the ZIGBEE_CHILD_AGING feature to support what you are trying to achieve.

    By setting the following in nwk_globals.h:

    #define KEEPALIVE_TIMEOUT_MAX     1    // Maximum Keepalive time in Minutes

    If children do not poll for 1 minute they will be aged out of the child table. Other mechanisms ensure that issues with child and parent being out of sync are resolved. I advise that you use the mechanism implemented in ZStack-Home-1.2.0, child aging has many corner cases where things can go wrong and trying to solve this in the application layer could be complex. 

    Regards, TC.

  • We had worked around this problem but it looks like it's causing a different problem when it occurs.

    This application is using Zstack version 2.5.1a.  The product is not trying to achieve any particular kind of ZigBee compliance and has some features that have to integrate with existing practices used on the legacy system.

    At this point, changing stack versions is not an option we're willing to consider unless someone from TI is willing to walk us through what all of the difference would be for our application.

    To repeat the original description of the problem: For what ever reason, some end devices think they are associated with a router.  Other code we have added to mac_tx.c sees the Data Requests and reports their short addresses to our coordinator/server.  The non-associated association seems to occur during some extremely high traffic that can occur in this system. It may become un-associated due to our application code or due to some other action within z-stack.

    In either case, we need to be able to correct the situation.  It seems like the correct way to do this when we know the short address is to use the NLME_DirectJoinRequestWithAddr() call to stick this one in our association table so that we can then send traffic back towards it.  Alternately, telling it to do a rejoin would solve the problem but there's no apparent way to do that unless we can get packets to that end device.

    Could someone answer my original question?  Why can we only get "success" back to a call to this function on the very first call?  Is there something that should be called or waited for afterward?  Is there some piece of z-stack that needs to be enabled to make this work?

    So far, we've gotten exactly zero solutions to the problems we've encountered using z-stack and posted here.  The best we have so far is one work around.

  • Can you confirm that you are calling NLME_DirectJoinRequestWithAddr() on the router (which was previous parent)?

    When it fails what is the error code? is it ZNwkAlreadyPresent, ZNwkTableFull or ZMemError?

    Can you call AssocRemove first? This will hopefully mean it can not fail with any of the above codes.

    However, I do not think forcing the device back into the parents association table is the correct fix. 

    Did the child not receive MAC Acks and Orphan? 

    You mention in a previous post:

    Andy Alexander said:
    We get to the point where the end device is sending DR's with the router being associated with it through NLME_LeaveReq():

    NLME_LeaveReq_t req = {0};

    req.extAddr = extAddr;

    req.silent = TRUE;

    NLME_LeaveReq( &req );

    Apparently we do this some time when we shouldn't, but the answer to why that is isn't important.  I want to restore the association when I see that it's not there anymore but probably should be.

    did you try it with req.rejoin=true?

    In ZigBee Light Link we have a critical use case where a deep sleeping lighting remote/switch wakes to turn on a light, we have know idea how long the remote has slept and if its parent is still around, but we must insure that the connection is reestablished even though we do not know if it is lost. We use the following function call each time we wake, this may be useful for you to try when you get into your issue:

    static void initiatorReJoinNwk( devStartModes_t startMode )
    {
      // Set NWK task to run
      nwk_setStateIdle( FALSE );
    
      // Set our short address
      ZMacSetReq( ZMacShortAddress, (byte*)&_NIB.nwkDevAddress);
    
      // Set our PAN ID
      ZMacSetReq( ZMacPanId, (byte*)&_NIB.nwkPanId);
    
     ZMacSetReq( ZMacChannel, &_NIB.nwkLogicalChannel);
    
      // Use the new network paramters
      zgConfigPANID = _NIB.nwkPanId;
      zgDefaultChannelList = _NIB.channelList;
      osal_cpyExtAddr( ZDO_UseExtendedPANID, _NIB.extendedPANID );
    
      devStartMode = MODE_RESUME;
    
      _tmpRejoinState = TRUE;
    
      // Start the network joining process
      osal_set_event( ZDAppTaskID, ZDO_NETWORK_INIT );
    }
    

    I think you would only need this:

      devStartMode = MODE_RESUME;
    
      _tmpRejoinState = TRUE;
    
      // Start the network joining process
      osal_set_event( ZDAppTaskID, ZDO_NETWORK_INIT );

    Regards, TC.