After playing around with Z-Stack samples, SerialApp and TransmitApp, I tried to combine these two sample applications to setup a template for my project.
In the beginning, I thought it's an easy work which can be done within one or two days. However, it actually took me almost TWO WEEKS to work, because the original samples doesn't fit in multiple endpoints scheme.
I used SerialApp as the basis and added TransmitApp (in fact, only TransmitApp.c and TransmitApp.h) in.
1. Follow "Create New Application For SmartRF05 + CC2530"(SWRA231) to create a new project based on SerialApp. In my case, the project name is OH6A.
2. Changes in OSAL_OH6A.c are:
- adding TransmitApp to the task array "tasksArr"
const pTaskEventHandlerFn tasksArr[] = {
macEventLoop,
nwk_event_loop,
Hal_ProcessEvent,
#if defined( MT_TASK )
MT_ProcessEvent,
#endif
APS_event_loop,
#if defined ( ZIGBEE_FRAGMENTATION )
APSF_ProcessEvent,
#endif
ZDApp_event_loop,
#if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )
ZDNwkMgr_event_loop,
#endif
SerialApp_ProcessEvent,
TransmitApp_ProcessEvent
};
- Invoking TransmitApp_Init() in the function "void osalInitTasks( void )"
3. I wish to use the same binding behavior as samples, thus, the key handlers has to be extend to accommodate multiple tasks
in onboard.c
- change registeredKeysTaskID to uint8 array
uint8 registeredKeysTaskID[REGISTER_KEY_TASK_NUM_MAX];
- modify RegisterForKeys() to allow multiple tasks to register to
uint8 RegisterForKeys( uint8 task_id )
{
char i;
for(i = 0; i < REGISTER_KEY_TASK_NUM_MAX; i++)
{
if(registeredKeysTaskID[i] == NO_TASK_ID)
{ registeredKeysTaskID[i] = task_id;
break;
}
}
if(i < REGISTER_KEY_TASK_NUM_MAX)
return (TRUE);
else
return (FALSE);
}
- modify OnBoard_SendKeys to send the key press event to all registered tasks
uint8 OnBoard_SendKeys( uint8 keys, uint8 state )
{
keyChange_t *msgPtr;
char i;
for(i = 0; (i < REGISTER_KEY_TASK_NUM_MAX) && (registeredKeysTaskID[i] != NO_TASK_ID); i++)
{
// Send the address to the task
msgPtr = (keyChange_t *)osal_msg_allocate( sizeof(keyChange_t) );
if ( msgPtr )
{
msgPtr->hdr.event = KEY_CHANGE;
msgPtr->state = state;
msgPtr->keys = keys;
osal_msg_send( registeredKeysTaskID[i], (uint8 *)msgPtr );
}
else
{
return ( ZFailure );
}
}
return ( ZSuccess );
}
- (OPTIONAL) I disabled SW2 (End_Device_Bind) in both SerialApp_HandleKeys()@SerialApp.c and TransmitApp_HandleKeys()@TransmitApp.c, since "One of the things I don’t like about this command is that if it returns success, the caller has no idea if the targets were bound or unbound. It’s a toggle!", quoted from Zigbee Wireless Networking, CH, Drew Gislason. (Don't know why "toggle" though but it's not the point in this experiment)
- (OPTIONAL) compile option "RFD_RCVC_ALWAYS_ON=TRUE" is added to preprocessor.
OK, it only took me a while to finish those steps above and I *THOUGHT* this experiment can be done by end of that day. It's NOT. TransmitApp seems working but apparently SerialApp doesn't.
After spending many day and night debugging, I found that the root cause is when processing
Match_Desc_rsp @SerialApp_ProcessZDOMsgs( zdoIncomingMsg_t *inMsg )@SerialApp.c, the
SerialApp_TxAddr.endPoint was assigned incorrect (actually, overwritten by the endpoint of TransmitApp).
In
SerialApp_Init( uint8 task_id ),
Match_Desc_rsp event was registered by
ZDO_RegisterForZDOMsg( SerialApp_TaskID, Match_Desc_rsp ). However, the callback/dispatch function,
handled = ZDO_SendMsgCBs( &inMsg )@ZDProfile.c is blindly dispatch ALL
Match_Desc_rsp message to ALL registered task. Z-Stack should have dealt with matching Match_Desc_req with corresponding Match_desc_rsp, before sending back to registered task.
4. To quickly fix this problem (not graceful, but I don't want to modify Z-Stack anyway), in both SerialApp.c and TransmitApp.c, I tried to keep track of APS "Transaction sequence number" when sending
Match_Desc_req and check the stored data when receiving
Match_Desc_rsp. Fortunately OSAL is not preemptive so it can work.
Take TransmitApp as example, in TransmitApp.c:
- adding global "byte TransmitApp_ZDP_TransID;" to store TransID
- in function TransmitApp_HandleKeys(), saving global variable ZDP_TransID which is used by
HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );
// Initiate a Match Description Request (Service Discovery)
dstAddr.addrMode = AddrBroadcast;
dstAddr.addr.shortAddr = NWK_BROADCAST_SHORTADDR;
TransmitApp_ZDP_TransID = ZDP_TransID; ZDP_MatchDescReq( &dstAddr, NWK_BROADCAST_SHORTADDR,
TRANSMITAPP_PROFID,
TRANSMITAPP_MAX_CLUSTERS, (cId_t *)TransmitApp_ClusterList,
TRANSMITAPP_MAX_CLUSTERS, (cId_t *)TransmitApp_ClusterList,
FALSE );
- in function TransmitApp_ProcessZDOMsgs(), checking the TransSeq within incoming msg with the stored TransID.
case Match_Desc_rsp:
{
ZDO_ActiveEndpointRsp_t *pRsp = ZDO_ParseEPListRsp( inMsg );
if ( pRsp )
{
if(TransmitApp_ZDP_TransID == inMsg->TransSeq)
if ( pRsp->status == ZSuccess && pRsp->cnt )
{
TransmitApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
TransmitApp_DstAddr.addr.shortAddr = pRsp->nwkAddr;
// Take the first endpoint, Can be changed to search through endpoints
TransmitApp_DstAddr.endPoint = pRsp->epList[0];
// Light LED
HalLedSet( HAL_LED_4, HAL_LED_MODE_ON );
}
osal_mem_free( pRsp );
}
}
break;
After those change, I can finally get two endpoints work on the same ZigBee device, based on IT's Z-stack.