I've seen this topic on this forum several times. I know SimpliciTi won't support this capability until v1.1.0 (unknown release date?). I suspect that plenty of people know how to do this and have done it, but besides Markus's guidelines, I haven't seen any other useful tips here. I'm making this post for two reasons: so people can learn from what I've done, and so the more knowledgeable may be able to warn me if I'm doing something "unsafe." Personally, I need to be able to unlink/relink devices because my network will evntually contain more end devices than the AP will be able to support at one time. I'll want to disconnect end devices from time to time, so that other end devices can link to the access point.
I was able to implement unlinking/relinking successfully with a v1.0.5 protocol that I ported to CCE. (v1.0.5? Yeah, I had trouble with the port of v1.0.6, but that's another topic) Anyways, I suspect that my methods will work with v1.0.6, but I have not tested that version. For my test setup, I had an AP acting as a data hub and one polling end device.
For the AP, The disconnection occurs in two basic steps.
1) nwk_freeConnection() is executed when you make a call to the api function SMPL_Ioctl(IOCTL_OBJ_CONNOBJ, IOCTL_ACT_DELETE, &lid);
2) nwk_freeConnection calls nwk_disconnect and nwk_QdiscardFrames
For the polling ED, I have it calling SMPL_Receive on a periodic basis. If the poll returns anything besides SMPL_SUCCESS or SMPL_NO_FRAME (as it will after the AP performs its disconnection routine), I know something is wrong with the connection. I have the end device attempt to reconnect by calling SMPL_Init to join and then SMPL_Link to link. Importantly, I make a call to the api function SMPL_Ioctl(IOCTL_OBJ_CONNOBJ, IOCTL_ACT_DELETE, &lid) to free the resources of the faulty connection before I attempt to reconnect.
In summary, the AP disconnects the end device at will, and then the end device can detect this and recover by forming a new connection. In the future, I will be disconnecting an end device to allow a different end device to connect to the access point.
If I had any one question for the more knowledgeable, it would be, is my function nwk_QdiscardFrames safe? I discard the store and forward frames for the removed end device in my AP's output queue by looping through the output queue and changing the fi_usage of the frames to FI_AVAILABLE. It seems to work...
Of course, if you see me doing something else that isn't particularly wise, I'd like to know.
And here's the important bits of my code:
Changes in nwk_join.c:
- Added nwk_disconnect function that removes an end device from sJoinedED and sSandFClients tables.
/******************************************************************************
* @fn nwk_disconnect
*
* @brief Disconnect ED by removing it from store and forward table and
* joined end devices table.
*
* input parameters
* @param address - address of device to remove
*
* output parameters
*
* @return void
*/
void nwk_disconnect(addr_t *addr)
{
uint8_t i, j;
/* Find address in sJoinedED, then shift remaining addresses down over the top of it. */
for (i = 0; i < NUM_CONNECTIONS; i++)
{
if (!memcmp(&sJoinedED[i].addr, addr, NET_ADDR_SIZE))
{
for (j = i; j < NUM_CONNECTIONS - 1; j++)
{
memcpy(&sJoinedED[j], &sJoinedED[j + 1], NET_ADDR_SIZE);
}
memcpy(&sJoinedED[j], 0, NET_ADDR_SIZE);
sNumJoined--;
}
}
/* Find address in sSandFClients, then shift remaining addresses down over the top of it. */
for (i = 0; i < NUM_STORE_AND_FWD_CLIENTS; i++)
{
if (!memcmp(&sSandFClients[i].addr, addr, NET_ADDR_SIZE))
{
for (j = i; j < NUM_STORE_AND_FWD_CLIENTS - 1; j++)
{
memcpy(&sSandFClients[j], &sSandFClients[j + 1], NET_ADDR_SIZE);
}
memcpy(&sSandFClients[j], 0, NET_ADDR_SIZE);
sCurNumSandFClients--;
}
}
}
Changes to nwk_QMgmt.c:
- Added nwk_QdiscardFrames to remove all store and forward frames from output queue destined for the removed end device.
/******************************************************************************
* @fn nwk_QdiscardFrames
*
* @brief Discard all the frames in the output queue corresponding to
* particular device address
*
* input parameters
* @param lid - dispose all frames destined for this device address
*/
void nwk_QdiscardFrames(addr_t *addr)
{
uint8_t i;
frameInfo_t *fiPtr = sOutFrameQ;
/* Loop through output queue and mark output frames being sent to particular device
* as available space in buffer */
for (i=0; i<SIZE_OUTFRAME_Q; ++i, fiPtr++)
{
if (FI_INUSE_UNTIL_FWD == fiPtr->fi_usage)
{
if (memcmp(MRFI_P_DST_ADDR(&fiPtr->mrfiPkt), addr, NET_ADDR_SIZE))
{
fiPtr->fi_usage = FI_AVAILABLE;
}
}
}
}
Changes to nwk.c:
- call nwk_disconnect and nwk_QdiscardFrames in nwk_freeConnection to remove connection from access point
/******************************************************************************
* @fn nwk_freeConnection
*
* @brief Return the connection structure to the free pool. Currently
* this routine is only called when a link freame is sent and
* no reply is received so the freeing steps are pretty simple.
* But eventually this will be more complex so this place-holder
* is introduced.
*
* input parameters
* @param pCInfo - pointer to entry to be freed
*
* output parameters
*
* @return None.
*/
void nwk_freeConnection(connInfo_t *pCInfo)
{
#if NUM_CONNECTIONS > 0
pCInfo->isValid = 0;
#ifdef ACCESS_POINT
/* Remove device from sSandFClients and sJoinedED in nwk_join.c */
nwk_disconnect((addr_t *)pCInfo->peerAddr);
/* Remove all frames from output queue for device. */
nwk_QdiscardFrames((addr_t *)pCInfo->peerAddr);
#endif
#endif
}